2009-05-23 35 views
19

我正在使用Robot類在Java中製作一個小程序。該程序接管了鼠標。而在調試過程中,如果它開始以我不想退出程序的方式進行操作,因爲我無法將鼠標移到eclipse中的終止按鈕上,也無法使用熱鍵點擊它,因爲鼠標在另一個窗口中不斷點擊,反而給予該窗口焦點。在Java中監聽沒有焦點的輸入

我想要做的就是掛上一個keylistener,這樣當我打q時我可以退出程序,但我知道如何做到這一點的唯一方法就是創建一個窗口,並且該窗口需要重點關注捕獲輸入。有沒有辦法從任何地方聽取鍵盤或鼠標輸入,無論焦點是什麼?

回答

13

這不是一個小問題,Java並沒有給你一種優雅的方式。您可以使用像banjollity建議的解決方案,但即使這樣也不會一直工作,例如,如果您的錯誤鼠標點擊打開您的任務欄中當前打開的另一個全尺寸窗口。

事實是,Java默認情況下給開發人員很少的操作系統控制權。這是由於兩個主要原因:安全性(由java文檔引用)和不同操作系統完全不同地處理事件以及使用統一模型來表示所有這些事實可能沒有太大意義。

所以要回答你的問題,我想你想要的是你的程序的某種行爲,它在全球範圍內監聽按鍵,而不僅僅是在你的應用程序中。像這樣的東西需要你訪問你所選擇的操作系統所提供的功能,並且你需要通過Java Native Interface(JNI)層來訪問它。

所以,你想要做的是:

  1. 實現在C程序,將聽您的操作系統的全球按鍵,如果操作系統是Windows比尋找文檔在其上還有docuemented窗鉤由微軟和MSDN在網絡和其他地方提供。如果您的操作系統是Linux或Mac OS X,那麼您將需要使用X11開發庫來監聽全局按鍵。這可以在ubunutu linux發行版上完成,根據我在http://ubuntuforums.org/showthread.php?t=864566

  2. 寫的一個Howto。通過JNI將您的C代碼連接到您的Java代碼。這一步實際上是更簡單的一步。請按照我在我的教程中使用的步驟在http://ubuntuforums.org/showthread.php?t=864566下在windows和linux下執行,因爲將C代碼連接到Java代碼的過程在兩個操作系統上都是相同的。

要記住的重要一點是,它更容易讓你的JNI代碼的工作,如果你第一個代碼和調試C/C++代碼,並確保其工作正常。然後將它與Java集成很容易。

+0

這可以用java curses完成嗎? http://sourceforge.net/projects/javacurses/ – RadijatoR 2015-07-29 15:37:08

0

從終端的命令行啓動程序並使用Ctrl-C來終止它。

+0

在我看來,這是正確的答案。這個問題表明它僅用於調試,並且完全不需要修改代碼。 – user2623008 2018-01-08 13:46:05

0

讓程序打開第二個窗口,該窗口顯示在主窗口下方,但被最大化,然後您的錯誤鼠標點擊將全部通過最大化窗口接收,並且它可以接收您的鍵盤輸入。

1

有同樣的問題。就我而言,機器人只是控制了一個Windows應用程序,這是最大化的。我將這些線放在驅動機器人的主循環頂部:

顏色iconCenterColor = new Color(255,0,0); //如果程序圖標爲紅色

if(iconCenterColor.equals(robot.getPixelColor(10,15))) 拋出新的IllegalStateException(「機器人不與正確的應用程序交互」。

要取消機器人,只需將alt-tab鍵切換到另一個應用程序即可。適用於簡單的應用程序驅動機器人。

+0

忘了否定測試。然後它很好用: – user467317 2010-10-05 21:13:45

17

有就是爲您做的辛勤工作庫: https://github.com/kwhat/jnativehook

+0

這個答案應該被標記爲正確的。顯然,Java生態系統確實提供了一個簡單的方法來優雅地完成此任務。 – 2016-09-20 21:09:28

0

這裏是一個純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(); 
}