Lenovoキーボードをもっと俺好みにしたい１

## 背景
[ThinkPad TrackPointキーボード](https://www.lenovo.com/jp/ja/p/accessories-and-software/keyboards-and-mice/keyboards/0b47208/) のキーボード基板のキーマトリックス解析に挑戦しました。
作成に至った詳細やハードウエアについては、[別のブログ記事](https://shk-maker.hatenablog.jp/entry/2023/05/20/215232) に書いています。
こちらのQiita記事では、電気回路とコード内容について書いています。

## 回路接続図
使用した部品は次の3つのみです。
|アイテム|数量|
|---|:-:|
|マイコンProMicro|1個|
|<a target="_blank" href="https://www.amazon.co.jp/gp/product/B0913BD2JS/?&_encoding=UTF8&tag=sito11702-22&linkCode=ur2&linkId=85eb7cc0c01c828dc2ada80c33b49b76&camp=247&creative=1211">1.0mmピッチ28ピンFFC変換基板</a>|1個|
|<a target="_blank" href="https://www.amazon.co.jp/dp/B09C1N57BC/?&_encoding=UTF8&tag=sito11702-22&linkCode=ur2&linkId=c064f6fa44eab4949dd73d0c06b1a56f&camp=247&creative=1211">MCP23017_I2C_IO拡張ボード</a>|1個|

線が多く配線図を書くのが大変なので、すみませんが写真で勘弁願います。  
![lenovo-kbd11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247233/e00a032b-7223-2700-af2c-9c75f7a899aa.jpeg)
写真左の28ピンコネクタのうち、12ピンは写真右下のマイコンと、16ピンは写真上側のMCP23017と配線。マイコンとMCP23017はI2C接続するように配線しました。    
左側基板のコネクタにキーボードのフレキを、右側のマイコンにUSB経由でPCと接続します。  

## コード内容
Arduino IDE 1.8.13 を使用しました。
Adafruit社のライブラリ、スケッチ例を参考にしました。

以下、コードを少し区切って説明します。
順番に全てを繋げれば動くはずですが、必要に応じて適時修正お願いします。

```cpp
#include <Wire.h>
#include "Adafruit_MCP23017.h"

Adafruit_MCP23017 mcp;

int fpcpins[29];    // FPCピンアサイン
int fpcinput[29];    // キーマトリックス入力結果
int outpin;
int i;

void setup() {  
  mcp.begin();

//  FPCコネクタとArduino、MCP23017の接続ピン配を指定
  fpcpins[1] = 19;
  fpcpins[2] = 18;
  fpcpins[3] = 15;
  fpcpins[4] = 14;
  fpcpins[5] = 16;
  fpcpins[6] = 10;
  
  for(i=7; i<13; i++){
    fpcpins[i] = 16-i;    //FPC07=arduino09...FPC12=arduino04
  }
  for(i=13; i<21; i++){
    fpcpins[i] = 28-i;    //FPC13=mcp15(PB7)...FPC20=mcp8(PB0)
  }
  for(i=21; i<29; i++){
    fpcpins[i] = i-21;    //FPC21=mcp0(PA0)...FPC28=mcp7(PA7)
  }
```
冒頭は、初期設定とI/Oピンの定義です。
fpcpins[] はFFC変換基板のピン配に合わせて定義（ゼロは使わず1から28まで）
右辺の数字は接続しているマイコンまたはMCP23017のピン番号を指定しています。

```cpp
//  FPC全pinを一度INPUTにする
  for(i=1; i<13; i++){
    pinMode(fpcpins[i], INPUT_PULLUP);
  }
  for(i=13; i<29; i++){
    mcp.pinMode(fpcpins[i], INPUT);
    mcp.pullUp(fpcpins[i], HIGH);
  }

//  FPCの1pinずつOUTPUTにする。ここは都度、書き換える....
  outpin = 1;
  pinMode(fpcpins[outpin], OUTPUT);     //outpin:1-12
//  mcp.pinMode(fpcpins[outpin], OUTPUT); //outpin:13-28
  
  digitalWrite(fpcpins[outpin], LOW);     //outpin:1-12
//  mcp.digitalWrite(fpcpins[outpin], LOW);  //outpin:13-28
}
```
コメント文で書いているとおり、マイコンとMCP23017の全てのピンを一旦入力にした後、任意の1ピンのみ出力に設定します。
1番で一通りキースキャンしたら、次は2番でキースキャン、また次は3番、、、、
とスケッチを都度、書き換えつつ28番まで繰り返し実行します。
マイコンとMCP23017でコマンドが異なるので、併せてコメント文も変更が必要です。

```cpp
void loop() {
//  FPC全pinの入力確認
  for(i=1; i<13; i++){
    fpcinput[i] = digitalRead(fpcpins[i]);
  }
  for(i=13; i<29; i++){
    fpcinput[i] = mcp.digitalRead(fpcpins[i]);
  }

  for(i=1; i<29; i++){
    if(i != outpin){
      if(fpcinput[i] == 0){
        Serial.print(outpin);
        Serial.print(" => ");
        Serial.println(i);
      }
    }
  }
  delay(100);

}
```
キーを押して通電したら、シリアルモニタに結果を表示します。
結果とは、何番ピンと何番ピンが繋がったか？（何番ピンから信号を出して何番ピンが受け取ったか？）を表しています。
これをひたすらメモしていくと、キーマトリックスを解読することができました。

## 解析結果！
![lenovo-kbd12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247233/c9d38fd5-72d6-0779-bc63-1fa00959cc42.jpeg)
![lenovo-kbd13.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247233/6f04bd3f-72d8-cc63-7a58-bcc92444a699.jpeg)
28ピンのうち、4ピンはマウスボタン入力用で、残り24ピンをマトリックスにしてキー入力となっていました。  
予想以上にバラバラの配置になっていました。Shift/Ctrl/Altなど同時押しする機会が多いキーだけ列を分けているのも何か理由がありそう。その割には問題のFnキーは独立していません。詳しい人の解説が欲しいですね。  
今回は双方向から解析しており行列どちらを出力にしても同じ結果となりました。つまり同時押し対策のダイオードは予想通り入ってませんでした。 

## まとめ
最後までお読みいただきありがとうございました。
同じようにキーマトリックス解析したい方（いるのかな？）の参考になれば幸いです。