はじめに
こちらの続き
Raspberry Pi Zero Wに Thinkpad TracPoint Bluetooth Keyboardをつなげて、
RaspiをUSB Keyboardに見せて、キー入力を転送して、最終的には最終的にはキーの入れ替えをします。
キー入力転送
USBのスキャンコードについては以下参照しました。
http://www3.airnet.ne.jp/saka/hardware/keyboard/109scode.html
from evdev import InputDevice, categorize, ecodes
# scancode
scancode = {}
scancode[ecodes.KEY_A] = 0x04
scancode[ecodes.KEY_B] = 0x05
scancode[ecodes.KEY_C] = 0x06
scancode[ecodes.KEY_D] = 0x07
scancode[ecodes.KEY_E] = 0x08
scancode[ecodes.KEY_F] = 0x09
scancode[ecodes.KEY_G] = 0x0a
scancode[ecodes.KEY_H] = 0x0b
scancode[ecodes.KEY_I] = 0x0c
scancode[ecodes.KEY_J] = 0x0d
scancode[ecodes.KEY_K] = 0x0e
scancode[ecodes.KEY_L] = 0x0f
scancode[ecodes.KEY_M] = 0x10
scancode[ecodes.KEY_N] = 0x11
scancode[ecodes.KEY_O] = 0x12
scancode[ecodes.KEY_P] = 0x13
scancode[ecodes.KEY_Q] = 0x14
scancode[ecodes.KEY_R] = 0x15
scancode[ecodes.KEY_S] = 0x16
scancode[ecodes.KEY_T] = 0x17
scancode[ecodes.KEY_U] = 0x18
scancode[ecodes.KEY_V] = 0x19
scancode[ecodes.KEY_W] = 0x1a
scancode[ecodes.KEY_X] = 0x1b
scancode[ecodes.KEY_Y] = 0x1c
scancode[ecodes.KEY_Z] = 0x1d
scancode[ecodes.KEY_1] = 0x1e
scancode[ecodes.KEY_2] = 0x1f
scancode[ecodes.KEY_3] = 0x20
scancode[ecodes.KEY_4] = 0x21
scancode[ecodes.KEY_5] = 0x22
scancode[ecodes.KEY_6] = 0x23
scancode[ecodes.KEY_7] = 0x24
scancode[ecodes.KEY_8] = 0x25
scancode[ecodes.KEY_9] = 0x26
scancode[ecodes.KEY_0] = 0x27
scancode[ecodes.KEY_ENTER] = 0x28
scancode[ecodes.KEY_ESC] = 0x29
scancode[ecodes.KEY_BACKSPACE] = 0x2a
scancode[ecodes.KEY_TAB] = 0x2b
scancode[ecodes.KEY_SPACE] = 0x2c
scancode[ecodes.KEY_MINUS] = 0x2d
scancode[ecodes.KEY_EQUAL] = 0x2e
scancode[ecodes.KEY_LEFTBRACE] = 0x2f
scancode[ecodes.KEY_RIGHTBRACE] = 0x30
scancode[ecodes.KEY_BACKSLASH] = 0x31
scancode[ecodes.KEY_SEMICOLON] = 0x33
scancode[ecodes.KEY_APOSTROPHE] = 0x34
scancode[ecodes.KEY_GRAVE] = 0x35
scancode[ecodes.KEY_COMMA] = 0x36
scancode[ecodes.KEY_DOT] = 0x37
scancode[ecodes.KEY_SLASH] = 0x38
scancode[ecodes.KEY_CAPSLOCK] = 0x39
scancode[ecodes.KEY_SYSRQ] = 0x46
scancode[ecodes.KEY_INSERT] = 0x49
scancode[ecodes.KEY_HOME] = 0x4a
scancode[ecodes.KEY_PAGEUP] = 0x4b
scancode[ecodes.KEY_DELETE] = 0x4c
scancode[ecodes.KEY_END] = 0x4d
scancode[ecodes.KEY_PAGEDOWN] = 0x4e
scancode[ecodes.KEY_RIGHT] = 0x4f
scancode[ecodes.KEY_LEFT] = 0x50
scancode[ecodes.KEY_DOWN] = 0x51
scancode[ecodes.KEY_UP] = 0x52
scancode[ecodes.KEY_RO] = 0x87
scancode[ecodes.KEY_KATAKANAHIRAGANA] = 0x88
scancode[ecodes.KEY_YEN] = 0x89
scancode[ecodes.KEY_HENKAN] = 0x8a
scancode[ecodes.KEY_MUHENKAN] = 0x8b
scancode[ecodes.KEY_LEFTMETA] = 0xe3
left_ctrl = ecodes.KEY_LEFTCTRL # convert ctrl key
def main():
dev = InputDevice("/dev/input/ThinkPadTracPointKeyboard")
print(dev)
shift = 0
ctrl = 0
alt = 0
for event in dev.read_loop():
if event.type == ecodes.EV_KEY:
buf = bytearray()
# shift
if event.code == ecodes.KEY_RIGHTSHIFT or event.code == ecodes.KEY_LEFTSHIFT:
if event.value == 1:
shift = 1
elif event.value == 0:
shift = 0
elif event.code == ecodes.KEY_RIGHTCTRL or event.code == ecodes.KEY_LEFTCTRL:
if event.value == 1:
ctrl = 1
elif event.value == 0:
ctrl = 0
elif event.code == ecodes.KEY_RIGHTALT or event.code == ecodes.KEY_LEFTALT:
if event.value == 1:
alt = 1
elif event.value == 0:
alt = 0
else:
if event.code in scancode:
if event.value == 1 or event.value == 2:
code = scancode[event.code]
modify = ctrl + (shift << 1) + (alt << 2)
buf.extend([modify, 0, code])
else:
buf.extend([0, 0, 0])
buf.extend([0, 0, 0, 0, 0])
with open("/dev/hidg1", mode="wb") as keyboard:
keyboard.write(buf)
keyboard.close()
else:
print(categorize(event))
if __name__ == "__main__":
main()
Fnキーを常時有効にする(できない)
Thinkpad TracPoint Keyboardのファンクションキーはデフォルト機能に割り当たっているので
Fnキーを押しながらでないと有効でないようです。
今の所、解決方法はなさそうです。
キー変換
capslockとleft ctrlの入れ替え
capslockで左コントロールキー、左コントロールキーでcapslockになるようにします
ESCと半角/全角の入替、無変換と変換に半角/全角を割り当て
これはMac的に使いたい好みの問題かな。
from evdev import InputDevice, categorize, ecodes
# scancode
scancode = {}
scancode[ecodes.KEY_A] = 0x04
scancode[ecodes.KEY_B] = 0x05
scancode[ecodes.KEY_C] = 0x06
scancode[ecodes.KEY_D] = 0x07
scancode[ecodes.KEY_E] = 0x08
scancode[ecodes.KEY_F] = 0x09
scancode[ecodes.KEY_G] = 0x0a
scancode[ecodes.KEY_H] = 0x0b
scancode[ecodes.KEY_I] = 0x0c
scancode[ecodes.KEY_J] = 0x0d
scancode[ecodes.KEY_K] = 0x0e
scancode[ecodes.KEY_L] = 0x0f
scancode[ecodes.KEY_M] = 0x10
scancode[ecodes.KEY_N] = 0x11
scancode[ecodes.KEY_O] = 0x12
scancode[ecodes.KEY_P] = 0x13
scancode[ecodes.KEY_Q] = 0x14
scancode[ecodes.KEY_R] = 0x15
scancode[ecodes.KEY_S] = 0x16
scancode[ecodes.KEY_T] = 0x17
scancode[ecodes.KEY_U] = 0x18
scancode[ecodes.KEY_V] = 0x19
scancode[ecodes.KEY_W] = 0x1a
scancode[ecodes.KEY_X] = 0x1b
scancode[ecodes.KEY_Y] = 0x1c
scancode[ecodes.KEY_Z] = 0x1d
scancode[ecodes.KEY_1] = 0x1e
scancode[ecodes.KEY_2] = 0x1f
scancode[ecodes.KEY_3] = 0x20
scancode[ecodes.KEY_4] = 0x21
scancode[ecodes.KEY_5] = 0x22
scancode[ecodes.KEY_6] = 0x23
scancode[ecodes.KEY_7] = 0x24
scancode[ecodes.KEY_8] = 0x25
scancode[ecodes.KEY_9] = 0x26
scancode[ecodes.KEY_0] = 0x27
scancode[ecodes.KEY_ENTER] = 0x28
scancode[ecodes.KEY_ESC] = 0x35 # 0x29 # assing to grave
scancode[ecodes.KEY_BACKSPACE] = 0x2a
scancode[ecodes.KEY_TAB] = 0x2b
scancode[ecodes.KEY_SPACE] = 0x2c
scancode[ecodes.KEY_MINUS] = 0x2d
scancode[ecodes.KEY_EQUAL] = 0x2e
scancode[ecodes.KEY_LEFTBRACE] = 0x2f
scancode[ecodes.KEY_RIGHTBRACE] = 0x30
scancode[ecodes.KEY_BACKSLASH] = 0x31
scancode[ecodes.KEY_SEMICOLON] = 0x33
scancode[ecodes.KEY_APOSTROPHE] = 0x34
scancode[ecodes.KEY_GRAVE] = 0x29 # 0x35 # assign to esc
scancode[ecodes.KEY_COMMA] = 0x36
scancode[ecodes.KEY_DOT] = 0x37
scancode[ecodes.KEY_SLASH] = 0x38
scancode[ecodes.KEY_CAPSLOCK] = 0xE0 # 0x39 # assign to left-ctrl
scancode[ecodes.KEY_SYSRQ] = 0x46
scancode[ecodes.KEY_INSERT] = 0x49
scancode[ecodes.KEY_HOME] = 0x4a
scancode[ecodes.KEY_PAGEUP] = 0x4b
scancode[ecodes.KEY_DELETE] = 0x4c
scancode[ecodes.KEY_END] = 0x4d
scancode[ecodes.KEY_PAGEDOWN] = 0x4e
scancode[ecodes.KEY_RIGHT] = 0x4f
scancode[ecodes.KEY_LEFT] = 0x50
scancode[ecodes.KEY_DOWN] = 0x51
scancode[ecodes.KEY_UP] = 0x52
scancode[ecodes.KEY_RO] = 0x87
scancode[ecodes.KEY_KATAKANAHIRAGANA] = 0x88
scancode[ecodes.KEY_YEN] = 0x89
scancode[ecodes.KEY_HENKAN] = 0x35 # 0x8a
scancode[ecodes.KEY_MUHENKAN] = 0x35 # 0x8b
scancode[ecodes.KEY_LEFTCTRL] = 0x39 # 0xE0 # assign to capslock
scancode[ecodes.KEY_LEFTMETA] = 0xe3
left_ctrl = ecodes.KEY_CAPSLOCK # convert ctrl key
def main():
dev = InputDevice("/dev/input/ThinkPadTracPointKeyboard")
print(dev)
shift = 0
ctrl = 0
alt = 0
for event in dev.read_loop():
if event.type == ecodes.EV_KEY:
buf = bytearray()
# shift
if event.code == ecodes.KEY_RIGHTSHIFT or event.code == ecodes.KEY_LEFTSHIFT:
if event.value == 1:
shift = 1
elif event.value == 0:
shift = 0
elif event.code == ecodes.KEY_RIGHTCTRL or event.code == left_ctrl:
if event.value == 1:
ctrl = 1
elif event.value == 0:
ctrl = 0
elif event.code == ecodes.KEY_RIGHTALT or event.code == ecodes.KEY_LEFTALT:
if event.value == 1:
alt = 1
elif event.value == 0:
alt = 0
else:
if event.code in scancode:
if event.value == 1 or event.value == 2:
code = scancode[event.code]
modify = ctrl + (shift << 1) + (alt << 2)
buf.extend([modify, 0, code])
else:
buf.extend([0, 0, 0])
buf.extend([0, 0, 0, 0, 0])
with open("/dev/hidg1", mode="wb") as keyboard:
keyboard.write(buf)
keyboard.close()
else:
print(categorize(event))
if __name__ == "__main__":
main()
自動起動を有効にする
raspiの起動時にUSBキーボードを有効にする
rc.localに/home/pi/hid_test/hid.shを追加
→デバイスの有効になるタイミングが良く無いのかhost側の認識がうまく行かないので、Bluetoothのキーボード認識時に行うことにする
udev rulesでスクリプトを起動する
うまく行かない。
udevでRUNするものはdaemonのようにずっと起動するものはダメらしい。
ー>rc.localでスクリプトを起動しておいて、bluetoothキーボード接続をポーリングするようにする
ACTION=="add" ATTRS{name}=="ThinkPad Compact Bluetooth Keyboard with TrackPoint Keyboard", RUN+="/home/pi/hid_test/keyboardFoundMessage.sh", SYMLINK+="input/ThinkPadTracPointKeyboard"
ACTION=="add" ATTRS{name}=="ThinkPad Compact Bluetooth Keyboard with TrackPoint Mouse", RUN+="/home/pi/hid_test/mouseFoundMessage.sh", SYMLINK+="input/ThinkPadTracPointKeyboardMouse"
/home/pi/hid_test/mouse.sh
/home/pi/hid_test/keyboard.sh
#!/bin/sh
DEVICE=/dev/input/ThinkPadTracPointKeyboardMouse
while [ ! -e $DEVICE ]
do
sleep 1
done
echo Thinkpad Tracpoint Bluetooth Keybord Tracpoint Connected
if [ -e /dev/hidg1 ]; then
echo HID device already started
else
/home/pi/hid_test/hid.sh
fi
MOUSE_PID=/var/run/mouse.pid
MOUSE=/home/pi/hid_test/mouse.py
$MOUSE &
echo $! > $MOUSE_PID
#!/bin/sh
DEVICE=/dev/input/ThinkPadTracPointKeyboard
while [ ! -e $DEVICE ]
do
sleep 1
done
echo Thinkpad Tracpoint Bluetooth Keybord Connected
if [ -e /dev/hidg0 ]; then
echo HID device already started
else
/home/pi/hid_test/hid.sh
fi
KEYBOARD_PID=/var/run/keyboard.pid
KEYBOARD=/home/pi/hid_test/keyboard.py
$KEYBOARD &
echo $! > $KEYBOARD_PID
#!/usr/bin/env python
from evdev import InputDevice, categorize, ecodes
device = '/dev/input/ThinkPadTracPointKeyboardMouse'
dev = InputDevice(device)
print(dev)
for event in dev.read_loop():
buf = bytearray()
if event.type == ecodes.EV_REL:
if event.code == ecodes.REL_X:
#print('REL_X:{}'. format(event.value))
if 0 < event.value:
buf.extend([0, event.value, 0])
else:
buf.extend([0, 0xFF + event.value, 0])
elif event.code == ecodes.REL_Y:
#print('REL_Y:{}'.format(event.value))
if 0 < event.value:
buf.extend([0, 0, event.value])
else:
buf.extend([0, 0, 0xFF + event.value])
#if event.code == ecodes.REL_WHEEL:
#print('REL_WHEEL:{}'.format(event.value))
elif event.type == ecodes.EV_KEY:
if event.code == ecodes.BTN_LEFT:
#print('BTN_LEFT:{}'.format(event.value))
buf.extend([1 * event.value, 0, 0])
elif event.code == ecodes.BTN_RIGHT:
#print('BTN_RIGHT:{}'.format(event.value))
buf.extend([2 * event.value, 0, 0])
if event.code == ecodes.BTN_MIDDLE:
#print('BTN_MIDDLE:{}'.format(event.value))
buf.extend([3 * event.value, 0, 0])
with open("/dev/hidg0", mode="wb") as mouse:
mouse.write(buf)
mouse.close()
#!/usr/bin/env python
from evdev import InputDevice, categorize, ecodes
# scancode
scancode = {}
scancode[ecodes.KEY_A] = 0x04
scancode[ecodes.KEY_B] = 0x05
scancode[ecodes.KEY_C] = 0x06
scancode[ecodes.KEY_D] = 0x07
scancode[ecodes.KEY_E] = 0x08
scancode[ecodes.KEY_F] = 0x09
scancode[ecodes.KEY_G] = 0x0a
scancode[ecodes.KEY_H] = 0x0b
scancode[ecodes.KEY_I] = 0x0c
scancode[ecodes.KEY_J] = 0x0d
scancode[ecodes.KEY_K] = 0x0e
scancode[ecodes.KEY_L] = 0x0f
scancode[ecodes.KEY_M] = 0x10
scancode[ecodes.KEY_N] = 0x11
scancode[ecodes.KEY_O] = 0x12
scancode[ecodes.KEY_P] = 0x13
scancode[ecodes.KEY_Q] = 0x14
scancode[ecodes.KEY_R] = 0x15
scancode[ecodes.KEY_S] = 0x16
scancode[ecodes.KEY_T] = 0x17
scancode[ecodes.KEY_U] = 0x18
scancode[ecodes.KEY_V] = 0x19
scancode[ecodes.KEY_W] = 0x1a
scancode[ecodes.KEY_X] = 0x1b
scancode[ecodes.KEY_Y] = 0x1c
scancode[ecodes.KEY_Z] = 0x1d
scancode[ecodes.KEY_1] = 0x1e
scancode[ecodes.KEY_2] = 0x1f
scancode[ecodes.KEY_3] = 0x20
scancode[ecodes.KEY_4] = 0x21
scancode[ecodes.KEY_5] = 0x22
scancode[ecodes.KEY_6] = 0x23
scancode[ecodes.KEY_7] = 0x24
scancode[ecodes.KEY_8] = 0x25
scancode[ecodes.KEY_9] = 0x26
scancode[ecodes.KEY_0] = 0x27
scancode[ecodes.KEY_ENTER] = 0x28
scancode[ecodes.KEY_ESC] = 0x35 # 0x29 # assing to grave
scancode[ecodes.KEY_BACKSPACE] = 0x2a
scancode[ecodes.KEY_TAB] = 0x2b
scancode[ecodes.KEY_SPACE] = 0x2c
scancode[ecodes.KEY_MINUS] = 0x2d
scancode[ecodes.KEY_EQUAL] = 0x2e
scancode[ecodes.KEY_LEFTBRACE] = 0x2f
scancode[ecodes.KEY_RIGHTBRACE] = 0x30
scancode[ecodes.KEY_BACKSLASH] = 0x31
scancode[ecodes.KEY_SEMICOLON] = 0x33
scancode[ecodes.KEY_APOSTROPHE] = 0x34
scancode[ecodes.KEY_GRAVE] = 0x29 # 0x35 # assign to esc
scancode[ecodes.KEY_COMMA] = 0x36
scancode[ecodes.KEY_DOT] = 0x37
scancode[ecodes.KEY_SLASH] = 0x38
scancode[ecodes.KEY_CAPSLOCK] = 0xE0 # 0x39 # assign to left-ctrl
scancode[ecodes.KEY_SYSRQ] = 0x46
scancode[ecodes.KEY_INSERT] = 0x49
scancode[ecodes.KEY_HOME] = 0x4a
scancode[ecodes.KEY_PAGEUP] = 0x4b
scancode[ecodes.KEY_DELETE] = 0x4c
scancode[ecodes.KEY_END] = 0x4d
scancode[ecodes.KEY_PAGEDOWN] = 0x4e
scancode[ecodes.KEY_RIGHT] = 0x4f
scancode[ecodes.KEY_LEFT] = 0x50
scancode[ecodes.KEY_DOWN] = 0x51
scancode[ecodes.KEY_UP] = 0x52
scancode[ecodes.KEY_RO] = 0x87
scancode[ecodes.KEY_KATAKANAHIRAGANA] = 0x88
scancode[ecodes.KEY_YEN] = 0x89
scancode[ecodes.KEY_HENKAN] = 0x35 # 0x8a
scancode[ecodes.KEY_MUHENKAN] = 0x35 # 0x8b
scancode[ecodes.KEY_LEFTCTRL] = 0x39 # 0xE0 # assign to capslock
scancode[ecodes.KEY_LEFTMETA] = 0xe3
left_ctrl = ecodes.KEY_CAPSLOCK # convert ctrl key
def main():
device="/dev/input/ThinkPadTracPointKeyboard"
dev = InputDevice(device)
print(dev)
shift = 0
ctrl = 0
alt = 0
for event in dev.read_loop():
if event.type == ecodes.EV_KEY:
buf = bytearray()
# shift
if event.code == ecodes.KEY_RIGHTSHIFT or event.code == ecodes.KEY_LEFTSHIFT:
if event.value == 1:
shift = 1
elif event.value == 0:
shift = 0
elif event.code == ecodes.KEY_RIGHTCTRL or event.code == left_ctrl:
if event.value == 1:
ctrl = 1
elif event.value == 0:
ctrl = 0
elif event.code == ecodes.KEY_RIGHTALT or event.code == ecodes.KEY_LEFTALT:
if event.value == 1:
alt = 1
elif event.value == 0:
alt = 0
else:
if event.code in scancode:
if event.value == 1 or event.value == 2:
code = scancode[event.code]
modify = ctrl + (shift << 1) + (alt << 2)
buf.extend([modify, 0, code])
else:
buf.extend([0, 0, 0])
buf.extend([0, 0, 0, 0, 0])
with open("/dev/hidg1", mode="wb") as keyboard:
keyboard.write(buf)
keyboard.close()
else:
print(categorize(event))
if __name__ == "__main__":
main()
# 今後やりたいこ
tracpoint keyboardはスクロールができるのでマウスにスクロールを追加したい