Add support for cirque glidepoint trackpad

This commit is contained in:
xs5871 2023-03-24 21:47:56 +00:00
parent 5448cb4479
commit ddaf9946eb
No known key found for this signature in database
GPG Key ID: 2A617DBC375C8352

212
kmk/modules/glidepoint.py Normal file
View File

@ -0,0 +1,212 @@
try:
from typing import Callable
except ImportError:
pass
from micropython import const
from kmk.keys import AX
from kmk.modules import Module
from kmk.utils import Debug
debug = Debug(__name__)
_ADDRESS = const(0x2A)
_MASK_READ = const(0xA0)
_MASK_WRITE = const(0x80)
_REG_FW_ID = const(0x00)
_REG_FW_VER = const(0x01)
_REG_STATUS = const(0x02)
_REG_SYS_CFG = const(0x03)
_REG_FEED_CFG1 = const(0x04)
_REG_FEED_CFG2 = const(0x05)
_REG_CAL_CFG = const(0x07)
_REG_AUX_CTL = const(0x08)
_REG_SAMPLE_RATE = const(0x09)
_REG_ZIDLE = const(0x0A)
_REG_Z_SCALER = const(0x0B)
_REG_SLEEP_INTERVAL = const(0x0C)
_REG_SLEEP_TIMER = const(0x0D)
_REG_DATA = const(0x12)
_FEED1_ENABLE = const(0x01)
_FEED1_ABSOLUTE = const(0x02)
_FEED1_NO_FILTER = const(0x04)
_FEED1_NO_X_DATA = const(0x08)
_FEED1_NO_Y_DATA = const(0x10)
_FEED1_INVERT_X = const(0x40)
_FEED1_INVERT_Y = const(0x80)
_FEED2_INTELLIMOUSE = const(0x01)
_FEED2_NO_TAPS = const(0x02)
_FEED2_NO_SEC_TAPS = const(0x04)
_FEED2_NO_SCROLL = const(0x08)
_FEED2_NO_GLIDEEXTEND = const(0x10)
_FEED2_SWAP_XY = const(0x80)
def with_i2c_lock(rw: Callable[[object, int], None]) -> Callable[[object, int], None]:
def _(self, n: int) -> None:
if not self._i2c.try_lock():
if debug.enabled:
debug("can't acquire lock")
return
try:
rw(self, n)
finally:
self._i2c.unlock()
return _
class AbsoluteHandler:
cfg = (
_REG_FEED_CFG2,
0x00,
_REG_FEED_CFG1,
_FEED1_ENABLE | _FEED1_NO_FILTER | _FEED1_ABSOLUTE | _FEED1_INVERT_X,
)
def handle(buffer: bytearray, keyboard) -> None:
button = buffer[0]
x_low = buffer[2]
y_low = buffer[3]
high = buffer[4]
z_lvl = buffer[5]
x_pos = ((high & 0x0F) << 8) | x_low
y_pos = ((high & 0xF0) << 4) | y_low
if debug.enabled:
debug(
'buttons:',
bin(button),
' x_pos:',
x_pos,
' y_pos:',
y_pos,
'z_lvl:',
z_lvl,
)
class RelativeHandler:
cfg = (
_REG_FEED_CFG2,
0x00,
_REG_FEED_CFG1,
_FEED1_ENABLE | _FEED1_NO_FILTER | _FEED1_INVERT_X,
)
def handle(buffer: bytearray, keyboard) -> None:
button = buffer[0] & 0b00000111
x_sign = buffer[0] & 0b00010000
y_sign = buffer[0] & 0b00100000
x_delta = buffer[1]
y_delta = buffer[2]
w_delta = buffer[3]
if x_sign:
x_delta -= 0xFF
if y_sign:
y_delta -= 0xFF
if x_delta != 0:
AX.X.move(keyboard, x_delta)
if y_delta != 0:
AX.Y.move(keyboard, y_delta)
if debug.enabled:
debug(
'buttons:',
bin(button),
' x_delta:',
x_delta,
' y_delta:',
y_delta,
' w_delta',
w_delta,
)
class GlidePoint(Module):
def __init__(self, i2c):
self._i2c = i2c
self._buffer = bytearray(8)
# self.handler = RelativeHandler
self.handler = AbsoluteHandler
@with_i2c_lock
def _read(self, n: int) -> None:
self._buffer[0] |= _MASK_READ
self._i2c.writeto_then_readfrom(
_ADDRESS, self._buffer, self._buffer, out_end=1, in_end=n
)
@with_i2c_lock
def _write(self, n: int) -> None:
for i in range(0, n, 2):
self._buffer[i] |= _MASK_WRITE
self._i2c.writeto(_ADDRESS, self._buffer, end=n)
def _check_firmware(self) -> bool:
self._buffer[0] = _REG_FW_ID
self._read(2)
return self._buffer[:2] == b'\x07:'
def _clear_status_flags(self) -> None:
self._buffer[0] = _REG_STATUS
self._buffer[1] = 0x00
self._write(2)
def _configure(self) -> None:
self._buffer[0] = _REG_SYS_CFG
self._buffer[1] = 0x00
for idx, val in enumerate(self.handler.cfg):
self._buffer[idx + 2] = val
self._write(2 + len(self.handler.cfg))
def _data_ready(self) -> bool:
self._buffer[0] = _REG_STATUS
self._read(1)
return self._buffer[0] != 0x00
def during_bootup(self, keyboard):
if not self._check_firmware:
raise OSError('Firmware ID mismatch')
self._clear_status_flags()
self._configure()
def before_matrix_scan(self, keyboard):
pass
def after_matrix_scan(self, keyboard):
if not self._data_ready():
return
self._buffer[0] = _REG_DATA
self._read(6)
self.handler.handle(self._buffer, keyboard)
self._clear_status_flags()
def before_hid_send(self, keyboard):
pass
def after_hid_send(self, keyboard):
pass
def on_powersave_enable(self, keyboard):
self._buffer[0] = _REG_SYS_CFG
self._buffer[1] = 0x04
self._write(2)
def on_powersave_disable(self, keyboard):
self._buffer[0] = _REG_SYS_CFG
self._buffer[1] = 0x00
self._write(2)