xpra icon
Bug tracker and wiki

Ticket #173: xi-events-v2.patch

File xi-events-v2.patch, 18.7 KB (added by Antoine Martin, 2 years ago)

updated patch for r15792

  • xpra/platform/features.py

     
    1515SYSTEM_TRAY_SUPPORTED = False
    1616REINIT_WINDOWS = False
    1717
     18INPUT_DEVICES = ["auto"]
     19
    1820CLIPBOARDS = []
    1921CLIPBOARD_WANT_TARGETS = envbool("XPRA_CLIPBOARD_WANT_TARGETS")
    2022CLIPBOARD_GREEDY = envbool("XPRA_CLIPBOARD_GREEDY")
     
    6264                   "CLIPBOARD_NATIVE_CLASS",
    6365                   "UI_THREAD_POLLING",
    6466                   "CLIENT_MODULES",
     67                   "INPUT_DEVICES",
    6568                   ]
    6669from xpra.platform import platform_import
    6770platform_import(globals(), "features", False,
  • xpra/platform/xposix/features.py

     
    2121
    2222DEFAULT_SSH_CMD = "ssh"
    2323CLIPBOARDS=["CLIPBOARD", "PRIMARY", "SECONDARY"]
     24
     25INPUT_DEVICES = ["auto", "xi"]
  • xpra/scripts/config.py

     
    489489                    "dbus-launch"       : str,
    490490                    "webcam"            : str,
    491491                    "mousewheel"        : str,
     492                    "input-devices"     : str,
    492493                    #ssl options:
    493494                    "ssl"               : str,
    494495                    "ssl-key"           : str,
     
    619620                  "quality", "min-quality", "speed", "min-speed",
    620621                  "compression_level",
    621622                  "dpi", "video-scaling", "auto-refresh-delay",
    622                   "webcam", "mousewheel", "pings",
     623                  "webcam", "mousewheel", "input-devices", "pings",
    623624                  "tray", "keyboard-sync", "cursors", "bell", "notifications",
    624625                  "xsettings", "system-tray", "sharing",
    625626                  "delay-tray", "windows", "readonly",
     
    811812                    "dbus-launch"       : "dbus-launch --close-stderr",
    812813                    "webcam"            : ["auto", "no"][OSX],
    813814                    "mousewheel"        : "on",
     815                    "input-devices"     : "auto",
    814816                    #ssl options:
    815817                    "ssl"               : "auto",
    816818                    "ssl-key"           : "",
  • xpra/scripts/main.py

     
    562562    group.add_option("--mousewheel", action="store",
    563563                      dest="mousewheel", default=defaults.mousewheel,
    564564                      help="Mouse wheel forwarding, can be used to disable the device or invert some axes. Default: %s." % defaults.webcam)
     565    from xpra.platform.features import INPUT_DEVICES
     566    if len(INPUT_DEVICES)>1:
     567        group.add_option("--input-devices", action="store", metavar="APINAME",
     568                          dest="input_devices", default=defaults.input_devices,
     569                          help="Which API to use for input devices. Default: %s." % defaults.input_devices)
     570    else:
     571        ignore({"input-devices" : INPUT_DEVICES[0]})
    565572    legacy_bool_parse("global-menus")
    566573    group.add_option("--global-menus", action="store",
    567574                      dest="global_menus", default=defaults.global_menus, metavar="yes|no",
  • xpra/x11/bindings/xi2_bindings.pyx

     
     1# This file is part of Xpra.
     2# Copyright (C) 2017 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6import os
     7import time
     8
     9from xpra.log import Logger
     10log = Logger("x11", "bindings", "keyboard")
     11
     12from xpra.x11.gtk2.common import X11Event
     13
     14from libc.stdint cimport uintptr_t
     15
     16
     17###################################
     18# Headers, python magic
     19###################################
     20cdef extern from "string.h":
     21    void* memset(void * ptr, int value, size_t num)
     22
     23cdef extern from "X11/Xutil.h":
     24    pass
     25
     26######
     27# Xlib primitives and constants
     28######
     29
     30include "constants.pxi"
     31ctypedef unsigned long CARD32
     32
     33cdef extern from "X11/Xlib.h":
     34    ctypedef struct Display:
     35        pass
     36
     37    ctypedef CARD32 XID
     38    ctypedef int Bool
     39    ctypedef int Status
     40    ctypedef CARD32 Atom
     41    ctypedef XID Window
     42    ctypedef CARD32 Time
     43
     44    ctypedef struct XGenericEventCookie:
     45        int            type     # of event. Always GenericEvent
     46        unsigned long  serial
     47        Bool           send_event
     48        Display        *display
     49        int            extension    #major opcode of extension that caused the event
     50        int            evtype       #actual event type
     51        unsigned int   cookie
     52        void           *data
     53
     54    Atom XInternAtom(Display * display, char * atom_name, Bool only_if_exists)
     55    int XFree(void * data)
     56
     57    Bool XQueryExtension(Display * display, char *name,
     58                         int *major_opcode_return, int *first_event_return, int *first_error_return)
     59
     60    Bool XGetEventData(Display *display, XGenericEventCookie *cookie)
     61    void XFreeEventData(Display *display, XGenericEventCookie *cookie)
     62
     63    Window XDefaultRootWindow(Display * display)
     64
     65    Bool XQueryPointer(display, w, root_return, child_return, root_x_return, root_y_return,
     66                       win_x_return, win_y_return, mask_return)
     67    int XFlush(Display *dpy)
     68
     69cdef extern from "X11/extensions/XInput2.h":
     70    ctypedef struct XIEventMask:
     71        int                 deviceid
     72        int                 mask_len
     73        unsigned char*      mask
     74
     75    ctypedef struct XIDeviceInfo:
     76        int                 deviceid
     77        char                *name
     78        int                 use
     79        int                 attachment
     80        Bool                enabled
     81        int                 num_classes
     82        #XIAnyClassInfo      **classes;
     83    Status XIQueryVersion(Display *display, int *major_version_inout, int *minor_version_inout)
     84    Status XISelectEvents(Display *display, Window win, XIEventMask *masks, int num_masks)
     85    int XIAllDevices
     86    XIDeviceInfo* XIQueryDevice(Display *display, int deviceid, int *ndevices_return)
     87    XIFreeDeviceInfo(XIDeviceInfo *info)
     88    Atom *XIListProperties(Display *display, int deviceid, int *num_props_return)
     89    Status XIGetProperty(Display *display, int deviceid, Atom property, long offset, long length,
     90                         Bool delete_property, Atom type, Atom *type_return,
     91                         int *format_return, unsigned long *num_items_return,
     92                         unsigned long *bytes_after_return, unsigned char **data)
     93
     94    int XI_LASTEVENT
     95    int XI_DeviceChanged
     96    int XI_KeyPress
     97    int XI_KeyRelease
     98    int XI_ButtonPress
     99    int XI_ButtonRelease
     100    int XI_Motion
     101    int XI_Enter
     102    int XI_Leave
     103    int XI_FocusIn
     104    int XI_FocusOut
     105    int XI_HierarchyChanged
     106    int XI_PropertyEvent
     107    int XI_RawKeyPress
     108    int XI_RawKeyRelease
     109    int XI_RawButtonPress
     110    int XI_RawButtonRelease
     111    int XI_RawMotion
     112    int XI_TouchBegin
     113    int XI_TouchUpdate
     114    int XI_TouchEnd
     115    int XI_TouchOwnership
     116    int XI_RawTouchBegin
     117    int XI_RawTouchUpdate
     118    int XI_RawTouchEnd
     119
     120    int XIAllDevices
     121    int XIAllMasterDevices
     122    ctypedef struct XIValuatorState:
     123        int           mask_len
     124        unsigned char *mask
     125        double        *values
     126
     127    ctypedef struct XIEvent:
     128        int           type
     129        unsigned long serial
     130        Bool          send_event
     131        Display       *display
     132        int           extension
     133        int           evtype
     134        Time          time
     135
     136    ctypedef struct XIRawEvent:
     137        int           type      #GenericEvent
     138        unsigned long serial
     139        Bool          send_event
     140        Display       *display
     141        int           extension #XI extension offset
     142        int           evtype    #XI_RawKeyPress, XI_RawKeyRelease, etc
     143        Time          time
     144        int           deviceid
     145        int           sourceid
     146        int           detail
     147        int           flags
     148        XIValuatorState valuators
     149        double        *raw_values
     150
     151    ctypedef struct XIButtonState:
     152        int           mask_len
     153        unsigned char *mask
     154
     155    ctypedef struct XIModifierState:
     156        int    base
     157        int    latched
     158        int    locked
     159        int    effective
     160
     161    ctypedef XIModifierState XIGroupState
     162
     163    ctypedef struct XIDeviceEvent:
     164        int           type
     165        unsigned long serial
     166        Bool          send_event
     167        Display       *display
     168        int           extension
     169        int           evtype
     170        Time          time
     171        int           deviceid
     172        int           sourceid
     173        int           detail
     174        Window        root
     175        Window        event
     176        Window        child
     177        double        root_x
     178        double        root_y
     179        double        event_x
     180        double        event_y
     181        int           flags
     182        XIButtonState       buttons
     183        XIValuatorState     valuators
     184        XIModifierState     mods
     185        XIGroupState        group
     186
     187
     188DEF MAX_XI_EVENTS = 64
     189DEF XI_EVENT_MASK_SIZE = (MAX_XI_EVENTS+7)//8
     190
     191XI_EVENT_NAMES = {
     192    XI_DeviceChanged    : "XI_DeviceChanged",
     193    XI_KeyPress         : "XI_KeyPress",
     194    XI_KeyRelease       : "XI_KeyRelease",
     195    XI_ButtonPress      : "XI_ButtonPress",
     196    XI_ButtonRelease    : "XI_ButtonRelease",
     197    XI_Motion           : "XI_Motion",
     198    XI_Enter            : "XI_Enter",
     199    XI_Leave            : "XI_Leave",
     200    XI_FocusIn          : "XI_FocusIn",
     201    XI_FocusOut         : "XI_FocusOut",
     202    XI_HierarchyChanged : "XI_HierarchyChanged",
     203    XI_PropertyEvent    : "XI_PropertyEvent",
     204    XI_RawKeyPress      : "XI_RawKeyPress",
     205    XI_RawKeyRelease    : "XI_RawKeyRelease",
     206    XI_RawButtonPress   : "XI_RawButtonPress",
     207    XI_RawButtonRelease : "XI_RawButtonRelease",
     208    XI_RawMotion        : "XI_RawMotion",
     209    XI_TouchBegin       : "XI_TouchBegin",
     210    XI_TouchUpdate      : "XI_TouchUpdate",
     211    XI_TouchEnd         : "XI_TouchEnd",
     212    XI_TouchOwnership   : "XI_TouchOwnership",
     213    XI_RawTouchBegin    : "XI_RawTouchBegin",
     214    XI_RawTouchUpdate   : "XI_RawTouchUpdate",
     215    XI_RawTouchEnd      : "XI_RawTouchEnd",
     216    }
     217
     218
     219from core_bindings cimport _X11CoreBindings
     220
     221cdef _X11XI2Bindings singleton = None
     222def X11XI2Bindings():
     223    global singleton
     224    if singleton is None:
     225        singleton = _X11XI2Bindings()
     226    return singleton
     227
     228cdef class _X11XI2Bindings(_X11CoreBindings):
     229
     230    cdef int opcode
     231
     232    def __init__(self):
     233        self.opcode = -1
     234
     235    def __repr__(self):
     236        return "X11XI2Bindings(%s)" % self.display_name
     237
     238    cdef int get_xi_opcode(self, int major=2, int minor=2):
     239        if self.opcode!=-1:
     240            return self.opcode
     241        cdef int opcode, event, error
     242        if not XQueryExtension(self.display, "XInputExtension", &opcode, &event, &error):
     243            log.warn("Warning: XI2 events are not supported")
     244            self.opcode = 0
     245            return 0
     246        cdef int rmajor = major, rminor = minor
     247        cdef int rc = XIQueryVersion(self.display, &rmajor, &rminor)
     248        if rc == BadRequest:
     249            log.warn("Warning: no XI2 %i.%i support,", major, minor)
     250            log.warn(" server supports version %i.%i only", rmajor, rminor)
     251            self.opcode = 0
     252            return 0
     253        elif rc:
     254            log.warn("Warning: Xlib bug querying XI2, code %i", rc)
     255            self.opcode = 0
     256            return 0
     257        self.opcode = opcode
     258        log("get_xi_opcode%s=%i", (major, minor), opcode)
     259        return opcode
     260
     261    cdef register_parser(self):
     262        log("register_parser()")
     263        if self.opcode>0:
     264            from xpra.x11.gtk2.gdk_bindings import add_x_event_parser
     265            add_x_event_parser(self.opcode, self.parse_xi_event)
     266
     267    cdef register_gdk_events(self):
     268        log("register_gdk_events()")
     269        if self.opcode>0:
     270            global XI_EVENT_NAMES
     271            from xpra.x11.gtk2.gdk_bindings import add_x_event_signal, add_x_event_type_name
     272            for e, xpra_event_name in {
     273                XI_DeviceChanged    : "xi-device-changed",
     274                XI_KeyPress         : "xi-key-press",
     275                XI_KeyRelease       : "xi-key-release",
     276                XI_ButtonPress      : "xi-button-press",
     277                XI_ButtonRelease    : "xi-button-release",
     278                XI_Motion           : "xi-motion",
     279                XI_Enter            : "xi-enter",
     280                XI_Leave            : "xi-leave",
     281                XI_FocusIn          : "xi-focus-in",
     282                XI_FocusOut         : "xi-focus-out",
     283                XI_HierarchyChanged : "xi-focus-changed",
     284                XI_PropertyEvent    : "xi-property-event",
     285                XI_RawKeyPress      : "xi-raw-key-press",
     286                XI_RawKeyRelease    : "xi-raw-key-release",
     287                XI_RawButtonPress   : "xi-raw-button-press",
     288                XI_RawButtonRelease : "xi-raw-button-release",
     289                XI_RawMotion        : "xi-raw-motion",
     290                XI_TouchBegin       : "xi-touch-begin",
     291                XI_TouchUpdate      : "xi-touch-update",
     292                XI_TouchEnd         : "xi-touch-end",
     293                XI_TouchOwnership   : "xi-touch-ownership",
     294                XI_RawTouchBegin    : "xi-raw-touch-begin",
     295                XI_RawTouchUpdate   : "xi-raw-touch-update",
     296                XI_RawTouchEnd      : "xi-raw-touch-end",
     297                }.items():
     298                event = self.opcode+e
     299                add_x_event_signal(event, (xpra_event_name, None))
     300                name = XI_EVENT_NAMES.get(event)
     301                add_x_event_type_name(event, name)
     302
     303    def select_xi2_events(self):
     304        cdef Window win = XDefaultRootWindow(self.display)
     305        log("select_xi2_events() root window=%#x", win)
     306        assert XI_LASTEVENT<MAX_XI_EVENTS, "bug: source needs to be updated, XI_LASTEVENT=%i" % XI_LASTEVENT
     307        cdef XIEventMask evmasks[1]
     308        cdef unsigned char mask1[XI_EVENT_MASK_SIZE]
     309        memset(mask1, 0, XI_EVENT_MASK_SIZE)
     310        #define XISetMask(ptr, event)   (((unsigned char*)(ptr))[(event)>>3] |=  (1 << ((event) & 7)))
     311        #XISetMask(mask1, XI_RawMotion)
     312        for e in (
     313            XI_RawKeyPress, XI_RawKeyRelease,
     314            XI_RawMotion,
     315            XI_HierarchyChanged,
     316            XI_RawButtonPress, XI_RawButtonRelease,
     317            XI_RawTouchBegin, XI_RawTouchUpdate, XI_RawTouchEnd,
     318            ):
     319            mask1[e>>3] = mask1[e>>3] | (1<< (e & 0x7))
     320        evmasks[0].deviceid = XIAllDevices  #XIAllMasterDevices    #XIAllDevices
     321        evmasks[0].mask_len = XI_EVENT_MASK_SIZE
     322        evmasks[0].mask = mask1
     323        #if envbool("R", False):
     324        XISelectEvents(self.display, win, evmasks, 1)
     325        XFlush(self.display)
     326
     327    def parse_xi_event(self, display, uintptr_t _cookie):
     328        log("parse_xi_event%s", (_cookie, ))
     329        cdef XGenericEventCookie *cookie = <XGenericEventCookie*> _cookie
     330        cdef XIDeviceEvent *device_e
     331        cdef XIEvent *xie
     332        cdef XIRawEvent *raw
     333        cdef int i = 0, j = 0
     334        if not XGetEventData(self.display, cookie):
     335            return None
     336        xie = <XIEvent*> cookie.data
     337        device_e = <XIDeviceEvent*> cookie.data
     338        cdef Window root = XDefaultRootWindow(self.display)
     339        cdef int xi_type = cookie.evtype
     340        etype = self.opcode+xi_type
     341        global XI_EVENT_NAMES
     342        event_type = XI_EVENT_NAMES.get(etype-self.opcode, etype-self.opcode)
     343   
     344        pyev = X11Event(event_type)
     345        pyev.type = etype
     346        pyev.display = display
     347        pyev.send_event = bool(xie.send_event)
     348        pyev.serial = xie.serial
     349        pyev.time = int(xie.time)
     350   
     351        if etype in (XI_RawKeyPress, XI_RawKeyRelease,
     352                     XI_RawButtonPress, XI_RawButtonRelease,
     353                     XI_RawMotion,
     354                     XI_RawTouchBegin, XI_RawTouchUpdate, XI_RawTouchEnd):
     355            raw = <XIRawEvent*> cookie.data
     356            pyev.source = raw.sourceid
     357            pyev.device = raw.deviceid
     358            pyev.detail = raw.detail
     359            pyev.flags = raw.flags
     360            mask = []
     361            values = []
     362            raw_values = []
     363            for i in range(raw.valuators.mask_len):
     364                if raw.valuators.mask[i//8] & (1 << (i & 0x7)):
     365                    mask.append(i)
     366                    values.append(j)
     367                    raw_values.append(raw.raw_values[j])
     368                    j += 1
     369            pyev.valuators = {
     370                "mask"      : mask,
     371                "values"    : values,
     372                }
     373        #cdef Window root_ret, child_ret
     374        #cdef int root_x, root_y, win_x, win_y
     375        #cdef unsigned int mask
     376        #if xi_type == XI_RawMotion:
     377        #    XQueryPointer(display, root, &root_ret, &child_ret, &root_x, &root_y, &win_x, &win_y, &mask):   
     378        #    pyev.update({
     379        #        "x" : win_x,
     380        #        "y" : win_y,
     381        #        })
     382        #if xi_type in (XI_RawKeyPress, XI_RawKeyRelease):
     383        #root, child
     384        #win =  _gw(d, XDefaultRootWindow(device_e.event))
     385        #pyev.root_x = device_e.root_x
     386        #pyev.root_y = device_e.root_y
     387        #pyev.event_x = device_e.event_x
     388        #pyev.event_y = device_e.event_y
     389        #log.info("%s event: root=%#x, event window=%#x, child window=%#x, root x=%i, y=%i, event x=%i, y=%i, flags=%#x",
     390        #         event_type, device_e.root, device_e.event, device_e.child, device_e.root_x, device_e.root_y, device_e.event_x, device_e.event_y, device_e.flags)
     391        #buttons = []
     392        #for i in range(device_e.buttons.mask_len):
     393        #    buttons.append(device_e.buttons.mask[i])
     394        #log.info("buttons state: %s", buttons)
     395        #log.info("modifiers: %s", (device_e.mods.base, device_e.mods.latched, device_e.mods.locked, device_e.mods.effective))
     396        #log.info("group: %s", (device_e.group.base, device_e.group.latched, device_e.group.locked, device_e.group.effective))
     397        XFreeEventData(self.display, cookie)
     398        pyev.window = int(root)
     399        pyev.delivered_to = int(root)
     400        #log("parse_xi_event()=%s", pyev)
     401        return pyev
     402
     403
     404    def gdk_inject(self):
     405        self.get_xi_opcode()
     406        self.register_parser()
     407        self.register_gdk_events()
     408        #self.select_xi2_events()