implement global pointing device axis handling
This commit is contained in:
		
							
								
								
									
										21
									
								
								kmk/hid.py
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								kmk/hid.py
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ from micropython import const | |||||||
| from storage import getmount | from storage import getmount | ||||||
|  |  | ||||||
| from kmk.keys import FIRST_KMK_INTERNAL_KEY, ConsumerKey, ModifierKey | from kmk.keys import FIRST_KMK_INTERNAL_KEY, ConsumerKey, ModifierKey | ||||||
|  | from kmk.utils import clamp | ||||||
|  |  | ||||||
| try: | try: | ||||||
|     from adafruit_ble import BLERadio |     from adafruit_ble import BLERadio | ||||||
| @@ -72,6 +73,10 @@ class AbstractHID: | |||||||
|         self._cc_report[0] = HIDReportTypes.CONSUMER |         self._cc_report[0] = HIDReportTypes.CONSUMER | ||||||
|         self._cc_pending = False |         self._cc_pending = False | ||||||
|  |  | ||||||
|  |         self._pd_report = bytearray(HID_REPORT_SIZES[HIDReportTypes.MOUSE] + 1) | ||||||
|  |         self._pd_report[0] = HIDReportTypes.MOUSE | ||||||
|  |         self._pd_pending = False | ||||||
|  |  | ||||||
|         self.post_init() |         self.post_init() | ||||||
|  |  | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
| @@ -80,7 +85,7 @@ class AbstractHID: | |||||||
|     def post_init(self): |     def post_init(self): | ||||||
|         pass |         pass | ||||||
|  |  | ||||||
|     def create_report(self, keys_pressed): |     def create_report(self, keys_pressed, axes): | ||||||
|         self.clear_all() |         self.clear_all() | ||||||
|  |  | ||||||
|         for key in keys_pressed: |         for key in keys_pressed: | ||||||
| @@ -97,6 +102,9 @@ class AbstractHID: | |||||||
|                     for mod in key.has_modifiers: |                     for mod in key.has_modifiers: | ||||||
|                         self.add_modifier(mod) |                         self.add_modifier(mod) | ||||||
|  |  | ||||||
|  |         for axis in axes.values(): | ||||||
|  |             self.move_axis(axis) | ||||||
|  |  | ||||||
|     def hid_send(self, evt): |     def hid_send(self, evt): | ||||||
|         # Don't raise a NotImplementedError so this can serve as our "dummy" HID |         # Don't raise a NotImplementedError so this can serve as our "dummy" HID | ||||||
|         # when MCU/board doesn't define one to use (which should almost always be |         # when MCU/board doesn't define one to use (which should almost always be | ||||||
| @@ -114,6 +122,10 @@ class AbstractHID: | |||||||
|             self.hid_send(self._cc_report) |             self.hid_send(self._cc_report) | ||||||
|             self._cc_pending = False |             self._cc_pending = False | ||||||
|  |  | ||||||
|  |         if self._pd_pending: | ||||||
|  |             self.hid_send(self._pd_report) | ||||||
|  |             self._pd_pending = False | ||||||
|  |  | ||||||
|         return self |         return self | ||||||
|  |  | ||||||
|     def clear_all(self): |     def clear_all(self): | ||||||
| @@ -193,6 +205,13 @@ class AbstractHID: | |||||||
|             self._cc_pending = True |             self._cc_pending = True | ||||||
|         self._cc_report[1] = 0x00 |         self._cc_report[1] = 0x00 | ||||||
|  |  | ||||||
|  |     def move_axis(self, axis): | ||||||
|  |         if axis.delta != 0 or self._pd_report[axis.code + 2] != 0: | ||||||
|  |             delta = clamp(axis.delta, -127, 127) | ||||||
|  |             axis.delta -= delta | ||||||
|  |             self._pd_report[axis.code + 2] = 0xFF & delta | ||||||
|  |             self._pd_pending = True | ||||||
|  |  | ||||||
|  |  | ||||||
| class USBHID(AbstractHID): | class USBHID(AbstractHID): | ||||||
|     REPORT_BYTES = 9 |     REPORT_BYTES = 9 | ||||||
|   | |||||||
| @@ -33,6 +33,15 @@ ALL_NUMBER_ALIASES = tuple(f'N{x}' for x in ALL_NUMBERS) | |||||||
| debug = Debug(__name__) | debug = Debug(__name__) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Axis: | ||||||
|  |     def __init__(self, code: int) -> None: | ||||||
|  |         self.code = code | ||||||
|  |         self.delta = 0 | ||||||
|  |  | ||||||
|  |     def __repr__(self) -> str: | ||||||
|  |         return f'Axis(code={self.code}, delta={self.delta})' | ||||||
|  |  | ||||||
|  |  | ||||||
| def maybe_make_key( | def maybe_make_key( | ||||||
|     code: Optional[int], |     code: Optional[int], | ||||||
|     names: Tuple[str, ...], |     names: Tuple[str, ...], | ||||||
|   | |||||||
| @@ -49,6 +49,7 @@ class KMKKeyboard: | |||||||
|     ##### |     ##### | ||||||
|     # Internal State |     # Internal State | ||||||
|     keys_pressed = set() |     keys_pressed = set() | ||||||
|  |     axes = {} | ||||||
|     _coordkeys_pressed = {} |     _coordkeys_pressed = {} | ||||||
|     hid_type = HIDModes.USB |     hid_type = HIDModes.USB | ||||||
|     secondary_hid_type = None |     secondary_hid_type = None | ||||||
| @@ -88,6 +89,7 @@ class KMKKeyboard: | |||||||
|                 f'  unicode_mode={self.unicode_mode}, ', |                 f'  unicode_mode={self.unicode_mode}, ', | ||||||
|                 f'_hid_helper={self._hid_helper},\n', |                 f'_hid_helper={self._hid_helper},\n', | ||||||
|                 f'  keys_pressed={self.keys_pressed},\n', |                 f'  keys_pressed={self.keys_pressed},\n', | ||||||
|  |                 f'  axes={self.axes},\n', | ||||||
|                 f'  _coordkeys_pressed={self._coordkeys_pressed},\n', |                 f'  _coordkeys_pressed={self._coordkeys_pressed},\n', | ||||||
|                 f'  hid_pending={self.hid_pending}, ', |                 f'  hid_pending={self.hid_pending}, ', | ||||||
|                 f'active_layers={self.active_layers}, ', |                 f'active_layers={self.active_layers}, ', | ||||||
| @@ -100,16 +102,24 @@ class KMKKeyboard: | |||||||
|         if debug.enabled: |         if debug.enabled: | ||||||
|             debug(f'coordkeys_pressed={self._coordkeys_pressed}') |             debug(f'coordkeys_pressed={self._coordkeys_pressed}') | ||||||
|             debug(f'keys_pressed={self.keys_pressed}') |             debug(f'keys_pressed={self.keys_pressed}') | ||||||
|  |             # debug(f'axis={[ax for ax in self.axis.__iter__()]}') | ||||||
|  |  | ||||||
|     def _send_hid(self) -> None: |     def _send_hid(self) -> None: | ||||||
|         if self._hid_send_enabled: |         if not self._hid_send_enabled: | ||||||
|             hid_report = self._hid_helper.create_report(self.keys_pressed) |             return | ||||||
|  |  | ||||||
|  |         self._hid_helper.create_report(self.keys_pressed, self.axes) | ||||||
|         try: |         try: | ||||||
|                 hid_report.send() |             self._hid_helper.send() | ||||||
|         except KeyError as e: |         except KeyError as e: | ||||||
|             if debug.enabled: |             if debug.enabled: | ||||||
|                 debug(f'HidNotFound(HIDReportType={e})') |                 debug(f'HidNotFound(HIDReportType={e})') | ||||||
|  |  | ||||||
|         self.hid_pending = False |         self.hid_pending = False | ||||||
|  |         for axis in self.axes.values(): | ||||||
|  |             if axis.delta != 0: | ||||||
|  |                 self.hid_pending = True | ||||||
|  |                 break | ||||||
|  |  | ||||||
|     def _handle_matrix_report(self, kevent: KeyEvent) -> None: |     def _handle_matrix_report(self, kevent: KeyEvent) -> None: | ||||||
|         if kevent is not None: |         if kevent is not None: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user