IOHIDSystemメモ
MacのHuman Interface Deviceのメモ。Tiger。
最近、RealForceをゲットしました。これ、最高です。ヤバいです。
が、Mac OS Xで、無変換キーとか、かなキーとかが効かない。そもそもキーコードすら拾えない。ここにいろいろキーをセットしたいのに、できない。
WinKというシェアウェアを使うと適当なキーを割り振ってくれるのですが、キーが固定なので気に入らない。何故にカスタマイズできないのかと。
WinKと同じようなもので、iJectとかuControlとかfKeysなどなどがある。でもやっぱりキーが固定。でも幸いこれらはオープンソースなので、足がかりにできる。
というわけで、とりあえずカーネルに潜入してみる。まぁ細かいことは後で考える。
で、レイヤーからして2つ方法がありそう。
1つは、USBキーボードのデバイスドライバを置き換える方法。
もう一つは、デバイスドライバのもう一つ上のレイヤーでキーコードをフックする方法。
iJectもuControlもfKeysも全部後者の方法を使っているので、その線で探る。ただUSBドライバの段階でキーコードを無視されていたら困るな。まぁ後で考える。
WinKは不明だけど、「対応キーボード一覧」などなどがあるところからして、前者っぽい。
さて、まずIOKitというのが怪しい。C++でできているらしい。
- IOHIDSystem
/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/Kernel.framework/Versions/Current/Headers/IOKit/hidsystem/IOHIDSystem.h
このクラスがとりあえずキーコードを拾ってきてくれるらしい。ウェブにはドキュメント無し。
で、このヘッダファイルの600行目付近、 「COMMAND GATE COMPATIBILITY」というのがおそらく使える。
/* * COMMAND GATE COMPATIBILITY: * The following method is part of the work needed to make IOHIDSystem * compatible with IOCommandGate. ...(中略)... The static methods * will be called from cmdGate->runAction and returns the appropriate * non-static helper method. ...(中略)... static IOReturn doKeyboardEvent (IOHIDSystem *self, void * args); void keyboardEventGated (unsigned eventType, unsigned flags, unsigned key, unsigned charCode, ...
とある。
An IOCommandGate instance is an extremely lightweight mechanism that executes an action on the driver's work-loop
- IOService
/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/Kernel.framework/Versions/Current/Headers/IOKit/IOService.h
IOHIDSystemの基底クラス。IOServiceのドキュメント
virtual IOWorkLoop * getWorkLoop() const;
- IOWorkLoop
virtual IOReturn addEventSource( IOEventSource *newEvent);
- IOEventSource
virtual void setAction( IOEventSource::Action action);
typedef void (*Action)( OSObject *owner, ...);
…いやマテマテ、IOWorkLoop自体のドキュメント(→Handling Events→EventSource)があった。
で、ここにIOHIDSSystemのソースコードがある。
IOHIDSystem::start()の中で、IOWorkLoopに、アクションがIOHIDSystem::doProcessKeyboardEQ()のIOInterruptEventSourceを登録している。
続いてI/Oのドキュメント→Handling Events→EventSource→IOFilterInterruptEventSourceを読む。IOWorkLoopは、IOInterruptEventSourceを呼ぶ前に、IOFilterInterruptEventSourceを呼んでくれて、そのIOInterruptEventSourceにフィルタがかけられるらしい。
というわけで、IOHIDSystemにgetWorkLoop()して、このIOWorkLoopに、フィルタ対象がIOHIDSystem::doProcessKeybaordEQ()のIOFilterInterruptEventSourceをaddEventSourceすればOKっぽい。
…あぁややこしい。
というわけで作ってみる。実験環境を作るのは面倒だ。いつも使っている環境でテストすればイイ!