キーボード共有機能に沸く2021年6月
WWDCから結構経っちゃいましたが、WWDC2021の最高潮のポイントは__Universal Control__だったのではないかと思います。
おおーと思ったものの、多くの人はこうも思ったと思うのです。
「iPadよりも隣に置いてあるWindowsやLinuxマシンとのキーボード共有がしたいんだけれど」
奥さん、できますよそれ
Barrier
本題です。KVMソフトBarrierを使ってMacをホストにしつつ、WindowsマシンでMagic KeyboardやMagic Mouseをそのまま使って気持ちよくなろうというのがこの記事です。
Windows-Mac間で使えるKVMソフトとしてはSynergyやSharemouseなどが有名だとは思いますが、これらは有料ライセンス販売のソフトになります。僕もちょっと前から存在は知っていましたが、有料であることと、JIS対応がどうやらイマイチっぽいような話を小耳に挟んでいたのであんまり試す気にはなれずに放置していました。WWDCをきっかけに再びKVMへの気持ちが湧き上がってきて調べていたところ、__Barrier__に出会いました。
BarrierはSynergyがオープンソースだった頃のソースコードからフォークされたプロジェクトで、UI部分も含めた状態で全て公開されています。
無料なら一旦使ってみるかという気持ちで導入してみました。
導入環境
本記事では以下のような環境への導入を行っています
サーバー: macOS 10.15(Mac mini 2018)
クライアント: Windows 10 20H2(AMD環境)
Barrierは現時点で最新のリリースビルドのv2.3.3をそれぞれの環境にインストールしています
できること・問題点
ざっと試してみてクリティカルなものから軽微なものまでいくつかぶつかった問題があったのでまとめていきます。
できる事
- Mac-Windows間のマウス・キーボードの共有
- サーバーから送信する修飾キー(
Ctrl
,Meta
,Super
,Alt
)のカスタマイズ - クリップボード共有、またそれぞれのクリップボード拡張アプリにヒストリーが蓄積される
- Windowsクライアント上でのAHKなどを用いたキー入力の上書き
- Macサーバー上でのKarabinerなどを用いて上書きしたキー入力の送信(一部ソフトでの結果は反映されず)
- Windowsクライアント上でのMagic Mouseの慣性スクロール
- Windowsクライアントへのボタン付きマウスのボタンの送信
思ったよりもしっかり動いてて感動しました。それぞれ有線LANに繋いでいる環境下ではありますが、遅延もほぼなく、日常動作では困らなさそうな精度を保っています。サーバー、クライアントそれぞれでキーバインドの変更などを行なっていることもあると思いますが、Karabiner・AHK・PowerToysは自分の環境では問題なく動作しています。ただ、Hammmerspoonやエレコムのマウスユーティリティはもう少し上のレイヤーで動作しているためかクライアントまでキーコードが伝播しませんでした。
サーバーから送信する修飾キー(Ctrl
, Meta
, Super
)のカスタマイズ
これが個人的には結構大きかったところなのですが、Barrierではコード弄らなくてもアプリケーション側から送信するキーをカスタマイズできます。
どういう事かというと通常Magic KeyboardなどMac配列のキーボードをそのままWindowsで使うとCommand(⌘)キー
がWindowsキー
に当たってしまって大変厳しい思いをするのですが、アプリケーションサイドで送信するキーをカスタマイズできるため、Windowsのレジストリなどを弄らなくても修飾キーの配列を変えることができます。ただし、修飾キーは全て__左側のキー__として認識されるため、左右で動作を変えるようにAHKを組むときなどは少し工夫が必要です。自分の環境ではControlキー
を左Control
、Commandキー
を右Control
として扱ってAHKを書いているので、Command
から送信されるキーを右側にする修正を入れています。
できない事
軽微な問題
-
かな・英数キー
が飛ばずにスペース
が飛ぶ -
ctrl+alt+del
がクライアントのWindows上で実行されない -
capslock
の挙動が怪しい(日本語入力モードでcapslock
を入れると入力を受け付けなくなるなど) -
Super
,Control
などの装飾キーが全て左側のキーとして送信される - Macサーバーにおいてクライアント側操作時でも、Barrierよりも上のレイヤーで動いているキーカスタマイズソフトを使っている場合はキー入力などがMac側に反映されてしまう
クリティカルな問題
- JISキーボードの__
¥(|)キー
が飛ばない__ - Mac同士を繋いだときにキーボード共有が効かない
- keystrokeでクライアントに送るキーコードをオーバーライドするとサーバー側で該当するキーが効かなくなる
JIS配列のキーがいくつか飛ばないなどの問題は事前にある程度情報を見ていたため、予想通りなところはあったのですが、Mac同士で繋ぐとそもそもキーが一切飛ばないのはちょっとびっくりしました。ここはUniversal Controlに期待ですね・・・
ctrl+alt+del
がクライアントのWindows上で実行されない
これに関しては困る人は困るかもしれませんが、僕の環境だとあんまり使うこともないのでそのままにしています。一応ソースコード上には__fakeCtrlAltDel
__なる関数があり、何やら実装されてそうな雰囲気がありますが、自分の環境では現状こいつは効いてなさそうでした。issueにも上がっていたのですが、ちょっと不思議なワークアラウンドを残してクローズされてしまっていました。こちらのワークアラウンドは実際に自分の環境でも再現できたので、修飾キーの送信で何か問題が起きているのかもしれませんが、デバッグログを見る限りはfakeCtrlAltDel
は通っていそうなので権限回りで弾かれてそうな感じもします。
capslock
の挙動が怪しい
英数入力だと問題ありませんが、日本語入力時に効かなくなります。
これの解決は簡単ですね。__CapsLockを無効化__してしまえば解決です。使わないキーは潰してしまいましょう。
...__OSXKeyState.cpp
__のキーモディファイア周りを触っていたときに正しく動作したりしていたので、この辺りの条件判定を弄くり回せば直りそうですが、そこまでの気持ちはなかったので放置しています。
JISキーボードの¥キー
が飛ばない
これはまぁまぁ厳しいです。
まず、MacのJISキーボードの¥は実はWindowsのようにバックスラッシュ
のキーコードを上書きしているとかいう動作ではなく、__international3
__という独自のキーコードが割り当てられています。現在最新のBarrier(v2.3.3)ではこのinternational3
のキーコードからWindows上での¥
にマッピングするコードがなく、そのままキーコードを送るとマッピングをすり抜けてキーコードが何も実行されないという状態になります。
これを解決するために
-
OSXKetState.cpp
内で__0x005c
にkVK_JIS_Yen(¥キーのキーコード)
__をマッピングする - サーバーのコンフィグに__
keystroke(Shift+Backspace) = keystroke(Bar)
__を追記する
といったワークアラウンドを紹介されているブログがあり、こちらの方法を試してはみたのですが、これでは完璧に解決には至りませんでした。
まず、なぜ上記のような手順になっているかというと、1のように¥キー
に直接Windowsにおける¥キー
のコード0x005c
を割り当てているのですが、 この0x005c
が厄介で、Barrierからこのキーコードを送信すると、¥(|)
のキーではなく、_(ろ)
から入力される¥キー
、すなわち__Win+_(アンダーバー)
__のキーコードが送信されます。なのでこのままShift+¥
を入力しても|(Bar)
が入力されないという状況になります。
これをなんとか|(Bar)
が入力されるようにするため行っているのが2の設定です。Barrier(Synergy)のサーバーコンフィグにはキー入力を上書きする設定、__keystroke__があるのですが、これを使うとクライアント側では設定が上書きされてちゃんと入力できるようになるものの、サーバーサイドでShift+¥
を入力したときに何も反応しなくなってしまいます。この問題はissueも立っているのですが、本家Synergyでは長年放置されている状態でいつ対応されるかわからないので一旦この方法は忘れて違う方向性で修正していくことにしました。
ということで以下の
-
かな・英数キー
が飛ばずにスペース
が飛ぶ -
Super
,Control
などの装飾キーが全て左側のキーとして送信される - JISキーボードの
¥(|)
キーが飛ばない
3つの問題について修正するコードを用意しました。
修正コード
...略
{ kKeyBrightnessDown, s_brightnessDown },
// JIS keyboards only
- { kKeyEisuToggle, kVK_JIS_Eisu },
- { kKeyKana, kVK_JIS_Kana }
+ { kKeyMuhenkan, kVK_JIS_Eisu },
+ { kKeyHenkan, kVK_JIS_Kana }
};
...略
if ((changed & KeyModifierSuper) != 0) {
- handleModifierKey(target, s_superVK, kKeySuper_L,
+ handleModifierKey(target, s_superVK, kKeySuper_R,
(newMask & KeyModifierSuper) != 0, newMask);
}
if ((changed & KeyModifierCapsLock) != 0) {
ここでは
-
かな・英数キー
にWindowsの変換・無変換キー
を当てる -
Commandキー
を左から右に変える
ということをやっています。1.に関してはどうもバグらしく、修正PRが今立っていますが、こちらを試しても自分の環境ではあんまりうまくいかなかったので、変換・無変換キー
にマップすることにしました。
2.は単純にL
をR
に置き換えただけです。ちなみにここからBarrier側の設定でSuper
をControl
に当てるということをやっていますが、右Control
として当てられていました。Altキー
に設定しても同様に右Alt
として割り当てられます。
static const KeyID kKeyMissionControl = 0xE0C0;
static const KeyID kKeyLaunchpad = 0xE0C1;
+ // for mac jis keyboard
+ static const KeyID kKeyMacJISYen = 0x00A5;
//@}
struct KeyNameMapEntry {
kKeyKP_6, 0x0036,
kKeyKP_7, 0x0037,
kKeyKP_8, 0x0038,
- kKeyKP_9, 0x0039
+ kKeyKP_9, 0x0039,
+ kKeyMacJISYen, 0x005c // keyremap for Mac JIS keyboard
};
ここでは
-
key_state.h
へのMacJISキーボードの¥キーコード
定義の追加 -
KeyState.cpp
では追加したMacJISキーボードの¥キーコード
へのWinでの¥キーコード
のマッピング
を行っています。
このKeyState.cppはサーバーから受け取ったキーコードの解決に使われていますが、該当コード内に適切なキーコード置き換えブロックがなかったため、とりあえずキーパッド(テンキー)
の置き換え箇所の中にねじ込んでいます。この方法においてはMacからの入力を別のキーコードに差し替えたりせず、クライアント側でのリマップに委ねているため、Shift+¥
はそのまま|
になります
Mac->Win間において0x00A5
に当たっているキーコードはなかったようなのでこのような実装にしてみましたが、他のOS環境下でぶつかるキーコードがあったら悪さをする可能性もあるのでご注意ください。
あとがき
これらの修正コードをビルドしてそれぞれの環境にインストールすればMacJIS環境とWindowsの快適なキーボード・マウス共有環境が出来上がります。
Barrierを導入するまでは複数デバイス切り替え機能つきのBluetoothキーボードにてそれぞれのデバイス間のキーボードの切り替えを行っていましたが、操作したいデバイスにキーボードを切り替え忘れていて、事故りそうになるなどが頻発していました。Barrierではマウスの位置にキーボードが追従するため、自然と見ている画面への入力ができるようになります。またBarrierとともにAutoHotKeyなどを併用することで、Windows上でそこそこMacに近いキーバインドも再現できています。
Windowsアレルギーだという方もこの環境であれば少しは気持ちよくWindowsを使えるようになるのではないかと思います。