|
| 1 | +# Xlib.ext.xinput -- XInput extension module |
| 2 | +# |
| 3 | +# Copyright (C) 2012 Outpost Embedded, LLC |
| 4 | +# Forest Bond <forest.bond@rapidrollout.com> |
| 5 | +# |
| 6 | +# This program is free software; you can redistribute it and/or modify |
| 7 | +# it under the terms of the GNU General Public License as published by |
| 8 | +# the Free Software Foundation; either version 2 of the License, or |
| 9 | +# (at your option) any later version. |
| 10 | +# |
| 11 | +# This program is distributed in the hope that it will be useful, |
| 12 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | +# GNU General Public License for more details. |
| 15 | +# |
| 16 | +# You should have received a copy of the GNU General Public License |
| 17 | +# along with this program; if not, write to the Free Software |
| 18 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 19 | + |
| 20 | +''' |
| 21 | +A very incomplete implementation of the XInput extension. |
| 22 | +''' |
| 23 | + |
| 24 | +import sys, array |
| 25 | + |
| 26 | +from Xlib.protocol import rq |
| 27 | + |
| 28 | + |
| 29 | +extname = 'XInputExtension' |
| 30 | + |
| 31 | +PropertyDeleted = 0 |
| 32 | +PropertyCreated = 1 |
| 33 | +PropertyModified = 2 |
| 34 | + |
| 35 | +NotifyNormal = 0 |
| 36 | +NotifyGrab = 1 |
| 37 | +NotifyUngrab = 2 |
| 38 | +NotifyWhileGrabbed = 3 |
| 39 | +NotifyPassiveGrab = 4 |
| 40 | +NotifyPassiveUngrab = 5 |
| 41 | + |
| 42 | +NotifyAncestor = 0 |
| 43 | +NotifyVirtual = 1 |
| 44 | +NotifyInferior = 2 |
| 45 | +NotifyNonlinear = 3 |
| 46 | +NotifyNonlinearVirtual = 4 |
| 47 | +NotifyPointer = 5 |
| 48 | +NotifyPointerRoot = 6 |
| 49 | +NotifyDetailNone = 7 |
| 50 | + |
| 51 | +GrabtypeButton = 0 |
| 52 | +GrabtypeKeycode = 1 |
| 53 | +GrabtypeEnter = 2 |
| 54 | +GrabtypeFocusIn = 3 |
| 55 | + |
| 56 | +AnyModifier = (1 << 31) |
| 57 | +AnyButton = 0 |
| 58 | +AnyKeycode = 0 |
| 59 | + |
| 60 | +AsyncDevice = 0 |
| 61 | +SyncDevice = 1 |
| 62 | +ReplayDevice = 2 |
| 63 | +AsyncPairedDevice = 3 |
| 64 | +AsyncPair = 4 |
| 65 | +SyncPair = 5 |
| 66 | + |
| 67 | +SlaveSwitch = 1 |
| 68 | +DeviceChange = 2 |
| 69 | + |
| 70 | +MasterAdded = (1 << 0) |
| 71 | +MasterRemoved = (1 << 1) |
| 72 | +SlaveAdded = (1 << 2) |
| 73 | +SlaveRemoved = (1 << 3) |
| 74 | +SlaveAttached = (1 << 4) |
| 75 | +SlaveDetached = (1 << 5) |
| 76 | +DeviceEnabled = (1 << 6) |
| 77 | +DeviceDisabled = (1 << 7) |
| 78 | + |
| 79 | +AddMaster = 1 |
| 80 | +RemoveMaster = 2 |
| 81 | +AttachSlave = 3 |
| 82 | +DetachSlave = 4 |
| 83 | + |
| 84 | +AttachToMaster = 1 |
| 85 | +Floating = 2 |
| 86 | + |
| 87 | +ModeRelative = 0 |
| 88 | +ModeAbsolute = 1 |
| 89 | + |
| 90 | +MasterPointer = 1 |
| 91 | +MasterKeyboard = 2 |
| 92 | +SlavePointer = 3 |
| 93 | +SlaveKeyboard = 4 |
| 94 | +FloatingSlave = 5 |
| 95 | + |
| 96 | +KeyClass = 0 |
| 97 | +ButtonClass = 1 |
| 98 | +ValuatorClass = 2 |
| 99 | + |
| 100 | +KeyRepeat = (1 << 16) |
| 101 | + |
| 102 | +AllDevices = 0 |
| 103 | +AllMasterDevices = 1 |
| 104 | + |
| 105 | +DeviceChanged = 1 |
| 106 | +KeyPress = 2 |
| 107 | +KeyRelease = 3 |
| 108 | +ButtonPress = 4 |
| 109 | +ButtonRelease = 5 |
| 110 | +Motion = 6 |
| 111 | +Enter = 7 |
| 112 | +Leave = 8 |
| 113 | +FocusIn = 9 |
| 114 | +FocusOut = 10 |
| 115 | +HierarchyChanged = 11 |
| 116 | +PropertyEvent = 12 |
| 117 | +RawKeyPress = 13 |
| 118 | +RawKeyRelease = 14 |
| 119 | +RawButtonPress = 15 |
| 120 | +RawButtonRelease = 16 |
| 121 | +RawMotion = 17 |
| 122 | + |
| 123 | +DeviceChangedMask = (1 << DeviceChanged) |
| 124 | +KeyPressMask = (1 << KeyPress) |
| 125 | +KeyReleaseMask = (1 << KeyRelease) |
| 126 | +ButtonPressMask = (1 << ButtonPress) |
| 127 | +ButtonReleaseMask = (1 << ButtonRelease) |
| 128 | +MotionMask = (1 << Motion) |
| 129 | +EnterMask = (1 << Enter) |
| 130 | +LeaveMask = (1 << Leave) |
| 131 | +FocusInMask = (1 << FocusIn) |
| 132 | +FocusOutMask = (1 << FocusOut) |
| 133 | +HierarchyChangedMask = (1 << HierarchyChanged) |
| 134 | +PropertyEventMask = (1 << PropertyEvent) |
| 135 | +RawKeyPressMask = (1 << RawKeyPress) |
| 136 | +RawKeyReleaseMask = (1 << RawKeyRelease) |
| 137 | +RawButtonPressMask = (1 << RawButtonPress) |
| 138 | +RawButtonReleaseMask = (1 << RawButtonRelease) |
| 139 | +RawMotionMask = (1 << RawMotion) |
| 140 | + |
| 141 | +DEVICEID = rq.Card16 |
| 142 | +DEVICE = rq.Card16 |
| 143 | +DEVICEUSE = rq.Card8 |
| 144 | + |
| 145 | + |
| 146 | +class XIQueryVersion(rq.ReplyRequest): |
| 147 | + _request = rq.Struct( |
| 148 | + rq.Card8('opcode'), |
| 149 | + rq.Opcode(47), |
| 150 | + rq.RequestLength(), |
| 151 | + rq.Card16('major_version'), |
| 152 | + rq.Card16('minor_version'), |
| 153 | + ) |
| 154 | + _reply = rq.Struct( |
| 155 | + rq.ReplyCode(), |
| 156 | + rq.Pad(1), |
| 157 | + rq.Card16('sequence_number'), |
| 158 | + rq.ReplyLength(), |
| 159 | + rq.Card32('major_version'), |
| 160 | + rq.Card32('minor_version'), |
| 161 | + rq.Pad(16), |
| 162 | + ) |
| 163 | + |
| 164 | + |
| 165 | +def query_version(self): |
| 166 | + return XIQueryVersion( |
| 167 | + display=self.display, |
| 168 | + opcode=self.display.get_extension_major(extname), |
| 169 | + major_version=2, |
| 170 | + minor_version=0, |
| 171 | + ) |
| 172 | + |
| 173 | + |
| 174 | +EventMask = rq.Struct( |
| 175 | + DEVICE('deviceid'), |
| 176 | + rq.LengthOf('mask', 2), |
| 177 | + rq.List('mask', rq.Card32), |
| 178 | + ) |
| 179 | + |
| 180 | + |
| 181 | +class XISelectEvents(rq.Request): |
| 182 | + _request = rq.Struct( |
| 183 | + rq.Card8('opcode'), |
| 184 | + rq.Opcode(46), |
| 185 | + rq.RequestLength(), |
| 186 | + rq.Window('window'), |
| 187 | + rq.LengthOf('masks', 2), |
| 188 | + rq.Pad(2), |
| 189 | + rq.List('masks', EventMask), |
| 190 | + ) |
| 191 | + |
| 192 | + |
| 193 | +def select_events(self, event_masks): |
| 194 | + ''' |
| 195 | + select_events(event_masks) |
| 196 | +
|
| 197 | + event_masks: |
| 198 | + Sequence of (deviceid, mask) pairs, where deviceid is a numerical device |
| 199 | + ID, or AllDevices or AllMasterDevices, and mask is either an unsigned |
| 200 | + integer or sequence of 32 byte unsigned values |
| 201 | + ''' |
| 202 | + |
| 203 | + masks = [] |
| 204 | + for deviceid, mask in event_masks: |
| 205 | + mask_seq = array.array(rq.struct_to_array_codes['L']) |
| 206 | + |
| 207 | + if isinstance(mask, (int, long)): |
| 208 | + # We need to build a "binary mask" that (as far as I can tell) is |
| 209 | + # encoded in native byte order from end to end. The simple case is |
| 210 | + # with a single unsigned 32-bit value, for which we construct an |
| 211 | + # array with just one item. For values too big to fit inside 4 |
| 212 | + # bytes we build a longer array, being careful to maintain native |
| 213 | + # byte order across the entire set of values. |
| 214 | + if sys.byteorder == 'little': |
| 215 | + f = lambda v: mask_seq.insert(0, v) |
| 216 | + elif sys.byteorder == 'big': |
| 217 | + f = mask_seq.append |
| 218 | + else: |
| 219 | + raise AssertionError(sys.byteorder) |
| 220 | + while mask: |
| 221 | + f(mask & 0xFFFFFFFF) |
| 222 | + mask = mask >> 32 |
| 223 | + else: |
| 224 | + mask_seq.extend(mask) |
| 225 | + |
| 226 | + masks.append({'deviceid': deviceid, 'mask': mask_seq}) |
| 227 | + |
| 228 | + return XISelectEvents( |
| 229 | + display=self.display, |
| 230 | + opcode=self.display.get_extension_major(extname), |
| 231 | + window=self, |
| 232 | + masks=masks, |
| 233 | + ) |
| 234 | + |
| 235 | + |
| 236 | +HierarchyInfo = rq.Struct( |
| 237 | + DEVICEID('deviceid'), |
| 238 | + DEVICEID('attachment'), |
| 239 | + DEVICEUSE('type'), |
| 240 | + rq.Bool('enabled'), |
| 241 | + rq.Pad(2), |
| 242 | + rq.Card32('flags'), |
| 243 | + ) |
| 244 | + |
| 245 | + |
| 246 | +HierarchyEventData = rq.Struct( |
| 247 | + DEVICEID('deviceid'), |
| 248 | + rq.Card32('time'), |
| 249 | + rq.Card32('flags'), |
| 250 | + rq.LengthOf('info', 2), |
| 251 | + rq.Pad(10), |
| 252 | + rq.List('info', HierarchyInfo), |
| 253 | + ) |
| 254 | + |
| 255 | + |
| 256 | +def init(disp, info): |
| 257 | + disp.extension_add_method('display', 'xinput_query_version', query_version) |
| 258 | + disp.extension_add_method('window', 'xinput_select_events', select_events) |
| 259 | + |
| 260 | + disp.ge_add_event_data(info.major_opcode, 11, HierarchyEventData) |
0 commit comments