マウスポインタ操作がある程度できるキーボードを設計してみた (original) (raw)

はじめに

前々から構想を練っていたのですが、やっぱり作って使ってみないとわからないということで、概念実証モデルとしてマウスポインタの操作がある程度できるキーボードを設計してみました。

使用状態

名前は、概念実証である点から、Xプレーンっぽい名前にするかな、と思っていたところ、スイッチと呼べるものの数が両手で52個であり、ちょうどX-52が欠番であるのをいいことに、「KX-52A」としました。「A」はアクリル(Aclylic)のAです。

最初は、ジョイスティック(アナログスティック)を採用しようと思っていたのですが、面積の関係上、比較的コンパクトに収まるスティックスイッチと呼ばれる部品を採用してみました。
また、配列を調整しつつ、チルト*1しつつテント*2している点も特徴です。

以下、詳細について紹介します。

設計の経緯

概念実証モデルと言っているのは、配列のデザインと、筐体全体のデザインはこんな感じかな、というものを図面に起こしたものが既にありました。

構想中のキーボードのレンダリング

このキーボードはチルトしつつテントしているのですが、これは、例えば、あらしさんのCorchimに影響されたもので、ちょっとテントさせると実は使いやすいのでは? と考えるようになったためです。
kbd.arashike.com

実際に、この角度でチルト&テントしているのが使いやすいかどうか、というのは試してみないとわからないと思っていました。
また、マウス操作ができると嬉しいのか、というのも使ってみないとわからないと思っていました。
よって、実際にレンダリングのものとほぼ同様のものをアクリルのサンドイッチ等で簡単に設計し、実際にしばらく使ってみよう、というのが経緯です。
なので、今回は打鍵音等はほとんど考慮せず、可能な限り加工費等が安くなるようにしつつ、手持ちのパーツで作りやすい設計としています。

配列

今回の配列は、特に湾曲などさせず、比較的オーソドックスなカラムスタッガード配列*3としています。

上面図

ここで、今回は珍しく配列が設計の中心ではなく、外形デザインを重視して配列の設計を行っています。見ていただくとわかりますが、全体の外形を平行四辺形になるようにしつつ、余白等のバランスがちょうどよくなるように配列の検討をしました。
比較的小指列の下げ幅を小さめにして、その分、親指クラスターを内側に寄せています。
また、小指列の上には独立したキーを置くスペースを設けています。このキーは、薬指を伸ばして取りに行くことを意図して配置しています。
なお、いつものごとくロータリーエンコーダが手のひらの下に配置されるようにしています。

全体としては、ケース全体がチルトすることを考慮して、下げ幅等が極端にならないように調整しました。

ケース

今回はアクリル等を用いたサンドイッチマウントのケースです。
ただし、一般的なサンドイッチマウントとは異なり、スイッチを固定するプレートの上に、さらにトッププレートを配置しています。これにより、キーキャップのエッジが隠れるように調整しています。

チルトの様子とキーキャップのエッジ

アクリルの厚みは3 mmのものを使用し、スイッチプレートの上面から、トッププレートの上面までの距離を約7.5 mmとなるようにしています。
この距離を7.5 mmにすると、cherryプロファイル等の背が低いキーキャップでは、打鍵時にトッププレートに指が触れてしまう可能性がある点は注意してください。

また、キーボード全体が所定の方向に傾斜するようにしています。
実は、最も長い平行四辺形の対角線を軸として6 °になるようにしており、そうすると、テント角が約3 °、チルト角が約4 °となります。
これはデザインをいろいろやっていてこの値に落ち着いたのですが、方向は若干異なるものの、Corchimとおおよそ同様の角度に落ち着いています。
やっていただければわかりますが、6 °以上の傾斜を斜め方向につけると、ちょっと美しくないのです。

さて、今回はアクリル板を用いてケースを作ったわけですが、このように斜め方向に傾斜させるのは、アクリル板のみでは簡単ではありません。
そこで、今回は3Dプリント品の脚でこのような角度をつけることにしました。

アクリル板に脚だけがついた状態

脚を押し出してから所定の平面でバッサリ切る手順で作ったので、当たり前にピッタリになるわけですが、実際にやってみた瞬間はかなり気持ちよかったです。

なお、アクリルは遊舎工房さんの廃番アクリルカットセールを利用させていただきました。
エッジグリーンという品番らしいですが、程よい透明感がある緑色で、廃番になるのが惜しいくらいのきれいさです。
廃番アクリルカットセール(2023/05)shop.yushakobo.jp
スイッチプレートは、POMの端材を遊舎工房さんでカットしてもらいました。
レーザー加工サービス クリアランスセールshop.yushakobo.jp

スティックスイッチ

今回、マウスポインタを操作するためのデバイスとしては、スティックスイッチと呼ばれるものを採用しました。
物としてはこちらの「RKJXL100401V」です。
RKJXL100401V 製品情報 | RKJXLシリーズ | スイッチタイプ | 多機能操作デバイス | 電子部品検索 | 製品・技術 | アルプスアルパイン
もう生産中止らしいですが、都合のいい特徴があったため採用しました。
このスティックスイッチですが、動作力がジョイスティックと大差なく、かつ、倒れ角がジョイスティックの半分程度、という特徴があります。
省スペース化を考えると、倒れ角が小さいというのはメリットです。また、現状で生産されている部品で、似たようなもの*4はあるのですが、やや動作力が大きいようで、採用を見送りました。

今回採用したものは、8方向に接点があるようで、それぞれの方向に倒すとその方向が導通するようです。
また、間の方向に倒した場合には、その方向の両隣の接点がONになるようです。

最初、QMKのMouse keyを採用すれば一発じゃん、と思っていたのですが、ここには大きな罠がありました。
docs.qmk.fm

せっかく斜め方向にも接点があるのだから、その方向にも動かせるようにするかと思い、独自のキーコードを用意して、例えば上方向と右方向を同時に押したことにすればいいじゃん、と思いました。
実際にやっている方もいましたので、参考にさせていただき、実装自体はすぐでした。
210-203-213-118.ppps.bbiq.jp

一方、実際に使ってみると、スイッチがONになる位置にしているはずなのに動かない、ということがありました。
上記のように書いてしまうと、例えば右上方向と上方向が同時にONになり、その後に右上方向がOFFになると、同時に上方向もOFFになってしまうためでした。
これは困ったということで、上記のページを参照して、QMKで用意している「report_mouse_t」という構造体にマウスの移動量をぶん投げるということを行ってみました。
確かに動きはするのですが、上記の記事でも言及されているように、確かにドラッグができません。

これは、上記の「report_mouse_t」が定義されているQMKのコードを参照すると、構造体のメンバーに、xyのレポート以外にマウスのスイッチのレポートが含まれていることから、xyのレポートのみを単独で投げてしまうと、スイッチが押されていることがレポートされないためと思われます。
qmk_firmware/tmk_core/protocol/report.h at 7aa2ce2b38e7cf38f148d0781eae525d72260b8b · qmk/qmk_firmware · GitHub

これも困ったということで、クリックのキーコードが押されているときにフラグを立て、フラグが立っているときにはxyのレポートと同時にクリックのレポートも送ってしまう、ということで一応の解決をみました。
(プログラマでもなんでもないのでお作法等の間違いがあったらご容赦ください。)

bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch(keycode){ ..... case KC_BTN1: if (record->event.pressed) { is_MS_BTN1 = true; }else{ is_MS_BTN1 = false; } break; .....

void matrix_scan_user (void) { report_mouse_t mouse_report = {0}; ..... if (!is_MS_move) && (!is_WH_move)){ //process_record_user関数内で取得したポインタの移動と //ホイールの移動のフラグが両方とも立っていなければ mouse_move_on_timer = 0; // ポインタの移動が開始されてからの経過 mouse_wheel_on_timer = 0; // ホイールの移動が開始されてからの経過 mouse_state.x = 0; //構造体の移動関係の値をリセット mouse_state.y = 0; mouse_state.v = 0; mouse_state.h = 0;

    if (is_MS_BTN1) { //クリックが押されているか否か
        mouse_state.buttons |= 1; //押されていれば1bit目を1に
    }else {
        mouse_state.buttons &= ~1; //押されていなければ1bit目を0に
    }
    host_mouse_send(&mouse_state); //いったんレポートを送り付ける
}

..... if (timer_elapsed(mouse_timer) > REPEAT_INTERVAL){ //マウス関係のボタンが押されてから所定の時間が経っていたら ..... (ポインタの移動関係の処理) ..... if (is_MS_BTN1) { //クリック状態を判定して mouse_report.buttons |= 1; }else{ mouse_report.buttons &= ~1; } .....

    host_mouse_send(&mouse_report); 
    //移動の状態とクリックの状態を合わせてレポートを送り付ける

.....

(2024.6.27 追記)
前回のコードでは、ドラッグも可能ですし、継ぎ足しのドラッグが可能でした。
しかし、ドラッグ後、マウスボタンを離し、その後何のマウス関係の動作も挟まずにポインタを動かすと、範囲選択が解除される(マウスのクリックが送信される)という事象が発生していました。
様々な検討を行いましたが、マウスの移動処理がされていないときに、レポートを投げていないとうまくいかない、ということがわかりました。
上記のコードで、ドラッグもできるし、継ぎ足しのドラッグもできるし、ドラッグ後、直ちにポインタを移動しても範囲選択が解除されない(クリックされない)ということは確認しましたので、上記のコードを修正版とし、コメントも追記しました。
(追記ここまで)

また、マウススイッチと似たような方法で、各方向のスイッチが押されているかのフラグをprocess_record_user関数内で立て、matrix_scan_user関数内でそのフラグをもとにどの方向にマウスを動かすか、というレポートを出力する、というまあ愚直な実装をしました。
この方法により、8方向接点のうち、隣り合う2方向がONになっている場合には、その間の方向(22.5 °方向)にカーソルを動かす、という実装にし、一応16方向に動くようにしました。

これらの実装については、mouse key自体の実装も参照しながら行いました。
正直結構大変でしたが、とりあえず思い通りに動くようになって良かったです。

あと、スティックのキャップも3Dプリント部品ですが、もうちょっと形状は工夫できたかなと思うので、また調整したいと思います。

マイクロスイッチ

親指クラスタの下に謎の形状の穴と部品らしきものがあるのはお気づきになったでしょうか。
この下にはマイクロスイッチを仕込んでいて、マウスのクリック、ちょっとしたショートカット等を仕込めるようにしています。
薄型のマイクロスイッチ*5があったので、これを採用してみましたが、ちょうど高さが3.5 mmであったため、スイッチプレートに切り欠きを作って、それを押すことで動作するようにしています。

このように独立したマウス用スイッチを設けたのは、慣れるかもしれませんが、レイヤー切り替え等で対応するとなると混乱する可能性があると考えたためです。
また、既存のキーボードからのキーマップをあまり変更したくなく、このように付加する形としています。
(ぶっちゃけた話、デザイン上スペースができたので仕込もう、と思ったというところもあります。)

ロータリーエンコーダ

いつも通りロータリーエンコーダを搭載しているのですが、今回は回路的にチャタリング対策をしています。
これは、五月雨さんから頂いた基板で、そのような対策がしてあり、確かに効果があると思ったためです。
回路自体は五月雨さんのものを参考に、時定数はメーカー推奨の値にしてみました。
note.com

機械式のロータリーエンコーダを多用していると、回しているのに入力が入らない、という現象に遭遇することがあります。
具体的には、右回転をしたはずが入力が入らず、さらに右回転を入力すると、ようやく右回転の結果が出力される、という状態です。この状態で左回転と右回転を交互に1回ずつ入力すると、どちらも入力されない、という状態になります。
EC11系のロータリーエンコーダでは発生頻度は高くありませんでしたが、確かに発生することはあったので、ロータリーエンコーダを多用する身としては、ハード的に対策してみるか、と思った次第です。

いただいた基板で検証したところ、意地悪なほど高速回転しても上記のような現象は発生せず、そこまで必要な部品も多くないしやっておくか、と思いました。
現状この文章を書いている時点では上記現象が発生する様子もなく、快適に使用できています。
この場を借りて五月雨さんにはお礼申し上げます。

使ってみた感想

まず、チルトとテントの角度についてですが、おそらくちょうどよさそう、という感触です。
ちょっと予想外だったのは、やや筐体が厚めなので、パームレストは使うんだろうなと思っていたのですが、パームレストなしでも違和感なく使えるという点です。
また、このようにややチルトすることで、下段のキーを打つ際に指を曲げる空間があり、窮屈な感じが解消されるということがわかりました。今まで平置きを前提にしていましたが、多少はチルトさせた方がいいのかもしれないと思い始めました。
何事も試してみるものですね。

テントについては、実は最近メインのキーボードもテントさせて使用しており、それと同じくらいの角度であるため、特に違和感なく使えています。
親指側が少し上がった状態で構えることになるため、無理に内旋する感覚もなく、疲れにくい印象です。

実際に仕事で使ってみて、疲労度等をみて、実際にこの角度で行くかは検証したいと思います。

次に、スティックスイッチですが、さすがにCADの操作はやりたくないですが、通常の操作はそこそこの精度でできるかな、といった感じです。
さすがにマウス(トラックボール)の方が速いので、連続してマウスポインタを操作をする場合にはマウスの方がよいと思いますが、文章作成の合間にマウスをちょっと触りたいという用事の場合にはこれで事足りるかな、といった感触です。
元々、ヘビーなマウス操作を意図したものではないので、これくらいでOKかもしれないと思いました。頑張って操作の挙動を実装した甲斐があったというものです。
また、スティックの位置は、人差し指をちょっと曲げた状態でアクセスでき、上下左右のどの方向でも操作しやすい位置としたつもりでしたが、位置としては正解のような気がします。
一方で、スティック自体の形状ですが、もうちょっと調整の余地があるかなと思いました。触って中央位置がわかりやすいように突起をつけましたが、位置は確かにわかりやすい一方、思ったよりこの突起が指に食い込むので、形状を調整したいと思います。

マイクロスイッチですが、こちらの位置が若干窮屈ではあるのですが、親指を曲げれば無理なくアクセスはできるし、ここ以外に配置のしようがないというのが正直なところなので、もう少し軽く押せるように機構を工夫したいと思います。
板を曲げる形式だと、曲げるための板の長さが確保しにくかったという面はありますが、やや重たくなりがちだなと思いました。
位置に関して言えば、押し間違いは思ったよりしにくく、分離しておく意味はあるかなと思っています。

おわりに

概念実証くらいのスタンスで、まあマイコンボードの実装方法が多少トリッキー*6でもいいでしょ、という無茶苦茶な部分はありますが、見た目も含めて思ったよりデバイスとしての完成度が高く、結構満足しています。

マイコンの位置に注目

配列およびチルト&テントの角度についても組み合わせのバランスがよくできたと思っています。
今までに設計したキーボードの中には、下段のキーの打ちにくさを感じる場面がありましたが、このキーボードはチルトのおかげか下段も打ちやすく、ちょうどいいバランスに仕上がったと思います。

外形に関しては、単純な形状の方がカッコいいのでは? という雑な思想に基づいてデザインしてみましたが、おおむねその通りで、単純な形状の持つある種の力強さみたいなものは大切なんだなと思いました。

さて、なかなかよさそうということがわかってくると、打鍵音とか打鍵感にこだわった同じ設計のキーボードが欲しくなってきてしまったので、構造の検討を続けていこうと思います。
実は、レンダリング画像のケースについていえば、発注できなくもないという段階まで内部の構造等も詰めてあったのですが、さすがにこのままGOするのはちょっと……と思って試作してみました。
内部構造はともかく、形状と配列などはよさそうということが確認できたので、詳細を詰めていこうと思います。

この記事は、マウス操作も含めてKX-52Aで書きました。