読者です 読者をやめる 読者になる 読者になる

IOHIDSystemメモ

Mac

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,
                                            ...

とある。


IOCommandGateのドキュメントより、

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

IOWorkLoopのドキュメント

virtual IOReturn addEventSource(
    IOEventSource *newEvent);
  • IOEventSource

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っぽい。



…あぁややこしい。


というわけで作ってみる。実験環境を作るのは面倒だ。いつも使っている環境でテストすればイイ!