🎱

Keyballを縦に回して横スクロールする

に公開

Keyballのデフォルトファームウェアでは、レイヤ3のボール操作でスクロールが可能です。初期状態では縦方向のスクロールのみできますが、これはトラックボールの回転方向に応じて縦横に自由にスクロールさせると誤操作が生じがちなことから、スクロールスナップと呼ぶ仕組みでスクロール方向を制限しているためです。
この記事では、Keyballのトラックボールを使って横スクロールする新たな操作方法を紹介します。

縦スクロールと自由スクロールの切り替え

History of Scroll Snapに「初期は垂直のみ、後に自由スクロールする」という記述があります。

モードを切り替えるキーコードが定義されており、デフォルトの配列ではレイヤ3に割り当てられています。

キーコード 説明
SSNP_VRT (Kb 13) 縦スクロールのみに制限
SSNP_HOR (Kb 14) 横スクロールのみに制限
SSNP_FRE (Kb 15) スクロール方向を制限しない

必要に応じてSSNP_FREでスクロールの制限を解除し、SSNP_VRTで再び縦スクロールのみに戻すという使い方が想定されてそうです。

制限を加えることで比較的利用頻度の高い縦スクロールの操作性を担保し、制限を解除する方法も用意しておくというのはある意味理にかなった仕様だと思います。

しかし、現実のアプリケーションの操作では、自由スクロールのモードだと誤操作しやすいことも確かです。例えばスプレッドシートで横方向にスクロールしようと制限を解除すると、横にスクロールしながら、縦方向にも多少スクロールしてしまうことがありえます。

比較のためホイール付きマウスの操作を見ると、縦スクロールはホイールの回転、横スクロールは左右へホイールを倒す操作で、縦スクロールと横スクロールの操作は明確に分離されており、自由スクロールはできません。実際、縦横斜めに自由にスクロールできることを要求するアプリケーションもぱっと思い浮かばない[1]ので、自由スクロールを使わない方式もよさそうです。

縦スクロールと横スクロールの切り替え

制限を解除するのではなく、SSNP_HORで横スクロールのみに制限するモードとの切り替えを考えてみます。この場合、モードに応じて縦方向のみあるいは横方向のみにしかスクロールできないので、自由スクロールでの誤操作は生じません。

ただし、モードを切り替えるのと合わせてトラックボールの回転方向を縦から横に変える必要があり、難易度が高めです。モードと直交した方向にトラックボールを回してしまうと、全然スクロールしないといったことも起きます。

縦の動きのみで縦横スクロールさせる

そういうわけで、トラックボールの回転の方向は変えずに縦横スクロールさせる方法を考えてみました。モードの切り替えもちょっと工夫して、

  1. レイヤにより縦スクロールと横スクロールを切り替える
  2. 横スクロールに制限する時に、操作方向を90度回転

と実装しました。

1.でモードの切り替えをレイヤ切り替えに同期させ、意識すべき状態を減らしてモードを戻すのを忘れないようにしています。

2.でスクロール操作時のボールの回転を常に縦方向としているので、モード切り替えと合わせてボールを回す指の動きを変える必要がなく、慣れてしまえば操作は容易です。

しばらく使っていますが、個人的にはいい感じです。

実装内容

ファームウェアの変更内容です

(補足)次のセクションに書きましたが、この実装をしなくてもWindows、macでは同様のことができます

レイヤに応じてモードを変える

レイヤ3では縦スクロール、レイヤ4では横スクロールとしました。Keyballの標準ファームウェアではレイヤは0-3の4枚ですが、私の場合はレイヤを一つ増やして0-4の5枚の構成にしています。

keymap.c
layer_state_t layer_state_set_user(layer_state_t state) {
    uint8_t layer = get_highest_layer(state);
    switch (layer) {
        case 3:
            keyball_set_scroll_mode(true);
            keyball_set_scrollsnap_mode(KEYBALL_SCROLLSNAP_MODE_VERTICAL);
            break;
        case 4:
            keyball_set_scroll_mode(true);
            keyball_set_scrollsnap_mode(KEYBALL_SCROLLSNAP_MODE_HORIZONTAL);
            break;
        default:
            keyball_set_scroll_mode(false);
            keyball_set_scrollsnap_mode(KEYBALL_SCROLLSNAP_MODE_VERTICAL);
            break;
    }
    return state;
}

縦回しで横スクロールさせる

横スクロールモードにおいて、垂直方向の変位で水平方向の変位を上書きします。

config.h
#define KEYBALL_SCROLLSNAP_ENABLE 2
#define SCROLLSNAP_HORIZONTAL_SCROLL_BY_VERTICAL_MOTION
keyball.c
__attribute__((weak)) void keyball_on_apply_motion_to_mouse_scroll(keyball_motion_t *m, report_mouse_t *r, bool is_left) {
    // ...
#if KEYBALL_SCROLLSNAP_ENABLE == 1
    // ...
#elif KEYBALL_SCROLLSNAP_ENABLE == 2
    // New behavior
    switch (keyball_get_scrollsnap_mode()) {
        case KEYBALL_SCROLLSNAP_MODE_VERTICAL:
            r->h = 0;
            break;
        case KEYBALL_SCROLLSNAP_MODE_HORIZONTAL:
#ifdef SCROLLSNAP_HORIZONTAL_SCROLL_BY_VERTICAL_MOTION
            r->h = -r->v; // 縦の動きを横スクロールに
#endif
            r->v = 0;
            break;
        default:
            // pass by without doing anything
            break;
    }
#endif
    // 以下略

(追記)標準的な操作の存在

この記事を書いてから、Shift押しながらマウスホイールで横スクロールできるという情報をいただきました。KeyballでもShiftを押しながら縦スクロール操作すると横スクロールになることをWindowsとmacで確認しました。

Firefox 58 でも、Shift + マウスホイールで「戻る/進む」をできるようにする方法 から参照されている Firefox のコードのコメントを見ると、macOSだとShift + マウスホイールでアプリケーションに横スクロールのイベントが来るが、Windowsではアプリケーション側でそれと同じ動作に合わせているようです。Chromeがそういう動きになっていることから標準的な操作と考えてよさそうです。

そういうわけでここで書いた実装は不要になってしまったのですが、自分の場合、レイヤ4の有効化はMO(3)を押しつつレイヤ3に配置したMO(4)を押すことで実現しており、Shift押しながら縦スクロール操作も似た操作なので、方向性としては妥当なものになっていたことがわかったのと、標準操作を学ぶことができたので良しとします。

脚注
  1. Miroでボタン2のドラッグ操作で自由スクロールはありますが、それは別の操作なので該当しません。 ↩︎

Discussion