Skip to content

Commit 89ce219

Browse files
committed
xinput: clean up parsing of device info
1 parent e73cbed commit 89ce219

1 file changed

Lines changed: 88 additions & 71 deletions

File tree

Xlib/ext/xinput.py

Lines changed: 88 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,27 @@
150150
DEVICE = rq.Card16
151151
DEVICEUSE = rq.Card8
152152

153+
class FP1616(rq.Int32):
154+
155+
def check_value(self, value):
156+
return int(value * 65536.0)
157+
158+
def parse_value(self, value, display):
159+
return float(value) / float(1 << 16)
160+
161+
class FP3232(rq.ValueField):
162+
structcode = 'lL'
163+
structvalues = 2
164+
165+
def check_value(self, value):
166+
return value
167+
168+
def parse_value(self, value, display):
169+
integral, frac = value
170+
ret = float(integral)
171+
# optimised math.ldexp(float(frac), -32)
172+
ret += float(frac) * (1.0 / (1 << 32))
173+
return ret
153174

154175
class XIQueryVersion(rq.ReplyRequest):
155176
_request = rq.Struct(
@@ -239,31 +260,57 @@ def select_events(self, event_masks):
239260
masks=masks,
240261
)
241262

242-
DeviceInfo = rq.Struct(
243-
DEVICEID('deviceid'),
244-
rq.Card16('use'),
245-
rq.Card16('attachment'),
246-
rq.Card16('num_classes'),
247-
rq.LengthOf('name', 2),
248-
rq.Bool('enabled'),
249-
rq.Pad(1),
250-
rq.String8('name', 4),
251-
# <num_classes> classes follow.
252-
)
253-
254263
AnyInfo = rq.Struct(
255264
rq.Card16('type'),
256265
rq.Card16('length'),
257266
rq.Card16('sourceid'),
258267
rq.Pad(2),
259268
)
260269

270+
class Mask(object):
271+
272+
def __init__(self, value, length):
273+
self._value = value
274+
self._length = length
275+
276+
def __len__(self):
277+
return self._length
278+
279+
def __getitem__(self, key):
280+
return self._value & (1 << key)
281+
282+
def __str__(self):
283+
return ('{0:0%ub}' % self._length).format(self._value)
284+
285+
def __repr__(self):
286+
return '%#0*x' % ((self._length + 3) / 8, self._value)
287+
288+
class ButtonState(rq.ValueField):
289+
290+
structcode = None
291+
292+
def __init__(self, name):
293+
rq.ValueField.__init__(self, name)
294+
295+
def parse_binary_value(self, data, display, length, format):
296+
# Mask: bitfield of <length> button states.
297+
mask_len = 4 * ((((length + 7) >> 3) + 3) >> 2)
298+
mask_data = data[:mask_len]
299+
mask_value = 0
300+
for b in reversed(struct.unpack('=%uB' % mask_len, mask_data)):
301+
mask_value <<= 8
302+
mask_value |= b
303+
data = buffer(data, mask_len)
304+
assert 0 == (mask_value & 1)
305+
return Mask(mask_value >> 1, length), data
306+
261307
ButtonInfo = rq.Struct(
262308
rq.Card16('type'),
263309
rq.Card16('length'),
264310
rq.Card16('sourceid'),
265-
rq.Card16('num_buttons'),
266-
# state mask and label atoms follow.
311+
rq.LengthOf(('state', 'labels'), 2),
312+
ButtonState('state'),
313+
rq.List('labels', rq.Card32),
267314
)
268315

269316
KeyInfo = rq.Struct(
@@ -274,20 +321,6 @@ def select_events(self, event_masks):
274321
rq.List('keycodes', rq.Card32),
275322
)
276323

277-
class FP3232(rq.ValueField):
278-
structcode = 'lL'
279-
structvalues = 2
280-
281-
def check_value(self, value):
282-
return value
283-
284-
def parse_value(self, value, display):
285-
integral, frac = value
286-
ret = float(integral)
287-
# optimised math.ldexp(float(frac), -32)
288-
ret += float(frac) * (1.0 / (1 << 32))
289-
return ret
290-
291324
ValuatorInfo = rq.Struct(
292325
rq.Card16('type'),
293326
rq.Card16('length'),
@@ -329,6 +362,31 @@ def parse_value(self, value, display):
329362
TouchClass: TouchInfo,
330363
}
331364

365+
class ClassInfoClass:
366+
367+
structcode = None
368+
369+
def parse_binary(self, data, display):
370+
class_type, length = struct.unpack('=HH', data[:4])
371+
class_struct = INFO_CLASSES.get(class_type, AnyInfo)
372+
class_data, _ = class_struct.parse_binary(data, display)
373+
data = buffer(data, length * 4)
374+
return class_data, data
375+
376+
ClassInfo = ClassInfoClass()
377+
378+
DeviceInfo = rq.Struct(
379+
DEVICEID('deviceid'),
380+
rq.Card16('use'),
381+
rq.Card16('attachment'),
382+
rq.LengthOf('classes', 2),
383+
rq.LengthOf('name', 2),
384+
rq.Bool('enabled'),
385+
rq.Pad(1),
386+
rq.String8('name', 4),
387+
rq.List('classes', ClassInfo),
388+
)
389+
332390
class XIQueryDevice(rq.ReplyRequest):
333391
_request = rq.Struct(
334392
rq.Card8('opcode'),
@@ -343,44 +401,11 @@ class XIQueryDevice(rq.ReplyRequest):
343401
rq.Pad(1),
344402
rq.Card16('sequence_number'),
345403
rq.ReplyLength(),
346-
rq.Card16('num_devices'),
404+
rq.LengthOf('devices', 2),
347405
rq.Pad(22),
406+
rq.List('devices', DeviceInfo),
348407
)
349408

350-
def _parse_response(self, data):
351-
self._response_lock.acquire()
352-
self._data, d = self._reply.parse_binary(data, self._display)
353-
self._data.devices = devices = []
354-
for _ in range(self._data.num_devices):
355-
devinfo, d = DeviceInfo.parse_binary(d, self._display)
356-
devinfo.classes = classes = []
357-
for _ in range(devinfo.num_classes):
358-
class_type, length = struct.unpack('=HH', d[:4])
359-
class_struct = INFO_CLASSES.get(class_type, None)
360-
if class_struct is not None:
361-
class_data, _ = class_struct.parse_binary(d, self._display)
362-
classes.append(class_data)
363-
# Parse ButtonInfo state mask and label atoms.
364-
if ButtonClass == class_type:
365-
# Mask: bitfield of size a multiple of 4.
366-
mask_offset = ButtonInfo.static_size
367-
mask_len = 4 * ((((class_data.num_buttons + 7) >> 3) + 3) >> 2)
368-
mask_data = d[mask_offset:mask_offset+mask_len]
369-
mask = 0
370-
for b in reversed(struct.unpack('=%uB' % mask_len, mask_data)):
371-
mask <<= 8
372-
mask |= b
373-
class_data.state = mask
374-
# Labels: a list of <num_buttons> atoms.
375-
labels_offset = mask_offset + mask_len
376-
labels_len = class_data.num_buttons * 4
377-
labels_data = d[labels_offset:labels_offset+labels_len]
378-
labels = struct.unpack('=%uL' % class_data.num_buttons, labels_data)
379-
class_data.labels = labels
380-
d = buffer(d, length * 4)
381-
devices.append(devinfo)
382-
self._response_lock.release()
383-
384409
def query_device(self, deviceid):
385410
return XIQueryDevice(
386411
display=self.display,
@@ -572,14 +597,6 @@ def ungrab_keycode(self, deviceid, keycode, modifiers):
572597
rq.Card8('effective_group'),
573598
)
574599

575-
class FP1616(rq.Int32):
576-
577-
def check_value(self, value):
578-
return int(value * 65536.0)
579-
580-
def parse_value(self, value, display):
581-
return float(value) / float(1 << 16)
582-
583600
DeviceEventData = rq.Struct(
584601
DEVICEID('deviceid'),
585602
rq.Card32('time'),

0 commit comments

Comments
 (0)