Raspy Zero WH でキー変換器を作る

# はじめに

Mac使いとしては、Windowsのキーボードの配置にはどうやっても馴染めません。
通常ならば[Change Key](https://forest.watch.impress.co.jp/library/software/changekey/)のお世話になりますが、借り物のPCなどではインストールできない場合があります。
なので、物理的に変換してやろうと思います。

(Apple Keyboardを使う案もありますが、どのみち[ドライバーをいれたり](https://bridgebook.jp/apple-wireless-keyboard-windows/)は借り物はダメなので。また、キーボードはThinkpad Tracpoint Keyboardを使いたいので）

# 使うもの
 - Raspberry Pi Zero WH：[秋月電子](http://akizukidenshi.com/catalog/g/gM-12958/)で購入
 - USB micro B OTGケーブル
 - Thinkpad Tracpoint Keyborad（USBではなくてBluetoothの方）

途中で分かったのですがRaspiZeroWをUSBデバイスとして動作させるとホストにはなれないのでUSBキーボードはつながりません。Bluetoothキーボードを準備することにします。

# 作り方
## Raspberry Pi Zero WHのセットアップ
### micro SDの準備
[ここ](https://www.raspberrypi.org/documentation/installation/installing-images/README.md)に従って作業を進める

 - Raspberry Pi Imager For MacOSを[ダウンロード](https://www.raspberrypi.org/downloads/)してインストール
 - Raspberry Pi Imagerを起動して、OSとSDカードを選択
 ![RaspiImager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92080/ee379acf-2e83-b874-73e2-002197ad1f1b.png)
![RaspiImagerSelectOS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92080/d5b2efb3-14c2-b089-e3f4-cffb8c966620.png)
![RaspiImagerSelectSD.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92080/1cd2c699-8f3d-5eb8-4350-04b22cee0b32.png)
 - 書込み
 ![RaspiImagerWriting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92080/c46f20bd-f06d-5e66-9ade-b06ff6ee194f.png)
 
 - "boot"がマウントされる

[この辺](https://ayame.space/2018/07/setup-raspberry-pi-zero-w-without-display/)を参考にしてSSHの有効かとWiFiの設定をしておく

 - SSHを有効にする
 
```
# cd /Volumes/boot
# touch ssh
```

 - WiFiを有効にする
   - 2.4GHzのアクセスポイントを選択（5GHzを指定していてハマった）
   - ステルスモードの時は"scan_ssid=1"を使う

```
# nano wpa_supplicant.conf
```
``` wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
        ssid="接続したいSSID"
        psk="SSIDのパスワード"
        scan_ssid=1
}
```
  - 生のパスワードが嫌な人は"wpa_passphrase"コマンドを使うといい([この辺](https://qiita.com/minatomirai21/items/6397ba560626f09fe42b)を参考に)

### 起動
#### 単体
 1. USBケーブルで母艦(Mac)につなぐ

#### Desktop
 1. HDMIでモニターつなぐ
 1. Thinkpad Tracpoint Keyboardをつなぐ
 1. 電源を入れる

## 母艦(Mac)からSSHで接続する

```
$ ssh pi@raspberrypi.local
```

## TODO: 母艦からシリアルでコンソールに接続する

## RaspiをUSB Keyboard(ThinkPad Tracpoint Keyboard)に見せる
### Keyboard、Tracpoint操作をモニターする

[参考](https://qiita.com/koara-local/items/6484723d29afad4c3afb)

#### USBにKeyboardを接続して、認識状況を確認する

(この結果は使わないかも。。。）

```
pi@raspberrypi:~ $ lsusb 
Bus 001 Device 002: ID 17ef:6047 Lenovo 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
```

```
pi@raspberrypi:~ $ usb-devices 
(省略)
T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=17ef ProdID=6047 Rev=03.30
S:  Manufacturer=Lenovo
S:  Product=ThinkPad Compact USB Keyboard with TrackPoint
C:  #Ifs= 2 Cfg#= 1 Atr=a0 MxPwr=100mA
I:  If#=0x0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=01 Driver=usbhid
I:  If#=0x1 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=usbhid
```
interface0がキーボード、1がtracpoint

```
pi@raspberrypi:~ $ cat /proc/bus/input/devices 
I: Bus=0003 Vendor=17ef Product=6047 Version=0100
N: Name="Lenovo ThinkPad Compact USB Keyboard with TrackPoint"
P: Phys=usb-20980000.usb-1/input0
S: Sysfs=/devices/platform/soc/20980000.usb/usb1/1-1/1-1:1.0/0003:17EF:6047.0005/input/input14
U: Uniq=
H: Handlers=sysrq kbd leds event0 
B: PROP=0
B: EV=120013
B: KEY=10000 7 ff800000 7ff febeffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=1f

I: Bus=0003 Vendor=17ef Product=6047 Version=0100
N: Name="Lenovo ThinkPad Compact USB Keyboard with TrackPoint Mouse"
P: Phys=usb-20980000.usb-1/input1
S: Sysfs=/devices/platform/soc/20980000.usb/usb1/1-1/1-1:1.1/0003:17EF:6047.0006/input/input15
U: Uniq=
H: Handlers=mouse0 event1 
B: PROP=0
B: EV=17
B: KEY=1f0000 0 0 0 0 0 0 0 0
B: REL=143
B: MSC=10

(省略)
```

 - tracpointを動かしてみる

```
pi@raspberrypi:~ $ hexdump /dev/input/mouse0 
0000000 ff18 0800 0100 ff18 1801 01fd ff18 1801
0000010 01ff ff18 0801 0100 0008 1801 03ff 0008
0000020 1803 03ff ff18 0803 0100 ff18 1803 03ff
0000030 0008 1803 01ff ff18 0803 0300 ff18 0803
0000040 0100 0008 0801 0100 0008 1803 01ff ff18
0000050 0803 0300 ff18 0803 0300 ff18 1803 03ff
0000060 ff18 0803 0400 ff18 1803 04ff ff18 1804
```

 - キー入力してみる

```
pi@raspberrypi:~ $ hexdump /dev/input/event0
0000000 a065 5eae 5f51 0009 0004 0004 0009 0007
0000010 a065 5eae 5f51 0009 0001 0021 0001 0000
0000020 a065 5eae 5f51 0009 0000 0000 0000 0000
0000030 a065 5eae 3639 000a 0004 0004 0009 0007
0000040 a065 5eae 3639 000a 0001 0021 0000 0000
0000050 a065 5eae 3639 000a 0000 0000 0000 0000
```

 - USBのディスクリプターを確認
 
```
pi@raspberrypi:~ $ sudo usbhid-dump 
001:002:001:DESCRIPTOR         1588590895.130327
 05 01 09 02 A1 01 85 01 05 09 19 01 29 05 15 00
 25 01 75 01 95 05 81 02 75 03 95 01 81 01 05 01
 09 01 A1 00 09 30 09 31 15 81 25 7F 75 08 95 02
 81 06 C0 09 38 95 01 81 06 05 0C 0A 38 02 81 06
 C0 05 0C 09 01 A1 01 85 10 15 00 26 3C 02 19 00
 2A 3C 02 75 10 95 01 81 00 C0 06 A3 FF 09 01 A1
 01 85 11 19 00 2A FF 00 15 00 26 FF 00 75 08 95
 02 81 02 C0 06 A0 FF 09 01 A1 01 85 15 1A F1 00
 2A FC 00 15 00 25 01 75 01 95 0D 81 02 95 03 81
 01 C0 06 A1 FF 09 01 A1 01 85 16 19 00 2A FF 00
 15 00 26 FF 00 75 08 95 02 81 02 C0 06 00 FF 09
 01 A1 01 85 13 09 01 15 00 26 FF 00 75 08 95 08
 81 02 09 02 75 08 95 08 91 02 09 03 75 08 95 08
 B1 02 C0

001:002:000:DESCRIPTOR         1588590895.133830
 05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01
 75 01 95 08 81 02 95 01 75 08 81 01 95 05 75 01
 05 08 19 01 29 05 91 02 95 01 75 03 91 01 95 06
 75 08 16 00 00 26 AF 00 05 07 1A 00 00 2A AF 00
 81 00 05 0C 09 00 15 80 25 7F 75 08 95 08 B1 02
 C0
```

[https://eleccelerator.com/usbdescreqparser/#](https://eleccelerator.com/usbdescreqparser/#)で内容を調べてみる

interface1 -> tracpoint

```
0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x02,        // Usage (Mouse)
0xA1, 0x01,        // Collection (Application)
0x85, 0x01,        //   Report ID (1)
0x05, 0x09,        //   Usage Page (Button)
0x19, 0x01,        //   Usage Minimum (0x01)
0x29, 0x05,        //   Usage Maximum (0x05)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0x01,        //   Logical Maximum (1)
0x75, 0x01,        //   Report Size (1)
0x95, 0x05,        //   Report Count (5)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x03,        //   Report Size (3)
0x95, 0x01,        //   Report Count (1)
0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
0x09, 0x01,        //   Usage (Pointer)
0xA1, 0x00,        //   Collection (Physical)
0x09, 0x30,        //     Usage (X)
0x09, 0x31,        //     Usage (Y)
0x15, 0x81,        //     Logical Minimum (-127)
0x25, 0x7F,        //     Logical Maximum (127)
0x75, 0x08,        //     Report Size (8)
0x95, 0x02,        //     Report Count (2)
0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              //   End Collection
0x09, 0x38,        //   Usage (Wheel)
0x95, 0x01,        //   Report Count (1)
0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x0C,        //   Usage Page (Consumer)
0x0A, 0x38, 0x02,  //   Usage (AC Pan)
0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              // End Collection
0x05, 0x0C,        // Usage Page (Consumer)
0x09, 0x01,        // Usage (Consumer Control)
0xA1, 0x01,        // Collection (Application)
0x85, 0x10,        //   Report ID (16)
0x15, 0x00,        //   Logical Minimum (0)
0x26, 0x3C, 0x02,  //   Logical Maximum (572)
0x19, 0x00,        //   Usage Minimum (Unassigned)
0x2A, 0x3C, 0x02,  //   Usage Maximum (AC Format)
0x75, 0x10,        //   Report Size (16)
0x95, 0x01,        //   Report Count (1)
0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              // End Collection
0x06, 0xA3, 0xFF,  // Usage Page (Vendor Defined 0xFFA3)
0x09, 0x01,        // Usage (0x01)
0xA1, 0x01,        // Collection (Application)
0x85, 0x11,        //   Report ID (17)
0x19, 0x00,        //   Usage Minimum (0x00)
0x2A, 0xFF, 0x00,  //   Usage Maximum (0xFF)
0x15, 0x00,        //   Logical Minimum (0)
0x26, 0xFF, 0x00,  //   Logical Maximum (255)
0x75, 0x08,        //   Report Size (8)
0x95, 0x02,        //   Report Count (2)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              // End Collection
0x06, 0xA0, 0xFF,  // Usage Page (Vendor Defined 0xFFA0)
0x09, 0x01,        // Usage (0x01)
0xA1, 0x01,        // Collection (Application)
0x85, 0x15,        //   Report ID (21)
0x1A, 0xF1, 0x00,  //   Usage Minimum (0xF1)
0x2A, 0xFC, 0x00,  //   Usage Maximum (0xFC)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0x01,        //   Logical Maximum (1)
0x75, 0x01,        //   Report Size (1)
0x95, 0x0D,        //   Report Count (13)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x03,        //   Report Count (3)
0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              // End Collection
0x06, 0xA1, 0xFF,  // Usage Page (Vendor Defined 0xFFA1)
0x09, 0x01,        // Usage (0x01)
0xA1, 0x01,        // Collection (Application)
0x85, 0x16,        //   Report ID (22)
0x19, 0x00,        //   Usage Minimum (0x00)
0x2A, 0xFF, 0x00,  //   Usage Maximum (0xFF)
0x15, 0x00,        //   Logical Minimum (0)
0x26, 0xFF, 0x00,  //   Logical Maximum (255)
0x75, 0x08,        //   Report Size (8)
0x95, 0x02,        //   Report Count (2)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              // End Collection
0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
0x09, 0x01,        // Usage (0x01)
0xA1, 0x01,        // Collection (Application)
0x85, 0x13,        //   Report ID (19)
0x09, 0x01,        //   Usage (0x01)
0x15, 0x00,        //   Logical Minimum (0)
0x26, 0xFF, 0x00,  //   Logical Maximum (255)
0x75, 0x08,        //   Report Size (8)
0x95, 0x08,        //   Report Count (8)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x02,        //   Usage (0x02)
0x75, 0x08,        //   Report Size (8)
0x95, 0x08,        //   Report Count (8)
0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x09, 0x03,        //   Usage (0x03)
0x75, 0x08,        //   Report Size (8)
0x95, 0x08,        //   Report Count (8)
0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0,              // End Collection

// 211 bytes
```

interface0 -> keyboard

```
0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x06,        // Usage (Keyboard)
0xA1, 0x01,        // Collection (Application)
0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
0x19, 0xE0,        //   Usage Minimum (0xE0)
0x29, 0xE7,        //   Usage Maximum (0xE7)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0x01,        //   Logical Maximum (1)
0x75, 0x01,        //   Report Size (1)
0x95, 0x08,        //   Report Count (8)
0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01,        //   Report Count (1)
0x75, 0x08,        //   Report Size (8)
0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x05,        //   Report Count (5)
0x75, 0x01,        //   Report Size (1)
0x05, 0x08,        //   Usage Page (LEDs)
0x19, 0x01,        //   Usage Minimum (Num Lock)
0x29, 0x05,        //   Usage Maximum (Kana)
0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x01,        //   Report Count (1)
0x75, 0x03,        //   Report Size (3)
0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x06,        //   Report Count (6)
0x75, 0x08,        //   Report Size (8)
0x16, 0x00, 0x00,  //   Logical Minimum (0)
0x26, 0xAF, 0x00,  //   Logical Maximum (175)
0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
0x1A, 0x00, 0x00,  //   Usage Minimum (0x00)
0x2A, 0xAF, 0x00,  //   Usage Maximum (0xAF)
0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x0C,        //   Usage Page (Consumer)
0x09, 0x00,        //   Usage (Unassigned)
0x15, 0x80,        //   Logical Minimum (-128)
0x25, 0x7F,        //   Logical Maximum (127)
0x75, 0x08,        //   Report Size (8)
0x95, 0x08,        //   Report Count (8)
0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0,              // End Collection

// 81 bytes
```

たくさんある。。。

#### Thinkpad Trackpoint Keyboard Bluetoothを繋げてみる

[こちら](https://qiita.com/sushisushiBoo/items/36ae9295368a79745bee)に記述しました。

### USBデバイスになる

 - 参考
  - [https://qiita.com/sgrk/items/7a818b2a059d5b06b209](https://qiita.com/sgrk/items/7a818b2a059d5b06b209)
  - [http://www.isticktoit.net/?p=1383](http://www.isticktoit.net/?p=1383)

 - 設定

 起動時にUSB Composite Driver を有効にします

```
pi@raspberrypi:~/hid_test $ echo "dtoverlay=dwc2" | sudo tee -a 
/boot/config.txt
pi@raspberrypi:~/hid_test $ echo "dwc2" | sudo tee -a /etc/modules
pi@raspberrypi:~/hid_test $ echo "libcomposite" | sudo tee -a /etc/modules
pi@raspberrypi:~/hid_test $ sudo reboot
```

KeyboardとMouseの複合デバイスを有効にします。

```
pi@raspberrypi:~/hid_test $ sudo sh ./hid.sh 
pi@raspberrypi:~/hid_test $ ls /dev/ | grep hidg
hidg0
hidg1
```

hidg0がmouseに、hidg1がkeyboardになります

keyboardとmouseを同時に有効にするのは[こちら](https://github.com/girst/hardpass-passwordmanager/blob/master/init_usb.sh)を参考にしました。

``` hid.sh
#!/bin/bash
# Snippet from https://github.com/girst/hardpass-sendHID/blob/master/README.md . In which, the following notice was left:

# this is a stripped down version of https://github.com/ckuethe/usbarmory/wiki/USB-Gadgets - I don't claim any rights

cd /sys/kernel/config/usb_gadget/
mkdir -p g1
cd g1
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2
mkdir -p strings/0x409
echo "0" > strings/0x409/serialnumber
echo "sushisuhiBoo" > strings/0x409/manufacturer
echo "USB Gadget (Keyborad and Mouse)" > strings/0x409/product

C=1
mkdir -p configs/c.$C/strings/0x409
echo "Config $C: ECM network" > configs/c.$C/strings/0x409/configuration 
echo 250 > configs/c.$C/MaxPower 

## Mouse
N2="usb0"
mkdir -p functions/hid.$N2
echo 2 > functions/hid.$N2/protocol
echo 1 > functions/hid.$N2/subclass
echo 8 > functions/hid.$N2/report_length
echo -ne \\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x01\\x05\\x01\\x09\\x30\\x09\\x31\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x02\\x81\\x06\\xc0\\xc0 > functions/hid.$N2/report_desc
ln -s functions/hid.$N2 configs/c.$C/
# End functions

## Keyboard
N1="usb1"
mkdir -p functions/hid.$N1
echo 1 > functions/hid.$N1/protocol
echo 1 > functions/hid.$N1/subclass
echo 8 > functions/hid.$N1/report_length
echo -ne \\x05\\x01\\x09\\x06\\xA1\\x01\\x05\\x07\\x19\\xE0\\x29\\xE7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x01\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x01\\x95\\x06\\x75\\x08\\x16\\x00\\x00\\x26\\xAF\\x00\\x05\\x07\\x1A\\x00\\x00\\x2A\\xAF\\x00\\x81\\x00\\x05\\x0C\\x09\\x00\\x15\\x80\\x25\\x7F\\x75\\x08\\x95\\x08\\xB1\\x02\\xC0 > functions/hid.$N1/report_desc
ln -s functions/hid.$N1 configs/c.$C/
## End function

## enable USB Device
ls /sys/class/udc > UDC
```

これで参考ページのようにデバイス(hidg0,hidg1）にデータを書き込むとUSBホストのPCを操作できます。

デバイスを無効にするには以下のコマンドを利用します。[参考](https://www.kernel.org/doc/Documentation/usb/gadget_configfs.txt)

```hid_del.sh
echo "" > /sys/kernel/config/usb_gadget/g1/UDC

cd /sys/kernel/config/usb_gadget
rm g1/configs/c.1/hid.usb0
rm g1/configs/c.1/hid.usb1
rmdir g1/configs/c.1/strings/0x409
rmdir g1/configs/c.1
rmdir g1/functions/hid.usb0
rmdir g1/functions/hid.usb1
rmdir g1/strings/0x409
rmdir g1
```


### Keyboard、TracPoint操作をUSBデバイスに送り込む

#### Tracpoint

/dev/input/event1(mouse)の入力するを/dev/hidg0に書き込みます。

```
sudo pip install pydev
sudo python mouse3.py
....
```

```mouse3.py
from evdev import InputDevice, categorize, ecodes

dev = InputDevice('/dev/input/ThinkPadTracPointKeyboardMouse')
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

まずはアルファベットのみ対応

```keyboard.py
from evdev import InputDevice, categorize, ecodes

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

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:
			# print(categorize(event))
			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:
						modify = ctrl + (shift << 1) + (alt << 2)
						buf.extend([modify, 0, scancode[event.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()

if __name__ == "__main__":
	main()
```

### キー変換する

長くなったので、残りのキー対応と変換はは別の記事で
[Raspy Zero WH でキー変換器を作る (その2）](https://qiita.com/sushisushiBoo/items/43f595c59bb3678fc884)