I am creating a script that, when a key combination is pressed, will minimize the currently active window and move to the next one. Then, when a key combination is pressed, expand the last minimized window.
There is problem in passing the focus to the next window, if there is one, after minimizing the active one.
In ShowWindow documentation it is written "SW_MINIMIZE 6 Minimizes the specified window and activates the next top-level window in the Z order.", but this doesn't work for me for some reason.
User32.java
import jnr.ffi.LibraryLoader;
import jnr.ffi.Pointer;
import jnr.ffi.annotations.Delegate;
import jnr.ffi.types.u_int32_t;
public interface User32 {
User32 INSTANCE = LibraryLoader.create(User32.class).load("user32");
@u_int32_t
long GetForegroundWindow();
boolean SetForegroundWindow(@u_int32_t long hWnd);
boolean ShowWindow(@u_int32_t long hWnd, @u_int32_t long nCmdShow);
boolean IsIconic(@u_int32_t long hWnd);
boolean IsWindowVisible(@u_int32_t long hwnd);
void keybd_event(byte bVk, byte bScan, @u_int32_t int dwFlags,
int dwExtraInfo);
interface WinEnumProc {
@Delegate
boolean apply(@u_int32_t long hwnd, Pointer data);
}
boolean EnumWindows(WinEnumProc lpEnumFunc, Pointer lParam);
}
WindowManager.java
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
public class WindowManager {
private static final Logger log = LogManager.getLogger(WindowManager.class.getName());
private static final int SW_MINIMIZE = 6;
private static final int SW_RESTORE = 9;
private static long lastWindow = 0;
public static void winMinimize() {
long activeWin = User32.INSTANCE.GetForegroundWindow();
log.info("Active window: {}", activeWin);
if (activeWin != 0) {
List<Long> windows = new ArrayList<>();
User32.INSTANCE.EnumWindows((hwnd, data) -> {
if (User32.INSTANCE.IsWindowVisible(hwnd)) {
windows.add(hwnd);
}
return true;
}, null);
lastWindow = activeWin;
User32.INSTANCE.ShowWindow(activeWin, SW_MINIMIZE);
int activeWinIndex = windows.indexOf(activeWin);
if (activeWinIndex != -1 && activeWinIndex + 1 < windows.size()) {
long nextWin = windows.get(activeWinIndex + 1);
log.info("Next win: {}", windows.get(activeWinIndex + 1));
// User32.INSTANCE.keybd_event((byte) 0xA4, (byte) 0x45, 0x2, 0);
User32.INSTANCE.SetForegroundWindow(nextWin);
}
log.info("Focus: {}", User32.INSTANCE.GetForegroundWindow());
}
}
public static void winRestore() {
if (lastWindow != 0 && User32.INSTANCE.IsIconic(lastWindow)) {
User32.INSTANCE.ShowWindow(lastWindow, SW_RESTORE);
User32.INSTANCE.SetForegroundWindow(lastWindow);
lastWindow = 0;
}
}
}
I create a list of maximized windows windows
, from which I get the next maximized window and try to call SetForegroundWindow
for it. This window starts blinking, but the focus is still not transferred.
I've also found a solution to simulate pressing the Alt key, User32.INSTANCE.keybd_event((byte) 0xA4, (byte) 0x45, 0x2, 0)
, but I find this odd. I would like to get the same behavior as when the mouse clicks the minimize window button.
I've read the documentation on SetForegroundWindow, and maybe the problem lies in the threads, but I don't understand what I need to do to solve it.
After suggestions from @IInspectable and @Starship, I read about RegisterHotKey and AttachThreadInput. This really solves my problem. I also found the jintellitype library which uses RegisterHotKey.