JNAを使用してグローバルキーストロークを登録する

こんにちは、この記事では、優れたJNAライブラリを使用して、Windows、Linux、BSD、およびMac OSXでJavaからグローバルキーストロークを登録する方法を説明します。



JNAとは何ですか?



Javaは、オペレーティングシステムとやり取りするためのブリッジを作成する必要があるため、デスクトップと友達になることは困難です。 これらの機能の1つはグローバルなホットキーです。これは、オーディオプレーヤーで非常に人気があり、非表示の状態でも特定のキーボードショートカットまたはメディアボタンを使用してプログラムを制御できます。 JNAが助けになります-ネイティブライブラリを呼び出すためのjniとlibffiのアドオンで、ほぼすべての一般的なプラットフォームをサポートし、長い間開発されており、非常に安定しています。



すべてのプラットフォーム用のJava用のかなり安定したライブラリが既にいくつかあります。Windows用のJIntelliType(メディアボタンもサポート)、Linuxシステム用のJXGrabKey 、Mac OSX用のossuport-connectorです。 ただし、これらはすべてjniを使用し、異なるインターフェイスを持ち、ネイティブライブラリへのパスを登録したり、システム容量を処理したりする必要があるため、jniでライブラリを操作するのが常に便利であるとは限りません。かなり少ない労力でJavaで完全に実行でき、クロスプラットフォームコードを簡単にサポートできます。



窓



Windowsでグローバルホットキーを使用する最も簡単な方法は次のとおりです。



パブリック クラス User32 {

static {

ネイティブ register ( NativeLibrary。getInstance ( "user32" 、W32APIOptions。DEFAULT_OPTIONS ) ) ;

}



public static final int MOD_ALT = 0x0001 ;

public static final int MOD_CONTROL = 0x0002 ;

public static final int MOD_SHIFT = 0x0004 ;

public static final int MOD_WIN = 0x0008 ;

public static final int WM_HOTKEY = 0x0312 ;



public static native boolean RegisterHotKey (ポインターhWnd、 int id、 int fsModifiers、 int vk ) ;

public static native boolean UnregisterHotKey ( Pointer hWnd、 int id ) ;

public static native boolean PeekMessage ( MSG lpMsg、Pointer hWnd、 int wMsgFilterMin、 int wMsgFilterMax、 int wRemoveMsg ) ;



パブリック スタティック クラス MSG は Structure {

パブリックポインターhWnd ;

public intメッセージ;

public int wParam ;

public int lParam ;

パブリック int時間。

public int x ;

public int y ;

}

}




ここでは、いわゆる直接マッピングを使用します。 静的インポートを行い、メソッドをネイティブメソッドとして使用できるため、高速であることに加えて、作業が簡単になります。 User32の3つのメソッドが必要です。



X11



残念なことに、FreeBSDで作業しているときに何らかの理由でエラーが発生するため、X11に直接マッピングを使用することはできません。 マッピングはもう少し複雑に見えます:



パブリック インターフェイス X11 はライブラリを拡張します{

public static X11 Lib = ( X11 ) ネイティブ 。 loadLibrary ( "X11" 、 X11。class ) ;

public static final int GrabModeAsync = 1 ;

public static final int KeyPress = 2 ;



public static final int ShiftMask = ( 1 ) ;

public static final int LockMask = ( 1 << 1 ) ;

public static final int ControlMask = ( 1 << 2 ) ;

public static final int Mod1Mask = ( 1 << 3 ) ;

public static final int Mod2Mask = ( 1 << 4 ) ;

public static final int Mod3Mask = ( 1 << 5 ) ;

public static final int Mod4Mask = ( 1 << 6 ) ;

public static final int Mod5Mask = ( 1 << 7 ) ;



パブリックポインターXOpenDisplay ( 文字列名) ;

パブリック NativeLong XDefaultRootWindow (ポインター表示) ;

public byte XKeysymToKeycode (ポインター表示、 長いキーシム) ;

public int XGrabKey (ポインター表示、 intコード、 int修飾子、NativeLongルート、 int ownerEvents、 int pointerMode、 int keyBoardMode ) ;

public int XUngrabKey (ポインター表示、 intコード、 int修飾子、NativeLongルート) ;

public int XNextEvent (ポインター表示、XEventイベント) ;

パブリック int XPending (ポインター表示) ;

public int XCloseDisplay (ポインター表示) ;



public static class XEvent は Union {を 拡張し ます

パブリック int型。

public XKeyEvent xkey ;

public NativeLong [ ] pad = new NativeLong [ 24 ] ;

}



public static class XKeyEvent extends Structure {

パブリック int型。 //イベントの

ネイティブNativeLongシリアル; //サーバーによって処理された最後のリクエストの数

public int send_event ; //これがSendEventリクエストから来た場合はtrue

パブリックポインターディスプレイ; // publicイベントの読み取り元を表示します

パブリック NativeLongウィンドウ。 //相対で報告される「イベント」ウィンドウ

パブリック NativeLongルート。 //イベントが発生したルートウィンドウ

パブリック NativeLongサブウィンドウ。 //子ウィンドウ

パブリック NativeLong時間; //ミリ秒

public int x、y ; //イベントウィンドウ内のポインターx、y座標

public int x_root、y_root ; //ルートを基準にした座標

パブリック int状態。 //キーまたはボタンマスク

public int keycode ; //詳細

public int same_screen ; //同じ画面フラグ

}

}




Mac OSX



Mac OSXのコードの基礎は、ossupport-connectorの作者であるTorsten Uhlmannの仕事です。



パブリック インターフェイス Carbon がライブラリを拡張 {

public static Carbon Lib = (カーボン) ネイティブ 。 loadLibrary ( "Carbon" 、 Carbon。class ) ;



public static final int cmdKey = 0x0100 ;

public static final int shiftKey = 0x0200 ;

public static final int optionKey = 0x0800 ;

public static final int controlKey = 0x1000 ;



// OS_TYPEは文字列文字をintに連結します

private static final int kEventClassKeyboard = OS_TYPE ( "keyb" ) ;

private static final int typeEventHotKeyID = OS_TYPE ( "hkid" ) ;

private static final int kEventParamDirectObject = OS_TYPE ( "----" ) ;



public Pointer GetEventDispatcherTarget ( ) ;



public int InstallEventHandler ( Pointer inTarget、EventHandlerProcPtr inHandler、 int inNumTypes、EventTypeSpec [ ] inList、Pointer inUserData、PointerByReference outRef ) ;

public int RegisterEventHotKey ( int inHotKeyCode、 int inHotKeyModifiers、EventHotKeyID。ByValue inHotKeyID、Pointer inTarget、 int inOptions、PointerByReference outRef ) ;

public int GetEventParameter ( Pointer inEvent、 int inName、 int inDesiredType、Pointer outActualType、 int inBufferSize、IntBuffer outActualSize、EventHotKeyID outData ) ;

public int RemoveEventHandler ( Pointer inHandlerRef ) ;

public int UnregisterEventHotKey ( Point inHotKey ) ;



パブリック クラス EventTypeSpec は Structure {

public int eventClass ;

public int eventKind ;

}



public static class EventHotKeyID extends Structure {

パブリック int署名。

public int id ;



パブリック スタティック クラス ByValue は、 EventHotKeyIDを拡張し、 Structureを実装します。 ByValue {

}

}



public static interface EventHandlerProcPtr extends Callback {

public intコールバック( Pointer inHandlerCallRef、Pointer inEvent、Pointer inUserData ) ;

}

}






おわりに



一般に、すべてが非常に単純ですが、FreeBSDで直接マッピングを使用するとクラッシュするなどの問題がありましたが、JNAはXGrabKeyのブール値をintにマッピングすることを拒否しました。ホットキーがすでに使用されている場合、プログラムが単純に削減されるため、Carbonに関するドキュメントを見つけるのが困難になります。



このコードはすべて、LGPL 3ライセンスの下でjkeymasterライブラリにコンパイルされ、インターフェイスはSwingのKeyStrokeに基づいており、WindowsおよびX11の場合、メディアボタン(再生/一時停止、停止、次のトラック、前のトラック)を登録できます。



コメントとパッチを歓迎します。



ps投稿はtulskiyによって書かれました 。これはmgarinのおかげで今ハブにあります 彼へのすべてのプラス。



All Articles