How to switch between runnng windows applications using java? - java

Suppose i run my program in eclipse and it'll switch to mozilla window(it is running simultaneously). Similarly when we click a icon in task bar. I have tried Robot class to stimulate click but that's hard-coding coordinates into the program and i don't want to do that.
Any suggestion how i can do this. Thanks.

As far as I understand things, you cannot switch to another running window by name using just core Java. You can swap windows by sending alt-tab keystrokes via a Robot, but this won't bring up a named window. To do this, I recommend using JNI, JNA or some OS-specific utility programming language, such as AutoIt if this were a Windows issue.
For example, using JNA, you could do something like this:
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.win32.StdCallLibrary;
public class SetForgroundWindowUtil {
public interface User32 extends StdCallLibrary {
User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
interface WNDENUMPROC extends StdCallCallback {
boolean callback(Pointer hWnd, Pointer arg);
}
boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer arg);
int GetWindowTextA(Pointer hWnd, byte[] lpString, int nMaxCount);
int SetForegroundWindow(Pointer hWnd);
Pointer GetForegroundWindow();
}
public static boolean setForegroundWindowByName(final String windowName,
final boolean starting) {
final User32 user32 = User32.INSTANCE;
return user32.EnumWindows(new User32.WNDENUMPROC() {
#Override
public boolean callback(Pointer hWnd, Pointer arg) {
byte[] windowText = new byte[512];
user32.GetWindowTextA(hWnd, windowText, 512);
String wText = Native.toString(windowText);
// if (wText.contains(WINDOW_TEXT_TO_FIND)) {
if (starting) {
if (wText.startsWith(windowName)) {
user32.SetForegroundWindow(hWnd);
return false;
}
} else {
if (wText.contains(windowName)) {
user32.SetForegroundWindow(hWnd);
return false;
}
}
return true;
}
}, null);
}
public static void main(String[] args) {
boolean result = setForegroundWindowByName("Untitled", true);
System.out.println("result: " + result);
}
}
I don't know any OS-agnostic way of solving this problem.

I Believe you're question may have been answered here: Active other process's window in Java.
Other than that, JNA would be your best bet for doing this, core java, or java in general doesn't allow
interaction with the operating system directly but JNA does.
The only other way i can think of is call the application, for example chrome with command like arguments(if it takes any) with
try{
Desktop.getDesktop().open(new File("Location\\to\\the\\program.exe"));
} catch(IOException ex){
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
edit:
use this method to call it with parameters
Process process = new ProcessBuilder("Location\\to\\the\\program.exe",
"param1","param2").start();

On linux, try this (this is kotlin code):
val window = "The window name you want to show"
Runtime.getRuntime().exec(arrayOf("/bin/bash", "-c", "wmctrl -a \"$window\""))
Works on Elementary (Loki)

Related

Get all visible windows with JNA

I am programming an overlay in Java showing information for multiple windows.
I need it to follow the window that it is tracking, and to do this I regularly take information about the current windows to update the position of my overlay. But I would also need to know if the windows are visible to hide the overlay if not. Ideally I should be able to do all this in real time but I'm afraid it's too performance-intensive.
I do all of this with JNA
public interface User32 extends StdCallLibrary {
User32 INSTANCE = (User32) Native.load("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS);
HWND FindWindow(String lpClassName, String lpWindowName);
int GetWindowRect(HWND handle, int[] rect);
boolean IsWindowVisible(HWND handle); // always true if window exist
}
public static int[] getWindowInformation(String windowName) {
int[] rectangle = {0,0,0,0};
HWND hwnd = User32.INSTANCE.FindWindow(null, windowName);
User32.INSTANCE.GetWindowRect(hwnd, rectangle);
boolean res = User32.INSTANCE.IsWindowVisible(hwnd);
System.out.println(windowName + " is visible ? " + res);
return rectangle;
}
Here is my code, you can see that I tried "IsWindowVisible" after read entirely the User32 API of JNA, but it doesn't do what I want.
Your intuition to use IsWindowVisible from User32 is good. JNA has actually implemented this in its WindowUtils class.
List<DesktopWindow> windows = WindowUtils.getAllWindows(true);
The boolean parameter is onlyVisibleWindows.
Note that "visible" here refers to the state of the window itself, not whether it is minimized (may have off-screen or "zero" coordinate) or "behind" vs. "on top" of other windows and thus visible to the user. From the IsWindowVisible documentation (note the second paragraph):
If the specified window, its parent window, its parent's parent window, and so forth, have the WS_VISIBLE style, the return value is nonzero. Otherwise, the return value is zero.
Because the return value specifies whether the window has the WS_VISIBLE style, it may be nonzero even if the window is totally obscured by other windows.
In order to determine whether the window is partially or fully obscured, you would have to evaluate its locAndSize rectangle relative to all windows "in front" of it using Z-order. You could do this on a pixel-by-pixel basis or just evaluate the corner points, depending on how you want to handle partially obscured windows.
The JNA getAllWindows() method returns a list (filtered by visibility) of JNA DesktopWindows encapsulating these fields:
private HWND hwnd;
private String title;
private String filePath;
private Rectangle locAndSize;
Internally you can see the implementation in the inner class W32WindowUtils, which uses a callback function sent to User32's EnumWindows function:
#Override
public List<DesktopWindow> getAllWindows(final boolean onlyVisibleWindows) {
final List<DesktopWindow> result = new LinkedList<DesktopWindow>();
final WNDENUMPROC lpEnumFunc = new WNDENUMPROC() {
#Override
public boolean callback(final HWND hwnd, final Pointer arg1) {
try {
final boolean visible = !onlyVisibleWindows
|| User32.INSTANCE.IsWindowVisible(hwnd);
if (visible) {
final String title = getWindowTitle(hwnd);
final String filePath = getProcessFilePath(hwnd);
final Rectangle locAndSize = getWindowLocationAndSize(hwnd);
result.add(new DesktopWindow(hwnd, title, filePath,
locAndSize));
}
} catch (final Exception e) {
// FIXME properly handle whatever error is raised
e.printStackTrace();
}
return true;
}
};
if (!User32.INSTANCE.EnumWindows(lpEnumFunc, null))
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
return result;
}
I maintain the JNA-based OSHI project, and have implemented this cross-platform via new SystemInfo().getOperatingSystem().getDesktopWindows(), which uses the above implementation on Windows and adds information from other functions to get the window ordering. OSHI's return list includes these fields and the returned list is already sorted in order to aid you in determining user visibility:
private final long windowId;
private final String title;
private final String command;
private final Rectangle locAndSize;
private final long owningProcessId;
private final int order;
private final boolean visible;

Is it possible to lock the Windows OS desktop using Java (Swing)? [duplicate]

This question already has an answer here:
is it is possible to disable the windows keys using java
(1 answer)
Closed 6 years ago.
I am trying to make a small application, similar to a cyber cafe software.
To be specific, what i want to do is that once the app starts, you can't do anything in the computer, and it's impossible to cease the locking, (Alt + F4, Ctrl + Alt + Del, Task Manager, etc.) unless you put up a certain username and password, and once a specific amount of time has passed by, the software will lock the computer again.
I am pretty much a novice in Java, so i couldn't find any answers that i could understand or that were what i was looking for. Is this possible to do?
Thanks in advance!
You'd probably need to use JNA to do things like that, or just change to C++/C#.
Such example as this:
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.platform.win32.WinUser.HHOOK;
import com.sun.jna.platform.win32.WinUser.KBDLLHOOKSTRUCT;
import com.sun.jna.platform.win32.WinUser.LowLevelKeyboardProc;
import com.sun.jna.platform.win32.WinUser.MSG;
public class KeyHook {
private static HHOOK hhk;
private static LowLevelKeyboardProc keyboardHook;
private static User32 lib;
public static void blockWindowsKey() {
if (isWindows()) {
new Thread(new Runnable() {
#Override
public void run() {
lib = User32.INSTANCE;
HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
keyboardHook = new LowLevelKeyboardProc() {
public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) {
if (nCode >= 0) {
switch (info.vkCode){
case 0x5B: //Around here would be where you add all your 0x key codes
case 0x5C:
return new LRESULT(1);
default: //do nothing
}
}
return lib.CallNextHookEx(hhk, nCode, wParam, info.getPointer());
}
};
hhk = lib.SetWindowsHookEx(13, keyboardHook, hMod, 0);
// This bit never returns from GetMessage
int result;
MSG msg = new MSG();
while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
if (result == -1) {
break;
} else {
lib.TranslateMessage(msg);
lib.DispatchMessage(msg);
}
}
lib.UnhookWindowsHookEx(hhk);
}
}).start();
}
}
public static void unblockWindowsKey() {
if (isWindows() && lib != null) {
lib.UnhookWindowsHookEx(hhk);
}
}
public static boolean isWindows(){
String os = System.getProperty("os.name").toLowerCase();
return (os.indexOf( "win" ) >= 0);
}
}
(That was not mine, ill explain in a bit)
Then see if it is running Windows by 'KeyHook.isWindows()'.
If it is, use things like 'blockWindowsKey()' or make your own functions like it. I put a comment where you'd change the key code.
FYI possible duplicate of is it is possible to disable the windows keys using java
Thats where the code came from.

how do i pass pointer ref to native method in JNI [duplicate]

This is native method from ITLSSPProc.dll
NOMANGLE int CCONV OpenSSPComPort (SSP_COMMAND * cmd);
Here, SSP_COMMAND is structure in ITLSSPProc.dll which is in C++
Language.
struct SSP_COMMAND
{
unsigned long BaudRate;
unsigned char PortNumber;
};
So, I have to access OpenSSPComPort (SSP_COMMAND * cmd) in java using
JNI. Here is a code i have written,
public class Main {
public interface ITLSSPProc extends Library {
ITLSSPProc INSTANCE = (ITLSSPProc) Native.loadLibrary(
(Platform.isWindows() ? "ITLSSPProc" : "simpleDLLWindowsPort"), ITLSSPProc.class);
int OpenSSPComPort(Pointer param);
int CloseSSPComPort();
}
public static void main(String[] args)throws IOException {
ITLSSPProc sdll = ITLSSPProc.INSTANCE;
Memory intMem = new Memory(10); // allocating space
intMem.setLong(0,9600);
intMem.setString(1,"com7");
if(sdll.OpenSSPComPort(intMem)==1)
{// calling function with int parameter&result
System.out.println("connected");
}
else
{
System.out.println("failed");
}
}
}
Output : failed
Port number is COM7 on which we are working. So, when i run this
application and as i passing baud rate as manually as given in user
manual and if port number is correct it has to print "connected" on
console. So, anybody know where i am going wrong, i dont understand
where is actual problem..
JNA documentation for basic types (long, char).
JNA documentation for aggregate types (struct, struct *).
// tl;dr
class SSP_COMMAND extends Structure {
public NativeLong BaudRate;
public byte PortNumber;
}
int OpenSSPComPort(SSP_COMMAND param)

JNA Using macros

Is it possible to map The following Macro function with JNA?
int ListView_FindItem(
HWND hwnd,
int iStart,
const LPLVFINDINFO plvfi
);
I've tried to map this function with StdCallLibraryb, but that does not seem to work
(Function not found exception is thrown).
Basically i am trying find the index of a particular item in List view of desktop.
I have the name of the item i intend to find.
EDIT:
i have tried using the send message feature, i get the following exception
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function
'GetMessage': The specified procedure could not be found.
at com.sun.jna.Function.<init>(Function.java:179)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:347)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:327)
at com.sun.jna.Library$Handler.invoke(Library.java:203)
at $Proxy0.GetMessage(Unknown Source)
at javaapplication4.Main.main(Main.java:43)
Java Result: 1
This is the code i used
public class Main {
public static class LVFINDINFO extends Structure {
public int flags =1002;
public String psz = "new folder3";
public LPARAM lParam ;
public POINT pt;
public int vkDirection;
}
public static class MSG extends Structure {
public HWND hWnd;
public int message;
public int wParam =-1;
public LVFINDINFO lParam1;
public int time;
public POINT pt;
public MSG(LVFINDINFO lParam) {
lParam1 = lParam;
}
}
public static void main(String[] args) {
User32 user32 = (User32) Native.loadLibrary("User32", User32.class);
LVFINDINFO i = new LVFINDINFO();
MSG m = new MSG(i);
user32.GetMessage(m, user32.GetDesktopWindow(), 0, 0);
System.out.println(user32.GetMessage(m, user32.GetDesktopWindow(), 0, 0));
}
}
Since a macro exists purely at compile-time, there's no way to call it using JNA.
You'll need to see what the macro actually does and do that instead. According to the documentation it sends the LVM_FINDITEM message. You need to find out how to send that message using JNA.

Can I change my Windows desktop wallpaper programmatically in Java/Groovy?

Is there a way I can use Java (or Groovy) to change my desktop wallpaper in Windows XP? I have a program that creates a new image every day (or whenever) and I would like a way to automatically update my desktop.
I've seem some questions on this site about C++ or .NET, but I did not see anything specific to Java.
Sorry I'm a bit behind #ataylor's answer because I was preparing a snippet to do it. Yes, JNA is a correct approach. Here you go:
import java.util.HashMap;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
import com.sun.jna.win32.*;
public class WallpaperChanger {
public static void main(String[] args) {
//supply your own path instead of using this one
String path = "C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg";
SPI.INSTANCE.SystemParametersInfo(
new UINT_PTR(SPI.SPI_SETDESKWALLPAPER),
new UINT_PTR(0),
path,
new UINT_PTR(SPI.SPIF_UPDATEINIFILE | SPI.SPIF_SENDWININICHANGE));
}
public interface SPI extends StdCallLibrary {
//from MSDN article
long SPI_SETDESKWALLPAPER = 20;
long SPIF_UPDATEINIFILE = 0x01;
long SPIF_SENDWININICHANGE = 0x02;
SPI INSTANCE = (SPI) Native.loadLibrary("user32", SPI.class, new HashMap<Object, Object>() {
{
put(OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
}
});
boolean SystemParametersInfo(
UINT_PTR uiAction,
UINT_PTR uiParam,
String pvParam,
UINT_PTR fWinIni
);
}
}
You need to have the JNA libraries on the classpath for this to work. This was tested in Windows 7, there might be some nuances in XP but I think it should work. That API is presumably stable.
References
Setting Wallpaper - Coding4Fun
How to determine if a screensaver is running in Java?
W32API.java
Edit (2010/01/20):
I had previously omitted the options SPIF_UPDATEINIFILE and SPIF_SENDWININICHANGE. These are now being used as they were suggested in the Coding4Fun MSDN article.
You can do it easier:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.PVOID;
import com.sun.jna.win32.W32APIOptions;
public class Wallpaper {
public static interface User32 extends Library {
User32 INSTANCE = (User32) Native.loadLibrary("user32",User32.class,W32APIOptions.DEFAULT_OPTIONS);
boolean SystemParametersInfo (int one, int two, String s ,int three);
}
public static void main(String[] args) {
User32.INSTANCE.SystemParametersInfo(0x0014, 0, "C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg" , 1);
}
}
You can write a batch file to change the wall-paper, and execute that batch file using,
Runtime.getRuntime.exec()
The JNA java library allows you to easily call Win32 API calls. In particular, to change the desktop background, you need to call the SystemParametersInfo function.
Take a look at this article for an introduction to JNA: http://today.java.net/article/2009/11/11/simplify-native-code-access-jna
Here is a Pure Java implementation which uses Project Panama to make the native callbacks into Windows USER32.DLL. Note that the API is incubating so has changed between JDK16, 17 and later builds. These samples use the versions of Panama that are in the current JDK16/17 release, some changes may be required if you switch to the latest Panama Early Access builds.
import java.lang.invoke.*;
import java.nio.file.Path;
import jdk.incubator.foreign.*;
/**
%JDK16%\bin\java -Dforeign.restricted=permit --add-modules jdk.incubator.foreign SetWallpaper.java A.JPG
*/
public class SetWallpaper {
static final int SPI_SETDESKWALLPAPER = 0x0014;
static final int SPIF_UPDATEINIFILE = 0x01;
static final int SPIF_SENDCHANGE = 0x02;
public static void main(String[] args) throws Throwable {
LibraryLookup user32 = LibraryLookup.ofLibrary("user32");
MethodHandle spi = CLinker.getInstance().downcallHandle(user32.lookup("SystemParametersInfoA").get()
// BOOL SystemParametersInfoA (UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
, MethodType.methodType(int.class, int.class, int.class, MemoryAddress.class, int.class)
, FunctionDescriptor.of(CLinker.C_LONG,CLinker.C_LONG, CLinker.C_LONG, CLinker.C_POINTER, CLinker.C_LONG));
Path path = Path.of(args[0]).toRealPath();
try (NativeScope scope = NativeScope.unboundedScope()) {
MemorySegment img = CLinker.toCString(path.toString(), scope);
int status = (int)spi.invokeExact(SPI_SETDESKWALLPAPER, 0, img.address(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
System.out.println("Changed wallpaper to "+path+" rc="+status+(status == 0 ? " *** ERROR ***": " OK"));
}
}
}
Small changes needed for JDK17:
/**
%JAVA_HOME%\bin\java --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.foreign SetWallpaper.java A.JPG
*/
public static void main(String[] args) throws Throwable {
System.loadLibrary("user32");
// BOOL SystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
MemoryAddress symbol = SymbolLookup.loaderLookup().lookup("SystemParametersInfoW").get();
MethodHandle SystemParametersInfoW = CLinker.getInstance().downcallHandle(symbol
, MethodType.methodType(int.class, int.class, int.class, MemoryAddress.class, int.class)
, FunctionDescriptor.of(CLinker.C_LONG,CLinker.C_LONG, CLinker.C_LONG, CLinker.C_POINTER, CLinker.C_LONG));
Path path = Path.of(args[0]).toRealPath();
try(ResourceScope scope = ResourceScope.newConfinedScope()) {
SegmentAllocator allocator = SegmentAllocator.arenaAllocator(scope);
// toCString as WIDE string
Addressable wide = allocator.allocateArray(CLinker.C_CHAR, (path+"\0").getBytes(StandardCharsets.UTF_16LE));
int status = (int)SystemParametersInfoW.invokeExact(SPI_SETDESKWALLPAPER, 0, wide.address(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
System.out.println("Changed wallpaper to "+path+" rc="+status+(status == 0 ? " *** ERROR ***": " OK"));
}
}
Expanding on the answer from #DuncG, here's an updated solution which uses Project Panama from JDK 18.
import jdk.incubator.foreign.*;
import java.lang.invoke.MethodHandle;
import java.nio.file.Path;
import static jdk.incubator.foreign.ValueLayout.*;
public class WindowsOperatingSystem {
private static final int SPI_SETDESKWALLPAPER = 0x0014;
private static final int SPIF_UPDATEINIFILE = 0x01;
private static final int SPIF_SENDCHANGE = 0x02;
private static final MethodHandle systemParametersInfoAFunction;
static {
System.loadLibrary("user32");
// BOOL SystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
systemParametersInfoAFunction = CLinker.systemCLinker().downcallHandle(
SymbolLookup.loaderLookup().lookup("SystemParametersInfoA").get(),
FunctionDescriptor.of(JAVA_BOOLEAN, JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT)
);
}
public static void setWallpaper(Path file) {
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
SegmentAllocator allocator = SegmentAllocator.nativeAllocator(scope);
Addressable nativeFilePath = allocator.allocateUtf8String(file.toString());
var result = (boolean)systemParametersInfoAFunction.invokeExact(
SPI_SETDESKWALLPAPER,
0,
nativeFilePath,
SPIF_UPDATEINIFILE | SPIF_SENDCHANGE
);
if (!result) {
throw new IllegalStateException();
}
} catch (Error | RuntimeException t) {
throw t;
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
}

Categories