I am trying to find out which of the applications that are currently running is the selected one.
For example, if the open applications are Chrome, Spotify, File Manager and the Settings. The user is in the Settings app, so that is the currently selected application.
I want to get the name or the PID or anything that identifies this application in Java.
I wrote this shortly before DuncG posted his answer. I realize it heavily overlaps his answer. (It’s interesting that we both had very similar ideas about which Windows native functions to use.) I have decided to post this anyway, as a more compact alternative that doesn’t require any extraction or code generation.
Like him, I suggest using the native GetForegroundWindow, GetWindowThreadProcessId, and GetWindowTextW functions of Windows:
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.lang.invoke.MethodHandle;
import java.lang.foreign.Linker;
import java.lang.foreign.SymbolLookup;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.ValueLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.Arena;
public class WindowsForegroundWindowDetector {
public record WindowInfo(long pid,
String title,
MemorySegment hwnd) {
// Deliberately empty.
}
private final MethodHandle GetForegroundWindow;
private final MethodHandle GetWindowThreadProcessId;
private final MethodHandle GetWindowTextW;
public WindowsForegroundWindowDetector() {
Linker linker = Linker.nativeLinker();
SymbolLookup lookup =
SymbolLookup.libraryLookup("User32", Arena.global());
GetForegroundWindow = linker.downcallHandle(
lookup.findOrThrow("GetForegroundWindow"),
FunctionDescriptor.of(
ValueLayout.ADDRESS)); // returns HWND
GetWindowThreadProcessId = linker.downcallHandle(
lookup.findOrThrow("GetWindowThreadProcessId"),
FunctionDescriptor.of(
ValueLayout.JAVA_INT, // returns DWORD
ValueLayout.ADDRESS.withName("hWnd"), // HWND
ValueLayout.ADDRESS.withName("lpdwProcessId")));// LPDWORD
GetWindowTextW = linker.downcallHandle(
lookup.findOrThrow("GetWindowTextW"),
FunctionDescriptor.of(
ValueLayout.JAVA_INT, // returns int
ValueLayout.ADDRESS.withName("hWnd"), // HWND
ValueLayout.ADDRESS.withName("lpString"), // LPWSTR
ValueLayout.JAVA_INT.withName("nMaxCount"))); // int
}
private WindowInfo toWindowInfo(MemorySegment hwnd) {
int rawPID;
String title;
try (Arena arena = Arena.ofConfined()) {
MemorySegment lpdwProcessId =
arena.allocateFrom(ValueLayout.JAVA_INT, 0);
int threadID;
try {
threadID = (int) GetWindowThreadProcessId.invokeExact(
hwnd, lpdwProcessId);
} catch (Throwable t) {
throw new RuntimeException(
"GetWindowThreadProcessId failed.", t);
}
if (threadID == 0) {
throw new RuntimeException("GetWindowThreadProcessId failed.");
}
rawPID = lpdwProcessId.get(ValueLayout.JAVA_INT, 0);
int maxTitleLength = 1024;
MemorySegment titleBuffer =
arena.allocate(ValueLayout.JAVA_CHAR, maxTitleLength);
int titleCharCount;
try {
titleCharCount = (int) GetWindowTextW.invokeExact(
hwnd, titleBuffer, maxTitleLength);
} catch (Throwable t) {
throw new RuntimeException("GetWindowTextW failed.", t);
}
if (titleCharCount == 0) {
throw new RuntimeException("GetWindowTextW failed.");
}
title = titleBuffer.getString(0, StandardCharsets.UTF_16LE);
}
long pid = ((long) rawPID) & 0xffffffffL;
return new WindowInfo(pid, title, hwnd);
}
public Optional<WindowInfo> detectForegroundWindow() {
MemorySegment hwnd;
try {
hwnd = (MemorySegment) GetForegroundWindow.invokeExact();
} catch (Throwable t) {
throw new RuntimeException("GetForegroundWindow failed.", t);
}
if (hwnd.equals(MemorySegment.NULL)) {
return Optional.empty();
} else {
return Optional.of(toWindowInfo(hwnd));
}
}
public static void main(String[] args) {
Optional<WindowInfo> info =
new WindowsForegroundWindowDetector().detectForegroundWindow();
if (info.isPresent()) {
System.out.println(info.get());
} else {
System.out.println("No foreground window found.");
}
}
}