M5Stack用ジェスチャーユニットを使ってiPadの書籍アプリを手軽に操作する方法

M5Stack用のジェスチャーユニット(PAJ7620U2)を利用して、iPadの書籍アプリ(Kindle、i文庫HDなど)を操作してみました。

iPadの起動からアプリの立ち上げ、ページめくり、画面キャプチャーまで、iPadに触れずに全ての操作が可能です。

m5StickCとiPadはBLEで接続しています。最初にペアリングするだけで、あとは特に何も設定は入りません。

BLEとの接続とコマンド送信についてはLang-shipさんを参考にさせていただきました。

記事中ではESP32-BLE-Keyboardライブラリが不安定でiOSで使えない。とありましたが、今は無事アップデートされて問題なく接続できているようです。

ソースコード

#include <M5StickC.h>               // M5StickC用のライブラリ
#include <BleKeyboard.h>            // Bluetoothキーボード用のライブラリ
#include <DFRobot_PAJ7620U2.h>      // ジェスチャーセンサ用のライブラリ

BleKeyboard bleKeyboard("M5StickC BLE Gesture ctrl for iPad");
// Bluetoothキーボードのインスタンスを生成

DFRobot_PAJ7620U2 sensor;
// ジェスチャーセンサのインスタンスを生成
unsigned long nextVbatCheck = 0;
// バッテリー残量の更新時間
const int BATTERY_UPDATE_INTERVAL = 60000;
// バッテリー残量の更新間隔

// 画面表示関数
void displayState(int textSize, int x, int y, String description) {
  M5.Lcd.setTextSize(textSize);
  M5.Lcd.setCursor(x, y);
  M5.Lcd.print(description);
}

void setDisplay() {
  // M5StickCの画面設定
  M5.Axp.ScreenBreath(8);
  setCpuFrequencyMhz(80);
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  displayState(2, 0, 30, "flipGesture"); //画面表示
  M5.Lcd.setTextSize(2);
  M5.Lcd.setCursor(0, 16);
}

// バッテリー残量を取得する関数
int getBatteryLevel() {
  float voltage = M5.Axp.GetBatVoltage();
  int level = (voltage - 3.2) / 0.8 * 100;
  level = max(0, min(100, level));
  return level;
}

// ワンショットキー関数
void pressKey(int key) {
  bleKeyboard.press(key);
  delay(10);
  bleKeyboard.releaseAll();
}

// コマンドキーと文字キーを同時に押す関数
void pressCommandAndKey(int commandKey, char key) {
  bleKeyboard.press(commandKey);
  delay(50);
  bleKeyboard.press(key);
  delay(50);
  bleKeyboard.releaseAll();
  delay(50);
}

// コマンドキーとShiftキーと文字キーを同時に押す関数
void pressCommandShiftKey(int commandKey, char key) {
  bleKeyboard.press(commandKey);
  delay(50);
  bleKeyboard.press(KEY_LEFT_SHIFT);
  delay(10);
  bleKeyboard.press(key);
  delay(50);
  bleKeyboard.releaseAll();
  delay(50);
}

// ブックアプリを呼び出す関数
void callApp(String book) {
      pressCommandAndKey(KEY_LEFT_GUI, 'h'); // ->command (Cmd + h)ホームボタン
      pressCommandAndKey(KEY_LEFT_GUI, ' '); // ->command (Cmd + Space)検索窓
      bleKeyboard.write(KEY_BACKSPACE);
      delay(50);
      bleKeyboard.print(book);
      delay(900);
      pressKey(KEY_RETURN);
      delay(100);
      pressKey(KEY_RETURN);
}

void setup() {
  M5.begin();
  Serial.begin(115200);  // シリアルポートの初期化
  setDisplay(); // 画面の初期化

  while (sensor.begin() != 0) {
      Serial.println("initial PAJ7620U2 failure!");
      delay(500);
  }
  
  sensor.setGestureHighRate(true); // ジェスチャーの高速モードに設定
  bleKeyboard.setBatteryLevel(getBatteryLevel());   // Bluetoothキーボードのバッテリー残量を設定
  bleKeyboard.begin();                              // Bluetoothキーボードを開始
}

void loop() {
  M5.update();
    /*
     * eGestureNone  eGestureRight  eGestureLeft  eGestureUp  eGestureDown
     * eGestureForward eGestureBackward  eGestureClockwise eGestureAntiClockwise
     * eGestureWave  eGestureWaveSlowlyDisorder eGestureWaveSlowlyLeftRight
     * eGestureWaveSlowlyUpDown  eGestureWaveSlowlyForwardBackward
     */
  DFRobot_PAJ7620U2::eGesture_t gesture = sensor.getGesture();  // ジェスチャーを取得
  if (gesture != sensor.eGestureNone) {
      /*
        * "None","Right","Left", "Up", "Down", "Forward", "Backward",
        * "Clockwise", "Anti-Clockwise", "Wave", "WaveSlowlyDisorder",
        * "WaveSlowlyLeftRight", "WaveSlowlyUpDown",
        * "WaveSlowlyForwardBackward"
        */
      String description = sensor.gestureDescription(gesture);
      Serial.println("Gesture = " + description);

      // ジェスチャーに応じて処理を実行
      if (description == "Right" ) {
        M5.Lcd.fillScreen(RED);
        displayState(4, 0, 16, description); //画面表示
        pressKey(KEY_LEFT_ARROW);
      }
      else if (description == "Left" ) {
        M5.Lcd.fillScreen(BLUE);
        displayState(4, 0, 16, description); //画面表示
        pressKey(KEY_RIGHT_ARROW);
      }
      else if (description == "Clockwise" ) {
        M5.Lcd.fillScreen(WHITE);
        displayState(3, 0, 20, "Capture"); //画面表示
        // ScreenShot(COMMAND + SHIFT + 3)
        pressCommandShiftKey(KEY_LEFT_GUI, '3');
      }
      else if (description == "Forward" ) {
        M5.Lcd.fillScreen(YELLOW);
        displayState(3, 0, 16, "App"); //画面表示
        // ScreenShot(COMMAND + h)
        pressCommandAndKey(KEY_LEFT_GUI, 'h');

        unsigned long startTime = millis(); // 現在時刻を取得する
        while (millis() - startTime < 5000) {
        DFRobot_PAJ7620U2::eGesture_t gesture = sensor.getGesture();
        String description = sensor.gestureDescription(gesture);
        // 5秒間ループするコード
          if (description == "Left" ) {
            displayState(3,20, 42, "ibunko"); //画面表示
            callApp("ibunko"); //i文庫を立ち上げる
            break; // whileループを抜ける
          }
          else if (description == "Right" ) {
            displayState(2,20, 42, "ComicShare"); //画面表示
            callApp("ComicShare"); //ComicShareを立ち上げる
            break; // whileループを抜ける
          }
          else if (description == "Up" ) {
            displayState(3,20, 42, "Kindle"); //画面表示
            callApp("kindle"); //Kindleを立ち上げる
            break; // whileループを抜ける
          }
        }
        M5.Lcd.fillScreen(BLACK);
      }
  }
  // Bluetoothキーボードが接続されている場合
  if (bleKeyboard.isConnected()) {
    // ボタンAが押された場合、スクリーンショットを撮影する
    if ( M5.BtnA.wasPressed() ) {
      // ScreenShot(COMMAND + SHIFT + 3)
      pressCommandShiftKey(KEY_LEFT_GUI, '3');
    }
    // ボタンBが押された場合、スクリーンショットを撮影する
    else if ( M5.BtnB.wasPressed() ) {
      // ScreenShot(COMMAND + SHIFT + 3)
      pressCommandShiftKey(KEY_LEFT_GUI, '3');
    }
  }
  // バッテリーレベルを更新する
  if (nextVbatCheck < millis()) {
    M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(112, 0);
    M5.Lcd.printf("%3d%%", getBatteryLevel());

    nextVbatCheck = millis() + BATTERY_UPDATE_INTERVAL;
  }
  // 1ミリ秒待つ
  delay(1);
}

スクリプトの

callApp("ComicShare")

を所有しているアプリ名に置き換えるだけです。

使い方

  • ページめくりは、右・左スワイプで可能です。
  • アプリの立ち上げは、手を上から被せるように下ろし、5秒以内に上右左どちらかにスワイプ。
  • キャプチャーは時計回りにくるくるします。

おすすめの設置場所

右手のトラックパッドの上あたりにジェスチャーユニットを配置すると、右手を大きく動かさずに、左側に縦向けに設置されたiPadを動かせるので、すこぶる快適です。

また、iPadがスリープでブラックアウトしていても、ジェスチャーで起動することができるので、実質立ち上げから読書に至るまで一切iPadに触れることなくできるので便利です。

書類を見ながら、パソコンで原稿を書くことが多い人はとても便利だと思います。

機材

ジェスチャーユニット

M5StickC(M5StickCは廃盤なのでM5StickC Plusがおすすめ)

Shareこの記事をシェアしよう!