29 Commits

Author SHA1 Message Date
cole
370eb151e2 removed unused file 2023-02-19 19:54:25 -08:00
cole
d0b93bd275 cleaning up 2023-02-19 19:30:50 -08:00
cole
f1f5ac01bd more striping 2023-02-19 19:26:51 -08:00
cole
8101f98860 why use docker inside 2023-02-19 19:17:23 -08:00
cole
3b4c00b1bb working on work flow 2023-02-19 19:06:31 -08:00
cole
4518983b36 workflow file 2023-02-19 19:00:25 -08:00
cole
d5106dd5e2 editing build script 2023-02-19 18:44:10 -08:00
cole
730a18437c editing build script 2023-02-19 18:39:49 -08:00
cole
1ae2de4315 working on work flow 2023-02-19 18:33:27 -08:00
cole
8bcaa7a235 working on work flow 2023-02-19 18:28:45 -08:00
cole
b2ae0d364a docker compose version bump 2023-02-19 18:21:20 -08:00
cole
51528cbb41 docker compose version bump 2023-02-19 18:17:31 -08:00
cole
db4030f49b working on work flow 2023-02-19 18:12:24 -08:00
cole
fb87de1d85 working on work flow 2023-02-19 18:11:07 -08:00
cole
f65f436273 made new docker file to build mpy files 2023-02-19 18:09:02 -08:00
xs5871
a90d569690 Fix CC HID report generation 2023-02-18 08:20:52 +00:00
xs5871
449aab7dcb Add BLE_DISCONNECT key 2023-02-17 03:03:40 +00:00
Stefan Misch
dc9b5f4512 fix encoder resolution for MacroPad10 2023-02-16 09:07:48 +00:00
Stefan Misch
cbaddef9a6 fix encoder resolution for Knobs3 2023-02-16 09:07:48 +00:00
Stefan Misch
804b5ec575 fix: encoder resolution for Knob 1 2023-02-16 09:07:48 +00:00
xs5871
a28df47199 Refactor affected modules to use global pointing device 2023-02-14 20:42:08 +00:00
xs5871
9e5d2c24e1 Refactor for nicer pointing device axes handling 2023-02-14 20:42:08 +00:00
xs5871
ca800331de Implement axis movement method 2023-02-14 20:42:08 +00:00
xs5871
1ca27dab58 refactor mouse_keys to use PeriodicTimer 2023-02-14 20:42:08 +00:00
xs5871
fc8d5edd52 refactor mouse_keys module to use global pd 2023-02-14 20:42:08 +00:00
xs5871
e84bbd0d75 add mouse buttons to pointing device 2023-02-14 20:42:08 +00:00
xs5871
69d47343e8 implement global pointing device axis handling 2023-02-14 20:42:08 +00:00
xs5871
470f16c97f factor out consumer control from keyboard hid 2023-02-14 20:42:08 +00:00
xs5871
27f101d139 remove hid awareness from layer module 2023-02-14 20:42:08 +00:00
22 changed files with 291 additions and 259 deletions

23
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: build_mpy
on: [push]
jobs:
build:
runs-on: ubuntu-latest
name: Build
steps:
- name: Checkout
uses: actions/checkout@v3
- name: run build script
run: ./docker_mpy_build.sh
- name: look
run: ls -la compiled/
- name: Archive
uses: actions/upload-artifact@v3
with:
name: mpy
path: compiled

View File

@@ -1,39 +1,20 @@
FROM python:3.9-slim-buster
ARG KMKPY_REF
ARG KMKPY_URL
ENV KMKPY_REF ${KMKPY_REF}
ENV KMKPY_URL ${KMKPY_URL}
RUN mkdir -p /app /dist
WORKDIR /app
RUN apt-get update && apt-get install -y build-essential curl gettext git git-lfs rsync wget zip lbzip2
RUN pip install pipenv
# Pull CircuitPython-designated ARM GCC to avoid mismatches/weird
# inconsistencies with upstream
RUN curl -L -o /tmp/gcc-arm.tar.bz2 https://adafruit-circuit-python.s3.amazonaws.com/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2 && \
tar -C /usr --strip-components=1 -xaf /tmp/gcc-arm.tar.bz2 && \
rm -rf /tmp/gcc-arm.tar.bz2
# Get a local copy of KMKPython and its dependencies. We don't provide MPY
# builds for kmkpython anymore, so we can get away with being opinionated
# here.
RUN git init /opt/kmkpython && \
git -C /opt/kmkpython remote add origin ${KMKPY_URL} && \
git -C /opt/kmkpython fetch --depth 1 origin ${KMKPY_REF} && \
git -C /opt/kmkpython checkout FETCH_HEAD && \
git -C /opt/kmkpython submodule update --init --recursive
# Build the MPY compiler
RUN make -C /opt/kmkpython/mpy-cross
ENV PATH=/opt/kmkpython/mpy-cross:${PATH}
RUN mkdir -p /opt/kmkpython/frozen/kmk/kmk
COPY ./build_kmkpython_release.sh /app/
COPY ./kmk /opt/kmkpython/frozen/kmk/kmk
CMD /app/build_kmkpython_release.sh
FROM python:3.9-slim-buster
RUN mkdir -p /app /dist
WORKDIR /app
RUN apt-get update && apt-get install -y curl
RUN curl https://adafruit-circuit-python.s3.amazonaws.com/bin/mpy-cross/linux-amd64/mpy-cross.static-amd64-linux-8.0.0 --output mpy-cross-8
RUN curl https://adafruit-circuit-python.s3.amazonaws.com/bin/mpy-cross/linux-amd64/mpy-cross.static-amd64-linux-7.0.0 --output mpy-cross-7
RUN chmod +x mpy-cross-8
RUN chmod +x mpy-cross-7
COPY ./docker_mpy_build.sh /app/build.sh
# COPY ./kmk /app/kmk/
CMD ["bash", "build.sh"]

View File

@@ -92,7 +92,7 @@ test: lint unit-tests
.PHONY: unit-tests
unit-tests: devdeps
@$(PIPENV) run python3 -m unittest ${TESTS}
@$(PIPENV) run python3 -m unittest
reset-bootloader:
@echo "===> Rebooting your board to bootloader (safe to ignore file not found errors)"

View File

@@ -15,6 +15,7 @@ knob.extensions.append(media_keys)
# Rotary encoder that also acts as a key
encoder_handler = EncoderHandler()
encoder_handler.divisor = 2
encoder_handler.pins = ((board.D1, board.D2, board.D0),)
encoder_handler.map = (((KC.VOLD, KC.VOLU, KC.MUTE),),)
knob.modules.append(encoder_handler)

View File

@@ -15,6 +15,7 @@ knob.extensions.append(media_keys)
# Rotary encoders that also acts as keys
encoder_handler = EncoderHandler()
encoder_handler.divisor = 2
encoder_handler.pins = (
(board.D1, board.D2, board.D0),
(board.D9, board.D10, board.D3),

View File

@@ -78,6 +78,7 @@ keyboard.keymap = [
# Rotary encoder that also acts as a key
encoder_handler = EncoderHandler()
encoder_handler.divisor = 2
encoder_handler.pins = ((board.D8, board.D7, board.D9),)
encoder_handler.map = (((KC.VOLD, KC.VOLU, KC.MUTE),),)
keyboard.modules.append(encoder_handler)

0
compiled/.gitkeep Normal file
View File

7
docker-compose.yml Normal file
View File

@@ -0,0 +1,7 @@
version: '3.3'
services:
mpy_kmk:
build: .
volumes:
- ./kmk:/app/kmk
- ./.compiled:/app/compiled

14
docker_mpy_build.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
echo "building mpy"
echo $(ls compiled)
find kmk/ -name "*.py" -exec sh -c 'mkdir -p compiled/8/$(dirname {}) &&\
./mpy-cross-8 -O2 {} -o compiled/8/$(dirname {})/$(basename -s .py {}).mpy' \;
find kmk/ -name "*.py" -exec sh -c 'mkdir -p compiled/7/$(dirname {}) &&\
./mpy-cross-7 -O2 {} -o compiled/7/$(dirname {})/$(basename -s .py {}).mpy' \;
echo $(ls compiled)
echo "done building"

View File

@@ -27,9 +27,7 @@ to Black formatting as documented in `pyproject.toml`)
Unit tests within the `tests` folder mock various CircuitPython modules to allow
them to be executed in a desktop development environment.
Execute tests using the command `make unit-tests`. The `unit-tests` target
accepts an additional environment variable for selection of specific tests,
example `make unit-tests TESTS="tests.test_kmk_keys tests.test_layers"`.
Execute tests using the command `python -m unittest`.
## Contributing Documentation
While KMK welcomes documentation from anyone with and understanding of the issues

View File

@@ -127,3 +127,13 @@ def ble_refresh(key, keyboard, *args, **kwargs):
keyboard._hid_helper.stop_advertising()
keyboard._hid_helper.start_advertising()
return keyboard
def ble_disconnect(key, keyboard, *args, **kwargs):
from kmk.hid import HIDModes
if keyboard.hid_type != HIDModes.BLE:
return keyboard
keyboard._hid_helper.clear_bonds()
return keyboard

View File

@@ -4,7 +4,8 @@ from micropython import const
from storage import getmount
from kmk.keys import FIRST_KMK_INTERNAL_KEY, ConsumerKey, ModifierKey
from kmk.keys import FIRST_KMK_INTERNAL_KEY, ConsumerKey, ModifierKey, MouseKey
from kmk.utils import clamp
try:
from adafruit_ble import BLERadio
@@ -68,6 +69,14 @@ class AbstractHID:
self.report_mods = memoryview(self._evt)[1:2]
self.report_non_mods = memoryview(self._evt)[3:]
self._cc_report = bytearray(HID_REPORT_SIZES[HIDReportTypes.CONSUMER] + 1)
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):
@@ -76,47 +85,27 @@ class AbstractHID:
def post_init(self):
pass
def create_report(self, keys_pressed):
def create_report(self, keys_pressed, axes):
self.clear_all()
consumer_key = None
for key in keys_pressed:
if isinstance(key, ConsumerKey):
consumer_key = key
break
if key.code >= FIRST_KMK_INTERNAL_KEY:
continue
reporting_device = self.report_device[0]
needed_reporting_device = HIDReportTypes.KEYBOARD
if isinstance(key, ModifierKey):
self.add_modifier(key)
elif isinstance(key, ConsumerKey):
self.add_cc(key)
elif isinstance(key, MouseKey):
self.add_pd(key)
else:
self.add_key(key)
if key.has_modifiers:
for mod in key.has_modifiers:
self.add_modifier(mod)
if consumer_key:
needed_reporting_device = HIDReportTypes.CONSUMER
if reporting_device != needed_reporting_device:
# If we are about to change reporting devices, release
# all keys and close our proverbial tab on the existing
# device, or keys will get stuck (mostly when releasing
# media/consumer keys)
self.send()
self.report_device[0] = needed_reporting_device
if consumer_key:
self.add_key(consumer_key)
else:
for key in keys_pressed:
if key.code >= FIRST_KMK_INTERNAL_KEY:
continue
if isinstance(key, ModifierKey):
self.add_modifier(key)
else:
self.add_key(key)
if key.has_modifiers:
for mod in key.has_modifiers:
self.add_modifier(mod)
return self
for axis in axes:
self.move_axis(axis)
def hid_send(self, evt):
# Don't raise a NotImplementedError so this can serve as our "dummy" HID
@@ -131,12 +120,24 @@ class AbstractHID:
self._prev_evt[:] = self._evt
self.hid_send(self._evt)
if self._cc_pending:
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):
for idx, _ in enumerate(self.report_keys):
self.report_keys[idx] = 0x00
self.remove_cc()
self.remove_pd()
self.clear_axis()
return self
def clear_non_modifiers(self):
@@ -175,9 +176,6 @@ class AbstractHID:
where_to_place = self.report_non_mods
if self.report_device[0] == HIDReportTypes.CONSUMER:
where_to_place = self.report_keys
for idx, _ in enumerate(where_to_place):
if where_to_place[idx] == 0x00:
where_to_place[idx] = key.code
@@ -193,15 +191,44 @@ class AbstractHID:
def remove_key(self, key):
where_to_place = self.report_non_mods
if self.report_device[0] == HIDReportTypes.CONSUMER:
where_to_place = self.report_keys
for idx, _ in enumerate(where_to_place):
if where_to_place[idx] == key.code:
where_to_place[idx] = 0x00
return self
def add_cc(self, cc):
# Add (or write over) consumer control report. There can only be one CC
# active at any time.
memoryview(self._cc_report)[1:3] = cc.code.to_bytes(2, 'little')
self._cc_pending = True
def remove_cc(self):
# Remove consumer control report.
report = memoryview(self._cc_report)[1:3]
if report != b'\x00\x00':
report[:] = b'\x00\x00'
self._cc_pending = True
def add_pd(self, key):
self._pd_report[1] |= key.code
self._pd_pending = True
def remove_pd(self):
if self._pd_report[1]:
self._pd_pending = True
self._pd_report[1] = 0x00
def move_axis(self, axis):
delta = clamp(axis.delta, -127, 127)
axis.delta -= delta
self._pd_report[axis.code + 2] = 0xFF & delta
self._pd_pending = True
def clear_axis(self):
for idx in range(2, len(self._pd_report)):
self._pd_report[idx] = 0x00
class USBHID(AbstractHID):
REPORT_BYTES = 9

View File

@@ -20,6 +20,7 @@ class KeyType:
SIMPLE = const(0)
MODIFIER = const(1)
CONSUMER = const(2)
MOUSE = const(3)
FIRST_KMK_INTERNAL_KEY = const(1000)
@@ -33,6 +34,29 @@ 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 move(self, keyboard: Keyboard, delta: int):
self.delta += delta
if self.delta:
keyboard.axes.add(self)
keyboard.hid_pending = True
else:
keyboard.axes.discard(self)
class AX:
W = Axis(2)
X = Axis(0)
Y = Axis(1)
def maybe_make_key(
code: Optional[int],
names: Tuple[str, ...],
@@ -340,6 +364,7 @@ def maybe_make_unicode_key(candidate: str) -> Optional[Key]:
def maybe_make_firmware_key(candidate: str) -> Optional[Key]:
keys = (
((('BLE_REFRESH',), handlers.ble_refresh)),
((('BLE_DISCONNECT',), handlers.ble_disconnect)),
((('BOOTLOADER',), handlers.bootloader)),
((('DEBUG', 'DBG'), handlers.debug_pressed)),
((('HID_SWITCH', 'HID'), handlers.hid_switch)),
@@ -688,6 +713,10 @@ class ConsumerKey(Key):
pass
class MouseKey(Key):
pass
def make_key(
code: Optional[int] = None,
names: Tuple[str, ...] = tuple(), # NOQA
@@ -718,6 +747,8 @@ def make_key(
constructor = ModifierKey
elif type == KeyType.CONSUMER:
constructor = ConsumerKey
elif type == KeyType.MOUSE:
constructor = MouseKey
else:
raise ValueError('Unrecognized key type')
@@ -750,6 +781,10 @@ def make_consumer_key(*args, **kwargs) -> Key:
return make_key(*args, **kwargs, type=KeyType.CONSUMER)
def make_mouse_key(*args, **kwargs) -> Key:
return make_key(*args, **kwargs, type=KeyType.MOUSE)
# Argumented keys are implicitly internal, so auto-gen of code
# is almost certainly the best plan here
def make_argumented_key(

View File

@@ -49,6 +49,7 @@ class KMKKeyboard:
#####
# Internal State
keys_pressed = set()
axes = set()
_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}, ',
@@ -102,15 +104,24 @@ class KMKKeyboard:
debug(f'keys_pressed={self.keys_pressed}')
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
if self.axes and debug.enabled:
debug(f'axes={self.axes}')
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:
axis.move(self, 0)
def _handle_matrix_report(self, kevent: KeyEvent) -> None:
if kevent is not None:
self._on_matrix_changed(kevent)

View File

@@ -4,9 +4,9 @@ import microcontroller
import time
from kmk.keys import AX
from kmk.modules import Module
from kmk.modules.adns9800_firmware import firmware
from kmk.modules.mouse_keys import PointingDevice
class REG:
@@ -70,7 +70,6 @@ class ADNS9800(Module):
DIR_READ = 0x7F
def __init__(self, cs, sclk, miso, mosi, invert_x=False, invert_y=False):
self.pointing_device = PointingDevice()
self.cs = digitalio.DigitalInOut(cs)
self.cs.direction = digitalio.Direction.OUTPUT
self.spi = busio.SPI(clock=sclk, MOSI=mosi, MISO=miso)
@@ -203,27 +202,14 @@ class ADNS9800(Module):
if self.invert_y:
delta_y *= -1
if delta_x < 0:
self.pointing_device.report_x[0] = (delta_x & 0xFF) | 0x80
else:
self.pointing_device.report_x[0] = delta_x & 0xFF
if delta_x:
AX.X.move(delta_x)
if delta_y < 0:
self.pointing_device.report_y[0] = (delta_y & 0xFF) | 0x80
else:
self.pointing_device.report_y[0] = delta_y & 0xFF
if delta_y:
AX.Y.move(delta_y)
if keyboard.debug_enabled:
print('Delta: ', delta_x, ' ', delta_y)
self.pointing_device.hid_pending = True
if self.pointing_device.hid_pending:
keyboard._hid_helper.hid_send(self.pointing_device._evt)
self.pointing_device.hid_pending = False
self.pointing_device.report_x[0] = 0
self.pointing_device.report_y[0] = 0
return
def after_matrix_scan(self, keyboard):
return

View File

@@ -4,8 +4,8 @@ Extension handles usage of AS5013 by AMS
from supervisor import ticks_ms
from kmk.keys import AX
from kmk.modules import Module
from kmk.modules.mouse_keys import PointingDevice
I2C_ADDRESS = 0x40
I2X_ALT_ADDRESS = 0x41
@@ -44,7 +44,6 @@ class Easypoint(Module):
self._i2c_bus = i2c
# HID parameters
self.pointing_device = PointingDevice()
self.polling_interval = 20
self.last_tick = ticks_ms()
@@ -82,12 +81,8 @@ class Easypoint(Module):
return
else:
# Set the X/Y from easypoint
self.pointing_device.report_x[0] = x
self.pointing_device.report_y[0] = y
self.pointing_device.hid_pending = x != 0 or y != 0
return
AX.X.move(keyboard, x)
AX.Y.move(keyboard, y)
def after_matrix_scan(self, keyboard):
return
@@ -96,9 +91,6 @@ class Easypoint(Module):
return
def after_hid_send(self, keyboard):
if self.pointing_device.hid_pending:
keyboard._hid_helper.hid_send(self.pointing_device._evt)
self._clear_pending_hid()
return
def on_powersave_enable(self, keyboard):
@@ -107,13 +99,6 @@ class Easypoint(Module):
def on_powersave_disable(self, keyboard):
return
def _clear_pending_hid(self):
self.pointing_device.hid_pending = False
self.pointing_device.report_x[0] = 0
self.pointing_device.report_y[0] = 0
self.pointing_device.report_w[0] = 0
self.pointing_device.button_status[0] = 0
def _read_raw_state(self):
'''Read data from AS5013'''
x, y = self._i2c_rdwr([X], length=2)

View File

@@ -114,17 +114,15 @@ class Layers(HoldTap):
'''
As MO(layer) but with mod active
'''
keyboard.hid_pending = True
# Sets the timer start and acts like MO otherwise
keyboard.keys_pressed.add(key.meta.kc)
keyboard.add_key(key.meta.kc)
self._mo_pressed(key, keyboard, *args, **kwargs)
def _lm_released(self, key, keyboard, *args, **kwargs):
'''
As MO(layer) but with mod active
'''
keyboard.hid_pending = True
keyboard.keys_pressed.discard(key.meta.kc)
keyboard.remove_key(key.meta.kc)
self._mo_released(key, keyboard, *args, **kwargs)
def _tg_pressed(self, key, keyboard, *args, **kwargs):

View File

@@ -1,7 +1,6 @@
from supervisor import ticks_ms
from kmk.hid import HID_REPORT_SIZES, HIDReportTypes
from kmk.keys import make_key
from kmk.keys import AX, make_key, make_mouse_key
from kmk.kmktime import PeriodicTimer
from kmk.modules import Module
@@ -24,31 +23,28 @@ class PointingDevice:
class MouseKeys(Module):
def __init__(self):
self.pointing_device = PointingDevice()
self._nav_key_activated = 0
self._up_activated = False
self._down_activated = False
self._left_activated = False
self._right_activated = False
self._mw_up_activated = False
self._mw_down_activated = False
self.max_speed = 10
self.ac_interval = 100 # Delta ms to apply acceleration
self._next_interval = 0 # Time for next tick interval
self.acc_interval = 10 # Delta ms to apply acceleration
self.move_step = 1
make_key(
make_mouse_key(
names=('MB_LMB',),
on_press=self._mb_lmb_press,
on_release=self._mb_lmb_release,
code=1,
)
make_key(
make_mouse_key(
names=('MB_MMB',),
on_press=self._mb_mmb_press,
on_release=self._mb_mmb_release,
code=4,
)
make_key(
make_mouse_key(
names=('MB_RMB',),
on_press=self._mb_rmb_press,
on_release=self._mb_rmb_release,
code=2,
)
make_key(
names=('MW_UP',),
@@ -94,38 +90,33 @@ class MouseKeys(Module):
)
def during_bootup(self, keyboard):
return
def matrix_detected_press(self, keyboard):
return keyboard.matrix_update is None
self._timer = PeriodicTimer(self.acc_interval)
def before_matrix_scan(self, keyboard):
return
def after_matrix_scan(self, keyboard):
if not self._timer.tick():
return
if self._nav_key_activated:
if self._next_interval <= ticks_ms():
# print("hello: ")
# print(ticks_ms())
self._next_interval = ticks_ms() + self.ac_interval
# print(self._next_interval)
if self.move_step < self.max_speed:
self.move_step = self.move_step + 1
if self.move_step < self.max_speed:
self.move_step = self.move_step + 1
if self._right_activated:
self.pointing_device.report_x[0] = self.move_step
AX.X.move(keyboard, self.move_step)
if self._left_activated:
self.pointing_device.report_x[0] = 0xFF & (0 - self.move_step)
AX.X.move(keyboard, -self.move_step)
if self._up_activated:
self.pointing_device.report_y[0] = 0xFF & (0 - self.move_step)
AX.Y.move(keyboard, -self.move_step)
if self._down_activated:
self.pointing_device.report_y[0] = self.move_step
self.pointing_device.hid_pending = True
return
AX.Y.move(keyboard, self.move_step)
if self._mw_up_activated:
AX.W.move(keyboard, 1)
if self._mw_down_activated:
AX.W.move(keyboard, -1)
def before_hid_send(self, keyboard):
if self.pointing_device.hid_pending and keyboard._hid_send_enabled:
keyboard._hid_helper.hid_send(self.pointing_device._evt)
self.pointing_device.hid_pending = False
return
def after_hid_send(self, keyboard):
@@ -137,50 +128,21 @@ class MouseKeys(Module):
def on_powersave_disable(self, keyboard):
return
def _mb_lmb_press(self, key, keyboard, *args, **kwargs):
self.pointing_device.button_status[0] |= self.pointing_device.MB_LMB
self.pointing_device.hid_pending = True
def _mb_lmb_release(self, key, keyboard, *args, **kwargs):
self.pointing_device.button_status[0] &= ~self.pointing_device.MB_LMB
self.pointing_device.hid_pending = True
def _mb_mmb_press(self, key, keyboard, *args, **kwargs):
self.pointing_device.button_status[0] |= self.pointing_device.MB_MMB
self.pointing_device.hid_pending = True
def _mb_mmb_release(self, key, keyboard, *args, **kwargs):
self.pointing_device.button_status[0] &= ~self.pointing_device.MB_MMB
self.pointing_device.hid_pending = True
def _mb_rmb_press(self, key, keyboard, *args, **kwargs):
self.pointing_device.button_status[0] |= self.pointing_device.MB_RMB
self.pointing_device.hid_pending = True
def _mb_rmb_release(self, key, keyboard, *args, **kwargs):
self.pointing_device.button_status[0] &= ~self.pointing_device.MB_RMB
self.pointing_device.hid_pending = True
def _mw_up_press(self, key, keyboard, *args, **kwargs):
self.pointing_device.report_w[0] = self.move_step
self.pointing_device.hid_pending = True
self._mw_up_activated = True
def _mw_up_release(self, key, keyboard, *args, **kwargs):
self.pointing_device.report_w[0] = 0
self.pointing_device.hid_pending = True
self._mw_up_activated = False
def _mw_down_press(self, key, keyboard, *args, **kwargs):
self.pointing_device.report_w[0] = 0xFF
self.pointing_device.hid_pending = True
self._mw_down_activated = True
def _mw_down_release(self, key, keyboard, *args, **kwargs):
self.pointing_device.report_w[0] = 0
self.pointing_device.hid_pending = True
self._mw_down_activated = False
# Mouse movement
def _reset_next_interval(self):
if self._nav_key_activated == 1:
self._next_interval = ticks_ms() + self.ac_interval
self.move_step = 1
def _check_last(self):
@@ -191,56 +153,38 @@ class MouseKeys(Module):
self._nav_key_activated += 1
self._reset_next_interval()
self._up_activated = True
self.pointing_device.report_y[0] = 0xFF & (0 - self.move_step)
self.pointing_device.hid_pending = True
def _ms_up_release(self, key, keyboard, *args, **kwargs):
self._up_activated = False
self._nav_key_activated -= 1
self._check_last()
self.pointing_device.report_y[0] = 0
self.pointing_device.hid_pending = False
def _ms_down_press(self, key, keyboard, *args, **kwargs):
self._nav_key_activated += 1
self._reset_next_interval()
self._down_activated = True
# if not self.x_activated and not self.y_activated:
# self.next_interval = ticks_ms() + self.ac_intervalle
self.pointing_device.report_y[0] = self.move_step
self.pointing_device.hid_pending = True
def _ms_down_release(self, key, keyboard, *args, **kwargs):
self._down_activated = False
self._nav_key_activated -= 1
self._check_last()
self.pointing_device.report_y[0] = 0
self.pointing_device.hid_pending = False
def _ms_left_press(self, key, keyboard, *args, **kwargs):
self._nav_key_activated += 1
self._reset_next_interval()
self._left_activated = True
self.pointing_device.report_x[0] = 0xFF & (0 - self.move_step)
self.pointing_device.hid_pending = True
def _ms_left_release(self, key, keyboard, *args, **kwargs):
self._nav_key_activated -= 1
self._left_activated = False
self._check_last()
self.pointing_device.report_x[0] = 0
self.pointing_device.hid_pending = False
def _ms_right_press(self, key, keyboard, *args, **kwargs):
self._nav_key_activated += 1
self._reset_next_interval()
self._right_activated = True
self.pointing_device.report_x[0] = self.move_step
self.pointing_device.hid_pending = True
def _ms_right_release(self, key, keyboard, *args, **kwargs):
self._nav_key_activated -= 1
self._right_activated = False
self._check_last()
self.pointing_device.report_x[0] = 0
self.pointing_device.hid_pending = False

View File

@@ -7,10 +7,9 @@ from micropython import const
import math
import struct
from kmk.keys import make_argumented_key, make_key
from kmk.keys import AX, KC, make_argumented_key, make_key
from kmk.kmktime import PeriodicTimer
from kmk.modules import Module
from kmk.modules.mouse_keys import PointingDevice
I2C_ADDRESS = 0x0A
I2C_ADDRESS_ALTERNATIVE = 0x0B
@@ -78,29 +77,16 @@ class TrackballHandler:
class PointingHandler(TrackballHandler):
def handle(self, keyboard, trackball, x, y, switch, state):
if x > 0:
trackball.pointing_device.report_x[0] = x
elif x < 0:
trackball.pointing_device.report_x[0] = 0xFF & x
if y > 0:
trackball.pointing_device.report_y[0] = y
elif y < 0:
trackball.pointing_device.report_y[0] = 0xFF & y
if x != 0 or y != 0:
trackball.pointing_device.hid_pending = True
if x:
AX.X.move(keyboard, x)
if y:
AX.Y.move(keyboard, y)
if switch == 1: # Button pressed
trackball.pointing_device.button_status[
0
] |= trackball.pointing_device.MB_LMB
trackball.pointing_device.hid_pending = True
keyboard.pre_process_key(KC.MB_LMB, is_pressed=True)
if not state and trackball.previous_state is True: # Button released
trackball.pointing_device.button_status[
0
] &= ~trackball.pointing_device.MB_LMB
trackball.pointing_device.hid_pending = True
keyboard.pre_process_key(KC.MB_LMB, is_pressed=False)
trackball.previous_state = state
@@ -114,17 +100,13 @@ class ScrollHandler(TrackballHandler):
y = -y
if y != 0:
pointing_device = trackball.pointing_device
pointing_device.report_w[0] = 0xFF & y
pointing_device.hid_pending = True
AX.W.move(keyboard, y)
if switch == 1: # Button pressed
pointing_device.button_status[0] |= pointing_device.MB_LMB
pointing_device.hid_pending = True
keyboard.pre_process_key(KC.MB_LMB, is_pressed=True)
if not state and trackball.previous_state is True: # Button released
pointing_device.button_status[0] &= ~pointing_device.MB_LMB
pointing_device.hid_pending = True
keyboard.pre_process_key(KC.MB_LMB, is_pressed=False)
trackball.previous_state = state
@@ -185,7 +167,6 @@ class Trackball(Module):
self._i2c_address = address
self._i2c_bus = i2c
self.pointing_device = PointingDevice()
self.mode = mode
self.previous_state = False # click state
self.handlers = handlers
@@ -234,9 +215,6 @@ class Trackball(Module):
return
def after_hid_send(self, keyboard):
if self.pointing_device.hid_pending:
keyboard._hid_helper.hid_send(self.pointing_device._evt)
self._clear_pending_hid()
return
def on_powersave_enable(self, keyboard):
@@ -280,13 +258,6 @@ class Trackball(Module):
next_index = 0
self.activate_handler(next_index)
def _clear_pending_hid(self):
self.pointing_device.hid_pending = False
self.pointing_device.report_x[0] = 0
self.pointing_device.report_y[0] = 0
self.pointing_device.report_w[0] = 0
self.pointing_device.button_status[0] = 0
def _read_raw_state(self):
'''Read up, down, left, right and switch data from trackball.'''
left, right, up, down, switch = self._i2c_rdwr([REG_LEFT], 5)

39
kmk_python_Dockerfile Normal file
View File

@@ -0,0 +1,39 @@
FROM python:3.9-slim-buster
ARG KMKPY_REF
ARG KMKPY_URL
ENV KMKPY_REF ${KMKPY_REF}
ENV KMKPY_URL ${KMKPY_URL}
RUN mkdir -p /app /dist
WORKDIR /app
RUN apt-get update && apt-get install -y build-essential curl gettext git git-lfs rsync wget zip lbzip2
RUN pip install pipenv
# Pull CircuitPython-designated ARM GCC to avoid mismatches/weird
# inconsistencies with upstream
RUN curl -L -o /tmp/gcc-arm.tar.bz2 https://adafruit-circuit-python.s3.amazonaws.com/gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2 && \
tar -C /usr --strip-components=1 -xaf /tmp/gcc-arm.tar.bz2 && \
rm -rf /tmp/gcc-arm.tar.bz2
# Get a local copy of KMKPython and its dependencies. We don't provide MPY
# builds for kmkpython anymore, so we can get away with being opinionated
# here.
RUN git init /opt/kmkpython && \
git -C /opt/kmkpython remote add origin ${KMKPY_URL} && \
git -C /opt/kmkpython fetch --depth 1 origin ${KMKPY_REF} && \
git -C /opt/kmkpython checkout FETCH_HEAD && \
git -C /opt/kmkpython submodule update --init --recursive
# Build the MPY compiler
RUN make -C /opt/kmkpython/mpy-cross
ENV PATH=/opt/kmkpython/mpy-cross:${PATH}
RUN mkdir -p /opt/kmkpython/frozen/kmk/kmk
COPY ./build_kmkpython_release.sh /app/
COPY ./kmk /opt/kmkpython/frozen/kmk/kmk
CMD /app/build_kmkpython_release.sh

BIN
mpy-cross-7 Executable file

Binary file not shown.

BIN
mpy-cross-8 Executable file

Binary file not shown.