t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

PS4コントローラーのアナログレバー(L2、R2)によるスクロールの改良案

今回は以前作成したPS4コントローラーをマクロキーボードとして使う件の改良案を紹介。
thom.hateblo.jp

従来のコードでスクロールを実現する仕組み

ブラウザや電子メールの閲覧ウインドウをスクロールする際は通常マウスホイールを使うが、上記のマクロキーボードではカーソルキーの「↓」と「↑」で代用している。
スクロールのスピードは、キー入力とキー入力の間に「↓、delay、↓、delay、↓、delay」のように遅延を挟み、この遅延量によってコントロールしている。

以前のコードは次のとおりである。

    if (PS4.getAnalogButton(R2)) {
      Keyboard.press(KEY_DOWN_ARROW);
      delay(256-PS4.getAnalogButton(R2));
      Keyboard.releaseAll();
    }

L2、R2キーはレバー式のボタンになっていて、押し込み量によって0~255までの値を取得できるので、256からボタンの押し込み値をマイナスした数値をDelayに使うことで押し込み量によってDelay値が1~255までの値になる。

問題点

問題その1

1つ目の問題はリモート環境でこれを使うと、最大まで押し込んでしまうとボタンを離してもしばらくスクロールが続いてしまうこと。
実際には記事を書いてリリースした直後には既に気づいていたんだけどまぁ使えるからいいやって感じで放置してた。。

原因は、Delayが少なすぎてアプリ側の処理が追い付かず、キー入力が遅れて到達する為だ。
パソコンのOSはマルチタスクで動作しているのでアプリの遅延などは日常茶飯事であるが、だからと言って入力したはずのキーがスキップされてしまうようなことがあっては使い物にならない。よって、キーボード入力はシステムメッセージキューに蓄えられ、それからアプリに送信される仕組みになっているようだ。
蓄えられるといっても通常人間が入力するようなスピードだと溜まることなくアプリケーションに到達するが、今回のようにプログラムから間髪入れずにキーが届く場合はアプリ側の処理が追い付かず、ボタンを離しても既にキューに溜まっている分がすべて出ていくまではアプリケーションにキーが送られ続けるということが起きる。

(参考)
wisdom.sakura.ne.jp

以前のコードではDelayの最小値が1となり、少なすぎた。色々検証した結果、私のケースではDelay が12以上あればアプリ側の処理を超えることが無いことが分かったので、最小Delayを12にすることにした。

問題その2

2つ目の問題はボタンの押し込み量で適切なスピードに調節するのが難しいこと。
そもそも1~255までの値を取れるといっても、狙って1ずつUpさせるのは無理である。
せいぜいこれくらい↓の操作が限界。
f:id:t-hom:20210105201028p:plain

そして、画面スクロールに必要なスピードの種類を考えてみると、3種類で十分であることが分かった。

低速スクロール:表示位置に拘りたい場合の位置合わせ用
中速スクロール:普通に文章を読む際のページ送り用
高速スクロール:読み飛ばしながら目的箇所を探す用

解決策

最終的に次のようなコードでやりたいことができた。

    int r2 = PS4.getAnalogButton(R2);
    if (r2) {
      Keyboard.press(KEY_DOWN_ARROW);
      if (r2 < 100) {
        delay(80);
      } else if (r2 < 255) {
        delay(24);
      } else {
        delay(12);
      }
      Keyboard.releaseAll();
    }

今回没にしたがアイデア備忘録として

L2とR2それぞれ3状態が取れるとしたら、それぞれの強弱を組み合わせて5段階くらいのスピード調節もできることに気づいたので一応アイデア備忘録として書いておく。
f:id:t-hom:20210105204240p:plain
まぁ今回は3段階で十分なのでこのアイデアは使わないんだけど。

また、押し込み量のみでなく押し込み時間で加速させていくという案も考えたので備忘録っておく。
たとえば最初の1秒は低速、2秒目から1秒ごとに加速する。緻密な操作が必要なときは、1秒押し込む度に放せば良い。

今回の学び

さて、今回学んだのはアナログボタンだからといってアナログ値をそのまま使うことに拘らなくて良いということ。
実現したいことが何なのかという目的に立ち返って考えることが重要だと思った。

こういう試行錯誤を繰り返すことで、直感的に操作できるデバイスになっていくんだろうなと思う。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。