Compare commits
19 Commits
mpy_build
...
refactor-p
Author | SHA1 | Date | |
---|---|---|---|
|
cbfcd34fae | ||
|
1d53d3a8da | ||
|
0e804ffd54 | ||
|
0cc308c055 | ||
|
c575fa396a | ||
|
a83e833d10 | ||
|
e9af3e542a | ||
|
16d319359f | ||
|
88c3616b6a | ||
|
6ab4154ad5 | ||
|
db2082f1c6 | ||
|
317f6407d6 | ||
|
08c255b6e4 | ||
|
61cf527370 | ||
|
38acda77b4 | ||
|
7ef2c2c2d3 | ||
|
1f751d8374 | ||
|
d4fe745e71 | ||
|
1674ff4ed7 |
103
Makefile
103
Makefile
@@ -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
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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 |
|
||||
|
Before Width: | Height: | Size: 400 KiB After Width: | Height: | Size: 400 KiB |
@@ -15,7 +15,7 @@ microcontrollers with only a single line change and less mistakes.
|
||||
|
||||
## Pro micro footprint pinout
|
||||
|
||||

|
||||

|
||||
|
||||
## Example
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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.
|
||||
|
@@ -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):
|
||||
|
@@ -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,
|
||||
|
@@ -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])
|
||||
|
@@ -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]
|
||||
|
Reference in New Issue
Block a user