/*---------------------------------------------
NEC PC-8001配列キーボード用スケッチ Rev. 0.01
-----------------------------------------------
・コンパイル等について
Arduino IDE 1.8.16 で動作検証しています。
コンパイルには、 Arduino IDEに2つのライブラリをインストールする必要があります。
「スケッチ」→「ライブラリをインクルード」→「ライブラリを管理」 で検索するか、
または、 各配布先urlからライブラリをzip形式でDownloadしてから、
「スケッチ」→「ライブラリをインクルード」→「.ZIP形式のライブラリをインストールする」を
実施して下さい。
・キー操作時のチャタリング制御について
チャタリングキャンセルのため、スキャン周期(KEY_SCAN_TIME)を5msにしています。
key_scan()条件は、一定周期でキー状態を読んで一致したかどうかのみ見ており、Timerも利用して
いないので、結構アバウトな制御です。
キー操作(まっすぐ押下or爪が引っ掛かった)等でも状況が変わりますが、1回の操作で複数回の
入力がされる等の症状が頻発する場合は、この値を増加させて(5→10など)様子を見てください。
逆に、操作したのに入力が抜ける場合は、この値を減らす等を試してみる事になりますが、
たいていの場合、キースイッチのはんだ付け不良ということがありますので、 特定キーのみで
チャタリングが発生する場合は、まずはその辺りのご確認をオススメします・・。
・キーリピート/Nキーロールオーバー対応について
基本的にライブラリ任せです。
PasocomMini向けにはBootKeyboard制御を使うとうまく認識するようです。
・「ALT」「Ctrl」制御
キーコードの上位側に制御ビットを追加して区別しています。
2021.09.18 あお( mail: qze12045@nifty.com )
*/
/* ----- ヘッダ ----- */
//(1)シリアルLEDライブラリ(配布先 https://github.com/adafruit/Adafruit_NeoPixel)
#include <Adafruit_NeoPixel.h>
//(2)Arduino HID Project 2.6.1(配布先 https://github.com/NicoHood/HID#arduino-hid-project)
#include <HID-Project.h>
#include <HID-Settings.h>
/* ----- 定数 ----- */
//コンパイルオプション
#define __BugFix 1 // 1:74HC164配線ミス用Fix
#define __UseI2C 1 // 1:I2C通信に対応する
#if __UseI2C
//(3)I2C通信用ライブラリ(Arduino標準)
#include <Wire.h>
#endif
//チャタリング判定用
#define KEY_SCAN_TIME 5 //キースキャン周期(ms)
#define KEY_SEND_TIME 1 //キーコード送信時間(ms)
//LED制御用 I/O定義
#define NUMPIXELS 2 // シリアルLED個数
#define NUM_LOCK_LED 21 // NumLock/動作モード状態LEDポート番号
//動作モード定義
enum{
MODE1 = 0 , //モード1( JIS )
MODE2 , //モード2( US )
MODE3 , //モード3( USER )
MODE_MAX
};
//キー押下時の動作ロジック定義
#define PLESS HIGH // キー押下
#define RELEASE LOW // キー離した
//KEY定義
// 各コードは、独自定義した修飾子(上位8bit)と、キーコード(下位8bit)で構成しており、
// キーコードはHID資料( http://www.usb.org/developers/hidpage/Hut1_12v2.pdf )の
// 「10 Keyboard/Keypad Page (0x07)」より、RAW送信用データとして利用しています。
// メディアキー(C_MEDIA)とモードキー(C_MODE)の下位8bitは独自コードとしており、
// key_code_send()で処理を分けています。
//キー修飾コード(特殊キーや同時押し指定など)
#define C_CTRL 0x0400 // Ctrl+ 指定コード
#define C_SHIFT 0x0800 // SHIFT+ 指定コード
#define C_ALT 0x1000 // ALT+ 指定コード
#define C_MEDIA 0x2000 // メディアキー(コンシューマー機能用)
#define C_MODE 0x4000 // 動作モード切替(ユーザー定義)
//動作モード指定キー
#define KC_DUMMY (C_MODE | 0x0 ) // Dummy
#define KC_MODE1 (C_MODE | 0x1 ) // MODE1
#define KC_MODE2 (C_MODE | 0x2 ) // MODE2
#define KC_MODE3 (C_MODE | 0x3 ) // MODE3
#define KC_FUNC (C_MODE | 0xf ) // FUNCTION KEY
//メディアキー(Windowsのみ?)
#define KC_CALC (C_MEDIA | 0x1 ) // 電卓キー
//制御キー
#define KC_LCTRL 0xe0 // 左 Ctrl
#define KC_LSHIFT 0xe1 // 左 SHIFT
#define KC_LALT 0xe2 // 左 ALT
//キーコード
#define KC_A 0x04 // Keyboard [A]
#define KC_B 0x05 // Keyboard [B]
#define KC_C 0x06 // Keyboard [C]
#define KC_D 0x07 // Keyboard [D]
#define KC_E 0x08 // Keyboard [E]
#define KC_F 0x09 // Keyboard [F]
#define KC_G 0x0A // Keyboard [G]
#define KC_H 0x0B // Keyboard [H]
#define KC_I 0x0C // Keyboard [I]
#define KC_J 0x0D // Keyboard [J]
#define KC_K 0x0E // Keyboard [K]
#define KC_L 0x0F // Keyboard [L]
#define KC_M 0x10 // Keyboard [M]
#define KC_N 0x11 // Keyboard [N]
#define KC_O 0x12 // Keyboard [O]
#define KC_P 0x13 // Keyboard [P]
#define KC_Q 0x14 // Keyboard [Q]
#define KC_R 0x15 // Keyboard [R]
#define KC_S 0x16 // Keyboard [S]
#define KC_T 0x17 // Keyboard [T]
#define KC_U 0x18 // Keyboard [U]
#define KC_V 0x19 // Keyboard [V]
#define KC_W 0x1a // Keyboard [W]
#define KC_X 0x1b // Keyboard [X]
#define KC_Y 0x1c // Keyboard [Y]
#define KC_Z 0x1d // Keyboard [Z]
#define KC_1 0x1e // Keyboard [1]
#define KC_2 0x1f // Keyboard [2]
#define KC_3 0x20 // Keyboard [3]
#define KC_4 0x21 // Keyboard [4]
#define KC_5 0x22 // Keyboard [5]
#define KC_6 0x23 // Keyboard [6]
#define KC_7 0x24 // Keyboard [7]
#define KC_8 0x25 // Keyboard [8]
#define KC_9 0x26 // Keyboard [9]
#define KC_0 0x27 // Keyboard [0]
#define KC_ENTER 0x28 // Keyboard [Enter]
#define KC_ESC 0x29 // Keyboard [ESCAPE]
#define KC_BS 0x2a // Keyboard [BACK SPACE]
#define KC_TAB 0x2b // Keyboard [TAB]
#define KC_SPC 0x2c // Keyboard [Spacebar]
#define KC_EQLU 0x2e // Keyboard [=] ( US配列 )
#define KC_EQLJ (C_SHIFT | 0x2d) // Keyboard [=] (JIS配列 [SHIFT]+[-])
#define KC_MINS 0x2d // Keyboard [-] (JIS配列 )
#define KC_LKA 0x2f // Keyboard "["
#define KC_RKA 0x30 // Keyboard "]"
#define KC_BSLAH 0x31 // Keyboard [\][|]
#define KC_SCRN 0x33 // Keyboard [;]
#define KC_CRN 0x34 // Keyboard [:]
#define KC_GRV 0x35 // Keyboard [半/全]
#define KC_DOT 0x37 // Keyboard [.]
#define KC_SLH 0x38 // Keyboard [/][?]
#define KC_F1 0x3a // Keyboard [F1]
#define KC_F2 0x3b // Keyboard [F2]
#define KC_F3 0x3c // Keyboard [F3]
#define KC_F4 0x3d // Keyboard [F4]
#define KC_F5 0x3e // Keyboard [F5]
#define KC_F6 0x3f // Keyboard [F6]
#define KC_F7 0x40 // Keyboard [F7]
#define KC_F8 0x41 // Keyboard [F8]
#define KC_F9 0x42 // Keyboard [F9]
#define KC_F10 0x43 // Keyboard [F10]
#define KC_F11 0x44 // Keyboard [F10]
#define KC_F12 0x45 // Keyboard [F10]
#define KC_PAUSE 0x48 // Keyboard [Pause]
#define KC_BSLHJ 0x89 // Keyboard [\][|] (JP)
#define KC_BSLHR 0x87 // Keyboard [\][ろ] (JP)
#define KC_KANA 0x88 // Keyboard [カナ] (JP)
#define KC_XFER 0x8a // Keyboard [変換][XFER] (JP)
#define KC_PGUP 0x4b // Keyboard [PageUp]
#define KC_PGDN 0x4e // Keyboard [PageDown]
#define KC_RMENU 0xe7 // Keyboard [右MENU]
#define KP_DOT 0x63 // Keypad [.]
#define KP_P0 0x62 // Keypad [0]
#define KP_P9 0x61 // Keypad [9]
#define KP_P8 0x60 // Keypad [8]
#define KP_P7 0x5f // Keypad [7]
#define KP_P6 0x5e // Keypad [6]
#define KP_P5 0x5d // Keypad [5]
#define KP_P4 0x5c // Keypad [4]
#define KP_P3 0x5b // Keypad [3]
#define KP_P2 0x5a // Keypad [2]
#define KP_P1 0x59 // Keypad [1]
#define KP_ENTER 0x58 // Keypad [Enter]
#define KP_PLUS 0x57 // Keypad [+]
#define KP_MINS 0x56 // Keypad [-]
#define KP_ASTR 0x55 // Keypad [*]
#define KP_DIV 0x54 // Keypad [/]
#define KC_NUML 0x53 // [NUM LOCK]
#define KC_DOWN 0x51 // Keyboard [DOWN]
#define KC_UP 0x52 // Keyboard [UP]
#define KC_RIGHT 0x4f // Keyboard [RIGHT]
#define KC_LEFT 0x50 // Keyboard [LEFT]
#define KC_HOME 0x4a // Keyboard [HOME]
#define KC_COMMA 0x36 // Keyboard [,]
#define KP_COMMA 0x85 // Keypad [,] PC-98配列
#define KP_EQL 0x86 // Keypad [=] PC-98配列
#define KC_0S (C_SHIFT | 0x27) // Keyboard [0] ( US配列[(] [SHIFT]+[0])
#define KC_9S (C_SHIFT | 0x26) // Keyboard [9] (JIS配列[(] or US配列[)] [SHIFT]+[9])
#define KC_8S (C_SHIFT | 0x25) // Keyboard [8] (JIS配列[)] [SHIFT]+[8])
#define KC_FSCRN (C_ALT | 0x28 ) // フルスクリーン切り替え([ALT]+[Enter])
#define KC_CTRB (C_CTRL | 0x05 ) // モニタ終了([Ctrl]+[B])
/* ----- 固定データ・他 ----- */
//KEY MAP定義(動作モード単位で記述する)
#define ROW_NUM 7 //KEY MAP行数
#define COL_NUM 14 //KEY MAP桁数
const unsigned int key_map[MODE_MAX][ROW_NUM][COL_NUM] =
{
{//MODE1 定義(PasocomMiniモード)
{ KC_DUMMY, KC_DUMMY , KC_LALT , KC_SPC , KP_P7 , KP_P8 , KP_P9 , KP_ASTR , KP_P4 , KP_P5 , KP_P6 , KP_PLUS , KC_DUMMY , KC_DUMMY }, // FUNC Y N STOP 7 8 9 *
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , KC_DUMMY , KP_P1 , KP_P2 , KP_P3 , KC_EQLJ , KP_P0 , KC_COMMA , KP_DOT , KC_ENTER , KC_DUMMY , KC_DUMMY }, // Z X C V 4 5 6 +
{ KC_DUMMY, KC_DUMMY , KC_F1 , KC_F2 , KC_F3 , KC_F4 , KC_F5 , KC_GRV , KC_UP , KC_RIGHT , KC_BS , KC_DUMMY , KC_DUMMY , KC_DUMMY }, //PF1 PF2 PF3 PF4 PF5 半全 UP -> BS
{ KC_1 , KC_2 , KC_3 , KC_4 , KC_5 , KC_6 , KC_7 , KC_8 , KC_9 , KC_0 , KC_MINS , KC_EQLU , KC_BSLHJ , KC_DUMMY }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_ESC , KC_Q , KC_W , KC_E , KC_R , KC_T , KC_Y , KC_U , KC_I , KC_O , KC_P , KC_LKA , KC_RKA , KC_ENTER }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_LCTRL, KC_A , KC_S , KC_D , KC_F , KC_G , KC_H , KC_J , KC_K , KC_L , KC_SCRN , KC_CRN , KC_BSLAH , KC_KANA }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_LSHIFT, KC_Z , KC_X , KC_C , KC_V , KC_B , KC_N , KC_M , KC_COMMA , KC_DOT , KC_SLH , KC_BSLHR , KC_LSHIFT , KC_DUMMY } // 0 / . RET
},
{//MODE2 定義(配列)
{ KC_DUMMY, KC_DUMMY , KC_LALT , KC_SPC , KP_P7 , KP_P8 , KP_P9 , KP_ASTR , KP_P4 , KP_P5 , KP_P6 , KP_PLUS , KC_DUMMY , KC_DUMMY }, // FUNC Y N STOP 7 8 9 *
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , KC_DUMMY , KP_P1 , KP_P2 , KP_P3 , KC_EQLJ , KP_P0 , KC_COMMA , KP_DOT , KC_ENTER , KC_DUMMY , KC_DUMMY }, // Z X C V 4 5 6 +
{ KC_DUMMY, KC_DUMMY , KC_F1 , KC_F2 , KC_F3 , KC_F4 , KC_F5 , KC_GRV , KC_UP , KC_RIGHT , KC_BS , KC_DUMMY , KC_DUMMY , KC_DUMMY }, //PF1 PF2 PF3 PF4 PF5 半全 UP -> BS
{ KC_1 , KC_2 , KC_3 , KC_4 , KC_5 , KC_6 , KC_7 , KC_8 , KC_9 , KC_0 , KC_MINS , KC_EQLU , KC_BSLHJ , KC_DUMMY }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_ESC , KC_Q , KC_W , KC_E , KC_R , KC_T , KC_Y , KC_U , KC_I , KC_O , KC_P , KC_LKA , KC_RKA , KC_ENTER }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_LCTRL, KC_A , KC_S , KC_D , KC_F , KC_G , KC_H , KC_J , KC_K , KC_L , KC_SCRN , KC_CRN , KC_BSLAH , KC_KANA }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_LSHIFT, KC_Z , KC_X , KC_C , KC_V , KC_B , KC_N , KC_M , KC_COMMA , KC_DOT , KC_SLH , KC_BSLHR , KC_LSHIFT , KC_DUMMY } // 0 / . RET
},
{//MODE3 定義(J80ノーマル配列)
{ KC_DUMMY, KC_DUMMY , KC_LALT , KC_SPC , KP_P7 , KP_P8 , KP_P9 , KP_ASTR , KP_P4 , KP_P5 , KP_P6 , KP_PLUS , KC_DUMMY , KC_DUMMY }, // FUNC Y N STOP 7 8 9 *
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , KC_DUMMY , KP_P1 , KP_P2 , KP_P3 , KC_EQLJ , KP_P0 , KC_COMMA , KP_DOT , KC_ENTER , KC_DUMMY , KC_DUMMY }, // Z X C V 4 5 6 +
{ KC_DUMMY, KC_DUMMY , KC_F1 , KC_F2 , KC_F3 , KC_F4 , KC_F5 , KC_GRV , KC_UP , KC_RIGHT , KC_BS , KC_DUMMY , KC_DUMMY , KC_DUMMY }, //PF1 PF2 PF3 PF4 PF5 半全 UP -> BS
{ KC_1 , KC_2 , KC_3 , KC_4 , KC_5 , KC_6 , KC_7 , KC_8 , KC_9 , KC_0 , KC_MINS , KC_EQLU , KC_BSLHJ , KC_DUMMY }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_ESC , KC_Q , KC_W , KC_E , KC_R , KC_T , KC_Y , KC_U , KC_I , KC_O , KC_P , KC_LKA , KC_RKA , KC_ENTER }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_LCTRL, KC_A , KC_S , KC_D , KC_F , KC_G , KC_H , KC_J , KC_K , KC_L , KC_SCRN , KC_CRN , KC_BSLAH , KC_KANA }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_LSHIFT, KC_Z , KC_X , KC_C , KC_V , KC_B , KC_N , KC_M , KC_COMMA , KC_DOT , KC_SLH , KC_BSLHR , KC_LSHIFT , KC_DUMMY } // 0 / . RET
}
};
const unsigned int func_key_map[ROW_NUM][COL_NUM] =
{//FUNC 定義(リセット/モード切替/NumLock)
{ KC_DUMMY, KC_DUMMY , KC_LALT , KC_SPC , KP_P7 , KP_P8 , KP_P9 , KP_ASTR , KP_P4 , KP_P5 , KP_P6 , KP_PLUS , KC_DUMMY , KC_DUMMY }, // FUNC Y N STOP 7 8 9 *
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , KC_DUMMY , KP_P1 , KP_P2 , KP_P3 , KC_EQLJ , KP_P0 , KC_COMMA , KP_DOT , KC_ENTER , KC_DUMMY , KC_DUMMY }, // Z X C V 4 5 6 +
{ KC_DUMMY, KC_DUMMY , KC_F1 , KC_F2 , KC_F3 , KC_F4 , KC_F5 , KC_GRV , KC_UP , KC_RIGHT , KC_BS , KC_DUMMY , KC_DUMMY , KC_DUMMY }, //PF1 PF2 PF3 PF4 PF5 半全 UP -> BS
{ KC_1 , KC_2 , KC_3 , KC_4 , KC_5 , KC_6 , KC_7 , KC_8 , KC_9 , KC_0 , KC_MINS , KC_EQLU , KC_BSLHJ , KC_DUMMY }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_ESC , KC_Q , KC_W , KC_E , KC_R , KC_T , KC_Y , KC_U , KC_I , KC_O , KC_P , KC_LKA , KC_RKA , KC_ENTER }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_LCTRL, KC_A , KC_S , KC_D , KC_F , KC_G , KC_H , KC_J , KC_K , KC_L , KC_SCRN , KC_CRN , KC_BSLAH , KC_KANA }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_LSHIFT, KC_Z , KC_X , KC_C , KC_V , KC_B , KC_N , KC_M , KC_COMMA , KC_DOT , KC_SLH , KC_BSLHR , KC_LSHIFT , KC_DUMMY } // 0 / . RET
};
#if __UseI2C
//I2C通信用キーマップ
const unsigned int key_map_i2c[3][ROW_NUM][COL_NUM] =
{
{//通常
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , ' ' , '7' , '8' , '9' , '*' , '4' , '5' , '6' , '+' , KC_DUMMY , KC_DUMMY }, // FUNC Y N STOP 7 8 9 *
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , KC_DUMMY , '1' , '2' , '3' , '=' , '0' , ',' , '.' , 13 , KC_DUMMY , KC_DUMMY }, // Z X C V 4 5 6 +
{ KC_DUMMY, KC_DUMMY , KC_F1 , KC_F2 , KC_F3 , KC_F4 , KC_F5 , 0x15 , 0xb5 , 0xb7 , 0x08 , KC_DUMMY , KC_DUMMY , KC_DUMMY }, //PF1 PF2 PF3 PF4 PF5 半全 UP -> BS
{ '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , '0' , '-' , '^' , '\\' , KC_DUMMY }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ 0x1b , 'q' , 'w' , 'e' , 'r' , 't' , 'y' , 'u' , 'i' , 'o' , 'p' , '@' , '[' , 13 }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_DUMMY, 'a' , 's' , 'd' , 'f' , 'g' , 'h' , 'j' , 'k' , 'l' , ';' , ':' , ']' , KC_KANA }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_DUMMY, 'z' , 'x' , 'c' , 'v' , 'b' , 'n' , 'm' , ',' , '.' , '/' , '\\' , KC_DUMMY , KC_DUMMY } // 0 / . RET
},
{//[Shift]押下中
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , ' ' , '7' , '8' , '9' , '*' , '4' , '5' , '6' , '+' , KC_DUMMY , KC_DUMMY }, // FUNC Y N STOP 7 8 9 *
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , KC_DUMMY , '1' , '2' , '3' , '=' , '0' , ',' , '.' , 13 , KC_DUMMY , KC_DUMMY }, // Z X C V 4 5 6 +
{ KC_DUMMY, KC_DUMMY , KC_F1 , KC_F2 , KC_F3 , KC_F4 , KC_F5 , 0x15 , 0xb5 , 0xb7 , 0x08 , KC_DUMMY , KC_DUMMY , KC_DUMMY }, //PF1 PF2 PF3 PF4 PF5 半全 UP -> BS
{ '!' , '"' , '#' , '$' , '%' , '&' , '\'' , '(' , ')' , ' ' , '=' , ' ' , KC_DUMMY , KC_DUMMY }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ 0x1b , 'Q' , 'W' , 'E' , 'R' , 'T' , 'Y' , 'U' , 'I' , 'O' , 'P' , KC_DUMMY , KC_DUMMY , 13 }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_DUMMY, 'A' , 'S' , 'D' , 'F' , 'G' , 'H' , 'J' , 'K' , 'L' , '+' , '*' , ' ' , KC_DUMMY }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_DUMMY, 'Z' , 'X' , 'C' , 'V' , 'B' , 'N' , 'M' , '<' , '>' , '?' , '_' , KC_DUMMY , KC_DUMMY } // 0 / . RET
},
{//[Ctrl]押下中
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY }, // FUNC Y N STOP 7 8 9 *
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , 13 , KC_DUMMY , KC_DUMMY }, // Z X C V 4 5 6 +
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY }, //PF1 PF2 PF3 PF4 PF5 半全 UP -> BS
{ KC_DUMMY, KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_MINS , KC_DUMMY , KC_DUMMY , KC_DUMMY }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_DUMMY, 17 , 23 , 5 , 18 , 20 , 25 , 21 , 9 , 15 , 16 , KC_DUMMY , KC_DUMMY , KC_ENTER }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_DUMMY, 1 , 19 , 4 , 6 , 7 , 8 , 10 , 11 , 12 , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY }, //SHFT SHFT GRAH SPC SPC 1 2 3 -
{ KC_DUMMY, 26 , 24 , 3 , 22 , 2 , 14 , 13 , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY , KC_DUMMY } // 0 / . RET
}
};
#endif
//KEY SCAN用 I/O定義
const int rowPins[ROW_NUM] = { 4, 5, 6, 7, 8, 9, 10 }; // INPUT指定ポート番号
#define pCLR 20 //カウンタクリア
#define pCLK 19 //シフト用クロック信号
#define pDATA 18 //シフト用データ
//シリアルLED定義
// RGB指定は、LED型番により適時変更が必要です。
// D2812 = NEO_RGB
// WS2812B = NEO_GRB
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, NUM_LOCK_LED, NEO_GRB + NEO_KHZ800); //NumLock LED制御Pin初期化
/* ----- 変数 ----- */
//動作モード制御
int key_mode; //動作モード
int old_key_mode; //前回動作モード
int func_key; //[Fn]キー押下状態
//キーチャタリング判定
int scan_cnt; //キースキャンカウント値(0<->1 トグル動作)
bool key_scan_sts[2][ROW_NUM][COL_NUM]; //周期的にキースキャンを実施し、キーを離したor前回と一致した場合にカレントに登録する。
//KEY状態を前回と最新状態で比較して、変化があった場合にキーコードを送信する
bool cur_key_sts[ROW_NUM][COL_NUM]; //最新のKEY状態
bool old_key_sts[ROW_NUM][COL_NUM]; //前回のKEY状態
//Ctrl同時押し
int LeftCtrl; //Ctrl制御状態(0:なし、0以外:Ctrl押下中)
//SHIFT同時押し
int shift; //SHIFT制御状態(0:なし、0以外:SHIFT押下中)
//ALT同時押し
int LeftAlt; //ALT制御状態(0:なし、0以外:ALT押下中)
//NumLock・LED制御
int cur_led_sts; //現在のホストLED状態(NumLock制御用)
int old_led_sts; //前回のホストLED状態(NumLock制御用)
int R[MODE_MAX]; // LED色 Red (0~255)
int G[MODE_MAX]; // LED色 Green(0~255)
int B[MODE_MAX]; // LED色 Blue (0~255)
#if __UseI2C
///////////////////////////////////////////////////////////////////////////////
//I2Cリクエスト処理
//ホスト機器からの要求に従い、キーコードを返す
///////////////////////////////////////////////////////////////////////////////
void ReqEvent()
{
int mode=0;
// [Shift]押下中
if (cur_key_sts[0][6] == PLESS )
{
mode = 1;
}
// [Cntl]押下中
else if (cur_key_sts[0][5] == PLESS )
{
mode = 2;
}
// KEY MAP状態チェック
for (int row = 0; row < ROW_NUM; row++)
{
//各キー状態チェック
for (int col = 0; col < COL_NUM; col++)
{
//キー状態は押下中?
if( cur_key_sts[row][col] == PLESS )
{
//I2C有効キーである
if ( key_map_i2c[mode][row][col] != KC_DUMMY )
{
Wire.write(key_map_i2c[mode][row][col]);
return;
}
}
}
}
}
#endif
///////////////////////////////////////////////////////////////////////////////
//動作モード取得処理
//キーコードに従い、動作モードを返す
//入力:キーコード
//出力:動作モード(MODE1~MODE3)
///////////////////////////////////////////////////////////////////////////////
int get_mode(unsigned int key)
{
switch(key)
{
// MODE1
case KC_MODE1:
return MODE1;
// MODE2
case KC_MODE2:
return MODE2;
// MODE3
case KC_MODE3:
return MODE3;
default:
return key_mode;
}
}
///////////////////////////////////////////////////////////////////////////////
//キーコード取得処理
//動作モード(key_mode)に従い、キーマップを(JIS/US/他に)切り替えて、
//指定されたスキャン位置(row,col)のキーコードを返す
//入力:スキャン位置 row,col
//出力:なし
///////////////////////////////////////////////////////////////////////////////
unsigned int get_key(int row,int col)
{
//Func押下中はマップを切り替える
if(func_key == PLESS)
{
//[Fn]モードのキーコードを返す
return func_key_map[row][col];
}
else
{
//現在の動作モードのキーコードを返す
return key_map[key_mode][row][col];
}
}
///////////////////////////////////////////////////////////////////////////////
//キー押下状態の確認処理
//現在のキー状態状態マップ(cur_key_sts[])の押下状態を調べる。
//maskに該当するキーが押下されている場合、1を返却。該当なしの場合0を返す
//入力:mask
//出力:0:該当なし、1:該当キーの押下検出
///////////////////////////////////////////////////////////////////////////////
int cur_key_check(int mask)
{
// KEY MAP状態チェック
for (int row = 0; row < ROW_NUM; row++)
{
//各キー状態チェック
for (int col = 0; col < COL_NUM; col++)
{
//現在のキー状態は押下である
if( cur_key_sts[row][col] == PLESS )
{
//キーコード取得
unsigned int key_code = get_key(row,col);
//対象キーが検出された
if( key_code & mask )
{
//該当有り
return 1;
}
}
}
}
//該当なし
return 0;
}
///////////////////////////////////////////////////////////////////////////////
//制御キーON
//ALT/SHIFT/CTRL対象キーが押されたら、該当キーを押下する
///////////////////////////////////////////////////////////////////////////////
void key_control_set(void)
{
int flags = 0;
//SHIFT制御中ではない
if(!shift)
{
//SHIFT制御対象キーの押下有り
if( cur_key_check( C_SHIFT ) == 1)
{
//SHIFTを押下する(+コード送信)
BootKeyboard.press(KeyboardKeycode(KC_LSHIFT));
//SHIFT制御開始
shift++;
//キー送出済み
flags = 1;
}
}
//CTRL制御中ではない
if(!LeftCtrl)
{
//CTRL制御対象キーの押下有り
if( cur_key_check( C_CTRL ) == 1)
{
//CTRLを押下する(+コード送信)
BootKeyboard.press(KeyboardKeycode(KC_LCTRL));
//制御開始
LeftCtrl++;
//キー送出済み
flags = 1;
}
}
//ALT制御中ではない
if(!LeftAlt)
{
//ALT制御対象キーの押下有り
if( cur_key_check( C_ALT ) == 1)
{
//CTRLを押下する(+コード送信)
BootKeyboard.press(KeyboardKeycode(KC_LALT));
//制御開始
LeftAlt++;
//キー送出済み
flags = 1;
}
}
//キー送出待ち
if( flags )
{
delay(KEY_SEND_TIME);
}
}
///////////////////////////////////////////////////////////////////////////////
//制御キーOFF
//ALT/SHIFT/CTRL対象キーをリリースする
///////////////////////////////////////////////////////////////////////////////
void key_control_release(void)
{
//SHIFT制御中である
if(shift)
{
//SHIFTキーを離す(コード登録のみで送信は行わない)
BootKeyboard.remove(KeyboardKeycode(KC_LSHIFT));
//SHIFT制御終了
shift = 0;
}
//Ctrl制御中である
if(LeftCtrl)
{
//CTRL制御対象キーを離した
if( cur_key_check( C_CTRL ) == 0)
{
//Ctrlキーを離す(コード登録のみで送信は行わない)
BootKeyboard.remove(KeyboardKeycode(KC_LCTRL));
//制御終了
LeftCtrl = 0;
}
}
//ALT制御中である
if(LeftAlt)
{
//ALT制御対象キーを離した
if( cur_key_check( C_ALT ) == 0)
{
//ALTキーを離す(コード登録のみで送信は行わない)
BootKeyboard.remove(KeyboardKeycode(KC_LALT));
//制御終了
LeftAlt = 0;
}
}
}
///////////////////////////////////////////////////////////////////////////////
//条件付き キーコード送信処理
//有効キーのうち、前回のキー入力結果と差分があり、かつ、maskで除外指定された
//種別以外のキーコードをホストに送信する。
//入力:除外キー種別(mask) 、0:除外なし
//出力:なし
///////////////////////////////////////////////////////////////////////////////
void key_code_send( int mask )
{
//KEY更新状態クリア
int chg = 0; //通常キー(BootKeyboard.send()対象)
int media = 0; //メディアキー(Consumer.write()対象)
// KEY MAP状態チェック
for (int row = 0; row < ROW_NUM; row++)
{
//各キー状態チェック
for (int col = 0; col < COL_NUM; col++)
{
// 前回の状態と変化あり?
if (cur_key_sts[row][col] != old_key_sts[row][col])
{
//キーコード取得
unsigned int key_code = get_key(row,col);
//マスク指定されたキー種別は除外(=処理しない)
if( !(key_code & mask) )
{
//キー状態は押下
if( cur_key_sts[row][col] == PLESS )
{
//動作モード変更キー指定?
if(key_code & C_MODE)
{
//動作モード切り替え
key_mode = get_mode(key_code);
//[Fn]キー押下
if (key_code==KC_FUNC)
{
//Func押下中
func_key = PLESS;
}
}
else
{
//メディアキー指定?
if(key_code & C_MEDIA)
{
//機能キー押下
media++;
}
else
{
//キー押下する
BootKeyboard.add(KeyboardKeycode(key_code & 0xff));
//KEY更新有り
chg++;
}
}
}
//キーは離された
else
{
//モード/メディアキー指定?
if(key_code & (C_MEDIA|C_MODE))
{
//[Fn]キー?
if (key_code == KC_FUNC)
{
//Func押下中解除
func_key = RELEASE;
}
//[Fn]キー以外はリリース時は何もしない
;
}
else
{
//キーリリース
BootKeyboard.remove(KeyboardKeycode(key_code & 0xff));
//KEY更新有り
chg++;
}
}
//現在のキー状態を前回の状態にコピーする(コード送信済みとする)
old_key_sts[row][col] = cur_key_sts[row][col];
}
}
}
}
//メディアキー押下
if( media )
{
//電卓キーを送信する
Consumer.write(ConsumerKeycode(CONSUMER_CALCULATOR));
}
//KEY更新有り
if( chg )
{
//ホスト側に変化したキーコードを送信する
BootKeyboard.send();
}
}
///////////////////////////////////////////////////////////////////////////////
//キースキャン処理(+チャタリングの除去)
//KEY SCAN用I/Oポートを走査してキーの状態を読み出す。
//前回スキャンした状態と一致するか、キーを離した場合に有効キーとして登録する。
//実行条件:なるべく一定周期(KEY_SCAN_TIME)毎に実行する。
///////////////////////////////////////////////////////////////////////////////
void key_scan(void)
{
//シフトレジスタデータクリア
digitalWrite( pCLR ,LOW ); //クリア信号=LOW
delayMicroseconds(1);
digitalWrite( pCLR ,HIGH ); //クリア信号=HIGH
//シフトレジスタ初期値セット
digitalWrite( pDATA ,HIGH ); //データ=HIGH
digitalWrite( pCLK ,LOW ); //クロック=LOW
digitalWrite( pCLK ,HIGH ); //クロック立ち上がりセット
digitalWrite( pDATA ,LOW ); //データ=LOW
//キースキャン実施
for (int col = 0; col < COL_NUM; col++)
{
#if __BugFix
//74HC164 Pin13=Hiの時は、CLKを1回多く挿入する(Bug fix)
if ( col == 7 )
{
//レジスタ値を更新(シフト)する
digitalWrite( pCLK ,LOW ); //クロック=LOW
digitalWrite( pCLK ,HIGH ); //クロック立ち上がり
}
#endif
// key matrix scan
for (int row = 0; row < ROW_NUM; row++)
{
// 行指定:キー状態読み出し(押下:HIGH)
key_scan_sts[scan_cnt][row][col] = digitalRead(rowPins[row]);
//チャタリングの除去条件
//キーを離したか、前回の状態と一致?
if (( key_scan_sts[scan_cnt][row][col]==RELEASE )||
( key_scan_sts[0][row][col] == key_scan_sts[1][row][col] ))
{
//現在のキー状態に登録する
cur_key_sts[row][col] = key_scan_sts[scan_cnt][row][col];
}
}
//レジスタ値を更新(シフト)する
digitalWrite( pCLK ,LOW ); //クロック=LOW
digitalWrite( pCLK ,HIGH ); //クロック立ち上がり
}
//シフトレジスタデータクリア
digitalWrite( pCLR ,LOW ); //クリア信号=LOW
//スキャンカウント更新
scan_cnt = (scan_cnt + 1)&0x1;
}
///////////////////////////////////////////////////////////////////////////////
//キーコード判定処理
//有効キーとして登録されたキーが、前回のキー状態から変化した場合に、
//キーコードに応じた処理を行う。
///////////////////////////////////////////////////////////////////////////////
void key_check(void)
{
//ALT/SHIFT/CTRL対象キー、メディアキー、モードキー「以外」を先に処理する
key_code_send(C_MEDIA|C_MODE|C_SHIFT|C_CTRL|C_ALT);
//ALT/SHIFT/CTRL制御状態に遷移する
key_control_set();
//残り(SHIFT対象キー、メディアキー、モードキー)を送付する。
key_code_send(0);
//ALT/SHIFT/CTRL状態を解除する
key_control_release();
}
///////////////////////////////////////////////////////////////////////////////
//LED表示制御
//テンキーの動作モードまたは、NumLock状態が変化した場合に、LED表示を更新する
///////////////////////////////////////////////////////////////////////////////
void led_display(void)
{
//ホスト側のLED状態を取得
cur_led_sts = BootKeyboard.getLeds();
//LED点灯状態または、動作モード変化あり
if(( cur_led_sts != old_led_sts )||( key_mode != old_key_mode ))
{
//ホスト側NumLock状態ON
if( cur_led_sts & LED_NUM_LOCK )
{
//LED点灯(key_modeに従いRGB指定する)
pixels.setPixelColor(1, pixels.Color(R[key_mode],G[key_mode],B[key_mode]));
}
else
{
//LED消灯(黒)
pixels.setPixelColor(1, pixels.Color(0,0,0));
}
//LED点灯(key_modeに従いRGB指定する)
pixels.setPixelColor(0, pixels.Color(R[key_mode],G[key_mode],B[key_mode]));
//LED出力
pixels.show();
//ホスト側のLED状態変化あり
if( cur_led_sts != old_led_sts )
{
//ホスト側のLED状態を保存する
old_led_sts = cur_led_sts;
}
//動作モード変化あり
if( key_mode != old_key_mode )
{
//動作モードを保存する
old_key_mode = key_mode;
}
}
}
///////////////////////////////////////////////////////////////////////////////
//初期化処理(起動時に1回だけ動作する)
///////////////////////////////////////////////////////////////////////////////
void setup()
{
// put your setup code here, to run once:
//動作モード初期化
key_mode = MODE1;
old_key_mode = MODE1;
//[Fn]解除
func_key = RELEASE;
//LED表示初期化(各動作モード別にRGBで色指定する)
//MODE1=緑
R[MODE1]=0;
G[MODE1]=10;
B[MODE1]=0;
//MODE2=青
R[MODE2]=0;
G[MODE2]=0;
B[MODE2]=10;
//MODE3=黄
R[MODE3]=15;
G[MODE3]=15;
B[MODE3]=0;
//キースキャン行のI/O Pinを初期化(INPUT指定)
for (int i = 0; i < ROW_NUM; i++)
{
pinMode(rowPins[i], INPUT);
}
//シフトレジスタ制御用I/O Pinを初期化(INPUT_PULLUP指定)
pinMode(pCLR,OUTPUT); //シフトレジスタクリア信号
pinMode(pCLK,OUTPUT); //シフトレジスタ用クロック信号
pinMode(pDATA,OUTPUT); //シフトレジスタ用データ
//シフトレジスタデータクリア
digitalWrite( pCLR ,LOW ); //クリア信号=LOW
digitalWrite( pCLK ,LOW ); //クロック信号=LOW
digitalWrite( pDATA ,LOW ); //データ=LOW
//キー押下状態を初期化する(Active=HIGH)
for (int row = 0; row < ROW_NUM; row++)
{
//キー状態を「RELEASE」とする
for (int c = 0; c < COL_NUM; c++)
{
key_scan_sts[0][row][c] = RELEASE;
key_scan_sts[1][row][c] = RELEASE;
cur_key_sts[row][c] = RELEASE;
old_key_sts[row][c] = RELEASE;
}
}
//シリアルLEDライブラリ初期化
pixels.begin();
//HIDデバイス初期化(ホストLED状態取得用)
BootKeyboard.begin();
//メディアキー機能
Consumer.begin();
//シフト状態クリア
shift = 0;
//Ctrl状態クリア
LeftCtrl = 0;
//ALT状態クリア
LeftAlt = 0;
//キースキャン開始
scan_cnt = 0;
key_scan();
#if __UseI2C
//I2C通信開始
Wire.begin(0x5f);
Wire.onRequest(ReqEvent);
#endif
}
///////////////////////////////////////////////////////////////////////////////
//メインループ処理
///////////////////////////////////////////////////////////////////////////////
void loop()
{
// put your main code here, to run repeatedly:
//前回のキースキャンから一定時間遅延させる。
delay(KEY_SCAN_TIME);
//キースキャン処理(+チャタリングの除去)
key_scan();
//キー判定処理
key_check();
//LED表示制御
led_display();
}