# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Utility functions for constructing HID report descriptors. """ import struct import hid_constants def ReportDescriptor(*items): return ''.join(items) def _PackItem(tag, typ, value=0, force_length=0): """Pack a multibyte value. See Device Class Definition for Human Interface Devices (HID) Version 1.11 section 5.8. Args: tag: Item tag. typ: Item type. value: Item value. force_length: Force packing to a specific width. Returns: Packed string. """ if value == 0 and force_length <= 0: return struct.pack('<B', tag << 4 | typ << 2 | 0) elif value <= 0xff and force_length <= 1: return struct.pack('<BB', tag << 4 | typ << 2 | 1, value) elif value <= 0xffff and force_length <= 2: return struct.pack('<BH', tag << 4 | typ << 2 | 2, value) elif value <= 0xffffffff and force_length <= 4: return struct.pack('<BI', tag << 4 | typ << 2 | 3, value) else: raise NotImplementedError('Long items are not implemented.') def _DefineItem(name, tag, typ): """Create a function which encodes a HID item. Args: name: Function name. tag: Item tag. typ: Item type. Returns: A function which encodes a HID item of the given type. """ assert tag >= 0 and tag <= 0xF assert typ >= 0 and typ <= 3 def EncodeItem(value=0, force_length=0): return _PackItem(tag, typ, value, force_length) EncodeItem.__name__ = name return EncodeItem def _DefineMainItem(name, tag): """Create a function which encodes a HID Main item. See Device Class Definition for Human Interface Devices (HID) Version 1.11 section 6.2.2.4. Args: name: Function name. tag: Item tag. Returns: A function which encodes a HID item of the given type. Raises: ValueError: If the tag value is out of range. """ assert tag >= 0 and tag <= 0xF def EncodeMainItem(*properties): value = 0 for bit, is_set in properties: if is_set: value |= 1 << bit return _PackItem(tag, hid_constants.Scope.MAIN, value, force_length=1) EncodeMainItem.__name__ = name return EncodeMainItem Input = _DefineMainItem('Input', 8) Output = _DefineMainItem('Output', 9) Feature = _DefineMainItem('Feature', 11) # Input, Output and Feature Item Properties # # See Device Class Definition for Human Interface Devices (HID) Version 1.11 # section 6.2.2.5. Data = (0, False) Constant = (0, True) Array = (1, False) Variable = (1, True) Absolute = (2, False) Relative = (2, True) NoWrap = (3, False) Wrap = (3, True) Linear = (4, False) NonLinear = (4, True) PreferredState = (5, False) NoPreferred = (5, True) NoNullPosition = (6, False) NullState = (6, True) NonVolatile = (7, False) Volatile = (7, True) BitField = (8, False) BufferedBytes = (8, True) def Collection(typ, *items): start = struct.pack('<BB', 0xA1, typ) end = struct.pack('<B', 0xC0) return start + ''.join(items) + end # Global Items # # See Device Class Definition for Human Interface Devices (HID) Version 1.11 # section 6.2.2.7. UsagePage = _DefineItem('UsagePage', 0, hid_constants.Scope.GLOBAL) LogicalMinimum = _DefineItem('LogicalMinimum', 1, hid_constants.Scope.GLOBAL) LogicalMaximum = _DefineItem('LogicalMaximum', 2, hid_constants.Scope.GLOBAL) PhysicalMinimum = _DefineItem('PhysicalMinimum', 3, hid_constants.Scope.GLOBAL) PhysicalMaximum = _DefineItem('PhysicalMaximum', 4, hid_constants.Scope.GLOBAL) UnitExponent = _DefineItem('UnitExponent', 5, hid_constants.Scope.GLOBAL) Unit = _DefineItem('Unit', 6, hid_constants.Scope.GLOBAL) ReportSize = _DefineItem('ReportSize', 7, hid_constants.Scope.GLOBAL) ReportID = _DefineItem('ReportID', 8, hid_constants.Scope.GLOBAL) ReportCount = _DefineItem('ReportCount', 9, hid_constants.Scope.GLOBAL) Push = _DefineItem('Push', 10, hid_constants.Scope.GLOBAL) Pop = _DefineItem('Pop', 11, hid_constants.Scope.GLOBAL) # Local Items # # See Device Class Definition for Human Interface Devices (HID) Version 1.11 # section 6.2.2.8. Usage = _DefineItem('Usage', 0, hid_constants.Scope.LOCAL) UsageMinimum = _DefineItem('UsageMinimum', 1, hid_constants.Scope.LOCAL) UsageMaximum = _DefineItem('UsageMaximum', 2, hid_constants.Scope.LOCAL) DesignatorIndex = _DefineItem('DesignatorIndex', 3, hid_constants.Scope.LOCAL) DesignatorMinimum = _DefineItem('DesignatorMinimum', 4, hid_constants.Scope.LOCAL) DesignatorMaximum = _DefineItem('DesignatorMaximum', 5, hid_constants.Scope.LOCAL) StringIndex = _DefineItem('StringIndex', 7, hid_constants.Scope.LOCAL) StringMinimum = _DefineItem('StringMinimum', 8, hid_constants.Scope.LOCAL) StringMaximum = _DefineItem('StringMaximum', 9, hid_constants.Scope.LOCAL) Delimiter = _DefineItem('Delimiter', 10, hid_constants.Scope.LOCAL)