第3回:Arduino・ラズパイPICOでマクロキーボード・プログラマブルキーボード自作(キー入力のカウントと長押し編)

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

第3回は、単一キーでコピペ専用キーを設定してみます。
1つのキーで2つ以上の操作を行うために、「キーのカウント」と「キーの長押し」を利用します。

単一キーコピペキー概要

今回のコピペキーの動作の概要です。
物理的キーは一つのみで動作します。キーを押すと、押した回数と押す長さによって以下の操作を繰り返します。

  1. 最初にキー押すとまずコピーします。
  2. もう一度押すとペーストします。
  3. その後は(キーを押下3回目以降)、キーを押すたびにペーストします。
  4. キーを長押しするとキー操作がリセットされます。
  5. 長押し後にキーを押すと最初のコピーに戻ります。

単一キーで3種類の動作を行う形になります。
また、今回は合わせて複数のキーの送信「ctrl+c 」や「ctrl+v」についても説明します。

単一コピペキースケッチ

単一キーでコピペを行うスケッチをChat GPTにお願いして少し手直ししました。
このスケッチでは、1回目の押下でCtrl+Cを送信し、2回目以降はキーを押すごとにCtrl+Vを送信します。また、1秒以上長押しすると回数がリセットされ、次にキーが押された時点で再度1回目に戻ります。

#include <Keyboard.h>

const int buttonPin = 2;
int buttonState = HIGH;
int lastButtonState = HIGH;
unsigned long buttonPressTime = 0;
int pressCount = 0;
const unsigned long longPressDuration = 1000; // 1秒

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  Keyboard.begin();
}

void loop() {
  int reading = digitalRead(buttonPin);
  
  // ボタンの状態が変わったとき
  if (reading != lastButtonState) {
    if (reading == LOW) { // ボタンが押されたとき
      buttonPressTime = millis();
    } else { // ボタンが離されたとき
      unsigned long pressDuration = millis() - buttonPressTime;
      if (pressDuration >= longPressDuration) {
        pressCount = 0; // 長押しのときはカウントをリセット
      } else {
        // 通常の押下のときは次のアクションに移動
        if (pressCount == 0) {
          // 1回目の押下でCtrl+Cを送信
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.write('c');
          Keyboard.release(KEY_LEFT_CTRL);
        } else {
          // 2回目以降の押下でCtrl+Vを送信
          Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.write('v');
          Keyboard.release(KEY_LEFT_CTRL);
        }
        pressCount++;
      }
    }
    delay(50); // デバウンス対策
  }
  lastButtonState = reading;
}

単一コピペキースケッチの説明:

説明

  • buttonPin: ボタンが接続されているデジタルピン(ここでは2番ピン)。
  • buttonState: 現在のボタンの状態。
  • lastButtonState: 前回のループでのボタンの状態。
  • buttonPressTime: ボタンが押された時刻を記録するための変数。
  • pressCount: ボタンが押された回数をカウントします。
  • longPressDuration: 長押しとみなす時間(ここでは1000ミリ秒=1秒)。

動作の確認

  • 1回目の押下でCtrl+Cを送信します。
  • 2回目以降の押下でCtrl+Vを送信します。
  • ボタンを1秒以上長押しするとカウントがリセットされ、次の押下で再びCtrl+Cを送信します。
  • キーのカウントはpressCount = 0で0からスタートしています。

キーコンビネーションの説明

      Keyboard.press(KEY_LEFT_CTRL);
      Keyboard.write('c');
      Keyboard.releaseAll();

上記の部分ですが、前回のpress関数でCTRLキーを押しています。
ポイントはpress関数なので押しっぱなしの状態
次に
write関数でcを押します。
ポイントはwrite関数なのでcを1回だけ押したことになります
※ここもpress関数にするとcを長押しにしていることになってしまいます(何度もcを送信することになります)。
releaseAll関数でCTRLキーを離しています
実際にキーボードでショートカットキーを使う場合も細かく動作を分けると
CTRLを押しっぱなしにする、Cを押す、Cを離す、CTRLを離す
の流れになると思います。
※Cキーはwrite関数の為releaseAllの関数の前ですでに離されています。
※次の動きのCTRL+Vも同様です。

今回出てきた「KEY_LEFT_CTRL」などはキーボード上の特殊キーなどを表す名称になります。
その他のキーに関しては下のリンクで確認してください(別の記事に飛びます)。

カウントに関しておまけスケッチ

先のスケッチですとボタンのカウント数が少ないので、実用的ではありませんがボタンを押すたびに内容が変わるサンプルスケッチをおまけで。
1回目 Hello Arduino
2回目 Ctrl+C
3回目 Ctrl+V
4回目 A
5回目 Ctrl+X
6回目 Ctrl+V
7回目以降 Good Bye
また、ボタンを1秒以上長押しすると最初のアクションに戻るようにします。
これも、Chat GPTにお願いして手直ししたものが下のスケッチです。

7回カウントのサンプルスケッチ

#include <Keyboard.h>

const int buttonPin = 2;
int buttonState = HIGH;
int lastButtonState = HIGH;
unsigned long buttonPressTime = 0;
int currentIndex = 1;
const unsigned long longPressDuration = 1000; // 1秒

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  Keyboard.begin();
}

void loop() {
  int reading = digitalRead(buttonPin);
  
  // ボタンの状態が変わったとき
  if (reading != lastButtonState) {
    if (reading == LOW) { // ボタンが押されたとき
      buttonPressTime = millis();
    } else { // ボタンが離されたとき
      unsigned long pressDuration = millis() - buttonPressTime;
      if (pressDuration >= longPressDuration) {
        currentIndex = 1; // 長押しのときは最初のアクションに戻る
      } else {
        // 通常の押下のときは次のアクションに移動
        switch(currentIndex) {
          case 1:
            Keyboard.print("Hello Arduino");
            break;
          case 2:
            Keyboard.press(KEY_LEFT_CTRL);
            Keyboard.write('c');
            Keyboard.release(KEY_LEFT_CTRL);
            break;
          case 3:
            Keyboard.press(KEY_LEFT_CTRL);
            Keyboard.write('v');
            Keyboard.release(KEY_LEFT_CTRL);
            break;
          case 4:
            Keyboard.write('A');
            break;
          case 5:
            Keyboard.press(KEY_LEFT_CTRL);
            Keyboard.write('x');
            Keyboard.release(KEY_LEFT_CTRL);
            break;
          case 6:
            Keyboard.press(KEY_LEFT_CTRL);
            Keyboard.write('v');
            Keyboard.release(KEY_LEFT_CTRL);
            break;
          default:
            Keyboard.print("Good Bye");
            break;
        }
        currentIndex++;
      }
    }
    delay(50); // デバウンス対策
  }
  lastButtonState = reading;
}

説明

  • buttonPin: ボタンが接続されているデジタルピン(ここでは2番ピン)。
  • buttonState: 現在のボタンの状態。
  • lastButtonState: 前回のループでのボタンの状態。
  • buttonPressTime: ボタンが押された時刻を記録するための変数。
  • currentIndex: 現在実行するアクションのインデックス。
  • longPressDuration: 長押しとみなす時間(ここでは1000ミリ秒=1秒)。

動作の確認

  • 1回目の押下で「Hello Arduino」を表示します。
  • 2回目の押下で Ctrl+C を送信します。
  • 3回目の押下で Ctrl+V を送信します。
  • 4回目の押下で ‘A’ を表示します。
  • 5回目の押下で Ctrl+X を送信します。
  • 6回目の押下で Ctrl+V を送信します。
  • 7回目以降の押下で「Good Bye」を表示し続けます。
  • ボタンを1秒以上長押しすると、最初のアクション(「Hello Arduino」)に戻ります。
  • ※途中のコピーが空振りの場合(選択範囲がない)場合は、前回のコピーされた内容がペーストされます。

難しいな?と思ったら

頑張らないプログラミングがモットーですので、細かな部分を覚える必要はありません。
マクロキーボードをカスタマイズするために最低限必要な部分は
press関数とrelease関数(装飾キーなど)
write関数(単一のキーを押す)
上記の組み合わせでコンビネーションキー(3個以上のキーコンビネーションももちろん可能です)
print関数(文字列の表示)
この関数を使って(またはサンプルから抜き出して)caseの部分を書き換えればOKです。
※上記のサンプルではcaseは1から始まり6までですが、実際はそのあとにもう一つdefault:があり7個の条件になります。不要caseを消す、またはcaseを追加すれば7個以下または7個以上へのカスタマイズも可能です。
長押しの時間の設定は1000=1秒ですので2秒なら2000です。
※あまり短いと通常のキー入力と長押しの区別がつかなくなりますのでご注意を。
頑張らないプログラミングがモットーですので、細かな部分を覚える必要はありません。
カスタマイズするために最低限必要な部分は
press関数とrelease関数(装飾キーなど)
write関数(単一のキーを押す)
上記の組み合わせでコンビネーションキー(3個以上のキーコンビネーションももちろん可能です)
print関数(文字列の表示)
この関数を使って(またはサンプルから抜き出して)caseの部分を書き換えればOKです。
※上記のサンプルではcaseは1から始まり6までですが、実際はそのあとにもう一つdefault:があり7個の条件になります。不要caseを消す、またはcaseを追加すれば7個以下または7個以上へのカスタマイズも可能です。
長押しの時間の設定は1000=1秒ですので2秒なら2000です。
※あまり短いと通常のキー入力と長押しの区別がつかなくなりますのでご注意を。

第3回まとめ

キーが一つでも、少し手を加えると様々な動作が追加できるのが面白いですね。
初心者の方には少し難しい内容かもしれませんが、とりあえず必要な部分だけを修正すればカスタマイズ可能だと思います。

コメント

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