4

Capslock のプレスをグローバルにインターセプトしてブロックするために、Quartz CGEventTap を使用しています (代わりに何か役に立つことをさせるため)。capslock の押下を検出することに成功しましたが、これまでのところそれらをブロックできませんでした。私のコード(このスタックオーバーフローの回答に由来する)は次のようなものです:

eventTap = CGEventTapCreate(kCGHIDEventTap,
                            kCGTailAppendEventTap, 
                            kCGEventTapOptionDefault, 
                            eventMask,
                            myCGEventCallback,
                            &oldFlags);

runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);

CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);

CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef theEvent, void *refcon)
{
    CGEventFlags *oldFlags = (CGEventFlags *)refcon; 

    switch (type)
    {
        case kCGEventFlagsChanged:
        {
            CGEventFlags newFlags = CGEventGetFlags(theEvent);
            CGEventFlags changedFlags = *oldFlags ^ newFlags; 
            *oldFlags = newFlags;

            if (changedFlags == 65536)
            {
                NSLog(@"Capslock pressed. Let's not return the event");
                return NULL;
            }
            break;
        }
        default:
            break;
    }

    NSLog(@"Different modifier than capslock. Returning the event");
    return theEvent;
}

私が正しく NULL を返すことを理解していれば、キープレスの伝播を効果的にブロックするはずです。実際、「通常の」キーアップおよびキーダウン イベントでも同様です。ただし、capslock は関係なくトグルします。それはなぜですか?私は間違った仮定をしていますか? および/または、目標を達成するためにどうすれば別のことを行うことができますか?

ありがとう、

ソー

4

1 に答える 1

9

そのように capslock をブロックすることはできません。Capslock は、Window Server や個々のアプリケーションではなく、キーボード ドライバーによって処理される状態です。キー押下イベントは、OS X で次のように伝播します。

キーボード ドライバー -> ウィンドウ サーバー -> ユーザー セッション -> アクティブなアプリケーション

各レベルの伝播 ("->" で示される) で、イベント タップを配置し、キー イベントをブロックおよび/または変更できます。キーボード ドライバーとウィンドウ サーバーはどちらも特権コンポーネントであり、他の 2 つは通常のユーザー レベルのコンポーネントです。

キーボード イベントを最も早くキャッ​​チできるのは、イベントがドライバー (カーネル スペース) からウィンドウ サーバー (ユーザー スペースですが、まだ権限が付与されている) に伝播するときです。ただし、前述のように、capslock の状態はドライバーの内部で処理されるため、そこでイベントをキャッチするのは既に遅すぎます。ドライバーは、キーボードの capslock ライトを既に有効にしており (必要な場合であり、ハードウェア自体によって実行されない場合)、capslock の状態がオンになっていることを記憶しています。これは、今後のすべてのキー押下に影響します。

HIDデバイスのcapslockライトをプログラムでオフにすることができます(Appleにはそのためのサンプルコードもあります)が、これはcapslockをオフにするのではなく、ライトをオフにするだけです.

イベント タップの使用を実装する唯一の方法は、capslock を使用してキーを押すたびに、capslock を使用しないキーを押すように手動で書き直すことです (capslock フラグが設定されておらず、添付されている文字がある場合は小文字です)。さらに、ユーザーを混乱させないために、Apple のサンプル コードに示されているように capslock ライトをオフにします。

他の代替手段は次のとおりです。Appleの標準ドライバーの代わりにキーボードを制御する独自のキーボードドライバーを作成するか(思ったほど難しくはありませんが、それでも十分に難しいです)、ドライバーにハッキングします(悪ですが、機能します)。たとえば、一部のキーボード リマッパーはドライバーの単一のメソッドのみをオーバーライドします (ドライバーは OS X では C++ であるため、オブジェクト指向オブジェクトであり、実行時に C++ メソッドを動的にオーバーライドできます。実際にオーバーライドするのではなく、メソッド テーブルを操作します)。これら 2 つの解決策の問題点は次のとおりです。最初の方法は、使用しているドライバーが Apple のものと同じくらい優れていない場合、そのドライバーで動作しない USB キーボードもあれば、動作するものもあるということです。システムは、カーネル パニックでこの間違いを罰します。

Macでcapslockをプログラムで切り替える方法を探していますが、これまでのところ成功していません。ただし、イベント タップは適していません。

于 2010-06-21T14:26:08.780 に答える