TrinketKeyboardで日本語キーボード109で正しく表示する方法


ATtiny85をdigispark化、キーボードとして自動入力をさせてる際、USキーボードになっていて正しく表示されない。左が正しくなく、同じスケッチで適正化したのが右。

この解決方法については、Toramin10さんが公開されていて、
DigiKeyboardのライブラリーを使っている場合は、ここの通りに実施すればよさそうだが、ATtinyCoreを使っている場合、TrinketKeyboardの組み合わせでないと、うまく動作しなかった事から、TrinketKeyboardで同じように、正しく表示する事を行った記録。

【スケッチの準備】

で作ったものを改変する。

#include <TrinketKeyboard.h>
// Attiny85
// PB5(reset)-|   |-VCC
//        PB3-|   |-PB2
//        PB4-|   |-PB1
//        GND-|   |-PB0

const int PB0pin = 0;
const int PB1pin = 1;
const int PB2pin = 2;
const int PB5pin = 5;
bool outputState = true;

void setup() {
   pinMode (PB0pin, INPUT_PULLUP);
   pinMode (PB1pin, INPUT_PULLUP);
   pinMode (PB2pin, INPUT_PULLUP);
   pinMode (PB5pin, INPUT_PULLUP);

   TrinketKeyboard.begin(); //start USB stuff
}
void loop() {
  TrinketKeyboard.poll();
   if (digitalRead(PB0pin) == LOW)
  {
    // type out a string using the Print class
    TrinketKeyboard.print("1234567890-^\\");
    TrinketKeyboard.pressKey(0,KEYCODE_ENTER);
    // this should push enter key
    TrinketKeyboard.pressKey(0, 0);
    // this releases the key
    delay(100);
  }

  if (digitalRead(PB1pin) == LOW)
  {
    // type out a string using the Print class
    TrinketKeyboard.print("!\"#$%&'()=~|");
     TrinketKeyboard.pressKey(0,KEYCODE_ENTER);
    //TrinketKeyboard.pressKey(0,KEYCODE_TAB);
    // this should push enter key
    TrinketKeyboard.pressKey(0, 0);
    // this releases the key
    delay(100);
  }

    if (digitalRead(PB2pin) == LOW)
  {
    // type out a string using the Print class
    TrinketKeyboard.print("@[;:],./\\ `{+*}<>?_");
    delay(100);
        TrinketKeyboard.pressKey(0,KEYCODE_ENTER);
    // this should push enter key
    TrinketKeyboard.pressKey(0, 0);
    // this releases the key
  }
      if (digitalRead(PB5pin) == LOW)
  {
    // type out a string using the Print class
    //TrinketKeyboard.pressKey(0,KEYCODE_INTERNATIONAL3);
    //TrinketKeyboard.pressKey(KEYCODE_MOD_LEFT_SHIFT,KEYCODE_INTERNATIONAL1);//_
    //TrinketKeyboard.pressKey(KEYCODE_MOD_LEFT_SHIFT,KEYCODE_INTERNATIONAL3);//|

    delay(100);
    TrinketKeyboard.pressKey(0,KEYCODE_ENTER);
    // this should push enter key
    TrinketKeyboard.pressKey(0, 0);
    // this releases the key
  }
  delay(1);
}
一つ目のボタン:キーボードの一番上の行を左の1から順に押していった場合
2つ目のボタン:シフトを押しながら一番上の行を押した場合
3つ目のボタン:キーボードの上から2行目以降の記号
4つ目のボタン:この時点ではコメントアウトしてありEnterで改行だけされる。

  TrinketKeyboard.print("@[;:],./\\ `{+*}<>?_");
\の文字を入れたい時は、\\二回かさねる。(上ではバックスラッシュ2回のところ)
あと”ダブルクォーテーションを入れる時も¥”と前に¥をつける。

これをボタンを押してメモ帳で確認すると
1234567890-&]
!*#$%':)^}
"@;+[,./] ‘~({<>?=
最後の行に至っては、途中で全角になり正しく表示されない。
例えば1234567890-&]は本来は、
1234567890-^\
と表示してほしい。これはキーボードが109になっていないから割り当てが異なるので違うキーコードを送っているから生じる


D:\Users\<ユーザー名>\Documents\Arduino\libraries\TrinketKeyboard
にライブラリーが入っているのでいくつかのファイルの編集をする。

【TrinketKeyboard.cpp】

このファイルに、
ASCII_to_keycode
という関数があるのでこここの関数を編集する。

一番最初だけ解説
  if (ascii >= 'A' && ascii <= 'Z')
  {
    *keycode = 4 + ascii - 'A'; // set letter
    if (bit_is_set(ledState, 1)) // if caps is on
    {
      *modifier = 0x00; // no shift
    }
    else
    {
      *modifier = _BV(1); // hold shift // hold shift
    }
  }

HIDHID(10進数)ASCIIHID(10進数)4+(ASCII-ASCII of A)
A0x0440x41654
B0x0550x42665
C0x0660x43676
D0x0770x44687
E0x0880x45698
F0x0990x46709
G0x0A100x477110

例えば”B”
アスキーコードは10進数で66 この66に4を足して、Aのアスキーコード65を引くと”5”になりHIDコード、つまりUSB経由で、PCに繰り込まれるキーコードに変換している。
といった具合に、アスキーコードから、HIDのキーコードに変換する関数.

A-Zや、小文字のa-zまた数字なんかは、連続しているので計算しやすしので一つ一つ書き出してもよいけどif文で書いている。

数字やアルファベットは問題にならず、問題になるのは、記号。
1234567890-^\
1234567890-&]
と出力される事からここのキーのアサインが異なっている。
”^”の所を見てみる。
      case '^':
        *modifier = _BV(1); // hold shift
        *keycode = 29 + 6;
        break;
^を押すと、キーコードの35が送り込まれる。
日本語キーボードの35は”6”のキーでシフトを押しながら、”6”を押すので、”&”が出力される結果になる。
これを正しく”^”を出力するのには、本来のキーコード”46”でシフトなしに編集する。
      case '^':
        //*modifier = _BV(1); // hold shift
        //*keycode = 29 + 6;
        *keycode = 46;
        break;

すべてのキー、特に記号は、すべてのキーについて見直して編集する。
Toramin10さんが日本語キーボードの絵に、番号を記載してくれているのでそれを見ながら編集すると簡単にできる。
このWEBサイトはキーコードを表示してくれるので、それを見て編集する。

Toramin10さんのテクニックを使わせてもらって、後々問題となるアスキーコードで
ASCIIHID
92104
95_105
124106
の3つについては、135や137ではなく、104、105,106を割り当てる。

全部書き換えたASCII_to_keycodeの関数が以下。
表示の都合で、”¥”が””と表示されているが、このままコピーして問題ない。
void ASCII_to_keycode(uint8_t ascii, uint8_t ledState, uint8_t* modifier, uint8_t* keycode)
{
  *keycode = 0x00;
  *modifier = 0x00;
 
  // see scancode.doc appendix C
 
  if (ascii >= 'A' && ascii <= 'Z')
  {
    *keycode = 4 + ascii - 'A'; // set letter
    if (bit_is_set(ledState, 1)) // if caps is on
    {
      *modifier = 0x00; // no shift
    }
    else
    {
      *modifier = _BV(1); // hold shift // hold shift
    }
  }
  else if (ascii >= 'a' && ascii <= 'z')
  {
    *keycode = 4 + ascii - 'a'; // set letter
    if (bit_is_set(ledState, 1)) // if caps is on
    {
      *modifier = _BV(1); // hold shift // hold shift
    }
    else
    {
      *modifier = 0x00; // no shift
    }
  }
  else if (ascii >= '0' && ascii <= '9')
  {
    *modifier = 0x00;
    if (ascii == '0')
    {
      *keycode = 0x27;
    }
    else
    {
      *keycode = 30 + ascii - '1';
    }
  }
  else
  {
    switch (ascii) // convert ascii to keycode according to documentation
      //ASCII code 92:\ 95:|  124:_ are assigned to 104,105,106
    {
      case '!':
        *modifier = _BV(1); // hold shift
        *keycode = 29 + 1;
        break;
      case '@':
        //*modifier = _BV(1); // hold shift
        //*keycode = 29 + 2;
        *keycode = 47;
        break;
      case '#':
        *modifier = _BV(1); // hold shift
        *keycode = 29 + 3;
        break;
      case '$':
        *modifier = _BV(1); // hold shift
        *keycode = 29 + 4;
        break;
      case '%':
        *modifier = _BV(1); // hold shift
        *keycode = 29 + 5;
        break;
      case '^':
        //*modifier = _BV(1); // hold shift
        //*keycode = 29 + 6;
        *keycode = 46;
        break;
      case '&':
        *modifier = _BV(1); // hold shift
        //*keycode = 29 + 7;
        *keycode = 35;
        break;

      case '*':
        *modifier = _BV(1); // hold shift
        //*keycode = 29 + 8;
        *keycode = 52;
        break;
      case '(':
        *modifier = _BV(1); // hold shift
        //*keycode = 29 + 9;
        *keycode = 37;
        break;
      case ')':
        *modifier = _BV(1); // hold shift
        //*keycode = 0x27;
        *keycode = 38;
        break;
      case '~':
        *modifier = _BV(1); // hold shift
        *keycode = 46;
        // fall through
        break;
      case '`':
        *modifier = _BV(1); // hold shift //add on original
        *keycode = 47;
        break;
      case '_':
        *modifier = _BV(1); // hold shift
        // fall through
        //keycode = 135;
        *keycode = 105;
        break;
      case '-':
        //*keycode = 0x2D;
        *keycode = 45;
        break;
      case '+':
        //*modifier = _BV(1); // hold shift
        // fall through
        *keycode = 0x57;
        break;

      case '=':
        //*keycode = 0x2E;
        *modifier = _BV(1); // hold shift
        *keycode = 45;
        break;
      case '{':
        *modifier = _BV(1); // hold shift
        // fall through
        *keycode = 48;
        break;
      case '[':
        //*keycode = 0x2F;
        *keycode = 48;
        break;
      case '}':
        *modifier = _BV(1); // hold shift
        // fall through
        *keycode = 49;
        break;
      case ']':
        //*keycode = 0x30;
        *keycode = 49;
        break;
      case '|':
        *modifier = _BV(1); // hold shift
        // fall through
        // keycode = 137;
        *keycode = 106;
        break;

      case '\\'://"\" mark
        //*keycode = 0x31;
        //keycode = 137;
        *keycode = 104;
        break;
      case ':':
        //*modifier = _BV(1); // hold shift
        // fall through
        *keycode =52;
        break;

      case ';':
        *keycode = 0x33;
        break;

      case '"':
        *modifier = _BV(1); // hold shift
        // fall through
        *keycode = 0x1F;
        break;

      case '\''://single quotation
        *modifier = _BV(1); // hold shift
        *keycode = 0x24;
        break;

      case '<':
        *modifier = _BV(1); // hold shift
        // fall through
        *keycode = 54;
        break;
      case ',':
        //*keycode = 0x36;
        *keycode = 54;
        break;
      case '>':
        *modifier = _BV(1); // hold shift
        // fall through
        *keycode = 55;
        break;
      case '.':
        //*keycode = 0x37;
        *keycode = 55;
        break;
      case '?':
        *modifier = _BV(1); // hold shift
        // fall through
        *keycode = 56;
        break;
      case '/':
        //*keycode = 0x38;
        *keycode = 56;
        break;
      case ' ':
        *keycode = 0x2C;
        break;
      case '\t':
        *keycode = 0x2B;
        break;
      case '\n':
        *keycode = 0x28;
        break;
    }
  }
}

ここまで関数を変更すると、
1234567890-^
!"#$%&'()=~
@[;:],./ `{+*}<>?
と表示されるようになる。しかしエンターキーの左上、バックスペースの左のキー”¥”と?の右隣、これも”¥”が表示されていない。
これは、そもそもUSキーボードには、これらのキーがないから。次にその対処。

HIDのレポートディスクリプタ

Toramin10さんがこの対処についても記載してくれている。
TrinketKeyboardでは、
TrinketKeyboardC.c
というにファイルにHIDのレポートディスクリプタの記載がある。
const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
  0x05, 0x01,  // USAGE_PAGE (Generic Desktop)
  0x09, 0x06,  // USAGE (Keyboard)
  0xA1, 0x01,  // COLLECTION (Application)
  0x05, 0x07,  //   USAGE_PAGE (Keyboard)(Key Codes)
  0x19, 0xE0,  //   USAGE_MINIMUM (Keyboard LeftControl)(224)
  0x29, 0xE7,  //   USAGE_MAXIMUM (Keyboard Right GUI)(231)
  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) ; Modifier byte
  0x95, 0x01,  //   REPORT_COUNT (1)
  0x75, 0x08,  //   REPORT_SIZE (8)
  0x81, 0x03,  //   INPUT (Cnst,Var,Abs) ; Reserved byte
  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) ; LED report
  0x95, 0x01,  //   REPORT_COUNT (1)
  0x75, 0x03,  //   REPORT_SIZE (3)
  0x91, 0x03,  //   OUTPUT (Cnst,Var,Abs) ; LED report padding
  0x95, 0x06,  //   REPORT_COUNT (6)
  0x75, 0x08,  //   REPORT_SIZE (8)
  0x15, 0x00,  //   LOGICAL_MINIMUM (0)
  0x25, 0x65,  //   LOGICAL_MAXIMUM (101)
  0x05, 0x07,  //   USAGE_PAGE (Keyboard)(Key Codes)
  0x19, 0x00,  //   USAGE_MINIMUM (Reserved (no event indicated))(0)
 // 0x29, 0x65,  //   USAGE_MAXIMUM (Keyboard Application)(101)
 0x29, 0x8c,  //   USAGE_MAXIMUM (Keyboard Application)(109)
  0x81, 0x00,  //   INPUT (Data,Ary,Abs)
  0xC0         // END_COLLECTION
};
下から3行目をコメントアウトして
0x29, 0x8c,  //   USAGE_MAXIMUM (Keyboard Application)(109)
に置き換える。

また、Toramin10さんを見習って、TrinketKeyboard.cppの中にある
typeCharという関数を以下に編集する。

void Trinket_Keyboard::typeChar(uint8_t ascii)
{
  uint8_t modifier, keycode;
  ASCII_to_keycode(ascii, getLEDstate(), &modifier, &keycode);
  switch (keycode) {
  case 104:
    pressKey(modifier, 135);
    break;
  case 105:
    pressKey(KEYCODE_MOD_LEFT_SHIFT, 135);
    break;
  case 106:
    pressKey(KEYCODE_MOD_LEFT_SHIFT, 137);
    break;
  default:
    pressKey(modifier, keycode);
    pressKey(0, 0); // immediately release the key after
  }
}

ここまでできると、

1234567890-^\
!"#$%&'()=~|
@[;:],./\ `{+*}<>?_

と正しく表示されるようになる。

【TrinketKeyboard.h】

文字列で正しく送り込みはできるが、他の単キーについてはも対応するためTrinketKeyboard.h
を編集する。
// some more keycodes
#define KEYCODE_LEFT_CONTROL  0xE0
#define KEYCODE_LEFT_SHIFT    0xE1
#define KEYCODE_LEFT_ALT    0xE2
#define KEYCODE_LEFT_GUI    0xE3
#define KEYCODE_RIGHT_CONTROL 0xE4
#define KEYCODE_RIGHT_SHIFT   0xE5
#define KEYCODE_RIGHT_ALT   0xE6
#define KEYCODE_RIGHT_GUI   0xE7

#define KEYCODE_1       0x1E
#define KEYCODE_2       0x1F
#define KEYCODE_3       0x20
#define KEYCODE_4       0x21
#define KEYCODE_5       0x22
#define KEYCODE_6       0x23
#define KEYCODE_7       0x24
#define KEYCODE_8       0x25
#define KEYCODE_9       0x26
#define KEYCODE_0       0x27
#define KEYCODE_A       0x04
#define KEYCODE_B       0x05
#define KEYCODE_C       0x06
#define KEYCODE_D       0x07
#define KEYCODE_E       0x08
#define KEYCODE_F       0x09
#define KEYCODE_G       0x0A
#define KEYCODE_H       0x0B
#define KEYCODE_I       0x0C
#define KEYCODE_J       0x0D
#define KEYCODE_K       0x0E
#define KEYCODE_L       0x0F
#define KEYCODE_M       0x10
#define KEYCODE_N       0x11
#define KEYCODE_O       0x12
#define KEYCODE_P       0x13
#define KEYCODE_Q       0x14
#define KEYCODE_R       0x15
#define KEYCODE_S       0x16
#define KEYCODE_T       0x17
#define KEYCODE_U       0x18
#define KEYCODE_V       0x19
#define KEYCODE_W       0x1A
#define KEYCODE_X       0x1B
#define KEYCODE_Y       0x1C
#define KEYCODE_Z       0x1D
#define KEYCODE_COMMA     0x36//
#define KEYCODE_PERIOD      0x37//
//^
#define KEYCODE_CARET     0x2E//46
//-
#define KEYCODE_MINUS     0x2D//45
//#define KEYCODE_BACKSLASH   0x31//
#define KEYCODE_INTERNATIONAL1  0x87 //135 One left of the right shift key
#define KEYCODE_INTERNATIONAL3  0x89 //137 \ key above enter key

//@
#define KEYCODE_ATMARK      0x2F //47
//#define KEYCODE_SQBRAK_LEFT 0x2F // [
#define KEYCODE_SQBRAK_LEFT   0x30 //48
//#define KEYCODE_SQBRAK_RIGHT  0x30 // ]
#define KEYCODE_SQBRAK_RIGHT  0x31 //49
//;
#define KEYCODE_SEMICOLON   0x33 //51
//:
#define KEYCODE_COLON     0x34 //52
// /
#define KEYCODE_SLASH     0x38 //56

#define KEYCODE_F1        0x3A
#define KEYCODE_F2        0x3B
#define KEYCODE_F3        0x3C
#define KEYCODE_F4        0x3D
#define KEYCODE_F5        0x3E
#define KEYCODE_F6        0x3F
#define KEYCODE_F7        0x40
#define KEYCODE_F8        0x41
#define KEYCODE_F9        0x42
#define KEYCODE_F10       0x43
#define KEYCODE_F11       0x44
#define KEYCODE_F12       0x45
#define KEYCODE_APP       0x65
#define KEYCODE_ENTER     0x28//
#define KEYCODE_BACKSPACE   0x2A//
#define KEYCODE_ESC       0x29//
#define KEYCODE_TAB       0x2B//
#define KEYCODE_SPACE     0x2C//
#define KEYCODE_INSERT      0x49//
#define KEYCODE_HOME      0x4A//
#define KEYCODE_PAGE_UP     0x4B//
#define KEYCODE_DELETE      0x4C//
#define KEYCODE_END       0x4D//
#define KEYCODE_PAGE_DOWN   0x4E//
#define KEYCODE_PRINTSCREEN   0x46//
#define KEYCODE_ARROW_RIGHT   0x4F//
#define KEYCODE_ARROW_LEFT    0x50//
#define KEYCODE_ARROW_DOWN    0x51//
#define KEYCODE_ARROW_UP    0x52//
#define KEYCODE_PAUSE    0x48// add pause key

使っているスケッチのコメントアウトしていた部分をはずして確認する。

1234567890-^\
!"#$%&'()=~|
@[;:],./\ `{+*}<>?_
\_|
"\","_","|"といった記号までちゃんと表示されるようになる。


コメント

このブログの人気の投稿

Attiny85とAQM0802A(LCD)のI2C接続

Attiny85 FuseRest

HS101 STM32の自作お手軽オシロスコープ