Esempio n. 1
0
    def _key_press_cb(self, widget, event):
        """App-wide keypress handler for toplevel windows."""

        # If an input widget has focus - their key handling is prioritized.
        consumed = widget.propagate_key_event(event)
        if consumed:
            return True
        if not self.enabled:
            return
        # See gtk sourcecode in gtkmenu.c function gtk_menu_key_press,
        # which uses the same code as below when changing an accelerator.
        keymap = Gdk.Keymap.get_default()

        # Instead of using event.keyval, we do it the lowlevel way.
        # Reason: ignoring CAPSLOCK and checking if SHIFT was pressed
        state = Gdk.ModifierType(event.state & ~Gdk.ModifierType.LOCK_MASK)
        res = keymap.translate_keyboard_state(event.hardware_keycode, state,
                                              event.group)
        if not res:
            # PyGTK returns None when gdk_keymap_translate_keyboard_state()
            # returns false.  Not sure if this is a bug or a feature - the only
            # time I have seen this happen is when I put my laptop into sleep
            # mode.
            logger.warning('translate_keyboard_state() returned None. '
                           'Strange key pressed?')
            return

        keyval = res[1]
        consumed_modifiers = res[4]

        # We want to ignore irrelevant modifiers like ScrollLock.  The stored
        # key binding does not include modifiers that affected its keyval.
        modifiers = (event.state
                     & Gtk.accelerator_get_default_mod_mask()
                     & ~consumed_modifiers)

        # Except that key bindings are always stored in lowercase.
        keyval_lower = Gdk.keyval_to_lower(keyval)
        if keyval_lower != keyval:
            modifiers |= Gdk.ModifierType.SHIFT_MASK
        action = self.keymap.get((keyval_lower, modifiers))
        if not action and not self.fallbacks_disabled():
            # try hardcoded keys
            action = self.keymap2.get((keyval_lower, modifiers))

        # Don't dispatch if the window is only sensitive to a subset of
        # actions, and the action is not in that set.
        if action is not None and isinstance(action, Gtk.Action):
            win_actions = self.window_actions.get(widget, None)
            if win_actions is not None:
                if action.get_name() not in win_actions:
                    return False

        # If the lookup succeeded, activate the corresponding action.
        if action:
            return self.activate_keydown_event(action, event)

        # Otherwise, dispatch the event to the active doc.
        return self._dispatch_fallthru_key_press_event(widget, event)
Esempio n. 2
0
def translate(hardware_keycode, state, group):
    # We may need to retry several times to deal with garbled text.

    keymap = Gdk.Keymap.get_default()

    # distinct
    it = list(set([group, 0, 1, 2]))

    ok_to_return = False
    keyval = None
    keyval_lower = None

    for g in it:
        res = keymap.translate_keyboard_state(hardware_keycode,
                                              Gdk.ModifierType(0), g)

        if not res:
            # PyGTK returns None when gdk_keymap_translate_keyboard_state()
            # returns false.  Not sure if this is a bug or a feature - the only
            # time I have seen this happen is when I put my laptop into sleep
            # mode.

            continue

        keyval = res[1]

        # consumed_modifiers = res[4]

        lbl = Gtk.accelerator_get_label(keyval, state)

        if is_ascii(lbl):
            ok_to_return = True
            break

    if not ok_to_return:
        logger.warning(
            'translate_keyboard_state() returned no valid response. '
            'Strange key pressed?')

        return None, None, None, None

    # We want to ignore irrelevant modifiers like ScrollLock.  The stored
    # key binding does not include modifiers that affected its keyval.
    mods = Gdk.ModifierType(state & Gtk.accelerator_get_default_mod_mask())

    keyval_lower = Gdk.keyval_to_lower(keyval)

    # If lowercasing affects the keysym, then we need to include
    # SHIFT in the modifiers. We re-upper case when we match against
    # the keyval, but display and save in caseless form.
    if keyval != keyval_lower:
        mods |= Gdk.ModifierType.SHIFT_MASK

    # So we get (<Shift>j, Shift+J) but just (plus, +). As I
    # understand it.

    accel_label = Gtk.accelerator_get_label(keyval_lower, mods)

    return keyval, keyval_lower, accel_label, mods
Esempio n. 3
0
    def _key_press_cb(self, widget, event):
        """App-wide keypress handler for toplevel windows."""

        # If an input widget has focus - their key handling is prioritized.
        consumed = widget.propagate_key_event(event)
        if consumed:
            return True
        if not self.enabled:
            return

        # Instead of using event.keyval, we do it the lowlevel way.
        # Reason: ignoring CAPSLOCK and checking if SHIFT was pressed
        keyval, keyval_lower, accel_label, modifiers = kb.translate(
            event.hardware_keycode, event.state, event.group)

        if not keyval:
            return

        # Except that key bindings are always stored in lowercase.
        keyval_lower = Gdk.keyval_to_lower(keyval)
        if keyval_lower != keyval:
            modifiers |= Gdk.ModifierType.SHIFT_MASK
        action = self.keymap.get((keyval_lower, modifiers))
        if not action and not self.fallbacks_disabled():
            # try hardcoded keys
            action = self.keymap2.get((keyval_lower, modifiers))

        # Don't dispatch if the window is only sensitive to a subset of
        # actions, and the action is not in that set.
        if action is not None and isinstance(action, Gtk.Action):
            win_actions = self.window_actions.get(widget, None)
            if win_actions is not None:
                if action.get_name() not in win_actions:
                    return False

        # If the lookup succeeded, activate the corresponding action.
        if action:
            return self.activate_keydown_event(action, event)

        # Otherwise, dispatch the event to the active doc.
        return self._dispatch_fallthru_key_press_event(widget, event)
    def _edit_dialog_key_press_cb(self, dialog, event, editable):
        if event.type != Gdk.EventType.KEY_PRESS:
            return False
        if event.is_modifier:
            return False
        if self._USE_NORMAL_DIALOG_KEYS:
            if event.keyval == Gdk.KEY_Return:
                dialog.response(Gtk.ResponseType.OK)
                return True
            elif event.keyval == Gdk.KEY_Escape:
                dialog.response(Gtk.ResponseType.CANCEL)
                return True
            elif event.keyval == Gdk.KEY_BackSpace:
                dialog.response(Gtk.ResponseType.REJECT)
                return True

        # Stolen from GTK 2.24's gtk/gtkmenu.c (gtk_menu_key_press())
        # Figure out what modifiers went into determining the key symbol
        keymap = Gdk.Keymap.get_default()
        bound, keyval, effective_group, level, consumed_modifiers = (
            keymap.translate_keyboard_state(
                event.hardware_keycode,
                event.state,
                # https://github.com/mypaint/mypaint/issues/974
                # event.group
                1))
        keyval = Gdk.keyval_to_lower(keyval)
        mods = Gdk.ModifierType(event.state
                                & Gtk.accelerator_get_default_mod_mask()
                                & ~consumed_modifiers)

        # If lowercasing affects the keysym, then we need to include
        # SHIFT in the modifiers. We re-upper case when we match against
        # the keyval, but display and save in caseless form.
        if keyval != event.keyval:
            mods |= Gdk.ModifierType.SHIFT_MASK
        accel_label = Gtk.accelerator_get_label(keyval, mods)
        # So we get (<Shift>j, Shift+J) but just (plus, +). As I
        # understand it.

        # This is rejecting some legit key combinations such as the
        # arrowkeys, so I had to remove it...
        #   if not Gtk.accelerator_valid(keyval, mods)
        #       return True

        clash_accel_path = None
        clash_action_label = None
        for path, kv, m, changed in self._get_accel_map_entries():
            if (kv, m) == (keyval, mods):
                clash_accel_path = path
                clash_action_label = _udecode(
                    self._action_labels.get(
                        clash_accel_path,
                        # TRANSLATORS: Part of the keybinding dialog, refers
                        # TRANSLATORS: to an action bound to a key combination.
                        _(u"Unknown Action"),
                    ))
                break
        if clash_accel_path == dialog.accel_path:  # no change
            self._edit_dialog_set_standard_hint(dialog)
            label = str(accel_label)
            dialog.accel_label_widget.set_text(label)
        elif clash_accel_path:
            markup_tmpl = _(
                # TRANSLATORS: Warning message when attempting to assign a
                # TRANSLATORS: keyboard combination that is already used.
                u"<b>{accel} is already in use for '{action}'. "
                u"The existing assignment will be replaced.</b>")
            markup = markup_tmpl.format(
                accel=lib.xml.escape(accel_label),
                action=lib.xml.escape(clash_action_label),
            )
            self._edit_dialog_set_hint(dialog, markup)
            label = u"%s (replace)" % (accel_label, )
            dialog.accel_label_widget.set_text(str(label))
        else:
            self._edit_dialog_set_standard_hint(dialog)
            label = u"%s (changed)" % (accel_label, )
            dialog.accel_label_widget.set_text(label)
        dialog.result_mods = mods
        dialog.result_keyval = keyval
        return True