web-dev-qa-db-ja.com

Java)でフォーカスなしで入力をリッスンする

Robotクラスを使用してJavaで小さなプログラムを作成しています。プログラムがマウスを引き継ぎます。デバッグの過程で、望まない方法で動作し始めた場合。 Eclipseの終了ボタンにマウスを移動できないため、プログラムを終了するのは困難です。また、マウスが別のウィンドウを常にクリックし、代わりにそのウィンドウにフォーカスを与えるため、ホットキーを使用してプログラムを押すことができません。

私がやりたいのは、qを押したときにプログラムを終了できるようにキーリスナーを接続することですが、これを行う方法を知る唯一の方法はウィンドウを作成することであり、そのウィンドウは入力をキャプチャするためにフォーカスを必要とします。何に焦点が合っているかに関係なく、どこからでもキーボードまたはマウスの入力を聞く方法はありますか?

21
Alex

これはささいな問題ではなく、Javaはエレガントにそれを行う方法を提供しません。 banjollityが提案するようなソリューションを使用できますが、たとえば、誤ったマウスクリックで現在タスクバーに開いている別のフルサイズのウィンドウを開くと、それでも常に機能するとは限りません。

実際のところ、デフォルトではJavaは開発者にOSの制御をほとんど与えません。これは2つの主な理由によるものです:セキュリティ(Javaドキュメントで引用)と、異なるオペレーティングシステムがイベントを完全に異なる方法で処理し、これらすべてを表す1つの統合モデルを作成してもそれほど多くはないでしょう。センスの。

ですから、あなたの質問に答えるために、あなたが望むのは、アプリケーションだけでなく、グローバルにキー押下をリッスンするプログラムのある種の動作だと思います。このような場合は、選択したOSが提供する機能にアクセスする必要があり、Javaでアクセスするには、Java Native Interface(JNI)を介してアクセスする必要があります。 )レイヤー。

だからあなたがしたいことは:

  1. このOSがWindowsの場合は、Webやその他の場所でMicrosoftやMSDNによって十分に文書化されているWindowsフックに関するドキュメントを探すよりも、OSでグローバルキー押下をリッスンするプログラムをCで実装します。 OSがLinuxまたはMacOS Xの場合は、X11開発ライブラリを使用してグローバルキーの押下をリッスンする必要があります。これは、私が http://ubuntuforums.org/showthread.php?t=864566 で書いたハウツーに従ってubunutulinuxディストリビューションで実行できます。

  2. JNIを介してCコードをJavaコードに接続します。このステップは実際には簡単なステップです。 WindowsとLinuxの両方で http://ubuntuforums.org/showthread.php?t=864566 のチュートリアルで使用する手順に従います。 CコードをJavaコードに接続する手順は、両方のOSで同じです。

覚えておくべき重要なことは、最初にC/C++コードをコーディングしてデバッグし、それが機能していることを確認すると、JNIコードを機能させるのがはるかに簡単になるということです。そうすれば、それをJavaと統合するのは簡単です。

13
ldog

あなたのために大変な仕事をするライブラリがあります: https://github.com/kwhat/jnativehook

24
MasterID

同じ問題がありました。私の場合、ロボットは最大化された単一のWindowsアプリを制御しました。ロボットを駆動するメインループの上部にこれらの線を配置しました。

色iconCenterColor = new Color(255,0,0); //プログラムアイコンが赤の場合

if(iconCenterColor.equals(robot.getPixelColor(10,15)))throw new IllegalStateException( "ロボットが適切なアプリと対話していません。");

ロボットをキャンセルするには、Altキーを押しながら別のアプリに移動します。シンプルな1つのアプリ駆動ロボットに最適です。

2
user467317

ターミナルのコマンドラインからプログラムを開始し、Ctrl-Cを使用してプログラムを終了します。

1
Glenn

プログラムに、メインウィンドウの下に表示されているが最大化されている2番目のウィンドウを開いてもらうと、誤ったマウスクリックがすべて最大化されたウィンドウによって受信され、キーボード入力を受信できるようになります。

0
banjollity

これがあなたが説明した問題を解決するための純粋なJava方法です(KeyListenerの問題ではありません...ロボットの問題を使用するときは早期にテストを終了してください):

テスト全体を通して、マウスの位置をテストで最近設定された位置と比較します。一致しない場合は、テストを終了します。注:重要このコードの一部はtestPositionメソッドです。最近使用したコードは次のとおりです。

public void testSomething() throws Exception {
    try {
        // snip

        // you can even extract this into a method "clickAndTest" or something
        robot.mouseMove(x2, y2);
        click();
        testPosition(x2, y2);

        // snip
    } catch (ExitEarlyException e) {
        // handle early exit
    }
}

private static void click() throws InterruptedException {
    r.mousePress(InputEvent.BUTTON1_DOWN_MASK);
    Thread.sleep(30 + Rand.nextInt(50));
    r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
    Thread.sleep(30 + Rand.nextInt(50));
}

private static void testPosition(int x2, int y2) throws ExitEarlyException {
    Point p = MouseInfo.getPointerInfo().getLocation();
    if(p.x != x2 || p.y != y2) throw new ExitEarlyException();
}
0
durron597