当我们同时按下WIN_HOME + L键时窗口被锁定。我们可以在VB中找到很好的例子来监听窗口锁定事件。但我正在为Java做窗口锁定监听器。我做了一些研究并制作了一个监听窗口锁定事件的监听程序。它有两个接口和一个带JFrame的主程序,并使用JNA库。
WindowUser32.java
public interface WindowUser32 extends User32
{ public static final WindowUser32 MYINSTANCE = (WindowUser32) Native.loadLibrary("user32", WindowUser32.class, W32APIOptions.UNICODE_OPTIONS);
public int SetWindowLong(WinDef.HWND hWnd, int nIndex, Callback callback);
}
WindowListener.java
public interface WindowListener extends StdCallCallback
{
public LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam);
}
主要类LockListener.java
public class LockListener
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setVisible(true);
HWND hwnd = new HWND();
hwnd.setPointer(Native.getWindowPointer(frame));
Wtsapi32.INSTANCE.WTSRegisterSessionNotification(hwnd, Wtsapi32.NOTIFY_FOR_ALL_SESSIONS);
WindowListener listener = new WindowListener()
{
@Override
public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WinUser.WM_SESSION_CHANGE)
{
switch (wParam.intValue())
{
case Wtsapi32.WTS_SESSION_LOCK:
System.out.println("Locked " + new Date());
break;
case Wtsapi32.WTS_SESSION_UNLOCK:
System.out.println("Unlocked " + new Date());
break;
}
}
return User32.INSTANCE.DefWindowProc(hWnd, uMsg, wParam, lParam);
}
};
WindowUser32.MYINSTANCE.SetWindowLong(hwnd, WindowUser32.GWL_WNDPROC, listener);
// Wtsapi32.INSTANCE.WTSUnRegisterSessionNotification(hwnd);
}
}
如果我们的框架处于可见状态,则上面的代码效果很好,但当框架可见性设置为false或框架被图标化时,上述代码不起作用。
如果框架被图标化,我们如何实现上面的监听器?
答案 0 :(得分:3)
它似乎适用于隐藏窗口"如JNA' Win32WindowDemo所示。因此,而不是附加一个"本机Windows事件监听器"到JFrame,使用"隐藏窗口"作为后台服务。
我将Win32WindowDemo剥离到与问题相关的部分,并添加了一些部分来启动和停止它作为后台服务。请注意,创建HWND的线程也必须用于读取HWND的消息(如果另一个线程尝试读取消息,则没有任何反应)。
首先显示带有来自Win32WindowDemo的消息的JFrame的主类:
import java.awt.*;
import javax.swing.*;
public class WinLockDetect {
public static void main(String[] args) {
try {
new WinLockDetect().demo();
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("serial")
void demo() throws Exception {
final JTextArea detectMsgs =new JTextArea();
final JFrame window = new JFrame() {{
getContentPane().add(detectMsgs);
setSize(400, 200);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}};
EventQueue.invokeLater(new Runnable() {
public void run() {
window.setVisible(true);
};
});
Win32EventDetector winSessionDetect = new Win32EventDetector();
winSessionDetect.setMsgLogger(detectMsgs);
new Thread(winSessionDetect).start();
Thread.sleep(500L);
window.setState(java.awt.Frame.ICONIFIED);
}
}
接下来将Win32WindowDemo的精简版本作为后台服务:
import java.util.concurrent.*;
import javax.swing.JTextArea;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.*;
import com.sun.jna.platform.win32.WinDef.*;
import com.sun.jna.platform.win32.WinUser.*;
public class Win32EventDetector implements WindowProc, Runnable {
/** FIXME: don't know if this number is a real message ID. */
private static final int DESTROY_LISTENER = 4242;
volatile boolean closed = true;
Semaphore closing = new Semaphore(0);
WString windowClass;
HMODULE hInst;
HWND hWnd;
JTextArea detectMsgs;
public void setMsgLogger(JTextArea detectMsgs) {
this.detectMsgs = detectMsgs;
}
void println(String msg) {
if (detectMsgs == null) {
System.out.println(msg);
} else {
detectMsgs.append('\n' + msg);
detectMsgs.setCaretPosition(detectMsgs.getDocument().getLength());
}
}
@Override
public void run() {
// define new window class
windowClass = new WString("Win32EventDetectorClass");
hInst = Kernel32.INSTANCE.GetModuleHandle("");
WNDCLASSEX wClass = new WNDCLASSEX();
wClass.hInstance = hInst;
wClass.lpfnWndProc = Win32EventDetector.this;
wClass.lpszClassName = windowClass;
// register window class
User32.INSTANCE.RegisterClassEx(wClass);
getLastError();
// create new window
hWnd = User32.INSTANCE
.CreateWindowEx(
User32.WS_EX_TOPMOST,
windowClass,
"My hidden helper window, used only to catch the windows events",
0, 0, 0, 0, 0,
null, // WM_DEVICECHANGE contradicts parent=WinUser.HWND_MESSAGE
null, hInst, null);
getLastError();
println("window sucessfully created! window hwnd: "
+ hWnd.getPointer().toString());
closed = false;
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() { close(); }
});
Wtsapi32.INSTANCE.WTSRegisterSessionNotification(hWnd,
Wtsapi32.NOTIFY_FOR_THIS_SESSION);
println("Listening for window messages.");
try {
MSG msg = new MSG();
while (User32.INSTANCE.GetMessage(msg, hWnd, 0, 0) != 0) {
if (msg.message == DESTROY_LISTENER) {
System.out.println("Got destroy message.");
break;
}
println("Got a new message: " + msg.message);
User32.INSTANCE.TranslateMessage(msg);
User32.INSTANCE.DispatchMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Stopped listening for window messages.");
destroy();
}
private void destroy() {
try {
Wtsapi32.INSTANCE.WTSUnRegisterSessionNotification(hWnd);
User32.INSTANCE.UnregisterClass(windowClass, hInst);
User32.INSTANCE.DestroyWindow(hWnd);
System.out.println("Hidden native window destroyed.");
} catch (Exception e) {
e.printStackTrace();
} finally {
closed = true;
closing.release();
}
}
public void close() {
if (closed) { return; }
User32.INSTANCE.PostMessage(hWnd, DESTROY_LISTENER, null, null);
try {
if (closing.tryAcquire(1000L, TimeUnit.MILLISECONDS)) {
System.out.println("Hidden native window closed.");
} else {
System.out.println("Hidden native window could not be closed within time-out.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public LRESULT callback(HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WinUser.WM_CREATE: {
println("onCreate: WM_CREATE");
return new LRESULT(0);
}
case WinUser.WM_DESTROY: {
User32.INSTANCE.PostQuitMessage(0);
return new LRESULT(0);
}
case WinUser.WM_SESSION_CHANGE: {
this.onSessionChange(wParam, lParam);
return new LRESULT(0);
}
default:
return User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
public int getLastError() {
int rc = Kernel32.INSTANCE.GetLastError();
if (rc != 0)
println("error: " + rc);
return rc;
}
protected void onSessionChange(WPARAM wParam, LPARAM lParam) {
switch (wParam.intValue()) {
case Wtsapi32.WTS_CONSOLE_CONNECT: {
println("WTS_CONSOLE_CONNECT");
break;
}
case Wtsapi32.WTS_CONSOLE_DISCONNECT: {
println("WTS_CONSOLE_DISCONNECT");
break;
}
case Wtsapi32.WTS_SESSION_LOGON: {
println("WTS_SESSION_LOGON");
break;
}
case Wtsapi32.WTS_SESSION_LOGOFF: {
println("WTS_SESSION_LOGOFF");
break;
}
case Wtsapi32.WTS_SESSION_LOCK: {
println("WTS_SESSION_LOCK");
break;
}
case Wtsapi32.WTS_SESSION_UNLOCK: {
println("WTS_SESSION_UNLOCK");
break;
}
default:
println("Session change " + wParam.intValue());
break;
}
}
}
我使用WINHOME_KEY + L在Windows Vista 64bit上使用JNA 4.1.0(从here下载)进行了测试。 "隐藏窗口的背景线程"使用shutdown-trigger停止,当主类的JFrame关闭时,该触发器被激活。
答案 1 :(得分:-1)
我认为你想在后台运行任务,所以我强烈建议使用swingworker,因此在这种情况下框架是否设置可见是否真实并不重要。此外,您还应该为窗口活动或状态选择特定事件。如果您对窗口进行图标化,并且仍想运行任务,则在该事件下复制代码。
Window activities or states can precede a window event:
请参阅一些示例如何实施swingworker
How do I make my SwingWorker example work properly?
Advanced Java: Multi-threading Part 15 -- Swing and the SwingWorker Class