1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Raspy Zero WH でキー変換器を作る (その2)

Last updated at Posted at 2020-05-10

はじめに

こちらの続き

Raspberry Pi Zero Wに Thinkpad TracPoint Bluetooth Keyboardをつなげて、
RaspiをUSB Keyboardに見せて、キー入力を転送して、最終的には最終的にはキーの入れ替えをします。

キー入力転送

USBのスキャンコードについては以下参照しました。
http://www3.airnet.ne.jp/saka/hardware/keyboard/109scode.html

keyboard.py
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的に使いたい好みの問題かな。

keyboard.py
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キーボード接続をポーリングするようにする

/etc/udev/rulesd/99-tracpoint-keyboard.rules
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"
/etc/rc.local
/home/pi/hid_test/mouse.sh
/home/pi/hid_test/keyboard.sh
mouse.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
keyboard.sh
#!/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
mouse.py
#!/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()
keyboard.py
#!/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はスクロールができるのでマウスにスクロールを追加したい

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?