シナリオは次のとおりです。2 つの Java アプリケーションがあります。1 つ目は、Swing GUI を使用するビジュアル アプリケーションで、すべてが非常に複雑な動作 (非常に古いコード ベース) を持つ JFrame にまとめられており、変更することはできません。JFrame オブジェクトへのフックがあるだけです。
2 番目のアプリケーションは、私が書いているもので、基本的には最初のアプリケーションのユニット テスターです。JFrame フックと JDI を使用して、これらのテストを実行するために必要なすべてのイントロスペクションを行うことができました。実際、私のテストはうまくいっているので、バックグラウンドで実行したいと思っています。ただし、私のテストの多くは KeyEvents と MouseEvents を JFrame にディスパッチする必要があるため、ウィンドウがフォーカスを失うとこれらは停止します。私が読んだことから、これはデフォルトの KeyboardFocusManager の要件が原因のようです。これは、これらのイベントを、表示され、フォーカスされているコンポーネントにのみディスパッチします (これには、それらを含むウィンドウが表示され、フォーカスされている必要もあります)。これは私の質問に私をもたらします:
KeyboardFocusManager がプロセスを停止することなく、特定のスイング コンポーネントにイベントを「強制的に」ディスパッチするにはどうすればよいですか?
重要な注意: これらのイベントをディスパッチしたいコンポーネントは、永続的なフォーカス所有者としても登録されます。これにより、ウィンドウがフォーカスされていないときにどのコンポーネントがイベントを受け取るべきかというあいまいさを取り除くことができます (KeyboardFocusManager.getGlobalPermanentFocusOwner())
イベントの作成方法: (かなり単純なもの)
public void keyPress(int keycode, char c) {
KeyEvent press = new KeyEvent(content, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, keycode, c);
pushEventToQueue(press);
}
public void mousePress(int buttons) {
MouseEvent press = new MouseEvent(content, MouseEvent.MOUSE_PRESSED,
System.currentTimeMillis(), buttons, curX, curY, 1, false);
pushEventToQueue(press);
}
私が試したこと(そしてなぜそれらがうまくいかなかったのか):
Component.dispatchEvent(event) を介してイベントをディスパッチします。コンポーネントが KeyboardFocusManager を介してルーティングされるため (奇妙なことに)、コンポーネントを表示する必要があるため、これは機能しません。
上記の理由により、KeyboardFocusManager.dispatchEvent(event) を介してイベントをディスパッチします。
Component.requestFocus() または .requestFocusInWindow() を呼び出すと、イベントを配信できますが、ウィンドウ コンテナーも強制的にフォーカスされ、ウィンドウが前面に表示されるため、うまくいきません。
パーマネント フォーカス オーナーのリスナーを繰り返し処理し、カスタム イベントでイベント関数を呼び出します。これが機能しなかった理由は正確にはわかりませんが、通常のアプリケーション機能でさまざまなフォーカス所有者を介した伝播が行われていないことに関係があると思われます。
これが私の現在の pushEventToQueue 関数で、失敗したコメントアウトされた部分が含まれています。
private void pushEventToQueue(AWTEvent evt) {
// Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(evt);
// Component perm = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
// if (perm == null) {
// content.dispatchEvent(evt);
// } else {
// if (evt instanceof KeyEvent) {
// for (KeyListener l:perm.getKeyListeners()) {
// if (evt.getID() == KeyEvent.KEY_PRESSED)
// l.keyPressed((KeyEvent) evt);
// else if (evt.getID() == KeyEvent.KEY_RELEASED)
// l.keyReleased((KeyEvent) evt);
// else if (evt.getID() == KeyEvent.KEY_TYPED)
// l.keyTyped((KeyEvent) evt);
// }
// } else if (evt instanceof MouseEvent) {
// for (MouseListener l:perm.getMouseListeners()) {
// if (evt.getID() == MouseEvent.MOUSE_PRESSED)
// l.mousePressed((MouseEvent) evt);
// else if (evt.getID() == MouseEvent.MOUSE_RELEASED)
// l.mouseReleased((MouseEvent) evt);
// else if (evt.getID() == MouseEvent.MOUSE_CLICKED)
// l.mouseClicked((MouseEvent) evt);
// }
// } else
// perm.dispatchEvent(evt);
// }
content.dispatchEvent(evt);
try {
Thread.sleep(50); //Minimal but necessary
} catch (InterruptedException e) {
e.printStackTrace();
}
}
現在考えられる唯一の方法は、KeyboardFocusManager クラスを拡張し、現在の JVM にウィンドウがない場合に、選択したフォーカスされていないコンポーネントにフォーカスをデフォルト設定する機能を追加することです。フォーカスがあります (つまり、すべての Java ウィンドウがバックグラウンドにあります)。デフォルト以外の動作を示す唯一のケースは、すべてのウィンドウがフォーカスされていない場合であるため、これによって既存のプログラム機能が妨げられないことが理想的です。
swing アプリケーションのコード ベースを変更できません。つまり、KeyListeners の代わりに KeyBindings を実装することも、swing コンポーネントの isFocused/isShowing メソッドをオーバーライドすることもできません。私にできることは、リフレクションまたは JDI が提供するものであれば何でも構いませんが、この場合は少し役に立たないようです。
誰もこれを経験していますか?誰でもガイダンスを提供できますか?