🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

1回答

3211閲覧

Arduino USBキーボードから送られてくるキーコードが格納されてる変数を見つけたい。

nakapy0918

総合スコア18

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2019/12/17 15:27

編集2019/12/19 15:48

前提・実現したいこと

USBキーボードから送られてくるキーコードをArduinoで取得したいと考えています。

接続順は 【USBキーボード】 → 【USBホストシールド】 → 【Arduino Pro Micro】 → 【PC】の順で

現在は下記のブログの記事を参考に、キーボード入力をArduinoを経由させてPCへ出力する所まで作成することができました。

ですが、どの変数にキー情報が格納されているかがわからず、開発が行き詰まっています。

もし分かる方が居られましたら、何卒宜しくお願いいたします。

【参考とさせて頂いた記事及びコード】
Pro Microにmini USB Hostシールドを付けてUSBキーボードを接続する

現状の理解

間違っている可能性も高いのですが、
下記の関数sendReport()がキー情報をPCへ送る関数と予想しています。
・2はID(1がマウス用のIDらしいのでキーボード用のIDと予測)
・&KeyReportがキー情報(←このアドレスの値を取得できれば解決?)
・sizeofの出力結果は8

//HIDクラスを使ってレポートを送信する関数 void sendReport() { HID().SendReport(2, &keyReport ,sizeof(KeyReport)); }

試したこと及び現在の状況

&keyReportを、print関数で出力しようとしたり、変数に格納しようと試して見たもののエラーが発生。
内部がどのような値になっているのかや、どのようにすれば取得できるかがわからずにいます。

###質問者のプログラミング経験
VBA,GAS,UWSCと操作の自動化でしか取り扱いの経験がなく、
Arduino(C/C++)言語は初めてまだ日が浅いため、修練中の身です。
###参考とさせて頂いてるコード

Arduino

1#include "HID.h" 2 3#include <hidboot.h> 4#include <usbhub.h> 5#include <SPI.h> 6 7static const uint8_t _hidReportDescriptor[] PROGMEM = { 8 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 9 0x09, 0x06, // USAGE (Keyboard) 10 0xa1, 0x01, // COLLECTION (Application) 11 0x85, 0x02, // REPORT_ID (2) --- Mouse.cppがID==1。 12 13 0x05, 0x07, // USAGE_PAGE (usage = keyboard page) 14 // モデファイヤキー(修飾キー) 15 0x19, 0xe0, // USAGE_MINIMUM (左CTRLが0xe0) 16 0x29, 0xe7, // USAGE_MAXIMUM (右GUIが0xe7) 17 0x15, 0x00, // LOGICAL_MINIMUM (0) 18 0x25, 0x01, // LOGICAL_MAXIMUM (1) 19 0x95, 0x08, // REPORT_COUNT (8) 全部で8つ(左右4つずつ)。 20 0x75, 0x01, // REPORT_SIZE (1) 各修飾キーにつき1ビット 21 0x81, 0x02, // INPUT (Data,Var,Abs) 8ビット長のInputフィールド(変数)が1つ。 22 // 予約フィールド 23 0x95, 0x01, // REPORT_COUNT (1) 24 0x75, 0x08, // REPORT_SIZE (8) 1ビットが8つ。 25 0x81, 0x01, // INPUT (Cnst,Var,Abs) 26 // LED状態のアウトプット 27 0x95, 0x05, // REPORT_COUNT (5) 全部で5つ。 28 0x75, 0x01, // REPORT_SIZE (1) 各LEDにつき1ビット 29 0x05, 0x08, // USAGE_PAGE (LEDs) 30 0x19, 0x01, // USAGE_MINIMUM (1) (NumLock LEDが1) 31 0x29, 0x05, // USAGE_MAXIMUM (5) (KANA LEDが5) 32 0x91, 0x02, // OUTPUT (Data,Var,Abs) // LED report 33 // LEDレポートのパディング 34 0x95, 0x01, // REPORT_COUNT (1) 35 0x75, 0x03, // REPORT_SIZE (3)  残りの3ビットを埋める。 36 0x91, 0x01, // OUTPUT (Cnst,Var,Abs) // padding 37 // 押下情報のインプット 38 0x95, 0x06, // REPORT_COUNT (6) 全部で6つ。 39 0x75, 0x08, // REPORT_SIZE (8) おのおの8ビットで表現 40 0x15, 0x00, // LOGICAL_MINIMUM (0) キーコードの範囲は、 41 0x25, 0xdd, // LOGICAL_MAXIMUM (221) 0~221(0xdd)まで 42 43 0x05, 0x07, // USAGE_PAGE (Keyboard) 44 0x19, 0x00, // USAGE_MINIMUM (0はキーコードではない) 45 0x29, 0xdd, // USAGE_MAXIMUM (Keypad Hexadecimalまで) 46 0x81, 0x00, // INPUT (Data,Ary,Abs) 47 0xc0 // END_COLLECTION 48}; 49 50#define REPORT_KEYS 6 51typedef struct { 52 uint8_t modifiers; 53 uint8_t reserved; 54 uint8_t keys[REPORT_KEYS]; 55} KeyReport; 56 57KeyReport keyReport; 58 59void sendReport() { 60 HID().SendReport(2, &keyReport ,sizeof(KeyReport)); 61} 62 63void releaseAll() { 64 memset(&keyReport, 0, sizeof(KeyReport)); 65 sendReport(); 66} 67 68void report_press(uint8_t key, uint8_t mod) { 69 if (key != 0) { 70 bool already = false; 71 int empty_slot = -1; 72 for(int i = 0; i < REPORT_KEYS; i++) { 73 if (keyReport.keys[i] == key) 74 already = true; 75 if (keyReport.keys[i] == 0 && empty_slot < 0) 76 empty_slot = i; 77 } 78 if (empty_slot < 0) // error condition. 79 return; 80 if (!already) 81 keyReport.keys[empty_slot] = key; 82 } 83 keyReport.modifiers = mod; 84 sendReport(); 85} 86 87void report_release(uint8_t key, uint8_t mod) { 88 if (key != 0) { 89 for(int i = 0; i < REPORT_KEYS; i++) { 90 if (keyReport.keys[i] == key) { 91 keyReport.keys[i] = 0; 92 break; 93 } 94 } 95 } 96 keyReport.modifiers = mod; 97 sendReport(); 98} 99 100class KeyboardEvent : public KeyboardReportParser { 101 protected: 102 void OnControlKeysChanged(uint8_t before, uint8_t after); 103 void OnKeyPressed(uint8_t key) {}; 104 void OnKeyDown (uint8_t mod, uint8_t key) { report_press(key, mod); }; 105 void OnKeyUp (uint8_t mod, uint8_t key) { report_release(key, mod); }; 106}; 107 108void KeyboardEvent::OnControlKeysChanged(uint8_t before, uint8_t after) { 109 uint8_t change = before ^ after; 110 if (change != 0) { 111 if (change & after) 112 report_press(0, after); 113 else 114 report_release(0, after); 115 } 116} 117 118USB Usb; 119HIDBoot<USB_HID_PROTOCOL_KEYBOARD> HidKeyboard(&Usb); 120KeyboardEvent kbd; 121 122void error_blink(int period) { 123 for(;;) { 124 TXLED1; delay(period); TXLED0; delay(period); 125 RXLED1; delay(period); RXLED0; delay(period); 126 } 127} 128 129void setup() { 130 static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor)); 131 HID().AppendDescriptor(&node); 132 delay(200); 133 releaseAll(); 134 if (Usb.Init() == -1) 135 error_blink(400); 136 delay( 200 ); 137 HidKeyboard.SetReportParser(0, &kbd); 138} 139 140void loop() { 141 Usb.Task(); 142} 143

###追記
・12/20 一度変数に格納することでコンパイル成功、どのキーを押しても169と表示されるので、1byte×8個の表記にするにはどうすればいいか、どこに問題があるのか模索中。

Arduino

1Serial.println(&keyReport);//コンパイル時にエラー 2 3//↓一度変数に格納するとコンパイル成功 4 5uint8_t a =&keyReport; 6Serial.println(&keyReport);//169 の数値が固定でログに表示される。 7 8

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/12/17 23:06

コードがないと答えようもないですが
nakapy0918

2019/12/18 10:58

リンク先の参考とさせて頂いてるコードを追記致しました。
guest

回答1

0

ベストアンサー

nakapy0918さん、

USB keyboardは、こんな感じで、8バイトのデータを送ります。
( https://wiki.osdev.org/USB_Human_Interface_Devices#USB_keyboard )

この辺がわかると...、というか、わかってないと、何やってるか、わからないですよね?
まずは、この辺から、調べてみるとよいかと思います。

投稿2019/12/17 17:37

mt08

総合スコア1825

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nakapy0918

2019/12/19 13:29

mt08さん回答ありがとうございます。 2番目のReserved field.(予約フィールド)の理解がまだ出来ずにいますが、 1番目が修飾キー(LeftCtrl(0)やRightShift(5))で3~8番目が複数押しを想定したキー情報(aなら4、bなら5) 16進数表記で1byteの情報が、8つ連なってレポートとして送られていると理解したのですが、あっていますでしょうか? 配列形式で格納されているのならと、Serial.println(keyReport[0]);と記述すればログに表示できるのではないかと、試したもののエラーとなってしまったため、質問させて頂いています。 どうにかログに表示させる方法はないでしょうか?
mt08

2019/12/19 23:19

nakapy0918さん、 > 2番目のReserved field.(予約フィールド)の理解がまだ出来ずにいますが、 は、使用されてないので、無視して大丈夫です。 > 16進数表記で1byteの情報が、8つ連なってレポートとして送られていると理解したのですが、あっていますでしょうか? はい。 1バイト目の8ビットそれぞれで、8つの修飾キー(modifier key:モディファイアキー)。2バイト目は予約(無視)、のこり6バイトで普通のキーです。ね。 動作の流れとしては、setup()中の、↓で、イベントハンドラを登録してます。 > HidKeyboard.SetReportParser(0, &kbd); KeyboardEvent kbd;なので、class KeyboardEvent : public KeyboardReportParser { のあたりを見ると、それっぽいメソッドが並んでるかと。 キーが押されると(ArduinoがUSBホストとして、デバイスのキーボードからデータ取得)、OnKeyDown()が実行され、report_press()がよばれて、 (ArduinoがUSBデバイスとして)うまくパケットを作って、PCにデータを送る、ってかんじですね。 みたところ、イベント(OnKeyDown() / OnKeyUp())では、modとkey、それぞれ一個ずつで呼ばれるので、修飾キーと、一つのキーのイベント(押された・離された)がわかるだけなので、それをもとに、現在押されているキーをうまくまとめて、送ってるんじゃないかと思います。 あと、KeyReporyは、構造体なので、printするなら、KeyReport.keys[0] でしょうか?
nakapy0918

2019/12/27 15:42

mt08さん、詳しく解答ありがとうございます。 sendReport()内に下記の記述をしたところ、 キー入力時に16進数表記で8個の情報をログに出力。 Serial.print(keyReport.modifiers, HEX); Serial.print(" "); Serial.print(keyReport.reserved, HEX); Serial.print(" "); for (int i = 0; i < REPORT_KEYS; i++) { Serial.print(keyReport.keys[i], HEX); Serial.print(" "); } Serial.println(); おかげさまでキー入力情報を得るための理解が叶いました。 加えて今まで理解できてなかった他関数も、1つの理解から辿るように見ていくと、何をしてるか理解できるように…。とても助かりました、mt08さん本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問