2021.4.30: ソースコードを修正(PC側でシリアル接続しないと動作しない問題修正)
参考にしたもの
[https://okiraku-camera.tokyo/blog/?p=8193]
作り方
- キーボード: Thinkpad keyboard with Tracpoint
- ハード:参考と一緒
- ソフト:参考にしたものはkeyboardだけだったのでArduinoの標準ライブラリの
USBHIDBootKbdAndMouse
のサンプルをもとに実装(tracpointが使いたい!!!) - 注意点:Aruduinoの標準ライブラリのKeyboardの
sendReport()
をprivate
からpublic
に変更した。
keybord_converter.ino
/**
* KeyCodeConvert
* original Keyboard Library must be modified.
* in Keyboard.h, function "sendReport()" should be change to "public" from "private".
*/
#include <hidboot.h>
#include <usbhub.h>
#include "Keyboard.h"
#include "Mouse.h"
// Satisfy IDE, which only needs to see the include statment in the ino.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>
// KeyReportのmodifiersのビット構成
static const uint8_t MODIFIRE_LEFT_CONTROL = 0x01;
static const uint8_t MODIFIRE_LEFT_SHIFT = 0x02;
static const uint8_t MODIFIRE_LEFT_ALT = 0x04;
static const uint8_t MODIFIRE_LEFT_GUI= 0x08;
static const uint8_t MODIFIRE_RIGHT_CONTROL = 0x10;
static const uint8_t MODIFIRE_RIGHT_SHIFT = 0x20;
static const uint8_t MODIFIRE_RIGHT_ALT = 0x40;
static const uint8_t MODIFIRE_RIGHT_GUI= 0x80;
//#define DEBUG_PRINT
class MouseRptParser : public MouseReportParser
{
protected:
void OnMouseMove(MOUSEINFO *mi);
void OnLeftButtonUp(MOUSEINFO *mi);
void OnLeftButtonDown(MOUSEINFO *mi);
void OnRightButtonUp(MOUSEINFO *mi);
void OnRightButtonDown(MOUSEINFO *mi);
void OnMiddleButtonUp(MOUSEINFO *mi);
void OnMiddleButtonDown(MOUSEINFO *mi);
};
void MouseRptParser::OnMouseMove(MOUSEINFO *mi)
{
#ifdef DEBUG_PRINT
Serial.print("dx=");
Serial.print(mi->dX, DEC);
Serial.print(" dy=");
Serial.println(mi->dY, DEC);
#else
Mouse.move(mi->dX, mi->dY);
#endif
};
void MouseRptParser::OnLeftButtonUp (MOUSEINFO *mi)
{
#ifdef DEBUG_PRINT
Serial.println("L Butt Up");
#else
Mouse.release(MOUSE_LEFT);
#endif
};
void MouseRptParser::OnLeftButtonDown (MOUSEINFO *mi)
{
#ifdef DEBUG_PRINT
Serial.println("L Butt Dn");
#else
Mouse.press(MOUSE_LEFT);
#endif
};
void MouseRptParser::OnRightButtonUp (MOUSEINFO *mi)
{
#ifdef DEBUG_PRINT
Serial.println("R Butt Up");
#else
Mouse.release(MOUSE_RIGHT);
#endif
};
void MouseRptParser::OnRightButtonDown (MOUSEINFO *mi)
{
#ifdef DEBUG_PRINT
Serial.println("R Butt Dn");
#else
Mouse.press(MOUSE_RIGHT);
#endif
};
void MouseRptParser::OnMiddleButtonUp (MOUSEINFO *mi)
{
#ifdef DEBUG_PRINT
Serial.println("M Butt Up");
#else
Mouse.release(MOUSE_MIDDLE);
#endif
};
void MouseRptParser::OnMiddleButtonDown (MOUSEINFO *mi)
{
#ifdef DEBUG_PRINT
Serial.println("M Butt Dn");
#else
Mouse.press(MOUSE_MIDDLE);
#endif
};
bool modifyKey(uint8_t* pKey, bool bDown);
bool modifyModifier(uint8_t before, uint8_t after);
void sendReport(KeyReport* report);
class KbdRptParser : public KeyboardReportParser
{
void PrintKey(uint8_t mod, uint8_t key);
protected:
void OnControlKeysChanged(uint8_t before, uint8_t after);
void OnKeyDown (uint8_t mod, uint8_t key);
void OnKeyUp (uint8_t mod, uint8_t key);
// void OnKeyPressed(uint8_t key);
};
KeyReport keyReport;
void sendReport(KeyReport* report)
{
Serial.print("== ");
Serial.print(report->modifiers, HEX);
Serial.print(":");
Serial.print(report->keys[0], HEX);
Serial.println(" ==");
Keyboard.sendReport(report);
}
/**
* 修飾キー変換
* @note Controlの場合はCapsLockに変更
* @param [in] MODIFIERKEYS before: 前回の修飾キー状態
* @param [in] MODIFIERKEYS after: 今回の修飾キー状態
* @return bool : 修飾キー変換したかどうか
*/
bool modifyModifier(MODIFIERKEYS before, MODIFIERKEYS after)
{
// Control->CAPSLOCK(0x39)
if (before.bmLeftCtrl != after.bmLeftCtrl)
{
if (after.bmLeftCtrl)
{
Serial.println("CAPSLOCK DOWN");
keyReport.keys[0] = 0x39;
}
else
{
Serial.println("CAPSLOCK UP");
keyReport.keys[0] = 0;
}
sendReport(&keyReport);
return true;
}
return false;
}
/**
* キー変換
* @param [in/out] uint8_t* pKey: キーコード
* @param [in] bool bDown: 押下
* @return bool : true キー変換実施, false modifierとして処理
*/
bool modifyKey(uint8_t* pKey, bool bDown)
{
switch(*pKey) {
case 0x29: // ESC(0x29)->半角/全角(0x35)
*pKey = 0x35;
break;
case 0x35: // 半角/全角(0x35)->ESC(0x29)
*pKey = 0x29;
break;
case 0x8A: // 変換(0x8A)->半角/全角(0x35)
*pKey = 0x35;
break;
case 0x8B: // 無変換(0x8B)->半角/全角(0x35)
*pKey = 0x35;
break;
case 0x39: // CAPSLOCK(0x39)->Control
{
KBDINFO* pKbdInfo;
pKbdInfo = (KBDINFO*)&keyReport;
if (bDown)
{
pKbdInfo->bmLeftCtrl = 1;
Serial.println("LeftCtrl down");
}
else
{
pKbdInfo->bmLeftCtrl = 0;
Serial.println("LeftCtrl up");
}
return false;
}
default:
break;
}
Serial.print("changed to ");
Serial.println(*pKey, HEX);
return true;
}
void KbdRptParser::PrintKey(uint8_t m, uint8_t key)
{
MODIFIERKEYS mod;
*((uint8_t*)&mod) = m;
Serial.print((mod.bmLeftCtrl == 1) ? "C" : " ");
Serial.print((mod.bmLeftShift == 1) ? "S" : " ");
Serial.print((mod.bmLeftAlt == 1) ? "A" : " ");
Serial.print((mod.bmLeftGUI == 1) ? "G" : " ");
Serial.print(" >");
PrintHex<uint8_t>(key, 0x80);
Serial.print("< ");
Serial.print((mod.bmRightCtrl == 1) ? "C" : " ");
Serial.print((mod.bmRightShift == 1) ? "S" : " ");
Serial.print((mod.bmRightAlt == 1) ? "A" : " ");
Serial.println((mod.bmRightGUI == 1) ? "G" : " ");
};
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)
{
// キー変換
if (modifyKey(&key, true))
{
Serial.print("DN ");
keyReport.keys[0] = key;
PrintKey(keyReport.modifiers, key);
sendReport(&keyReport);
// uint8_t c = OemToAscii(mod, key);
// if (c)
// OnKeyPressed(c);
}
}
void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key)
{
if (modifyKey(&key, false))
{
Serial.print("UP ");
keyReport.keys[0] = 0;
PrintKey(keyReport.modifiers, key);
sendReport(&keyReport);
}
}
void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) {
MODIFIERKEYS beforeMod;
*((uint8_t*)&beforeMod) = before;
MODIFIERKEYS afterMod;
*((uint8_t*)&afterMod) = after;
if (before != after) {
if (modifyModifier(beforeMod, afterMod))
{
return;
}
Serial.print("Modifer changed:");
Serial.println(after);
}
keyReport.modifiers = after;
if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl) {
Serial.println("LeftCtrl changed");
}
if (beforeMod.bmLeftShift != afterMod.bmLeftShift) {
Serial.println("LeftShift changed");
}
if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt) {
Serial.println("LeftAlt changed");
}
if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI) {
Serial.println("LeftGUI changed");
}
if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl) {
Serial.println("RightCtrl changed");
}
if (beforeMod.bmRightShift != afterMod.bmRightShift) {
Serial.println("RightShift changed");
}
if (beforeMod.bmRightAlt != afterMod.bmRightAlt) {
Serial.println("RightAlt changed");
}
if (beforeMod.bmRightGUI != afterMod.bmRightGUI) {
Serial.println("RightGUI changed");
}
}
//void KbdRptParser::OnKeyPressed(uint8_t key)
//{
// Serial.print("ASCII: ");
// Serial.println((char)key);
// Keyboard.write(key);
//};
USB Usb;
USBHub Hub(&Usb);
HIDBoot < USB_HID_PROTOCOL_KEYBOARD | USB_HID_PROTOCOL_MOUSE > HidComposite(&Usb);
HIDBoot<USB_HID_PROTOCOL_KEYBOARD> HidKeyboard(&Usb);
HIDBoot<USB_HID_PROTOCOL_MOUSE> HidMouse(&Usb);
KbdRptParser KbdPrs;
MouseRptParser MousePrs;
void setup()
{
Serial.begin( 9600 );
#if 0 // シリアル接続待ちするので無効化 #if !defined(__MIPSEL__)
while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
Serial.println("Start");
if (Usb.Init() == -1)
Serial.println("OSC did not start.");
delay( 200 );
HidComposite.SetReportParser(0, &KbdPrs);
HidComposite.SetReportParser(1, &MousePrs);
HidKeyboard.SetReportParser(0, &KbdPrs);
HidMouse.SetReportParser(0, &MousePrs);
Mouse.begin();
Keyboard.begin();
}
void loop()
{
Usb.Task();
}