できた。
使ってみた。
ダメだ。
もちろん、前に作ったものよりは格段に良くなったのだが,残念ながらこれを普段使いにしたいとは思えない。慣れれば使えないことはない,というレベル。
一番の問題は、キーをすり鉢状に傾けすぎたせいで,押したときにデバイスが逃げるように動いてしまう点。
前に作ったときそれが嫌だったので,手のひらで押さえながら指だけで打てるようにする,というコンセプトで作ったが,やはり手のひらでずっと押さえているというのは使っていて気持ち良くない。最初のキー配置決める時は粘土だったから、ずっしりしてて問題なかったんだよな。おもりつけたらまだいいかも。
前回の記事の後でやったことを書いておく。
もう少しで完成,と思っていたが,最後にまあまあの難関が残っていた。
Arduino IDEが日本語キーボードに対応していない問題
Arduino IDEの標準機能では,日本語キーボードには対応していないのである。すでに解決してくれている人がいるので助かるが,まだいろいろうまく行かず,キーボードの仕様がよくわからなくなって,結局,まあまあちゃんと勉強してしまったので、別記事にまとめておいた。
manva.hatenablog.com
全角/半角キーで日本語に切替えられず,「`」になる問題で苦労したが,これはキーボード側のソフトの問題ではなく,Windows側で英語キーボードとして認識されているせいだった。最近,X-Bows↓という英語キーボードを使っていたので,英語キーボードの設定になっていた。
x-bows.com
Windowsでは,複数のキーボードを接続した場合,日本語と英語の切換えは基本的にキーボードごとの設定ではなく,全てのキーボードが同じ設定になるようだ。レジストリをいじったら日本語キーボードとして使えるようになったのだが,今度はX-Bowsの方まで日本語キーボードとして扱われてしまい、いくつかのキーが刻印と一致しなくなった。この問題はまだ解決できていない。
その他は細々した問題。
チャタリングの問題
キーを押したとき,何回かに1回くらい,チャタリングで同じ文字が2個入力される問題があった。
まずは,QMKではどうしているか勉強↓。
Debounce API - QMK
タイマーで実時間で設定できた方が良いのだろうが,自分の作る処理の演算時間がそんなに大幅に変わる予定もないので,普通にループでカウントダウンするだけにしよう。
QMKでは,Eager(押したらすぐ反応し,しばらくは無視)か,Defer(しばらく押されていたら反応)かを選べるようだが,Eagerの実装にしよう。
キーを押したままレイヤー切換えると離しても押しっぱなしになる問題
これは単純にレイヤー切替えたときReleaseAll()することで解決。
void SetLayerTo( int layernum ){ if( layer!=layernum ){ layer = layernum; Keyboard.releaseAll(); //押したままレイヤー切換えたら押しっぱなしになるので全部離す } }
レイヤーをどうするか
QMK firmwareのLAYOUTマクロをパクってキー配置をビジュアル的に見やすくした。キーの定義もQMKっぽく名前をつけた。
#define LAYOUT( \ L31, L41, L32, L42, L33, L43, L24, L34, R45, R55, R36, R46, R37, R47, R38, R48, \ L21, L51, L22, L52, L23, L53, L14, R65, R26, R56, R27, R57, R28, R58, \ L11, L61, L12, L62, L13, L63, L64, L54, L44, R35, R25, R15, R16, R66, R17, R67, R18, R68 \ ) \ { \ { L11, L12, L13, L14, R15, R16, R17, R18 }, \ { L21, L22, L23, L24, R25, R26, R27, R28 }, \ { L31, L32, L33, L34, R35, R36, R37, R38 }, \ { L41, L42, L43, L44, R45, R46, R47, R48 }, \ { L51, L52, L53, L54, R55, R56, R57, R58 }, \ { L61, L62, L63, L64, R65, R66, R67, R68 } \ }
レイヤーは、数字シフトキーというのを用意し、押している間は数字レイヤ。数字レイヤでは,ホームポジションの行を数字、その上の行をシフトキー+数字で入力される記号とした。下の行は,キーを減らしたせいではみ出た記号のキーを並べた。もう1つ,ファンクションシフトキーを押している間はファンクションレイヤ。ファンクションキーとかカーソルキーとかを集めた。
シフトキーと親指のキーはレイヤーによらず共通。エンターキーは,小指でターン!と叩くのが好きそうな人をよく見かけるので,小指のキーを減らしてもその快感を奪わないよう,親指の端にして手首逆回転でターンとできるようにした。
const byte keymaps[NUM_LAYER][NUM_ROW][NUM_COL_ALL] = {
LAYOUT( \
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, _______, KC_LGUI, KC_RALT, KC_RCTL, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_AT, \
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, _______, _______, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_COLN, \
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_BSPC, KC_SPC, KC_DEL, KC_ENT, KC_SPC, KC_ZKHK, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT ),
LAYOUT( \
KC_ESC, KC_EXLM, KC_DQOT, KC_HASH, KC_DLR, KC_PERC, _______, KC_LGUI, KC_RALT, KC_RCTL, KC_AMPR, KC_QUOT, KC_LPRN, KC_RPRN, KC_P, KC_EQL, \
KC_CAPS, KC_1, KC_2, KC_3, KC_4, KC_5, _______, _______, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, \
KC_LSFT, KC_BSLS, KC_CIRC, KC_YEN, KC_TILD, KC_PIPE, KC_BSPC, KC_SPC, KC_DEL, KC_ENT, KC_SPC, KC_ZKHK, KC_LBRC, KC_RBRC, KC_LLBR, KC_RLBR, KC_UNDS, KC_RSFT ),
LAYOUT( \
KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, _______, KC_LGUI, KC_RALT, KC_RCTL, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, \
KC_CAPS, _______, KC_LEFT, KC_UP, KC_RGHT, _______, _______, _______, _______, KC_HOME, KC_PGUP, KC_END, KC_PSCR, _______, \
KC_LSFT, _______, _______, KC_DOWN, _______, _______, KC_BSPC, KC_SPC, KC_DEL, KC_ENT, KC_SPC, KC_ZKHK, _______, _______, KC_PGDN, _______, _______, KC_RSFT )
};
通信速度
左右デバイス間の通信速度(ボーレート)を上げた。ArduinoのMax 115200bpsに上げたら動かなかったので,19200bpsにしておいた。元々の設定9600bpsから2倍にしているが,体感では違いがわからない。
マウスを動かしたときのザラザラ感
右手用の裏にマウスソール↓(滑りを良くするやつ)を貼った。
パワーサポート ほぼ全てのマウス対応マウスソール 丸形0.45mm厚 16個入り AS-44
- メディア: Personal Computers
とにかく、これで完成。やりたかったことは大体やったので,これ以上やって完璧を目指してもあまり大幅な改善は期待できない。
結論:マウスはキーボードに内蔵しない方が良い
しばらく別のことしよう。
参考までにソースコードを載せておく。
右手用
KeybouseR.ino
// 右手用 #include <SPI.h> #include <Mouse.h> #include <Keyboard.h> #include "ADNS3050.h" #define PIN_NUM_PHASE_A 2 //pin2->int1 phaseA #define PIN_NUM_PHASE_B 3 //pin3->int0 phaseB #define INT_NUM_PHASE_A 1 #define INT_NUM_PHASE_B 0 #define NUM_ROW 6 #define NUM_COL 4 typedef struct { int row; int col; } str_keypos; const int PIN_NUM_ROW[NUM_ROW] = { 4, 5, 6, 7, 8, 9 }; const int PIN_NUM_COL[NUM_COL] = { A3, A2, A1, A0 }; const str_keypos KEYPOS_MOUSE_SHIFT = {5,4}; bool PreviousKeyState[NUM_ROW][NUM_COL]; byte MouseDeltaX = 0; byte MouseDeltaY = 0; byte WheelCount = 0; volatile bool PreviousA = 0; volatile bool PreviousB = 0; bool flgMouseMode; //----------------------------------------------------------------- void setup(){ int row, col; startupImageSensor(); Mouse.begin(); Keyboard.begin(); Serial1.begin(19200); //左右通信用 pinMode( PIN_NUM_PHASE_A, INPUT_PULLUP ); pinMode( PIN_NUM_PHASE_B, INPUT_PULLUP ); attachInterrupt( INT_NUM_PHASE_A, EncoderA_Change, CHANGE ); attachInterrupt( INT_NUM_PHASE_B, EncoderB_Change, CHANGE ); for( row = 0; row < NUM_ROW; row++ ){ pinMode( PIN_NUM_ROW[row], OUTPUT ); } for( row = 0; row < NUM_COL; row++ ){ pinMode( PIN_NUM_COL[row], INPUT_PULLUP ); } for( row = 0; row < NUM_ROW; row++){ for( col = 0; col < NUM_COL; col++){ PreviousKeyState[row][col] = HIGH; } digitalWrite( PIN_NUM_ROW[row], HIGH ); } } //----------------------------------------------------------------- void EncoderA_Change(){ int CurrentA, CurrentB; CurrentA = digitalRead( PIN_NUM_PHASE_A ); CurrentB = digitalRead( PIN_NUM_PHASE_B ); //※本来,値が変化したときにだけ割込が入るはずなので,Previousを残しておく必要はないし,else ifの条件も要らないはずなのだが, //なぜか割込が呼ばれているのにAが変わっていない時がある。チャタリングしていて,割込が入ってから値を読むまでの間に戻った? if( ((PreviousA==0)&&(CurrentA==1)&&(CurrentB==0))||((PreviousA==1)&&(CurrentA==0)&&(CurrentB==1)) ){ WheelCount++; }else if( ((PreviousA==0)&&(CurrentA==1)&&(CurrentB==1))||((PreviousA==1)&&(CurrentA==0)&&(CurrentB==0)) ){ WheelCount--; } PreviousA = CurrentA; } //----------------------------------------------------------------- void EncoderB_Change(){ int CurrentA, CurrentB; CurrentA = digitalRead( PIN_NUM_PHASE_A ); CurrentB = digitalRead( PIN_NUM_PHASE_B ); if( ((PreviousB==0)&&(CurrentB==1)&&(CurrentA==1))||((PreviousB==1)&&(CurrentB==0)&&(CurrentA==0)) ){ WheelCount++; }else if( ((PreviousB==0)&&(CurrentB==1)&&(CurrentA==0))||((PreviousB==1)&&(CurrentB==0)&&(CurrentA==1)) ){ WheelCount--; } PreviousB = CurrentB; } //----------------------------------------------------------------- void SendMouseMove( byte MouseDeltaX, byte MouseDeltaY, byte WheelCount ){ byte sendData; // データフォーマット // 先頭bit: マウスデータフラグ,2番目bit: 同期フラグ // 後ろ 6bit x 4 で 8bitデータ3つを送信 sendData = 0b11000000 | ( MouseDeltaX >> 2 ); Serial1.write( sendData ); sendData = 0b10000000 | ( ( MouseDeltaX & 0b00000011 ) << 4 | MouseDeltaY >> 4 ); Serial1.write( sendData ); sendData = 0b10000000 | ( ( MouseDeltaY & 0b00001111 ) << 2 | WheelCount >> 6 ); Serial1.write( sendData ); sendData = 0b10000000 | ( WheelCount & 0b00111111 ); Serial1.write( sendData ); } //----------------------------------------------------------------- bool CheckSpecialKey( str_keypos* keypos1, str_keypos* keypos2 ){ if( ( keypos1->row==keypos2->row ) &&( keypos1->col==keypos2->col ) ){ return true; }else{ return false; } } //----------------------------------------------------------------- void SendKeyPress( str_keypos* keypos ){ Serial1.write( 1<<6 | keypos->row<<3 | keypos->col ); } //----------------------------------------------------------------- void SendKeyRelease( str_keypos* keypos ){ Serial1.write( keypos->row<<3 | keypos->col ); } //----------------------------------------------------------------- void ClearImageSensorDeltaXY( void ){ MouseDeltaX = 0; MouseDeltaY = 0; GetImageSensorDeltaX(); // 読取ったら消える GetImageSensorDeltaY(); } //----------------------------------------------------------------- void loop(){ int CurrentKeyState, row, col; str_keypos keypos; bool isMouseShiftKey; for( row=0; row<NUM_ROW; row++ ){ // キーボードキー状態送信 digitalWrite( PIN_NUM_ROW[row], LOW ); for( col=0; col<NUM_COL; col++ ){ CurrentKeyState = digitalRead( PIN_NUM_COL[col] ); keypos.row = row; keypos.col = col + 4; isMouseShiftKey = CheckSpecialKey( &KEYPOS_MOUSE_SHIFT, &keypos ); if( CurrentKeyState == LOW ){ //押しているとき if( PreviousKeyState[row][col] == HIGH ){ //今押した SendKeyPress( &keypos ); if( isMouseShiftKey ){ ClearImageSensorDeltaXY(); } } if( isMouseShiftKey ){ flgMouseMode = 1; } }else{ //離しているとき if( PreviousKeyState[row][col] == LOW ){ //今離した SendKeyRelease( &keypos ); } if( isMouseShiftKey ){ flgMouseMode = 0; } } PreviousKeyState[row][col] = CurrentKeyState; } digitalWrite( PIN_NUM_ROW[row], HIGH ); } MouseDeltaX = GetImageSensorDeltaX(); MouseDeltaY = -GetImageSensorDeltaY(); //if( flgMouseMode ){ // マウスモード SendMouseMove( MouseDeltaX, MouseDeltaY, WheelCount ); WheelCount = 0; //↑とセット。使った直後にリセット //} }
ADNS3050.h
これは↓のソースを少し書き換えたもの。
Interfacing an Arduino With a Mouse Sensor (ADNS-3050) : 3 Steps - Instructables
#include <SPI.h> // SPI and misc pins for the ADNS #define PIN_SCLK SCK #define PIN_MISO MISO #define PIN_MOSI MOSI #define PIN_NCS 10 // レジスタ #define DELTA_X 0x03 #define DELTA_Y 0x04 #define MOUSE_CTRL 0x0d #define RESET 0x3a #define MOTION_CTRL 0x41 byte ImageSensorRead( byte reg_addr ){ digitalWrite( PIN_NCS, LOW );//begin communication // send address of the register, with MSBit = 0 to say it's reading SPI.transfer( reg_addr & 0x7f ); delayMicroseconds(100); // read data byte data = SPI.transfer(0); delayMicroseconds(30); digitalWrite( PIN_NCS, HIGH );//end communication delayMicroseconds(30); return data; } void ImageSensorWrite( byte reg_addr, byte SPIdata ){ digitalWrite( PIN_NCS, LOW ); //send address of the register, with MSBit = 1 to say it's writing SPI.transfer( reg_addr | 0x80 ); //send data SPI.transfer( SPIdata ); delayMicroseconds(30); digitalWrite( PIN_NCS, HIGH );//end communication delayMicroseconds(30); } void ImageSensorComStart(){ digitalWrite( PIN_NCS, HIGH ); delay(20); digitalWrite( PIN_NCS, LOW ); } void startupImageSensor(){ //--------Setup SPI Communication--------- byte out = 0; byte read = 0; byte bit = 0; pinMode( PIN_MISO, INPUT ); pinMode( PIN_NCS, OUTPUT ); SPI.begin(); // set the details of the communication SPI.setBitOrder( MSBFIRST ); // transimission order of bits SPI.setDataMode( SPI_MODE3 ); // sampling on rising edge SPI.setClockDivider( SPI_CLOCK_DIV16 ); // 16MHz/16 = 1MHz delay(10); //----------------- Power Up and config --------------- ImageSensorComStart(); ImageSensorWrite( RESET, 0x5a ); // force reset delay(100); // wait for it to reboot ImageSensorWrite( MOUSE_CTRL, 0x20 ); //Setup Mouse Control ImageSensorWrite( MOTION_CTRL, 0x00 ); //Clear Motion Control register delay(100); } byte GetImageSensorDeltaX(){//returns the X acceleration value return( ImageSensorRead( DELTA_X ) ); } byte GetImageSensorDeltaY(){//returns the Y acceleration value return( ImageSensorRead( DELTA_Y ) ); }
左手用
KeybouseL.ino
// 左手用 #include <Mouse.h> #include <Keyboard_jp.h> #include "KeyDefine.h" #define NUM_ROW 6 #define NUM_COL 4 #define NUM_COL_ALL 8 #define NUM_LAYER 3 //レイヤの数 #define PRESS 0 //押した(アクティブロー) #define RELEASE 1 //離した #define LAYER_MAIN 0 //メインレイヤのレイヤ番号 #define LAYER_NUM 1 //数字レイヤのレイヤ番号 #define LAYER_FN 2 //ファンクションレイヤのレイヤ番号 typedef struct { int row; int col; } str_keypos; byte MouseDeltaX = 0; byte MouseDeltaY = 0; byte WheelCount = 0; byte readMouseData[4]; int readMouseDataCount = 0; int layer = 0; int PreviousKeyState[NUM_ROW][NUM_COL]; bool flgMouseMode = false; const int PIN_NUM_ROW[NUM_ROW] = { 9, 8, 7, 6, 5, 4 }; const int PIN_NUM_COL[NUM_COL] = { A0, A1, A2, A3 }; const int debounce = 100; const byte keymaps[NUM_LAYER][NUM_ROW][NUM_COL_ALL] = { LAYOUT( \ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, _______, KC_LGUI, KC_RALT, KC_RCTL, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_AT, \ KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, _______, _______, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_COLN, \ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_BSPC, KC_SPC, KC_DEL, KC_ENT, KC_SPC, KC_ZKHK, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT ), LAYOUT( \ KC_ESC, KC_EXLM, KC_DQOT, KC_HASH, KC_DLR, KC_PERC, _______, KC_LGUI, KC_RALT, KC_RCTL, KC_AMPR, KC_QUOT, KC_LPRN, KC_RPRN, KC_P, KC_EQL, \ KC_CAPS, KC_1, KC_2, KC_3, KC_4, KC_5, _______, _______, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, \ KC_LSFT, KC_BSLS, KC_CIRC, KC_YEN, KC_TILD, KC_PIPE, KC_BSPC, KC_SPC, KC_DEL, KC_ENT, KC_SPC, KC_ZKHK, KC_LBRC, KC_RBRC, KC_LLBR, KC_RLBR, KC_UNDS, KC_RSFT ), LAYOUT( \ KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, _______, KC_LGUI, KC_RALT, KC_RCTL, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, \ KC_CAPS, _______, KC_LEFT, KC_UP, KC_RGHT, _______, _______, _______, _______, KC_HOME, KC_PGUP, KC_END, KC_PSCR, _______, \ KC_LSFT, _______, _______, KC_DOWN, _______, _______, KC_BSPC, KC_SPC, KC_DEL, KC_ENT, KC_SPC, KC_ZKHK, _______, _______, KC_PGDN, _______, _______, KC_RSFT ) }; const str_keypos KEYPOS_MOUSE_SHIFT = {5,4}; const str_keypos KEYPOS_LEFT_CLICK = {4,5}; const str_keypos KEYPOS_RIGHT_CLICK = {1,6}; const str_keypos KEYPOS_NUM_SHIFT = {0,3}; const str_keypos KEYPOS_FN_SHIFT = {1,3}; //----------------------------------------------------------------- void setup(){ int row, col; Mouse.begin(); //start mouse emulation Keyboard.begin(); Serial1.begin( 19200 ); //左右通信用 for( row = 0; row < NUM_ROW; row++ ){ pinMode( PIN_NUM_ROW[row], OUTPUT ); } for( col = 0; col < NUM_COL; col++ ){ pinMode( PIN_NUM_COL[col], INPUT_PULLUP ); } for( row = 0; row < NUM_ROW; row++){ for( col = 0; col < NUM_COL; col++){ PreviousKeyState[row][col] = HIGH; // 全てのキーの前回値を「押してない」にしておく } digitalWrite( PIN_NUM_ROW[row], HIGH ); // 全てのキーを無効にしておく } } //----------------------------------------------------------------- void MousePressRelease( bool isPress, str_keypos* keypos ){ if( CheckSpecialKey( &KEYPOS_LEFT_CLICK, keypos ) ){ if( isPress ){ Mouse.press( MOUSE_LEFT ); }else{ Mouse.release( MOUSE_LEFT ); } } if( CheckSpecialKey( &KEYPOS_RIGHT_CLICK, keypos ) ){ if( isPress ){ Mouse.press( MOUSE_RIGHT ); }else{ Mouse.release( MOUSE_RIGHT ); } } } //----------------------------------------------------------------- void KeyboardPress( str_keypos* keypos ){ Keyboard.press( keymaps[layer][keypos->row][keypos->col] ); } //----------------------------------------------------------------- void KeyboardRelease( str_keypos* keypos ){ Keyboard.release( keymaps[layer][keypos->row][keypos->col] ); } //----------------------------------------------------------------- void KeyboardPressRelease( bool isPress, str_keypos* keypos ){ if( isPress ){ KeyboardPress( keypos ); }else{ KeyboardRelease( keypos ); } } //----------------------------------------------------------------- bool CheckSpecialKey( str_keypos* keypos1, str_keypos* keypos2 ){ if( ( keypos1->row==keypos2->row ) &&( keypos1->col==keypos2->col ) ){ return true; }else{ return false; } } //----------------------------------------------------------------- void SetLayer( void ){ if( PreviousKeyState[KEYPOS_NUM_SHIFT.row][KEYPOS_NUM_SHIFT.col] == PRESS ){ SetLayerTo( LAYER_NUM ); }else if( PreviousKeyState[KEYPOS_FN_SHIFT.row][KEYPOS_FN_SHIFT.col] == PRESS ){ SetLayerTo( LAYER_FN ); }else{ SetLayerTo( LAYER_MAIN ); } } //----------------------------------------------------------------- void SetLayerTo( int layernum ){ if( layer!=layernum ){ layer = layernum; Keyboard.releaseAll(); //押したままレイヤー切換えたら押しっぱなしになるので全部離す } } //----------------------------------------------------------------- void CheckMouseModeKey( bool isPress, str_keypos* keypos ){ if( CheckSpecialKey( &KEYPOS_MOUSE_SHIFT, keypos ) ){ if( isPress ){ flgMouseMode = true; }else{ flgMouseMode = false; } } } //----------------------------------------------------------------- void SetMouseMove( byte readData ){ if ( readData & 0b01000000 ){ // 同期 readMouseDataCount = 0; }else{ readMouseDataCount++; } readMouseData[readMouseDataCount] = readData & 0b00111111; // 上位2ビット消去 if( readMouseDataCount==3 ){ // データが揃ったら MouseDeltaX = (readMouseData[0]<<2) | (readMouseData[1]>>4); MouseDeltaY = (readMouseData[1]<<4) | (readMouseData[2]>>2); WheelCount = (signed char)(readMouseData[2]<<6) | readMouseData[3]; Mouse.move( MouseDeltaX, MouseDeltaY, WheelCount ); // カーソルとホイール } } //----------------------------------------------------------------- void loop() { int CurrentKeyState; str_keypos keypos; byte readData; bool isPress; // 左手キーボード SetLayer(); for( keypos.row=0; keypos.row<NUM_ROW; keypos.row++ ){ digitalWrite( PIN_NUM_ROW[keypos.row], LOW ); // keypos.row列目のキー入力を有効にする for( keypos.col=0; keypos.col<NUM_COL; keypos.col++ ){ CurrentKeyState = digitalRead( PIN_NUM_COL[keypos.col] ); // keypos.col行目の値を読む if( PreviousKeyState[keypos.row][keypos.col]>1 ){ // 離したばかり PreviousKeyState[keypos.row][keypos.col]--; // チャタリング対策のカウントダウン }else if( PreviousKeyState[keypos.row][keypos.col]<0 ){ // 押したばかり PreviousKeyState[keypos.row][keypos.col]++; // チャタリング対策のカウントダウン }else if( PreviousKeyState[keypos.row][keypos.col]==RELEASE ){ // 離してから一定時間経過 if( CurrentKeyState==PRESS ){ // 押した KeyboardPress( &keypos ); PreviousKeyState[keypos.row][keypos.col] = -debounce; } }else if( PreviousKeyState[keypos.row][keypos.col]==PRESS ){ // 押してから一定時間経過 if( CurrentKeyState==RELEASE ){ // 離した KeyboardRelease( &keypos ); PreviousKeyState[keypos.row][keypos.col] = debounce; } } } digitalWrite( PIN_NUM_ROW[keypos.row], HIGH ); // keypos.row列目のキー入力を無効に戻す } //右手キーボード&マウス if( Serial1.available() ){ // 右手から通信データが来ていたら readData = Serial1.read(); // 読む if ( readData & 0b10000000 ){ // マウスデータなら SetMouseMove( readData ); }else{ // キーボードキー状態データなら isPress = (readData & 0b01000000) >> 6; keypos.row = (readData & 0b00111000) >> 3; keypos.col = readData & 0b00000111; CheckMouseModeKey( isPress, &keypos ); if( flgMouseMode ){ // マウスモード MousePressRelease( isPress, &keypos ); }else{ // キーボードモード KeyboardPressRelease( isPress, &keypos ); } } } }
KeyDefine.h
ASCIIベースで作ってしまったが,記事に書いたとおり,Usage IDベースの方が良かった。名前はできるだけQMK firmwareと同じにした。
#define NONE 0x00 #define _______ 0x00 #define KC_SPC 32 #define KC_EXLM 33 // ! #define KC_DQOT 34 // " #define KC_HASH 35 // # #define KC_DLR 36 // $ #define KC_PERC 37 // % #define KC_AMPR 38 // & #define KC_QUOT 39 // ' #define KC_LPRN 40 // ( #define KC_RPRN 41 // ) #define KC_ASTR 42 // * #define KC_PLS 43 // + #define KC_COMM 44 // , #define KC_MINS 45 // - #define KC_DOT 46 // . #define KC_SLSH 47 // / #define KC_0 0x30 #define KC_1 0x31 #define KC_2 0x32 #define KC_3 0x33 #define KC_4 0x34 #define KC_5 0x35 #define KC_6 0x36 #define KC_7 0x37 #define KC_8 0x38 #define KC_9 0x39 #define KC_COLN 58 // : #define KC_SCLN 59 // ; #define KC_LESS 60 // < #define KC_EQL 61 // = #define KC_GRAT 62 // > #define KC_QSTN 63 // ? #define KC_AT 64 // @ #define KC_LLBR 91 // [ #define KC_YEN 92 // z #define KC_RLBR 93 // ] #define KC_CIRC 94 // ^ CIRCUMFLEX #define KC_UNDS 95 // _ #define KC_A 0x61 #define KC_B 0x62 #define KC_C 0x63 #define KC_D 0x64 #define KC_E 0x65 #define KC_F 0x66 #define KC_G 0x67 #define KC_H 0x68 #define KC_I 0x69 #define KC_J 0x6A #define KC_K 0x6B #define KC_L 0x6C #define KC_M 0x6D #define KC_N 0x6E #define KC_O 0x6F #define KC_P 0x70 #define KC_Q 0x71 #define KC_R 0x72 #define KC_S 0x73 #define KC_T 0x74 #define KC_U 0x75 #define KC_V 0x76 #define KC_W 0x77 #define KC_X 0x78 #define KC_Y 0x79 #define KC_Z 0x7A #define KC_LBRC 123 // { #define KC_PIPE 124 // | #define KC_RBRC 125 // } #define KC_TILD 126 // ~ //USB の Usage ID に 0x58 を足したキーコード // Usage ID #define KC_ENT 0x80 // 0x28 #define KC_ESC 0x81 // 0x29 #define KC_BSPC 0x82 // 0x2a #define KC_TAB 0x83 // 0x2b #define KC_ZKHK 0x8d //全角半角 #define KC_CAPS 0x91 // 0x39 #define KC_F1 0x92 // 0x3a #define KC_F2 0x93 // 0x3b #define KC_F3 0x94 // 0x3c #define KC_F4 0x95 // 0x3d #define KC_F5 0x96 // 0x3e #define KC_F6 0x97 // 0x3f #define KC_F7 0x98 // 0x40 #define KC_F8 0x99 // 0x41 #define KC_F9 0x9a // 0x42 #define KC_F10 0x9b // 0x43 #define KC_F11 0x9c // 0x44 #define KC_F12 0x9d // 0x45 #define KC_PSCR 0x9e // 0x46 #define KC_INS 0xa1 // 0x49 #define KC_HOME 0xa2 // 0x4a #define KC_PGUP 0xa3 // 0x4b #define KC_DEL 0xa4 // 0x4c #define KC_END 0xa5 // 0x4d #define KC_PGDN 0xa6 // 0x4e #define KC_RGHT 0xa7 // 0x4f #define KC_LEFT 0xa8 // 0x50 #define KC_DOWN 0xa9 // 0x51 #define KC_UP 0xaa // 0x52 #define KC_BSLS 223 // \ backslash #define KC_LCTL 0xf8 // 0xe0 #define KC_LSFT 0xf9 // 0xe1 #define KC_LALT 0xfa // 0xe2 #define KC_LGUI 0xfb // 0xe3 #define KC_RCTL 0xfc // 0xe4 #define KC_RSFT 0xfd // 0xe5 #define KC_RALT 0xfe // 0xe6 #define KC_RGUI 0xff // 0xe7 #define LAYOUT( \ L31, L41, L32, L42, L33, L43, L24, L34, R45, R55, R36, R46, R37, R47, R38, R48, \ L21, L51, L22, L52, L23, L53, L14, R65, R26, R56, R27, R57, R28, R58, \ L11, L61, L12, L62, L13, L63, L64, L54, L44, R35, R25, R15, R16, R66, R17, R67, R18, R68 \ ) \ { \ { L11, L12, L13, L14, R15, R16, R17, R18 }, \ { L21, L22, L23, L24, R25, R26, R27, R28 }, \ { L31, L32, L33, L34, R35, R36, R37, R38 }, \ { L41, L42, L43, L44, R45, R46, R47, R48 }, \ { L51, L52, L53, L54, R55, R56, R57, R58 }, \ { L61, L62, L63, L64, R65, R66, R67, R68 } \ }