最近BlenderやUnityなど、3D系のソフトを使う機会が多くなってきたんですが、普段使いのトラックボールは致命的なことに、ミドルボタン(ホイールボタン?)がありません。
大抵の3Dソフトでは、視点操作でこのボタンを多用するので、その時だけ仕方なく3ボタンマウスに持ち替えたりしていました。
ここはひとつ、自作キーボードの知見を活かして、トラックボールのエンドゲームを目指してやろうという話です。
コンパニオンアプリは使いたくない派
そもそも専用アプリでボタン操作をカスタマイズできるので、それを使えば良いというご意見もあると思います。
しかし、複数PCに差し替えて使いたかったり、会社PCにコンパニオンアプリがうまく入らないなどといったやんごとなき理由があるので、今回はハードウェア的に解決することにしました。
欲しい機能は何か?
さて、多くの3Dソフトでは、ミドルボタンはModキー(CtrlとかShiftとか)との同時押しでオービット、視点移動などに割り当てられていることが多いです。
そういえば、いま思えば左手でCtrlを押しながら右手でマウス操作というのも地味に面倒だったので、ついでにここでまとめてやっつけようと思います。
ボタンの組み合わせは、操作するソフトによって違うので、後々モード切り替え的な機能も作ろうと思いますが、まずは一番使う頻度の高いblenderをターゲットにします。
そうすると必要なボタンはこの3つ。
- オービット: Middle
- 平面移動: Shift + Middle
- スムースズーム: Ctrl + Middle
これにモード切り替えを付けるとして、4つのボタンがあればとりあえず良さそうです。
コントローラーやらファームウェアやら
タイトルのとおり、作ろうとしているものはほぼ自作キーボードというか、マクロパッド的なものです。
コントローラーには、最近いつも使っているラズパイピコ互換機を使うことにします。本家はUSBがMicro-Bですが、この互換機(厳密には一部ピンが違う)はType Cなので最高なのです。
ファームウェアは、自キ系のをサクッと入れれば良いでしょという考えでしたが、次のような紆余曲折あって、素のCorcuitPythonを使うことにしました。
- RubyベースのPRK Firmwareを使ってみたい
- マウスキーの機能が開発途上ぽい?
- いつものPythonベースKMK Firmware
- なぜかマウスキーとMODキーの順番がコントロールできない、どうやってもマウスキー先押しになってしまう。
- 重鎮QMK Firmware
- ビルド環境の立ち上げがメンドい
そもそも自キファームウェア導入の最大メリットって、キーマップと同時押しの管理だと思います。
4キーしかない上に、物理的に同時押しもできない今回の用途なら、CircuitPythonでコンパクトにまとめるのが気楽だなってなりました。
図面
考えているだけでは、なかなか手を動かすに至らないので、まずは図面というかポンチ絵を描きました。(経験上、プロトタイプを作る前に机上で作り込んでしまうと、頭の中でだけブラッシュアップされて一向にモノができない状態になりがちなので、プロトタイプ用のメモはきれいに書かないというのが最近のマイルールです)
これをもとに、ガシガシとプロトタイプを作っていきます。
静音スイッチを使いたい
スイッチはタクトスイッチを使うのが一番安上がりで簡単ですが、せっかく静音化したトラックボール(※以下ツイート参照)に、またカチカチを追加するのは良い気がしません。
たまたま背の低いゴムタイプの静音スイッチが手元にあったらので、これを採用することにしました。
つくる
ここまで来たらあとは作るだけです。
仮設なので、スイッチは両面テープで貼り付けて
配線すればハードウェアは完成です。
最終的にはUSBハブモジュールを組み込んでケーブルを一本にまとめる予定ですが、とりあえずはパラで2本挿しする運用でいきます。
プログラム
CircuitPythonデバイスをUSB HIDをして動かすには、Adafruit HIDライブラリを使います。
そして、こちらがエイヤッと書いたプログラムです。 キーマップ周りがちょっと最適化されてない感はありますが、まあ自分的には及第点。
import time import board import digitalio import usb_hid from adafruit_hid.keyboard import Keyboard from adafruit_hid.keycode import Keycode from adafruit_hid.mouse import Mouse keypress_pins = [board.GP10,board.GP11,board.GP12,board.GP13,] key_pin_array = [] time.sleep(1) keyboard = Keyboard(usb_hid.devices) mouse = Mouse(usb_hid.devices) for pin in keypress_pins: key_pin = digitalio.DigitalInOut(pin) key_pin.direction = digitalio.Direction.INPUT key_pin.pull = digitalio.Pull.UP key_pin_array.append(key_pin) led = digitalio.DigitalInOut(board.LED) led.direction = digitalio.Direction.OUTPUT # Button layout # 0 # 2 # 1 # 3 keymap = [ Keycode.CONTROL, Keycode.ALT, Keycode.SHIFT, '', ] while True: print("Waiting for key ...") for key_pin in key_pin_array: if not key_pin.value: # コモンをGNDにしたので、value=0がON led.value = True i = key_pin_array.index(key_pin) print(f"Pin #{i} is grounded.") # キーとマウス中ボタンをセットで送出 if keymap[i] is not '': keyboard.press(keymap[i]) mouse.press(Mouse.MIDDLE_BUTTON) # キーを離すまで待機 while not key_pin.value: pass # キーを離したらぜんぶリリース keyboard.release_all() mouse.release_all() led.value = False time.sleep(0.01)
使用感
しばらく使ってみたところ、これは期待以上の使用感!
片手で3Dの視点操作が完結するので、これはもう簡易的な3Dマウスと言っていいんじゃないだろうか。
なんなら、市販の3Dマウスはカーソル操作ができなかったりするので、用途によってはこっちの方が良いこともあるかも。
あと、その気になればいくらでもカスタマイズできる自由度の高さが、心の余裕につながります。
つぎの課題
さて、期待以上の使用感とは言ったものの、完成度はまだまだ概念実証レベルといった感じ。
ここからは、トラックボールのエンドゲームを目指して、スイッチの種類や配置を模索してみようと思うので、その話も近々。