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 kmk.keys import FIRST_KMK_INTERNAL_KEY, ConsumerKey, ModifierKey
 | 
			
		||||
from kmk.utils import clamp
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    from adafruit_ble import BLERadio
 | 
			
		||||
@@ -72,6 +73,10 @@ class AbstractHID:
 | 
			
		||||
        self._cc_report[0] = HIDReportTypes.CONSUMER
 | 
			
		||||
        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()
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
@@ -80,7 +85,7 @@ class AbstractHID:
 | 
			
		||||
    def post_init(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def create_report(self, keys_pressed):
 | 
			
		||||
    def create_report(self, keys_pressed, axes):
 | 
			
		||||
        self.clear_all()
 | 
			
		||||
 | 
			
		||||
        for key in keys_pressed:
 | 
			
		||||
@@ -97,6 +102,9 @@ class AbstractHID:
 | 
			
		||||
                    for mod in key.has_modifiers:
 | 
			
		||||
                        self.add_modifier(mod)
 | 
			
		||||
 | 
			
		||||
        for axis in axes.values():
 | 
			
		||||
            self.move_axis(axis)
 | 
			
		||||
 | 
			
		||||
    def hid_send(self, evt):
 | 
			
		||||
        # 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
 | 
			
		||||
@@ -114,6 +122,10 @@ class AbstractHID:
 | 
			
		||||
            self.hid_send(self._cc_report)
 | 
			
		||||
            self._cc_pending = False
 | 
			
		||||
 | 
			
		||||
        if self._pd_pending:
 | 
			
		||||
            self.hid_send(self._pd_report)
 | 
			
		||||
            self._pd_pending = False
 | 
			
		||||
 | 
			
		||||
        return self
 | 
			
		||||
 | 
			
		||||
    def clear_all(self):
 | 
			
		||||
@@ -193,6 +205,13 @@ class AbstractHID:
 | 
			
		||||
            self._cc_pending = True
 | 
			
		||||
        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):
 | 
			
		||||
    REPORT_BYTES = 9
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,15 @@ ALL_NUMBER_ALIASES = tuple(f'N{x}' for x in ALL_NUMBERS)
 | 
			
		||||
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(
 | 
			
		||||
    code: Optional[int],
 | 
			
		||||
    names: Tuple[str, ...],
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@ class KMKKeyboard:
 | 
			
		||||
    #####
 | 
			
		||||
    # Internal State
 | 
			
		||||
    keys_pressed = set()
 | 
			
		||||
    axes = {}
 | 
			
		||||
    _coordkeys_pressed = {}
 | 
			
		||||
    hid_type = HIDModes.USB
 | 
			
		||||
    secondary_hid_type = None
 | 
			
		||||
@@ -88,6 +89,7 @@ class KMKKeyboard:
 | 
			
		||||
                f'  unicode_mode={self.unicode_mode}, ',
 | 
			
		||||
                f'_hid_helper={self._hid_helper},\n',
 | 
			
		||||
                f'  keys_pressed={self.keys_pressed},\n',
 | 
			
		||||
                f'  axes={self.axes},\n',
 | 
			
		||||
                f'  _coordkeys_pressed={self._coordkeys_pressed},\n',
 | 
			
		||||
                f'  hid_pending={self.hid_pending}, ',
 | 
			
		||||
                f'active_layers={self.active_layers}, ',
 | 
			
		||||
@@ -100,16 +102,24 @@ class KMKKeyboard:
 | 
			
		||||
        if debug.enabled:
 | 
			
		||||
            debug(f'coordkeys_pressed={self._coordkeys_pressed}')
 | 
			
		||||
            debug(f'keys_pressed={self.keys_pressed}')
 | 
			
		||||
            # debug(f'axis={[ax for ax in self.axis.__iter__()]}')
 | 
			
		||||
 | 
			
		||||
    def _send_hid(self) -> None:
 | 
			
		||||
        if self._hid_send_enabled:
 | 
			
		||||
            hid_report = self._hid_helper.create_report(self.keys_pressed)
 | 
			
		||||
            try:
 | 
			
		||||
                hid_report.send()
 | 
			
		||||
            except KeyError as e:
 | 
			
		||||
                if debug.enabled:
 | 
			
		||||
                    debug(f'HidNotFound(HIDReportType={e})')
 | 
			
		||||
        if not self._hid_send_enabled:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        self._hid_helper.create_report(self.keys_pressed, self.axes)
 | 
			
		||||
        try:
 | 
			
		||||
            self._hid_helper.send()
 | 
			
		||||
        except KeyError as e:
 | 
			
		||||
            if debug.enabled:
 | 
			
		||||
                debug(f'HidNotFound(HIDReportType={e})')
 | 
			
		||||
 | 
			
		||||
        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:
 | 
			
		||||
        if kevent is not None:
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user