xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #567: modifiers-ignore.patch

File modifiers-ignore.patch, 21.8 KB (added by Antoine Martin, 7 years ago)

work in progress patch so each keyboard implementation can specify which modifiers should be ignored and when

  • xpra/client/client_window_base.py

     
    308308        #see UIXpraClient.dbus_call
    309309        return self._client.dbus_call(self._id, *args, **kwargs)
    310310
     311
     312    def send_mouse_packet(self, *packet):
     313        if self._client.mouse_modignore:
     314            #add list of "modifiers to ignore" to packet:
     315            packet = list(packet) + [self._client.get_modifiers_ignore(keyboard_event=False)]
     316            mouselog("mouse packet, added modignore: %s", packet[-1])
     317        self._client.send_positional(*packet)
     318
    311319    def do_motion_notify_event(self, event):
    312320        if self._client.readonly:
    313321            return
    314322        pointer, modifiers, buttons = self._pointer_modifiers(event)
    315323        mouselog("do_motion_notify_event(%s) wid=%s, pointer=%s, modifiers=%s, buttons=%s", event, self._id, pointer, modifiers, buttons)
    316         self._client.send_mouse_position(["pointer-position", self._id,
    317                                           pointer, modifiers, buttons])
     324        self.send_mouse_packet("pointer-position", self._id, pointer, modifiers, buttons)
    318325
    319326    def _button_action(self, button, event, depressed):
    320327        if self._client.readonly:
     
    322329        pointer, modifiers, buttons = self._pointer_modifiers(event)
    323330        mouselog("_button_action(%s, %s, %s) wid=%s, pointer=%s, modifiers=%s, buttons=%s", button, event, depressed, self._id, pointer, modifiers, buttons)
    324331        def send_button(pressed):
    325             self._client.send_positional(["button-action", self._id,
    326                                           button, pressed,
    327                                           pointer, modifiers, buttons])
     332            self.send_mouse_packet("button-action", self._id, button, pressed,
     333                                          pointer, modifiers, buttons)
    328334        pressed_state = self.button_state.get(button, False)
    329335        if pressed_state is False and depressed is False:
    330336            mouselog("button action: simulating a missing mouse-down event for window %s before sending the mouse-up event", self._id)
  • xpra/client/keyboard_helper.py

     
    175175        """
    176176        if self.key_handled_as_shortcut(window, key_event.keyname, key_event.modifiers, key_event.pressed):
    177177            return
    178         self.keyboard.process_key_event(self.send_key_action, wid, key_event)
     178        self.keyboard.process_key_event(self.send_key_action, wid, key_event, keyboard_event=True)
    179179
    180     def send_key_action(self, wid, key_event):
     180    def send_key_action(self, wid, key_event, keyboard_event=False):
    181181        log("send_key_action(%s, %s)", wid, key_event)
    182182        packet = ["key-action", wid]
    183183        for x in ("keyname", "pressed", "modifiers", "keyval", "string", "keycode", "group"):
    184184            packet.append(getattr(key_event, x))
     185        #we should check the client "modignore" flag here..
     186        packet.append(self.keyboard.get_modifiers_ignore(keyboard_event=keyboard_event))
    185187        self.send(*packet)
    186188        if self.keyboard_sync and self.key_repeat_delay>0 and self.key_repeat_interval>0:
    187189            self._key_repeat(key_event)
     
    213215            log("scheduling key repeat for %s: delay=%s, interval=%s (from %s and %s)", keyname, delay, interval, self.key_repeat_delay, self.key_repeat_interval)
    214216            def send_key_repeat():
    215217                modifiers = self.get_current_modifiers()
    216                 self.send_now("key-repeat", wid, keyname, keyval, keycode, modifiers)
     218                modignore = self.keyboard.get_modifiers_ignore(keyboard_event=False)
     219                self.send_now("key-repeat", wid, keyname, keyval, keycode, modifiers, modignore)
    217220            def continue_key_repeat(*args):
    218221                #if the key is still pressed (redundant check?)
    219222                #confirm it and continue, otherwise stop
  • xpra/client/ui_client_base.py

     
    159159        self.opengl_props = {}
    160160        self.toggle_cursors_bell_notify = False
    161161        self.toggle_keyboard_sync = False
     162        self.mouse_modignore = False
    162163        self.force_ungrab = False
    163164        self.window_unmap = False
    164165        self.window_refresh_config = False
     
    702703            return []
    703704        return self.keyboard_helper.mask_to_names(mask)
    704705
     706    def get_modifiers_ignore(self, *args, **kwargs):
     707        if self.keyboard_helper and self.keyboard_helper.keyboard:
     708            return self.keyboard_helper.keyboard.get_modifiers_ignore(*args, **kwargs)
     709        return []
    705710
     711
    706712    def set_default_window_icon(self, window_icon):
    707713        if not window_icon:
    708714            window_icon = self.get_icon_filename("xpra.png")
     
    715721
    716722    def send_focus(self, wid):
    717723        focuslog("send_focus(%s)", wid)
    718         self.send("focus", wid, self.get_current_modifiers())
     724        packet = ["focus", wid, self.get_current_modifiers()]
     725        if self._client.mouse_modignore:
     726            #add list of "modifiers to ignore" to packet:
     727            packet.append(self.get_modifiers_ignore(keyboard_event=False))
     728        self.send(*packet)
    719729
    720730    def update_focus(self, wid, gotit):
    721731        focuslog("update_focus(%s, %s) focused=%s, grabbed=%s", wid, gotit, self._focused, self._window_with_grab)
     
    11861196        self.server_platform = c.strget("platform")
    11871197        self.toggle_cursors_bell_notify = c.boolget("toggle_cursors_bell_notify")
    11881198        self.toggle_keyboard_sync = c.boolget("toggle_keyboard_sync")
     1199        self.mouse_modignore = c.boolget("mouse_modignore")
    11891200
    11901201        self.server_display = c.strget("display")
    11911202        self.server_max_desktop_size = c.intpair("max_desktop_size")
  • xpra/platform/darwin/keyboard.py

     
    55# later version. See the file COPYING for details.
    66
    77
    8 import gtk.gdk
     8from xpra.gtk_common.gtk_util import META_MASK
    99from xpra.platform.keyboard_base import KeyboardBase, log
    1010from xpra.platform.darwin.osx_menu import getOSXMenuHelper
    1111
     
    4747                self.key_translations[orig_keysym] = new_def
    4848        log("set_modifier_mappings(..) swap keys translations=%s", self.key_translations)
    4949
     50    def get_modifiers_ignore(self, *args, **kwargs):
     51        #override here so we can tell the server to ignore
     52        #a missing "control" modifier when swap keys is on:
     53        #(that's because META_MASK is not set when Meta is pressed...)
     54        #but it is set from the keyboard events (go figure)
     55        if self.swap_keys and not kwargs.get("keyboard_event", False):
     56            return ["control"]
     57        return []
     58
    5059    def find_translation(self, orig_keysym):
    5160        new_def = None
    5261        #ie: keysyms : ["Meta_L", "Alt_L"]
     
    7685    def mask_to_names(self, mask):
    7786        names = KeyboardBase.mask_to_names(self, mask)
    7887        if self.swap_keys and self.meta_modifier is not None and self.control_modifier is not None:
    79             meta_on = bool(mask & gtk.gdk.META_MASK)
     88            meta_on = bool(mask & META_MASK)
    8089            meta_set = self.meta_modifier in names
    8190            control_set = self.control_modifier in names
    8291            log("mask_to_names names=%s, meta_on=%s, meta_set=%s, control_set=%s", names, meta_on, meta_set, control_set)
  • xpra/platform/darwin/shadow_server.py

     
    8181    def makeRootWindowModel(self):
    8282        return  OSXRootWindowModel(self.root)
    8383
    84     def _process_mouse_common(self, proto, wid, pointer, modifiers):
     84    def _process_mouse_common(self, proto, wid, pointer, modifiers, modignore):
    8585        CG.CGWarpMouseCursorPosition(pointer)
    8686
    8787    def get_keycode(self, ss, client_keycode, keyname, modifiers):
  • xpra/platform/keyboard_base.py

     
    5050        """
    5151        return  {}, [], ["lock"]
    5252
     53    def get_modifiers_ignore(self, *args, **kwargs):
     54        return []
     55
    5356    def get_keymap_spec(self):
    5457        return "", ""
    5558
  • xpra/platform/win32/keyboard_config.py

     
    3333        log("get_keycode%s=%s", (client_keycode, keyname, modifiers), keycode)
    3434        return keycode
    3535
    36     def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None):
    37         log("make_keymask_match%s", (modifier_list, ignored_modifier_keycode, ignored_modifier_keynames))
     36    def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None, ignored_modifiers=None):
     37        log("make_keymask_match%s", (modifier_list, ignored_modifier_keycode, ignored_modifier_keynames, ignored_modifiers))
    3838        mods = self.get_modifiers_state()
    3939        log("modifiers_state=%s", mods)
    4040        log("GetKeyboardState=%s", [int(x!=0) for x in win32api.GetKeyboardState()])
  • xpra/platform/win32/shadow_server.py

     
    3737    def makeRootWindowModel(self):
    3838        return GTKRootWindowModel(self.root)
    3939
    40     def _process_mouse_common(self, proto, wid, pointer, modifiers):
     40    def _process_mouse_common(self, proto, wid, pointer, modifiers, modignore):
    4141        #adjust pointer position for offset in client:
    4242        x, y = pointer
    4343        wx, wy = self.mapped_at[:2]
     
    6464
    6565    def _process_button_action(self, proto, packet):
    6666        wid, button, pressed, pointer, modifiers = packet[1:6]
    67         self._process_mouse_common(proto, wid, pointer, modifiers)
     67        modignore = []
     68        if len(packet)>=7:
     69            modignore = packet[6]
     70        self._process_mouse_common(proto, wid, pointer, modifiers, modignore)
    6871        self._server_sources.get(proto).user_event()
    6972        event = BUTTON_EVENTS.get((button, pressed))
    7073        if event is None:
  • xpra/server/gtk_server_base.py

     
    126126        display = gtk.gdk.display_get_default()
    127127        display.warp_pointer(display.get_default_screen(), x, y)
    128128
    129     def _process_mouse_common(self, proto, wid, pointer, modifiers):
     129    def _process_mouse_common(self, *args):
    130130        pass
    131131
    132132    def _process_button_action(self, proto, packet):
  • xpra/server/keyboard_config_base.py

     
    4040    def set_default_keymap(self):
    4141        pass
    4242
    43     def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None):
     43    def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None, ignored_modifiers=None):
    4444        pass
    4545
    4646    def get_keycode(self, client_keycode, keyname, modifiers):
  • xpra/server/server_base.py

     
    10551055        pass
    10561056
    10571057
    1058     def _focus(self, server_source, wid, modifiers):
    1059         focuslog("_focus(%s,%s)", wid, modifiers)
     1058    def _focus(self, server_source, wid, modifiers, modignore):
     1059        focuslog("_focus(%s, %s, %s)", wid, modifiers, modignore)
    10601060
    10611061    def get_focus(self):
    10621062        #can be overriden by subclasses that do manage focus
     
    13141314    def _process_focus(self, proto, packet):
    13151315        wid = packet[1]
    13161316        focuslog("process_focus: wid=%s", wid)
     1317        modifiers, modignore = None, None
    13171318        if len(packet)>=3:
    13181319            modifiers = packet[2]
    1319         else:
    1320             modifiers = None
     1320        if len(packet)>=4:
     1321            modignore = packet[3]
    13211322        ss = self._server_sources.get(proto)
    13221323        if ss:
    1323             self._focus(ss, wid, modifiers)
     1324            self._focus(ss, wid, modifiers, modignore)
    13241325
    13251326    def _process_layout(self, proto, packet):
    13261327        layout, variant = packet[1:3]
     
    13421343        ss.make_keymask_match(modifiers)
    13431344
    13441345    def _process_key_action(self, proto, packet):
    1345         wid, keyname, pressed, modifiers, keyval, _, client_keycode = packet[1:8]
    13461346        ss = self._server_sources.get(proto)
    13471347        if ss is None:
    13481348            return
     1349        wid, keyname, pressed, modifiers, keyval, _, client_keycode = packet[1:8]
     1350        modignore = None
     1351        if len(packet)>=9:
     1352            modignore = packet[8]
    13491353        keycode = self.get_keycode(ss, client_keycode, keyname, modifiers)
    13501354        log("process_key_action(%s) server keycode=%s", packet, keycode)
    13511355        #currently unused: (group, is_modifier) = packet[8:10]
    13521356        self._focus(ss, wid, None)
    1353         ss.make_keymask_match(modifiers, keycode, ignored_modifier_keynames=[keyname])
     1357        ss.make_keymask_match(modifiers, keycode, ignored_modifier_keynames=[keyname], ignored_modifiers=modignore)
    13541358        #negative keycodes are used for key events without a real keypress/unpress
    13551359        #for example, used by win32 to send Caps_Lock/Num_Lock changes
    13561360        if keycode>0:
     
    14271431            self.keys_repeat_timers[keycode] = self.timeout_add(delay_ms, _key_repeat_timeout, now)
    14281432
    14291433    def _process_key_repeat(self, proto, packet):
    1430         wid, keyname, keyval, client_keycode, modifiers = packet[1:6]
    14311434        ss = self._server_sources.get(proto)
    14321435        if ss is None:
    14331436            return
     1437        wid, keyname, keyval, client_keycode, modifiers = packet[1:6]
     1438        modignore = None
     1439        if len(packet)>=9:
     1440            modignore = packet[8]
    14341441        keycode = ss.get_keycode(client_keycode, keyname, modifiers)
    14351442        #key repeat uses modifiers from a pointer event, so ignore mod_pointermissing:
    1436         ss.make_keymask_match(modifiers)
     1443        ss.make_keymask_match(modifiers, ignored_modifiers=modignore)
    14371444        if not self.keyboard_sync:
    14381445            #this check should be redundant: clients should not send key-repeat without
    14391446            #having keyboard_sync enabled
     
    14561463    def _move_pointer(self, wid, pos):
    14571464        raise NotImplementedError()
    14581465
    1459     def _process_mouse_common(self, proto, wid, pointer, modifiers):
     1466    def _process_mouse_common(self, proto, wid, pointer, modifiers, modignore):
    14601467        pass
    14611468
    14621469    def _process_button_action(self, proto, packet):
     
    14641471
    14651472    def _process_pointer_position(self, proto, packet):
    14661473        wid, pointer, modifiers = packet[1:4]
    1467         self._process_mouse_common(proto, wid, pointer, modifiers)
     1474        modignore = []
     1475        if len(packet)>=5:
     1476            modignore = packet[4]
     1477        self._process_mouse_common(proto, wid, pointer, modifiers, modignore)
    14681478
    14691479
    14701480    def _process_damage_sequence(self, proto, packet):
  • xpra/server/source.py

     
    866866            self.keyboard_config.compute_modifier_keynames()
    867867        keylog("keys_changed() updated keyboard config=%s", self.keyboard_config)
    868868
    869     def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None):
     869    def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None, ignored_modifiers=None):
    870870        if self.keyboard_config and self.keyboard_config.enabled:
    871             self.keyboard_config.make_keymask_match(modifier_list, ignored_modifier_keycode, ignored_modifier_keynames)
     871            self.keyboard_config.make_keymask_match(modifier_list, ignored_modifier_keycode, ignored_modifier_keynames, ignored_modifiers)
    872872
    873873    def set_default_keymap(self):
    874874        keylog("set_default_keymap() keyboard_config=%s", self.keyboard_config)
  • xpra/x11/server.py

     
    530530
    531531
    532532
    533     def _focus(self, server_source, wid, modifiers):
     533    def _focus(self, server_source, wid, modifiers, modignore):
    534534        focuslog("focus wid=%s has_focus=%s", wid, self._has_focus)
    535535        if self._has_focus==wid:
    536536            #nothing to do!
     
    568568        gobject.idle_add(give_focus)
    569569        if server_source and modifiers is not None:
    570570            focuslog("focus: will set modified mask to %s", modifiers)
    571             server_source.make_keymask_match(modifiers)
     571            server_source.make_keymask_match(modifiers, ignored_modifiers=modignore)
    572572        self._has_focus = wid
    573573
    574574    def get_focus(self):
  • xpra/x11/server_keyboard_config.py

     
    298298        _, _, current_mask = gtk.gdk.get_default_root_window().get_pointer()
    299299        return mask_to_names(current_mask, self.modifier_map)
    300300
    301     def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None):
     301    def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None, ignored_modifiers=None):
    302302        """
    303303            Given a list of modifiers that should be set, try to press the right keys
    304304            to make the server's modifier list match it.
     
    335335
    336336        current = set(self.get_current_mask())
    337337        wanted = set(modifier_list)
     338        if ignored_modifiers:
     339            current -= set(ignored_modifiers)
     340            wanted -= set(ignored_modifiers)
    338341        if current==wanted:
    339342            return
    340         log("make_keymask_match(%s) current mask: %s, wanted: %s, ignoring=%s/%s, keys_pressed=%s", modifier_list, current, wanted, ignored_modifier_keycode, ignored_modifier_keynames, self.keys_pressed)
     343        log("make_keymask_match(%s) current mask: %s, wanted: %s, ignoring=%s/%s/%s, keys_pressed=%s", modifier_list, current, wanted, ignored_modifier_keycode, ignored_modifier_keynames, ignored_modifiers, self.keys_pressed)
    341344
    342345        def change_mask(modifiers, press, info):
    343346            for modifier in modifiers:
  • xpra/x11/shadow_x11_server.py

     
    2323    def makeRootWindowModel(self):
    2424        return GTKRootWindowModel(self.root)
    2525
    26     def _process_mouse_common(self, proto, wid, pointer, modifiers):
     26    def _process_mouse_common(self, proto, wid, pointer, modifiers, modignore):
    2727        #adjust pointer position for offset in client:
    2828        x, y = pointer
    2929        wx, wy = self.mapped_at[:2]
    3030        pointer = x-wx, y-wy
    31         X11ServerBase._process_mouse_common(self, proto, wid, pointer, modifiers)
     31        X11ServerBase._process_mouse_common(self, proto, wid, pointer, modifiers, modignore)
    3232
    3333    def make_hello(self):
    3434        capabilities = X11ServerBase.make_hello(self)
  • xpra/x11/x11_server_base.py

     
    145145
    146146    def make_hello(self):
    147147        capabilities = GTKServerBase.make_hello(self)
    148         capabilities["resize_screen"] = self.randr
    149         capabilities["force_ungrab"] = True
     148        capabilities.update({
     149                     "resize_screen"    : self.randr,
     150                     "force_ungrab"     : True,
     151                     "mouse_modignore"  : True})
    150152        return capabilities
    151153
    152154    def do_get_info(self, proto, server_sources, window_ids):
     
    467469        display = gtk.gdk.display_get_default()
    468470        display.warp_pointer(display.get_default_screen(), x, y)
    469471
    470     def _process_mouse_common(self, proto, wid, pointer, modifiers):
     472    def _process_mouse_common(self, proto, wid, pointer, modifiers, modignore):
    471473        ss = self._server_sources.get(proto)
    472474        if ss is None:
    473475            return
     
    475477        if pos==pointer:
    476478            return
    477479        trap.swallow_synced(self._move_pointer, wid, pointer)
    478         ss.make_keymask_match(modifiers)
     480        ss.make_keymask_match(modifiers, ignored_modifiers=modignore)
    479481
    480482    def _process_button_action(self, proto, packet):
    481483        ss = self._server_sources.get(proto)
     
    482484        if ss is None:
    483485            return
    484486        wid, button, pressed, pointer, modifiers = packet[1:6]
    485         self._process_mouse_common(proto, wid, pointer, modifiers)
     487        modignore = []
     488        if len(packet)>=7:
     489            modignore = packet[6]
     490        self._process_mouse_common(proto, wid, pointer, modifiers, modignore)
    486491        ss.user_event()
    487492        try:
    488493            trap.call_synced(X11Keyboard.xtest_fake_button, button, pressed)