Compare commits
1 Commits
mpy_build
...
enhancemen
Author | SHA1 | Date | |
---|---|---|---|
|
490e94e4e3 |
23
.github/workflows/build.yml
vendored
23
.github/workflows/build.yml
vendored
@@ -1,23 +0,0 @@
|
||||
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
|
59
Dockerfile
59
Dockerfile
@@ -1,20 +1,39 @@
|
||||
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"]
|
||||
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
|
||||
|
2
Makefile
2
Makefile
@@ -92,7 +92,7 @@ test: lint unit-tests
|
||||
|
||||
.PHONY: unit-tests
|
||||
unit-tests: devdeps
|
||||
@$(PIPENV) run python3 -m unittest
|
||||
@$(PIPENV) run python3 -m unittest ${TESTS}
|
||||
|
||||
reset-bootloader:
|
||||
@echo "===> Rebooting your board to bootloader (safe to ignore file not found errors)"
|
||||
|
@@ -15,7 +15,6 @@ 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)
|
||||
|
@@ -15,7 +15,6 @@ 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),
|
||||
|
@@ -78,7 +78,6 @@ 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)
|
||||
|
@@ -1,7 +0,0 @@
|
||||
version: '3.3'
|
||||
services:
|
||||
mpy_kmk:
|
||||
build: .
|
||||
volumes:
|
||||
- ./kmk:/app/kmk
|
||||
- ./.compiled:/app/compiled
|
@@ -1,14 +0,0 @@
|
||||
|
||||
#!/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"
|
@@ -27,7 +27,9 @@ 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 `python -m unittest`.
|
||||
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"`.
|
||||
|
||||
## Contributing Documentation
|
||||
While KMK welcomes documentation from anyone with and understanding of the issues
|
||||
|
@@ -127,13 +127,3 @@ 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
|
||||
|
113
kmk/hid.py
113
kmk/hid.py
@@ -4,8 +4,7 @@ from micropython import const
|
||||
|
||||
from storage import getmount
|
||||
|
||||
from kmk.keys import FIRST_KMK_INTERNAL_KEY, ConsumerKey, ModifierKey, MouseKey
|
||||
from kmk.utils import clamp
|
||||
from kmk.keys import FIRST_KMK_INTERNAL_KEY, ConsumerKey, ModifierKey
|
||||
|
||||
try:
|
||||
from adafruit_ble import BLERadio
|
||||
@@ -69,14 +68,6 @@ 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):
|
||||
@@ -85,27 +76,47 @@ class AbstractHID:
|
||||
def post_init(self):
|
||||
pass
|
||||
|
||||
def create_report(self, keys_pressed, axes):
|
||||
def create_report(self, keys_pressed):
|
||||
self.clear_all()
|
||||
|
||||
consumer_key = None
|
||||
for key in keys_pressed:
|
||||
if key.code >= FIRST_KMK_INTERNAL_KEY:
|
||||
continue
|
||||
if isinstance(key, ConsumerKey):
|
||||
consumer_key = key
|
||||
break
|
||||
|
||||
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)
|
||||
reporting_device = self.report_device[0]
|
||||
needed_reporting_device = HIDReportTypes.KEYBOARD
|
||||
|
||||
for axis in axes:
|
||||
self.move_axis(axis)
|
||||
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
|
||||
|
||||
def hid_send(self, evt):
|
||||
# Don't raise a NotImplementedError so this can serve as our "dummy" HID
|
||||
@@ -120,24 +131,12 @@ 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):
|
||||
@@ -176,6 +175,9 @@ 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
|
||||
@@ -191,44 +193,15 @@ 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
|
||||
|
35
kmk/keys.py
35
kmk/keys.py
@@ -20,7 +20,6 @@ class KeyType:
|
||||
SIMPLE = const(0)
|
||||
MODIFIER = const(1)
|
||||
CONSUMER = const(2)
|
||||
MOUSE = const(3)
|
||||
|
||||
|
||||
FIRST_KMK_INTERNAL_KEY = const(1000)
|
||||
@@ -34,29 +33,6 @@ 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, ...],
|
||||
@@ -364,7 +340,6 @@ 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)),
|
||||
@@ -713,10 +688,6 @@ class ConsumerKey(Key):
|
||||
pass
|
||||
|
||||
|
||||
class MouseKey(Key):
|
||||
pass
|
||||
|
||||
|
||||
def make_key(
|
||||
code: Optional[int] = None,
|
||||
names: Tuple[str, ...] = tuple(), # NOQA
|
||||
@@ -747,8 +718,6 @@ def make_key(
|
||||
constructor = ModifierKey
|
||||
elif type == KeyType.CONSUMER:
|
||||
constructor = ConsumerKey
|
||||
elif type == KeyType.MOUSE:
|
||||
constructor = MouseKey
|
||||
else:
|
||||
raise ValueError('Unrecognized key type')
|
||||
|
||||
@@ -781,10 +750,6 @@ 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(
|
||||
|
@@ -49,7 +49,6 @@ class KMKKeyboard:
|
||||
#####
|
||||
# Internal State
|
||||
keys_pressed = set()
|
||||
axes = set()
|
||||
_coordkeys_pressed = {}
|
||||
hid_type = HIDModes.USB
|
||||
secondary_hid_type = None
|
||||
@@ -89,7 +88,6 @@ 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}, ',
|
||||
@@ -104,24 +102,15 @@ class KMKKeyboard:
|
||||
debug(f'keys_pressed={self.keys_pressed}')
|
||||
|
||||
def _send_hid(self) -> None:
|
||||
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})')
|
||||
|
||||
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})')
|
||||
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)
|
||||
|
@@ -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,6 +70,7 @@ 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)
|
||||
@@ -202,14 +203,27 @@ class ADNS9800(Module):
|
||||
if self.invert_y:
|
||||
delta_y *= -1
|
||||
|
||||
if delta_x:
|
||||
AX.X.move(delta_x)
|
||||
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_y:
|
||||
AX.Y.move(delta_y)
|
||||
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 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
|
||||
|
@@ -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,6 +44,7 @@ class Easypoint(Module):
|
||||
self._i2c_bus = i2c
|
||||
|
||||
# HID parameters
|
||||
self.pointing_device = PointingDevice()
|
||||
self.polling_interval = 20
|
||||
self.last_tick = ticks_ms()
|
||||
|
||||
@@ -81,8 +82,12 @@ class Easypoint(Module):
|
||||
return
|
||||
else:
|
||||
# Set the X/Y from easypoint
|
||||
AX.X.move(keyboard, x)
|
||||
AX.Y.move(keyboard, y)
|
||||
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
|
||||
|
||||
def after_matrix_scan(self, keyboard):
|
||||
return
|
||||
@@ -91,6 +96,9 @@ 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):
|
||||
@@ -99,6 +107,13 @@ 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)
|
||||
|
@@ -114,15 +114,17 @@ class Layers(HoldTap):
|
||||
'''
|
||||
As MO(layer) but with mod active
|
||||
'''
|
||||
keyboard.hid_pending = True
|
||||
# Sets the timer start and acts like MO otherwise
|
||||
keyboard.add_key(key.meta.kc)
|
||||
keyboard.keys_pressed.add(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.remove_key(key.meta.kc)
|
||||
keyboard.hid_pending = True
|
||||
keyboard.keys_pressed.discard(key.meta.kc)
|
||||
self._mo_released(key, keyboard, *args, **kwargs)
|
||||
|
||||
def _tg_pressed(self, key, keyboard, *args, **kwargs):
|
||||
|
@@ -1,6 +1,7 @@
|
||||
from supervisor import ticks_ms
|
||||
|
||||
from kmk.hid import HID_REPORT_SIZES, HIDReportTypes
|
||||
from kmk.keys import AX, make_key, make_mouse_key
|
||||
from kmk.kmktime import PeriodicTimer
|
||||
from kmk.keys import make_key
|
||||
from kmk.modules import Module
|
||||
|
||||
|
||||
@@ -23,28 +24,31 @@ 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.acc_interval = 10 # Delta ms to apply acceleration
|
||||
self.ac_interval = 100 # Delta ms to apply acceleration
|
||||
self._next_interval = 0 # Time for next tick interval
|
||||
self.move_step = 1
|
||||
|
||||
make_mouse_key(
|
||||
make_key(
|
||||
names=('MB_LMB',),
|
||||
code=1,
|
||||
on_press=self._mb_lmb_press,
|
||||
on_release=self._mb_lmb_release,
|
||||
)
|
||||
make_mouse_key(
|
||||
make_key(
|
||||
names=('MB_MMB',),
|
||||
code=4,
|
||||
on_press=self._mb_mmb_press,
|
||||
on_release=self._mb_mmb_release,
|
||||
)
|
||||
make_mouse_key(
|
||||
make_key(
|
||||
names=('MB_RMB',),
|
||||
code=2,
|
||||
on_press=self._mb_rmb_press,
|
||||
on_release=self._mb_rmb_release,
|
||||
)
|
||||
make_key(
|
||||
names=('MW_UP',),
|
||||
@@ -90,33 +94,38 @@ class MouseKeys(Module):
|
||||
)
|
||||
|
||||
def during_bootup(self, keyboard):
|
||||
self._timer = PeriodicTimer(self.acc_interval)
|
||||
return
|
||||
|
||||
def matrix_detected_press(self, keyboard):
|
||||
return keyboard.matrix_update is None
|
||||
|
||||
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.move_step < self.max_speed:
|
||||
self.move_step = self.move_step + 1
|
||||
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._right_activated:
|
||||
AX.X.move(keyboard, self.move_step)
|
||||
self.pointing_device.report_x[0] = self.move_step
|
||||
if self._left_activated:
|
||||
AX.X.move(keyboard, -self.move_step)
|
||||
self.pointing_device.report_x[0] = 0xFF & (0 - self.move_step)
|
||||
if self._up_activated:
|
||||
AX.Y.move(keyboard, -self.move_step)
|
||||
self.pointing_device.report_y[0] = 0xFF & (0 - self.move_step)
|
||||
if self._down_activated:
|
||||
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)
|
||||
self.pointing_device.report_y[0] = self.move_step
|
||||
self.pointing_device.hid_pending = True
|
||||
return
|
||||
|
||||
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):
|
||||
@@ -128,21 +137,50 @@ 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._mw_up_activated = True
|
||||
self.pointing_device.report_w[0] = self.move_step
|
||||
self.pointing_device.hid_pending = True
|
||||
|
||||
def _mw_up_release(self, key, keyboard, *args, **kwargs):
|
||||
self._mw_up_activated = False
|
||||
self.pointing_device.report_w[0] = 0
|
||||
self.pointing_device.hid_pending = True
|
||||
|
||||
def _mw_down_press(self, key, keyboard, *args, **kwargs):
|
||||
self._mw_down_activated = True
|
||||
self.pointing_device.report_w[0] = 0xFF
|
||||
self.pointing_device.hid_pending = True
|
||||
|
||||
def _mw_down_release(self, key, keyboard, *args, **kwargs):
|
||||
self._mw_down_activated = False
|
||||
self.pointing_device.report_w[0] = 0
|
||||
self.pointing_device.hid_pending = True
|
||||
|
||||
# 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):
|
||||
@@ -153,38 +191,56 @@ 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
|
||||
|
@@ -7,9 +7,10 @@ from micropython import const
|
||||
import math
|
||||
import struct
|
||||
|
||||
from kmk.keys import AX, KC, make_argumented_key, make_key
|
||||
from kmk.keys import 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
|
||||
@@ -77,16 +78,29 @@ class TrackballHandler:
|
||||
|
||||
class PointingHandler(TrackballHandler):
|
||||
def handle(self, keyboard, trackball, x, y, switch, state):
|
||||
if x:
|
||||
AX.X.move(keyboard, x)
|
||||
if y:
|
||||
AX.Y.move(keyboard, y)
|
||||
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 switch == 1: # Button pressed
|
||||
keyboard.pre_process_key(KC.MB_LMB, is_pressed=True)
|
||||
trackball.pointing_device.button_status[
|
||||
0
|
||||
] |= trackball.pointing_device.MB_LMB
|
||||
trackball.pointing_device.hid_pending = True
|
||||
|
||||
if not state and trackball.previous_state is True: # Button released
|
||||
keyboard.pre_process_key(KC.MB_LMB, is_pressed=False)
|
||||
trackball.pointing_device.button_status[
|
||||
0
|
||||
] &= ~trackball.pointing_device.MB_LMB
|
||||
trackball.pointing_device.hid_pending = True
|
||||
|
||||
trackball.previous_state = state
|
||||
|
||||
@@ -100,13 +114,17 @@ class ScrollHandler(TrackballHandler):
|
||||
y = -y
|
||||
|
||||
if y != 0:
|
||||
AX.W.move(keyboard, y)
|
||||
pointing_device = trackball.pointing_device
|
||||
pointing_device.report_w[0] = 0xFF & y
|
||||
pointing_device.hid_pending = True
|
||||
|
||||
if switch == 1: # Button pressed
|
||||
keyboard.pre_process_key(KC.MB_LMB, is_pressed=True)
|
||||
pointing_device.button_status[0] |= pointing_device.MB_LMB
|
||||
pointing_device.hid_pending = True
|
||||
|
||||
if not state and trackball.previous_state is True: # Button released
|
||||
keyboard.pre_process_key(KC.MB_LMB, is_pressed=False)
|
||||
pointing_device.button_status[0] &= ~pointing_device.MB_LMB
|
||||
pointing_device.hid_pending = True
|
||||
|
||||
trackball.previous_state = state
|
||||
|
||||
@@ -167,6 +185,7 @@ 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
|
||||
@@ -215,6 +234,9 @@ 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):
|
||||
@@ -258,6 +280,13 @@ 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)
|
||||
|
@@ -1,39 +0,0 @@
|
||||
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
BIN
mpy-cross-7
Binary file not shown.
BIN
mpy-cross-8
BIN
mpy-cross-8
Binary file not shown.
Reference in New Issue
Block a user