3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【QMK Firmware】トラックボールに精密カーソルモードと縦横スクロール機能を実装する

3
Posted at

はじめに

最近、トラックボール付きのキーボードを自作しました。

image.png

Auto-Keyboard-Design-Kit(auto-kdk)という便利なツールを利用して0から自分好みのキーボードを作ることができて、しばらくは満足に仕事に趣味に大活躍させていました。

しかし、ある時気が付いてしまいました...
自分がトラックボールの動作に満足できていないことに。

具体的には、下記の3機能を実装したくなりました。

  • マウスカーソルの動きを大きくしたい
  • とはいえ細かい操作をすることもあるので、精密モードを実装したい
  • トラックボールによる縦横スクロール機能を実装したい

無事実装できたので、同じような方のために方法を共有します。
QMK firmwareを採用しているキーボードであれば同様に実装できると思いますので、参考になれば幸いです。

マウスカーソルの動きを大きくする

paw3222.c
report_mouse_t paw3222_get_report(report_mouse_t mouse_report) {
  report_paw3222_t data = paw3222_read();
  if (data.isMotion) {
    pd_dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y);

-    mouse_report.x = data.x;
-    mouse_report.y = data.y;
+    mouse_report.x = data.x * 3;
+    mouse_report.y = data.y * 3;
  }

  return mouse_report;
}

まずは、マウスカーソルの動きを大きくする方法です。
単純に考えると、上記のpaw3222.cに対する変更のようにmouse_report.xmouse_report.yを決めているところを見つけて、そこに倍率をかけてあげるとカーソルの動きもその分速くなりそうです。

ところがどうやら、mouse_report.xmouse_report.yとして設定できる値には上限と下限(-127~127)があり、倍率をかけて値の絶対値が127を超える場合は上限と下限までしか加速できないようです。

ではどうするか?
QMK firmwareのドキュメントを読むと、config.h#define MOUSE_EXTENDED_REPORTという設定を追加するとその上限と下限を-32767~32767に上げることができると書いてあります。

・#define MOUSE_EXTENDED_REPORT
 ・Enables support for extended reports (-32767 to 32767, instead of -127 to 127), which may allow for smoother reporting, and prevent maxing out of the reports. Applies to both Pointing Device and Mousekeys.
引用:Quantum Mechanical Keyboard Firmware
https://docs.qmk.fm/config_options

config.h
#pragma once

#define VIAL_KEYBOARD_UID {0x4c, 0x94, 0x48, 0x5e, 0x0c, 0x21, 0xae, 0x6c}
#define DYNAMIC_KEYMAP_LAYER_COUNT 6
#define VIAL_TAP_DANCE_ENTRIES 8
#define VIAL_COMBO_ENTRIES 8
#define PICO_FLASH_SIZE_BYTES (1 * 1024 * 1024)
#define POINTING_DEVICE_INVERT_X
#define POINTING_DEVICE_INVERT_Y
+#define MOUSE_EXTENDED_REPORT

ドキュメントの通り追加してみると、トラックボールの動きに対してのカーソルの動きが大きくスムーズになりました。

精密カーソルモード

トラックボールの動きが速くなると、今度は細かいカーソル操作が難しくなってしまいました。そこで、Ctrlキーを押している間だけカーソルの動きがゆっくりになる、いわゆる精密カーソルモードを実装することにしました。

そのためにはまず、Ctrlキーが押されていることを検知する必要があります。
QMK Firmwareの実装を見ると、今押されている修飾キーをbitmaskで返してくれるget_modsという関数がありました。これを使うことにします。

action_util.c
/**
* @brief Retrieve current state of modifiers.
*
* @return Current state of the modifier keys as a bitmask.
*/
uint8_t get_mods(void) {
   return real_mods;
}

出典:QMK Firmware
https://github.com/qmk/qmk_firmware/blob/master/quantum/action_util.c

get_modsを使うためにaction_util.hをインクルードして、通常時はデフォルトの3倍のスピードでマウスポインタを動かし、Ctrlキーが押されているときはデフォルトのスピードでマウスポインタを動かす実装にしました。

paw3222.c
+#include "action_util.h"
+#define TRACKBALL_DEFAULT_SPEED_MULTIPLIER 3
+#define TRACKBALL_SLOW_SPEED_MULTIPLIER 1

report_mouse_t paw3222_get_report(report_mouse_t mouse_report) {
  report_paw3222_t data = paw3222_read();
  if (data.isMotion) {
    pd_dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y);

+    uint8_t multiplier = (get_mods() & MOD_MASK_CTRL)
+                             ? TRACKBALL_SLOW_SPEED_MULTIPLIER
+                             : TRACKBALL_DEFAULT_SPEED_MULTIPLIER;
+    int16_t x = data.x * multiplier;
+    int16_t y = data.y * multiplier;
-    mouse_report.x = data.x * 3;
-    mouse_report.y = data.y * 3;
+    mouse_report.x = x;
+    mouse_report.y = y;
  }

  return mouse_report;
}

実際の動きはこんな感じです👇

縦横スクロール

次に縦横のスクロールです。
Altキーを押している間だけトラックボールの動きをマウスポインタではなくスクロールホイールの動きとして扱うことにしました。

上下スクロールはmouse_report.v、左右スクロールはmouse_report.hに移動したい距離を設定すれば実現できます。
上下スクロールと左右スクロールが同時に走ると混乱しそうなので、トラックボールの縦方向の移動量の絶対値と、横方向の移動量の絶対値を比べて大きく動いている方のスクロールのみ行う実装としました。また、動かしてみたところスクロールの動きが早すぎたので、トラックボールからの入力をSCROLL_DIVISOR 12で割っています。

paw3222.c
+#define SCROLL_DIVISOR 12

report_mouse_t paw3222_get_report(report_mouse_t mouse_report) {
  report_paw3222_t data = paw3222_read();
  if (data.isMotion) {
    pd_dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y);

    uint8_t multiplier = (get_mods() & MOD_MASK_CTRL)
                             ? TRACKBALL_SLOW_SPEED_MULTIPLIER
                             : TRACKBALL_DEFAULT_SPEED_MULTIPLIER;
    int16_t x = data.x * multiplier;
    int16_t y = data.y * multiplier;

+    if (get_mods() & MOD_MASK_ALT) {
+      if ((x < 0 ? -x : x) > (y < 0 ? -y : y)) {
+        mouse_report.h = x / SCROLL_DIVISOR;
+      } else {
+        mouse_report.v = y / SCROLL_DIVISOR;
+      }
+    } else {
      mouse_report.x = x;
      mouse_report.y = y;
+    }
  }

  return mouse_report;
}

上記の実装でもまあまあいい感じにスクロールできたのですが、調べると、トラックボールの動きを変数にためておいて実際にスクロールが発生したらそのスクロールに対応する分だけためておいた移動量を減らすというやり方でスムーズにスクロールできるらしいことが分かりました。(下記リンク参照)

上記の実装を参考に、トラックボールが動いた分にできる限り正確に対応した量のスクロールが発生する実装に修正しました。

paw3222.c
report_mouse_t paw3222_get_report(report_mouse_t mouse_report) {
+  static int16_t scroll_h_remainder = 0;
+  static int16_t scroll_v_remainder = 0;

  report_paw3222_t data = paw3222_read();
  if (data.isMotion) {
    pd_dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y);

    uint8_t multiplier = (get_mods() & MOD_MASK_CTRL)
                             ? TRACKBALL_SLOW_SPEED_MULTIPLIER
                             : TRACKBALL_DEFAULT_SPEED_MULTIPLIER;
    int16_t x = data.x * multiplier;
    int16_t y = data.y * multiplier;

    if (get_mods() & MOD_MASK_ALT) {
      if ((x < 0 ? -x : x) > (y < 0 ? -y : y)) {
+        scroll_h_remainder += x;
+        scroll_v_remainder = 0;
-        mouse_report.h = x / SCROLL_DIVISOR;
+        mouse_report.h = scroll_h_remainder / SCROLL_DIVISOR;
+        scroll_h_remainder -= mouse_report.h * SCROLL_DIVISOR;
      } else {
+        scroll_v_remainder += y;
+        scroll_h_remainder = 0;
-        mouse_report.h = x / SCROLL_DIVISOR;
+        mouse_report.v = scroll_v_remainder / SCROLL_DIVISOR;
+        scroll_v_remainder -= mouse_report.v * SCROLL_DIVISOR;
      }
    } else {
+      scroll_h_remainder = 0;
+      scroll_v_remainder = 0;
      mouse_report.x = x;
      mouse_report.y = y;
    }
  }

  return mouse_report;
}

実際の動きはこんな感じです👇

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?