19 Commits

Author SHA1 Message Date
xs5871
cbfcd34fae Move trackball id check to during_bootup 2023-02-24 19:33:20 +00:00
xs5871
1d53d3a8da Implement PixelBuf interface for pimoroni trackball 2023-02-24 19:33:20 +00:00
xs5871
0e804ffd54 Use rotation matrix instead of trig for angle correction 2023-02-24 19:33:20 +00:00
xs5871
0cc308c055 Read trackball only if state changed 2023-02-24 19:33:20 +00:00
xs5871
c575fa396a Fix trackball switch handling 2023-02-24 19:33:20 +00:00
xs5871
a83e833d10 Remove infinite blocking loop on I2C error 2023-02-24 19:33:20 +00:00
xs5871
e9af3e542a Use debug() for error messages 2023-02-24 19:33:20 +00:00
xs5871
16d319359f Make trackball constants const() 2023-02-24 19:33:19 +00:00
xs5871
88c3616b6a Refactor Makefile copy-* targets for improved readability 2023-02-24 18:17:59 +00:00
xs5871
6ab4154ad5 Make copy-board target copy all BOARD/.*py files 2023-02-24 18:17:59 +00:00
xs5871
db2082f1c6 Add make target for compiled mpy code 2023-02-24 18:17:59 +00:00
xs5871
317f6407d6 Improve mpy-cross compilation target 2023-02-24 18:17:59 +00:00
xs5871
08c255b6e4 Add optional selection of specific unit test to Makefile 2023-02-24 18:17:59 +00:00
Aldoo
61cf527370 Removed extra ".__iter__()" in KeyAttrDict iterator: iterating elements in the partition already implicitly calls its __iter__ method.
Actually using the dictionary iterator with this extra call would trigger an error since an iterator does not have an iterator. This is no longer the case.
2023-02-22 19:37:20 +00:00
claycooper
38acda77b4 Moved pro micro image to fix render issues 2023-02-21 01:26:39 +00:00
claycooper
7ef2c2c2d3 Removed HTML br's from markdown 2023-02-21 01:26:39 +00:00
xs5871
1f751d8374 Add mouse buttons 4/5 2023-02-21 00:57:39 +00:00
xs5871
d4fe745e71 Cleanup PointingDevice from mouse_keys 2023-02-21 00:57:39 +00:00
xs5871
1674ff4ed7 Add linter format exception for kb.py 2023-02-20 20:42:23 +00:00
20 changed files with 192 additions and 275 deletions

View File

@@ -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

View File

@@ -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

103
Makefile
View File

@@ -30,19 +30,19 @@ TIMESTAMP := $(shell date +%s)
all: copy-kmk copy-bootpy copy-keymap copy-board
compile: $(MPY_TARGET_DIR)/.mpy.compiled
$(MPY_TARGET_DIR)/.mpy.compiled: $(PY_KMK_TREE)
.PHONY: compile compile-check
compile: compile-check
ifeq ($(MPY_CROSS),)
compile-check:
@echo "===> Could not find mpy-cross in PATH, exiting"
@false
endif
else
compile-check: $(PY_KMK_TREE:%.py=$(MPY_TARGET_DIR)/%.mpy)
@echo "===> Compiling all py files to mpy with flags $(MPY_FLAGS)"
@mkdir -p $(MPY_TARGET_DIR)
@echo "KMK_RELEASE = '$(DIST_DESCRIBE)'" > $(MPY_SOURCES)/release_info.py
@find $(MPY_SOURCES) -name "*.py" -exec sh -c 'mkdir -p $(MPY_TARGET_DIR)/$$(dirname {}) && $(MPY_CROSS) $(MPY_FLAGS) {} -o $(MPY_TARGET_DIR)/$$(dirname {})/$$(basename -s .py {}).mpy' \;
@rm -rf $(MPY_SOURCES)/release_info.py
@touch $(MPY_TARGET_DIR)/.mpy.compiled
$(MPY_TARGET_DIR)/%.mpy: %.py
@mkdir -p $(dir $@)
@$(MPY_CROSS) $(MPY_FLAGS) $? -o $@
endif
.devdeps: Pipfile.lock
@echo "===> Installing dependencies with pipenv"
@@ -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)"
@@ -102,55 +102,44 @@ reset-board:
@echo "===> Rebooting your board (safe to ignore file not found errors)"
@-timeout -k 5s 10s $(PIPENV) run ampy -p /dev/ttyACM0 -d ${AMPY_DELAY} -b ${AMPY_BAUD} run util/reset.py
ifdef MOUNTPOINT
$(MOUNTPOINT)/kmk/.copied: $(shell find kmk/ -name "*.py" | xargs -0)
@echo "===> Copying KMK source folder"
@rsync -rh kmk $(MOUNTPOINT)/
@touch $(MOUNTPOINT)/kmk/.copied
@sync
copy-kmk: $(MOUNTPOINT)/kmk/.copied
else
copy-kmk:
echo "**** MOUNTPOINT must be defined (wherever your CIRCUITPY drive is mounted) ****" && exit 1
endif
copy-board: $(MOUNTPOINT)/kb.py
$(MOUNTPOINT)/kb.py: $(BOARD)
@echo "===> Copying your board to kb.py"
@rsync -rh $(BOARD) $@
@sync
ifdef MOUNTPOINT
$(MOUNTPOINT)/kmk/boot.py: boot.py
@echo "===> Copying required boot.py"
@rsync -rh boot.py $(MOUNTPOINT)/
@sync
copy-bootpy: $(MOUNTPOINT)/kmk/boot.py
else
copy-bootpy:
echo "**** MOUNTPOINT must be defined (wherever your CIRCUITPY drive is mounted) ****" && exit 1
endif
ifdef MOUNTPOINT
ifndef USER_KEYMAP
$(MOUNTPOINT)/main.py:
@echo "**** USER_KEYMAP must be defined (ex. USER_KEYMAP=user_keymaps/noop.py) ****" && exit 1
else
$(MOUNTPOINT)/main.py: $(USER_KEYMAP)
@echo "===> Copying your keymap to main.py"
@rsync -rh $(USER_KEYMAP) $@
@sync
endif # USER_KEYMAP
copy-keymap: $(MOUNTPOINT)/main.py
else
copy-keymap:
echo "**** MOUNTPOINT must be defined (wherever your CIRCUITPY drive is mounted) ****" && exit 1
ifdef BOARD
copy-board: $(MOUNTPOINT)/kb.py
copy-board:
@echo "===> Copying your board from $(BOARD) to $(MOUNTPOINT)"
@rsync -rhu $(BOARD)/*.py $(MOUNTPOINT)/
@sync
else # BOARD
copy-board:
@echo "**** Missing BOARD argument ****" && exit 1
endif # BOARD
endif # MOUNTPOINT
copy-bootpy:
@echo "===> Copying required boot.py"
@rsync -rhu boot.py $(MOUNTPOINT)/boot.py
@sync
copy-compiled:
@echo "===> Copying compiled KMK folder"
@rsync -rhu $(MPY_TARGET_DIR)/* $(MOUNTPOINT)/
@sync
ifdef USER_KEYMAP
copy-keymap:
@echo "===> Copying your keymap to main.py"
@rsync -rhu $(USER_KEYMAP) $(MOUNTPOINT)/main.py
@sync
else # USER_KEYMAP
copy-keymap:
@echo "**** Missing USER_KEYMAP argument ****" && exit 1
endif # USER_KEYMAP
copy-kmk:
@echo "===> Copying KMK source folder"
@rsync -rhu kmk $(MOUNTPOINT)/
@sync
else # MOUNTPOINT
copy-board copy-bootpy copy-compiled copy-keymap copy-kmk:
@echo "**** MOUNTPOINT must be defined (wherever your CIRCUITPY drive is mounted) ****" && exit 1
endif # ifndef MOUNTPOINT

View File

View File

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

View File

@@ -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"

View File

@@ -4,7 +4,6 @@
KMK is a keyboard focused layer that sits on top of [CircuitPython](https://circuitpython.org/). As such, it should work with most [boards that support CircuitPython](https://circuitpython.org/downloads). KMK requires CircuitPython version 7.0 or above.
Known working and recommended devices can be found [here](Officially_Supported_Microcontrollers.md)
<br>
## TL;DR Quick start guide
> To infinity and beyond!
@@ -13,7 +12,7 @@ Known working and recommended devices can be found [here](Officially_Supported_M
3. Unzip it and copy the KMK folder and the boot.py file at the root of the USB drive corresponding to your board (often appearing as CIRCUITPY)
4. Create a new *code.py* or *main.py* file in the same root directory (same level as boot.py) with the example content hereunder:
***IMPORTANT:*** adapt the GP0 / GP1 pins to your specific board ! <br>
***IMPORTANT:*** adapt the GP0 / GP1 pins to your specific board !
```
print("Starting")
@@ -45,7 +44,6 @@ if __name__ == '__main__':
6. If it prints the letter "a" (or a "Q" or ... depending on your keyboard layout), you're done!
<br>
## Now that you're up and running, you may want to go further...
@@ -56,7 +54,7 @@ If your keyboard and microcontroller are officially supported, simply visit the
### You've got another, maybe DIY, board and want to customize KMK for it
First, be sure to understand how your device work, and particularly its specific matrix configuration. You can have a look [here](http://pcbheaven.com/wikipages/How_Key_Matrices_Works/) or read the [guide](https://docs.qmk.fm/#/hand_wire) provided by the QMK team for handwired keyboards
<br>Once you've got the gist of it:
Once you've got the gist of it:
- You can have a look [here](config_and_keymap.md) and [here](keys.md) to start customizing your code.py / main.py file
- There's a [reference](keycodes.md) of the available keycodes
- [International](international.md) extension adds keys for non US layouts and [Media Keys](media_keys.md) adds keys for ... media
@@ -69,7 +67,6 @@ And to go even further:
Want to have fun features such as RGB, split keyboards and more? Check out what builtin [modules](modules.md) and [extensions](extensions.md) can do!
You can also get ideas from the various [user examples](https://github.com/KMKfw/kmk_firmware/tree/master/user_keymaps) that we provide and dig into our [documentation](README.md).
<br>
## Additional help and support
> Roads? Where we're going we don't need roads.

View File

@@ -27,7 +27,12 @@ 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 optional environment variable for specifying a subset of tests with python
unittest syntax:
```sh
make unit-tests TESTS="tests.test_capsword tests.test_hold_tap"
```
## Contributing Documentation
While KMK welcomes documentation from anyone with and understanding of the issues

View File

@@ -15,6 +15,8 @@ keyboard.modules.append(MouseKeys())
| `KC.MB_LMB` | Left mouse button |
| `KC.MB_RMB` | Right mouse button |
| `KC.MB_MMB` | Middle mouse button |
| `KC.MB_BTN4` | mouse button 4 |
| `KC.MB_BTN5` | mouse button 5 |
| `KC.MW_UP` | Mouse wheel up |
| `KC.MW_DOWN`, `KC.MW_DN` | Mouse wheel down |
| `KC.MS_UP` | Move mouse cursor up |

View File

Before

Width:  |  Height:  |  Size: 400 KiB

After

Width:  |  Height:  |  Size: 400 KiB

View File

@@ -15,7 +15,7 @@ microcontrollers with only a single line change and less mistakes.
## Pro micro footprint pinout
![pro micro footprint pins](../img/pro_micro_pinout.png)
![pro micro footprint pins](pro_micro_pinout.png)
## Example

View File

@@ -9,7 +9,6 @@ KMK は[CircuitPython](https://circuitpython.org/)の上に配置されるキー
CircuitPython の最適化バージョン(特定のボードの容量制限に対処した、プリインストールされた関連モジュールの選択が可能なバージョン)も提供しています。
<br>
## TL;DR クイックスタートガイド
> To infinity and beyond!
@@ -25,7 +24,7 @@ CircuitPython の最適化バージョン(特定のボードの容量制限に
4. 同じルートディレクトリーboot.py と同レベル)に新規で*code.py* または *main.py*のファイルを作成する。中身は以下の例とする。
***重要:*** GP0 / GP1 ピンを使用ボードに合わせて下さい<br>
***重要:*** GP0 / GP1 ピンを使用ボードに合わせて下さい
```
@@ -56,8 +55,6 @@ if __name__ == '__main__':
2. "A"や"Q"(キーボードのレイアウトによって異なる)が表示されたら、完成!
<br>
## とりあえず一通り動くようになったので、もっとに先へ進みたい場合
> This is your last chance. After this, there is no turning back. You take the blue pill—the story ends, you wake up in your bed and believe whatever you want to believe. You take the red pill—you stay in Wonderland, and I show you how deep the rabbit hole goes. Remember: all I'm offering is the truth. Nothing more.
@@ -72,7 +69,7 @@ if __name__ == '__main__':
最初にデバイスの動作や具体的なマトリックス構成についてしっかり理解してください。
QMK チームが提供している手配線キーボード用の[ガイド](https://docs.qmk.fm/#/hand_wire)と[ドキュメント](http://pcbheaven.com/wikipages/How_Key_Matrices_Works/) を確認できます。
<br>要旨をつかめてきたら:
要旨をつかめてきたら:
- [ここ](config_and_keymap.md) と [ここ](keys.md)を見て、code.py / main.py ファイルをカスタイマイズできます。
- 使用可能なキーコードの[リファレンス](keycodes.md)があります。
@@ -89,7 +86,6 @@ RGB や分裂型などの機能を楽しめたい場合は、ビルトイン[モ
私たちが提供する、いろんな [ユーザー事例](https://github.com/KMKfw/user_keymaps)や[ドキュメント](https://github.com/KMKfw/kmk_firmware/tree/master/docs)からアイデアを得ることもできます。
<br>
## ヘルプ/サポート
> Roads? Where we're going we don't need roads.

View File

@@ -13,7 +13,6 @@ Também fornecemos uma versão de CircuitPython otimizada para teclados
(simplificada para lidar com os limites de certas placas e com a seleção dos
módulos relevantes pré-instalados). Se você estiver se perguntando por que usar
<br>
## Guia Rápido
> Ao Infinito e Além!
@@ -30,7 +29,7 @@ módulos relevantes pré-instalados). Se você estiver se perguntando por que us
4. Crie um novo arquivo *code.py* ou *main.py* no mesmo diretório raiz (no
mesmo nível de boot.py) com o exemplo contido abaixo:
***IMPORTANTE:*** adapte os pinos GP0 / GP1 para a tua placa específica! <br>
***IMPORTANTE:*** adapte os pinos GP0 / GP1 para a tua placa específica!
```
print("Starting")
@@ -61,7 +60,6 @@ if __name__ == '__main__':
6. Se ela imprimir um "A" (ou um "Q" ou o que depender do teu layout de
teclado), você conseguiu!
<br>
## Agora que tudo está no seu lugar, você pode querer ir além...
@@ -88,7 +86,7 @@ sua configuração matricial específica. Você pode observar
[guia](https://docs.qmk.fm/#/hand_wire) feito pelo time da QMK para teclados
artesanais.
<br>Uma vez que você compreendeu a essência da coisa:
Uma vez que você compreendeu a essência da coisa:
- Você pode dar uma olhada [aqui](config_and_keymap.md) e [aqui](keys.md) para
começar a customizar seu arquivo code.py / main.py.
- Eis uma [referência](keycodes.md) dos códigos de teclas (*keycodes*)
@@ -115,7 +113,6 @@ Você também pode obter ideias dos vários [exemplos de
usuários](https://github.com/KMKfw/user_keymaps) que fornecemos e fuce nossa
[documentação](https://github.com/KMKfw/kmk_firmware/tree/master/docs).
<br>
## Ajuda e Suporte Adicionais
> Estradas? Para onde vamos, estradas são desnecessárias.

View File

@@ -435,7 +435,7 @@ class KeyAttrDict:
def __iter__(self):
for partition in self.__cache:
for name in partition.__iter__():
for name in partition:
yield name
def __setitem__(self, name: str, key: Key):

View File

@@ -1,26 +1,8 @@
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.modules import Module
class PointingDevice:
MB_LMB = 1
MB_RMB = 2
MB_MMB = 4
_evt = bytearray(HID_REPORT_SIZES[HIDReportTypes.MOUSE] + 1)
def __init__(self):
self.key_states = {}
self.hid_pending = False
self.report_device = memoryview(self._evt)[0:1]
self.report_device[0] = HIDReportTypes.MOUSE
self.button_status = memoryview(self._evt)[1:2]
self.report_x = memoryview(self._evt)[2:3]
self.report_y = memoryview(self._evt)[3:4]
self.report_w = memoryview(self._evt)[4:]
class MouseKeys(Module):
def __init__(self):
self._nav_key_activated = 0
@@ -46,6 +28,14 @@ class MouseKeys(Module):
names=('MB_RMB',),
code=2,
)
make_mouse_key(
names=('MB_BTN4',),
code=8,
)
make_mouse_key(
names=('MB_BTN5',),
code=16,
)
make_key(
names=('MW_UP',),
on_press=self._mw_up_press,

View File

@@ -6,45 +6,48 @@ from micropython import const
import math
import struct
from adafruit_pixelbuf import PixelBuf
from kmk.keys import AX, KC, make_argumented_key, make_key
from kmk.kmktime import PeriodicTimer
from kmk.modules import Module
from kmk.utils import Debug
I2C_ADDRESS = 0x0A
I2C_ADDRESS_ALTERNATIVE = 0x0B
_I2C_ADDRESS = const(0x0A)
_I2C_ADDRESS_ALTERNATIVE = const(0x0B)
CHIP_ID = 0xBA11
VERSION = 1
_CHIP_ID = const(0xBA11)
_VERSION = const(1)
REG_LED_RED = 0x00
REG_LED_GRN = 0x01
REG_LED_BLU = 0x02
REG_LED_WHT = 0x03
_REG_LED_RED = const(0x00)
_REG_LED_GRN = const(0x01)
_REG_LED_BLU = const(0x02)
_REG_LED_WHT = const(0x03)
REG_LEFT = 0x04
REG_RIGHT = 0x05
REG_UP = 0x06
REG_DOWN = 0x07
REG_SWITCH = 0x08
MSK_SWITCH_STATE = 0b10000000
_REG_LEFT = const(0x04)
_REG_RIGHT = const(0x05)
_REG_UP = const(0x06)
_REG_DOWN = const(0x07)
_REG_SWITCH = const(0x08)
_MSK_SWITCH_STATE = const(0b10000000)
REG_USER_FLASH = 0xD0
REG_FLASH_PAGE = 0xF0
REG_INT = 0xF9
MSK_INT_TRIGGERED = 0b00000001
MSK_INT_OUT_EN = 0b00000010
REG_CHIP_ID_L = 0xFA
RED_CHIP_ID_H = 0xFB
REG_VERSION = 0xFC
REG_I2C_ADDR = 0xFD
REG_CTRL = 0xFE
MSK_CTRL_SLEEP = 0b00000001
MSK_CTRL_RESET = 0b00000010
MSK_CTRL_FREAD = 0b00000100
MSK_CTRL_FWRITE = 0b00001000
_REG_USER_FLASH = const(0xD0)
_REG_FLASH_PAGE = const(0xF0)
_REG_INT = const(0xF9)
_MSK_INT_TRIGGERED = const(0b00000001)
_MSK_INT_OUT_EN = const(0b00000010)
_REG_CHIP_ID_L = const(0xFA)
_REG_CHIP_ID_H = const(0xFB)
_REG_VERSION = const(0xFC)
_REG_I2C_ADDR = const(0xFD)
_REG_CTRL = const(0xFE)
_MSK_CTRL_SLEEP = const(0b00000001)
_MSK_CTRL_RESET = const(0b00000010)
_MSK_CTRL_FREAD = const(0b00000100)
_MSK_CTRL_FWRITE = const(0b00001000)
ANGLE_OFFSET = 0
debug = Debug(__name__)
class TrackballHandlerKeyMeta:
@@ -82,13 +85,8 @@ class PointingHandler(TrackballHandler):
if y:
AX.Y.move(keyboard, y)
if switch == 1: # Button pressed
keyboard.pre_process_key(KC.MB_LMB, is_pressed=True)
if not state and trackball.previous_state is True: # Button released
keyboard.pre_process_key(KC.MB_LMB, is_pressed=False)
trackball.previous_state = state
if switch == 1: # Button changed state
keyboard.pre_process_key(KC.MB_LMB, is_pressed=state)
class ScrollHandler(TrackballHandler):
@@ -102,13 +100,8 @@ class ScrollHandler(TrackballHandler):
if y != 0:
AX.W.move(keyboard, y)
if switch == 1: # Button pressed
keyboard.pre_process_key(KC.MB_LMB, is_pressed=True)
if not state and trackball.previous_state is True: # Button released
keyboard.pre_process_key(KC.MB_LMB, is_pressed=False)
trackball.previous_state = state
if switch == 1: # Button changed state
keyboard.pre_process_key(KC.MB_LMB, is_pressed=state)
class KeyHandler(TrackballHandler):
@@ -155,8 +148,8 @@ class Trackball(Module):
self,
i2c,
mode=TrackballMode.MOUSE_MODE,
address=I2C_ADDRESS,
angle_offset=ANGLE_OFFSET,
address=_I2C_ADDRESS,
angle_offset=0,
handlers=None,
):
self.angle_offset = angle_offset
@@ -168,17 +161,10 @@ class Trackball(Module):
self._i2c_bus = i2c
self.mode = mode
self.previous_state = False # click state
self.handlers = handlers
self.current_handler = self.handlers[0]
self.polling_interval = 20
chip_id = struct.unpack('<H', bytearray(self._i2c_rdwr([REG_CHIP_ID_L], 2)))[0]
if chip_id != CHIP_ID:
raise RuntimeError(
f'Invalid chip ID: 0x{chip_id:04X}, expected 0x{CHIP_ID:04X}'
)
make_key(
names=('TB_MODE', 'TB_NEXT_HANDLER', 'TB_N'),
on_press=self._tb_handler_next_press,
@@ -191,8 +177,17 @@ class Trackball(Module):
)
def during_bootup(self, keyboard):
chip_id = struct.unpack('<H', bytearray(self._i2c_rdwr([_REG_CHIP_ID_L], 2)))[0]
if chip_id != _CHIP_ID:
raise RuntimeError(
f'Invalid chip ID: 0x{chip_id:04X}, expected 0x{_CHIP_ID:04X}'
)
self._timer = PeriodicTimer(self.polling_interval)
a = math.pi * self.angle_offset / 180
self.rot = [[math.cos(a), math.sin(a)], [-math.sin(a), math.cos(a)]]
def before_matrix_scan(self, keyboard):
'''
Return value will be injected as an extra matrix update
@@ -200,14 +195,15 @@ class Trackball(Module):
if not self._timer.tick():
return
if not (self._i2c_rdwr([_REG_INT], 1)[0] & _MSK_INT_TRIGGERED):
return
up, down, left, right, switch, state = self._read_raw_state()
x, y = self._calculate_movement(right - left, down - up)
self.current_handler.handle(keyboard, self, x, y, switch, state)
return
def after_matrix_scan(self, keyboard):
return
@@ -225,23 +221,23 @@ class Trackball(Module):
def set_rgbw(self, r, g, b, w):
'''Set all LED brightness as RGBW.'''
self._i2c_rdwr([REG_LED_RED, r, g, b, w])
self._i2c_rdwr([_REG_LED_RED, r, g, b, w])
def set_red(self, value):
'''Set brightness of trackball red LED.'''
self._i2c_rdwr([REG_LED_RED, value & 0xFF])
self._i2c_rdwr([_REG_LED_RED, value & 0xFF])
def set_green(self, value):
'''Set brightness of trackball green LED.'''
self._i2c_rdwr([REG_LED_GRN, value & 0xFF])
self._i2c_rdwr([_REG_LED_GRN, value & 0xFF])
def set_blue(self, value):
'''Set brightness of trackball blue LED.'''
self._i2c_rdwr([REG_LED_BLU, value & 0xFF])
self._i2c_rdwr([_REG_LED_BLU, value & 0xFF])
def set_white(self, value):
'''Set brightness of trackball white LED.'''
self._i2c_rdwr([REG_LED_WHT, value & 0xFF])
self._i2c_rdwr([_REG_LED_WHT, value & 0xFF])
def activate_handler(self, handler):
if isinstance(handler, TrackballHandler):
@@ -250,7 +246,8 @@ class Trackball(Module):
try:
self.current_handler = self.handlers[handler]
except KeyError:
print(f'no handler found with id {handler}')
if debug.enabled:
debug(f'no handler found with id {handler}')
def next_handler(self):
next_index = self.handlers.index(self.current_handler) + 1
@@ -260,17 +257,17 @@ class Trackball(Module):
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)
switch, switch_state = (
switch & ~MSK_SWITCH_STATE,
(switch & MSK_SWITCH_STATE) > 0,
left, right, up, down, switch = self._i2c_rdwr([_REG_LEFT], 5)
switch_changed, switch_state = (
switch & ~_MSK_SWITCH_STATE,
(switch & _MSK_SWITCH_STATE) > 0,
)
return up, down, left, right, switch, switch_state
return up, down, left, right, switch_changed, switch_state
def _i2c_rdwr(self, data, length=0):
'''Write and optionally read I2C data.'''
while not self._i2c_bus.try_lock():
pass
if not self._i2c_bus.try_lock():
return
try:
if length > 0:
@@ -298,17 +295,24 @@ class Trackball(Module):
if raw_x == 0 and raw_y == 0:
return 0, 0
var_accel = 1
power = 2.5
scale = math.sqrt(raw_x**2 + raw_y**2)
x = (self.rot[0][0] * raw_x + self.rot[0][1] * raw_y) * scale
y = (self.rot[1][0] * raw_x + self.rot[1][1] * raw_y) * scale
angle_rad = math.atan2(raw_y, raw_x) + self.angle_offset
vector_length = math.sqrt(pow(raw_x, 2) + pow(raw_y, 2))
vector_length = pow(vector_length * var_accel, power)
x = math.floor(vector_length * math.cos(angle_rad))
y = math.floor(vector_length * math.sin(angle_rad))
return int(x), int(y)
limit = 127 # hid size limit
x_clamped = max(min(limit, x), -limit)
y_clamped = max(min(limit, y), -limit)
return x_clamped, y_clamped
class TrackballPixel(PixelBuf):
'''PixelBuf interface for the Trackball RGBW LED'''
def __init__(self, trackball, **kwargs):
self.trackball = trackball
kwargs['byteorder'] = 'RGBW'
super().__init__(1, **kwargs)
def deinit(self):
super().deinit()
self.trackball.set_rgbw(0, 0, 0, 0)
def _transmit(self, b):
self.trackball.set_rgbw(b[0], b[1], b[2], b[3])

View File

@@ -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

Binary file not shown.

Binary file not shown.

View File

@@ -23,6 +23,7 @@ per-file-ignores =
# your imports in whatever order you want
user_keymaps/**/*.py: E131,F401,E501,E241,E131,BLK100,I003
boards/**/main.py: E131,F401,E501,E241,E131,BLK100,I003
boards/**/kb.py: E131,F401,E501,E241,E131,BLK100,I003
tests/test_data/keymaps/**/*.py: F401,E501
[isort]