第7回:Arduino・ラズパイPICOでマクロキーボード自作(メディアコントローラー編)

自作マクロキーボード Arduino
1列用は幅がギリギリです
記事内には広告が含まれています。

今回は、音楽や動画などの再生・停止、早送り・巻き戻し、音量の調節などをキーに割り当ててメディアコントローラーを作成してみようと思います。
Arduinoを使用してメディアコントローラーを作成するためには、すでに何度も使ってきたKeyboard.hライブラリと特殊キーの組み合わせで作成するか、HID-Project.hライブラリを利用して作成するかどちらかになりますが、今回は2パターンともご紹介しますのでお好きなほうをお使いください。
また、今回新しく出てきたHID-Project.hライブラリについても後ほど詳しく説明いたします。

Keyboard.hを利用したメディアコントローラー

Keyboard.hライブラリを使ったパターン概要

Keyboard.hライブラリを使ってメディアコントローラーを作成します。このライブラリは、キーボードエミュレーションをサポートしていますが、メディアキーはサポートしていません。そのため、メディアコントロールは標準のキーボードショートカットを使用します。

Keyboard.hライブラリを使ったスケッチ

#include <Keyboard.h>

// ボタンのピン番号を定義
const int buttonPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 16};

// ボタンの状態を記録する配列
bool buttonStates[10];

void setup() {
  // 各ボタンピンを入力に設定
  for (int i = 0; i < 10; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
    buttonStates[i] = HIGH;
  }
  // キーボードを開始
  Keyboard.begin();
}

void loop() {
  // 各ボタンの状態をチェック
  for (int i = 0; i < 10; i++) {
    bool currentState = digitalRead(buttonPins[i]);
    if (currentState != buttonStates[i]) {
      // ボタンが押されたとき
      if (currentState == LOW) {
        handleButtonPress(i);
      }
      buttonStates[i] = currentState;
    }
  }
}

void handleButtonPress(int buttonIndex) {
  switch (buttonIndex) {
    case 0: Keyboard.press(KEY_MEDIA_VOLUME_UP); delay(100); Keyboard.release(KEY_MEDIA_VOLUME_UP); break;
    case 1: Keyboard.press(KEY_MEDIA_VOLUME_DOWN); delay(100); Keyboard.release(KEY_MEDIA_VOLUME_DOWN); break;
    case 2: Keyboard.press(KEY_MEDIA_PLAY_PAUSE); delay(100); Keyboard.release(KEY_MEDIA_PLAY_PAUSE); break;
    case 3: Keyboard.press(KEY_MEDIA_NEXT_TRACK); delay(100); Keyboard.release(KEY_MEDIA_NEXT_TRACK); break;
    case 4: Keyboard.press(KEY_MEDIA_PREVIOUS_TRACK); delay(100); Keyboard.release(KEY_MEDIA_PREVIOUS_TRACK); break;
    case 5: Keyboard.press(KEY_MEDIA_STOP); delay(100); Keyboard.release(KEY_MEDIA_STOP); break;
    case 6: Keyboard.press(KEY_MEDIA_MUTE); delay(100); Keyboard.release(KEY_MEDIA_MUTE); break;
    case 7: Keyboard.press(KEY_MEDIA_EJECT); delay(100); Keyboard.release(KEY_MEDIA_EJECT); break;
    case 8: Keyboard.press(KEY_MEDIA_FAST_FORWARD); delay(100); Keyboard.release(KEY_MEDIA_FAST_FORWARD); break;
    case 9: Keyboard.press(KEY_MEDIA_REWIND); delay(100); Keyboard.release(KEY_MEDIA_REWIND); break;
  }
}

スケッチの説明

#include <Keyboard.h>

Keyboardライブラリをインクルードします。このライブラリは、キーボードエミュレーションを提供します。

const int buttonPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 16};

ボタンが接続されているピン番号を配列として定義します。

bool buttonStates[10];

ボタンの状態を記録する配列を定義します。

void setup() {
  for (int i = 0; i < 10; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
    buttonStates[i] = HIGH;
  }
  Keyboard.begin();
}

setup関数では、各ボタンピンを入力プルアップに設定し、キーボード機能を初期化します。

void loop() {
  for (int i = 0; i < 10; i++) {
    bool currentState = digitalRead(buttonPins[i]);
    if (currentState != buttonStates[i]) {
      if (currentState == LOW) {
        handleButtonPress(i);
      }
      buttonStates[i] = currentState;
    }
  }
}

loop関数では、各ボタンの状態をチェックし、状態が変わった場合にボタンの処理を行います。

void handleButtonPress(int buttonIndex) {
  switch (buttonIndex) {
    case 0: Keyboard.press(KEY_MEDIA_VOLUME_UP); delay(100); Keyboard.release(KEY_MEDIA_VOLUME_UP); break;
    case 1: Keyboard.press(KEY_MEDIA_VOLUME_DOWN); delay(100); Keyboard.release(KEY_MEDIA_VOLUME_DOWN); break;
    case 2: Keyboard.press(KEY_MEDIA_PLAY_PAUSE); delay(100); Keyboard.release(KEY_MEDIA_PLAY_PAUSE); break;
    case 3: Keyboard.press(KEY_MEDIA_NEXT_TRACK); delay(100); Keyboard.release(KEY_MEDIA_NEXT_TRACK); break;
    case 4: Keyboard.press(KEY_MEDIA_PREVIOUS_TRACK); delay(100); Keyboard.release(KEY_MEDIA_PREVIOUS_TRACK); break;
    case 5: Keyboard.press(KEY_MEDIA_STOP); delay(100); Keyboard.release(KEY_MEDIA_STOP); break;
    case 6: Keyboard.press(KEY_MEDIA_MUTE); delay(100); Keyboard.release(KEY_MEDIA_MUTE); break;
    case 7: Keyboard.press(KEY_MEDIA_EJECT); delay(100); Keyboard.release(KEY_MEDIA_EJECT); break;
    case 8: Keyboard.press(KEY_MEDIA_FAST_FORWARD); delay(100); Keyboard.release(KEY_MEDIA_FAST_FORWARD); break;
    case 9: Keyboard.press(KEY_MEDIA_REWIND); delay(100); Keyboard.release(KEY_MEDIA_REWIND); break;
  }
}

handleButtonPress関数では、ボタンが押された場合に対応するメディアコントロールショートカットをキーボードとして送信します。各ショートカットの送信後に100ミリ秒の遅延を入れ、キーを解放します。

メディア操作のショートカットキーの一覧は別記事にまとめていますのでカスタマイズ時に参考にしてください。

HDI-Project.hを利用したメディアコントローラー

HDI-Project.hライブラリを使ったパターン概要

HID-Project.hライブラリを使ってメディアコントローラーを作成する場合のスケッチとその説明です。

HDI-Project.hライブラリを使ったスケッチ

#include <HID-Project.h>

// ボタンのピン番号を定義
const int buttonPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 16};

// ボタンの状態を記録する配列
bool buttonStates[10];

void setup() {
  // 各ボタンピンを入力に設定
  for (int i = 0; i < 10; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
    buttonStates[i] = HIGH;
  }
  // HIDを開始
  HID.begin();
}

void loop() {
  // 各ボタンの状態をチェック
  for (int i = 0; i < 10; i++) {
    bool currentState = digitalRead(buttonPins[i]);
    if (currentState != buttonStates[i]) {
      // ボタンが押されたとき
      if (currentState == LOW) {
        handleButtonPress(i);
      }
      buttonStates[i] = currentState;
    }
  }
}

void handleButtonPress(int buttonIndex) {
  switch (buttonIndex) {
    case 0: Consumer.write(MEDIA_VOLUME_UP); break;
    case 1: Consumer.write(MEDIA_VOLUME_DOWN); break;
    case 2: Consumer.write(MEDIA_PLAY_PAUSE); break;
    case 3: Consumer.write(MEDIA_NEXT); break;
    case 4: Consumer.write(MEDIA_PREVIOUS); break;
    case 5: Consumer.write(MEDIA_STOP); break;
    case 6: Consumer.write(MEDIA_MUTE); break;
    case 7: Consumer.write(MEDIA_EJECT); break;
    case 8: Consumer.write(MEDIA_FAST_FORWARD); break;
    case 9: Consumer.write(MEDIA_REWIND); break;
  }
}

HID-Project.hライブラリを使ったパターン

スケッチの説明

#include <HID-Project.h>

HID-Projectライブラリをインクルードします。このライブラリは、HIDデバイスとしての機能を提供します。

const int buttonPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 16};

ボタンが接続されているピン番号を配列として定義します。

bool buttonStates[10];

ボタンの状態を記録する配列を定義します。

void setup() {
  for (int i = 0; i < 10; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
    buttonStates[i] = HIGH;
  }
  HID.begin();
}

setup関数では、各ボタンピンを入力プルアップに設定し、HID機能を初期化します。

void loop() {
  for (int i = 0; i < 10; i++) {
    bool currentState = digitalRead(buttonPins[i]);
    if (currentState != buttonStates[i]) {
      if (currentState == LOW) {
        handleButtonPress(i);
      }
      buttonStates[i] = currentState;
    }
  }
}

loop関数では、各ボタンの状態をチェックし、状態が変わった場合にボタンの処理を行います。

void handleButtonPress(int buttonIndex) {
  switch (buttonIndex) {
    case 0: Consumer.write(MEDIA_VOLUME_UP); break;
    case 1: Consumer.write(MEDIA_VOLUME_DOWN); break;
    case 2: Consumer.write(MEDIA_PLAY_PAUSE); break;
    case 3: Consumer.write(MEDIA_NEXT); break;
    case 4: Consumer.write(MEDIA_PREVIOUS); break;
    case 5: Consumer.write(MEDIA_STOP); break;
    case 6: Consumer.write(MEDIA_MUTE); break;
    case 7: Consumer.write(MEDIA_EJECT); break;
    case 8: Consumer.write(MEDIA_FAST_FORWARD); break;
    case 9: Consumer.write(MEDIA_REWIND); break;
  }
}

handleButtonPress関数では、ボタンが押された場合に対応するメディアコントロールコマンドを送信します。

HID-Project.hライブラリに関して補足

HID-Project.hを利用した場合は、メディアコントロールきーに対してwrite関数が使えるので、press、releaseを記載する必要がなくコードが短くて済みます。

HID-Project.hで利用できるメディアコントロールキー

HID-Project.hライブラリでは、以下のメディアキー定数が利用できます。

  • MEDIA_PLAY_PAUSE:再生/一時停止
  • MEDIA_NEXT:次のトラック
  • MEDIA_PREVIOUS:前のトラック
  • MEDIA_STOP:停止
  • MEDIA_VOLUME_UP:音量を上げる
  • MEDIA_VOLUME_DOWN:音量を下げる
  • MEDIA_MUTE:ミュート
  • MEDIA_EJECT:イジェクト
  • MEDIA_FAST_FORWARD:早送り
  • MEDIA_REWIND:巻き戻し

Kyeboard.hライブラリとの違い

Kyeboard.hライブラリとHID-Project.hライブラリの一番の違いは、HID-Project.hライブラリはキーボード以外、マウスやジョイスティックなどのHIDデバイス全般の制御が出来るライブラリです。
前回でKeyboard.hライブラリとMouse.hライブラリの2つのライブラリを読み込みましたが、HID-Project.hライブラリを利用した場合は1つのライブラリでキー制御とマウス制御が行えます。

また、メディアキーなどを利用する場合はHID-Project.hライブラリにメディアキー定数として含まれているのでwriteが利用でき非常に楽ですが、マイクのミュートを行いたいと思った場合は、メディアキー定数にない為、Keyboard.hライブラリと同様なスケッチが必要になります。
以下のサンプルスケッチはマイクミュートのショートカットキーを送っています(Windows用)。

#include <HID-Project.h>

// ボタンのピン番号を定義
const int buttonPins[] = {2}; // マイクミュートボタンを1つだけ定義

// ボタンの状態を記録する変数
bool buttonState = HIGH;

void setup() {
  pinMode(buttonPins[0], INPUT_PULLUP); // ボタンピンを入力プルアップに設定
  HID.begin(); // HIDを開始
}

void loop() {
  bool currentState = digitalRead(buttonPins[0]); // ボタンの状態を読み取る
  if (currentState != buttonState) {
    if (currentState == LOW) {
      handleButtonPress();
    }
    buttonState = currentState;
  }
}

void handleButtonPress() {
  // Ctrl + Shift + M を送信
  Keyboard.press(KEY_LEFT_CTRL);
  Keyboard.press(KEY_LEFT_SHIFT);
  Keyboard.press('M');
  delay(100);
  Keyboard.release('M');
  Keyboard.release(KEY_LEFT_SHIFT);
  Keyboard.release(KEY_LEFT_CTRL);
}

キー操作のみを行う前提であればKeyboard.hライブラリで良いでしょうし、今回のマクロキーボードなどキーボード、マウスなどHIDデバイスを総合的に制御したい場合はHID-Project.hライブラリを使うと良いと思います。
※もちろん両方のライブラリを読み込んで使い分けも可能です。

HID-Project.hライブラリの関数などの詳しい情報は別記事にアップしていますので興味のある方は下のリンクからご覧ください。

まとめ

これまで7回に分けてマクロキーボードに必要なライブラリや関数などを説明してきました。

  • 単一文字送信
  • 複数文字送信
  • スイッチの長押しなどでの条件分け
  • 複数のキーでの操作
  • ショートカットキー送信
  • 順次キー送信をしてアプリやファイルの起動
  • キーでのマウス操作
  • メディアコントロールなどの特殊操作

上記の組み合わせを行えば、マクロキーボードとして十分利用できるレベルになると思います。
せっかくですので、ぜひスケッチをカスタマイズして好みのマクロキーボードに仕上げてください。

コメント

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