5

キーバインディングが、マッピングされている文字ではなく、キーボード上のキーの位置に固有であるアプリケーションを作成したいと思います。たとえば、US キーボードの t と u の間にあるキーは、それが米国の Y であるか、ドイツの Z であるかに関係なく、特定の機能を実行する必要があります。

これを行う方法は、キーボードからOSに与えられた実際のスキャンコードを取得して、押されたキーを表すことだと思います。Javaでこれを行うにはどうすればよいですか?

または、同じ機能を実現する別の方法はありますか?

4

2 に答える 2

5

Oracle の KeyEvent ソース コードからの抜粋:

//set from native code.
private transient long rawCode = 0;
private transient long primaryLevelUnicode = 0;
private transient long scancode = 0; // for MS Windows only
private transient long extendedKeyCode = 0;

まず、KeyEvent のtoString()の戻り値にスキャンコードが含まれているため、これを解析することを考えました。しかし、その後、リフレクションを使用するユーティリティ メソッド (Windows 8 で正常に試行されました) を作成しました。

final public static Integer getScancodeFromKeyEvent(final KeyEvent keyEvent) {

    Integer ret;
    Field field;

    try {
        field = KeyEvent.class.getDeclaredField("scancode");
    } catch (NoSuchFieldException nsfe) {
        System.err.println("ATTENTION! The KeyEvent object does not have a field named \"scancode\"! (Which is kinda weird.)");
        nsfe.printStackTrace();
        return null;
    }

    try {
        field.setAccessible(true);
    } catch (SecurityException se) {
        System.err.println("ATTENTION! Changing the accessibility of the KeyEvent class' field \"scancode\" caused a security exception!");
        se.printStackTrace();
        return null;
    }

    try {
        ret = (int) field.getLong(keyEvent);
    } catch (IllegalAccessException iae) {
        System.err.println("ATTENTION! It is not allowed to read the field \"scancode\" of the KeyEvent instance!");
        iae.printStackTrace();
        return null;
    }

    return ret;
}

setAccessible() 行がコメントアウトされているときにこのメソッドを使用すると例外が発生したため、後でフィールドのアクセシビリティをリセットする必要はないようです。(私はその場で前後に変更し、ランタイムがまだオンになっている間に IntelliJ で再コンパイルしました。Eclipse でも同じはずです。) ただし、最初に isAccessible() メソッドを使用すると、簡単に可能になります。

キーボード言語を QWERTZ と QWERTY の間で変更すると音符が完全に入れ替わるため、キーボードで音楽を再生するためのスキャンコードが必要でした。スキャンコードのような値に合法的にアクセスできないのは本当に悲しいことです。上記のソリューションは、現在のキーボード レイアウト構成を正常に無視しました。

ちなみに、US キーボード レイアウトでの「z」と「y」の toString の戻り値は次のとおりです。

[KEY_PRESSED,keyCode=90,keyText=Z,keyChar='z',keyLocation=KEY_LOCATION_STANDARD,rawCode=90,primaryLevelUnicode=122,scancode=44,extendedKeyCode=0x5a] on frame0]
[KEY_PRESSED,keyCode=89,keyText=Y,keyChar='y',keyLocation=KEY_LOCATION_STANDARD,rawCode=89,primaryLevelUnicode=121,scancode=21,extendedKeyCode=0x59] on frame0]

DE キーボード レイアウトの場合:

[KEY_PRESSED,keyCode=89,keyText=Y,keyChar='y',keyLocation=KEY_LOCATION_STANDARD,rawCode=89,primaryLevelUnicode=121,scancode=44,extendedKeyCode=0x59] on frame0]
[KEY_PRESSED,keyCode=90,keyText=Z,keyChar='z',keyLocation=KEY_LOCATION_STANDARD,rawCode=90,primaryLevelUnicode=122,scancode=21,extendedKeyCode=0x5a] on frame0]

スキャンコードに注意してください。

おまけとして、トピック外:

[KEY_PRESSED,keyCode=10,keyText=Enter,keyChar=Enter,keyLocation=KEY_LOCATION_STANDARD,rawCode=13,primaryLevelUnicode=13,scancode=28,extendedKeyCode=0xa] on frame0]
[KEY_PRESSED,keyCode=10,keyText=Enter,keyChar=Enter,keyLocation=KEY_LOCATION_NUMPAD,rawCode=13,primaryLevelUnicode=13,scancode=28,extendedKeyCode=0xa] on frame0]
[KEY_PRESSED,keyCode=49,keyText=1,keyChar='1',keyLocation=KEY_LOCATION_STANDARD,rawCode=49,primaryLevelUnicode=49,scancode=2,extendedKeyCode=0x31] on frame0]
[KEY_PRESSED,keyCode=97,keyText=NumPad-1,keyChar='1',keyLocation=KEY_LOCATION_NUMPAD,rawCode=97,primaryLevelUnicode=49,scancode=79,extendedKeyCode=0x61] on frame0]
于 2014-11-01T11:29:49.237 に答える
4

MadProgrammerが言ったように: JNA または JNI を使用する必要があります。これらのプロジェクトもご覧いただけます。

JIntellitype は、Microsoft Intellitype コマンドとやり取りしたり、Java アプリケーションでグローバル ホットキーを登録したりするための Java API です。API は、C++ DLL を使用して Windows とのすべての通信を行う Java JNI ライブラリです。

同様のプロジェクトLinuxMac OS Xがあります。


JNativeHook は、Java 用のグローバル キーボードおよびマウス リスナーを提供するライブラリです。これにより、ピュア Java では不可能なグローバル ショートカットやマウス モーションをリッスンできます。このタスクを達成するために、JNativeHook は Java のネイティブ インターフェイスを介してプラットフォーム依存のネイティブ コードを利用して、低レベルのシステム全体のフックを作成し、それらのイベントをアプリケーションに配信します。


Windows のみ、Win 7 / 8 (32 および 64 ビット) に対応


于 2013-06-22T23:04:50.270 に答える