Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to move (or do anything with) the mouse

How to interact with the Windows API using Java and the JNA (Java Native Access)?. I'm trying to make the mouse do something by queuing a mouse event on the mouse input stream, and the code works, in that the SendInput(...) method returns 1 suggesting that it has successfully queued the event, but yet the mouse itself does nothing.

My SSCCE:

Edit: edited to fill in the dwFlags field. I've tried several combinations of constants either by themselves or bit-or combined without success still. Again, the SendInput method returns 1 as it should suggesting a functioning method, but the mouse doesn't budge:

import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef.*;
import com.sun.jna.platform.win32.WinUser.*;
import com.sun.jna.win32.StdCallLibrary;

public class MouseUtils {
   public interface User32 extends StdCallLibrary {
      public static final long MOUSEEVENTF_MOVE = 0x0001L; 
      public static final long MOUSEEVENTF_VIRTUALDESK = 0x4000L; 
      public static final long MOUSEEVENTF_ABSOLUTE = 0x8000L;

      User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
      DWORD SendInput(DWORD dWord, INPUT[] input, int cbSize);
   }
   
   public static void main(String[] args) {
      INPUT input = new INPUT();
      input.type = new DWORD(INPUT.INPUT_MOUSE);

      input.input.mi.dx = new LONG(500);
      input.input.mi.dy = new LONG(500);
      input.input.mi.mouseData = new DWORD(0);
      input.input.mi.dwFlags = new DWORD(User32.MOUSEEVENTF_MOVE
            | User32.MOUSEEVENTF_VIRTUALDESK | User32.MOUSEEVENTF_ABSOLUTE);
      // input.input.mi.dwFlags = new DWORD(0x8000L);
      input.input.mi.time = new DWORD(0);
      
      INPUT[] inArray = {input};
            
      int cbSize = input.size(); // mouse input struct size
      DWORD nInputs = new DWORD(1); // number of inputs
      DWORD result = User32.INSTANCE.SendInput(nInputs , inArray, cbSize);
      System.out.println("result: " + result); // return 1 if the 1 event successfully inserted
   }
}

Edit 2:

Doing more reading, and it seems that my understanding of arrays with JNA is deficient, that I have to think in terms of C arrays where an array is simply a pointer to a region of contiguous memory. More to come (I hope!).

like image 675
Hovercraft Full Of Eels Avatar asked Dec 06 '11 23:12

Hovercraft Full Of Eels


People also ask

Why can't I click on anything with my mouse?

The first step to fix mouse (or keyboard) issues is to disconnect and reconnect the mouse on the computer, or to connect the mouse to another USB port. Also, if you 're using a Wireless mouse replace its batteries.

How do I use my mouse?

To hold the mouse, keep your thumb on the side of the mouse, index finger on the left button, and middle finger on the right button. While holding the mouse relax your hand and make sure your hand is straight with your arm. You should never have your wrist at an angle while using the mouse.


2 Answers

JNA document Using Structures And Unions reads:

Unions are generally interchangeable with Structures, but require that you indicate which union field is active with the setType method before it can be properly passed to a function call.

I guess you missed setType part. Also, when using MOUSEEVENTF_ABSOLUTE, dx and dy are specified as the coordinate of the mouse, not pixels.

Following works:

public interface User32 extends StdCallLibrary {
    ...
    public static final int SM_CXSCREEN = 0x0;
    public static final int SM_CYSCREEN = 0x1;
    int GetSystemMetrics(int index);
}

public static void main(String[] args) {    
    ...
    input.input.setType("mi");
    input.input.mi.dx = new LONG(500 * 65536 / User32.INSTANCE.GetSystemMetrics(User32.SM_CXSCREEN));
    input.input.mi.dy = new LONG(500 * 65536 / User32.INSTANCE.GetSystemMetrics(User32.SM_CYSCREEN));
    ...
}
like image 137
edwardw Avatar answered Oct 06 '22 12:10

edwardw


Call the toArray() method on your structure to obtain a contiguous block of memory.

INPUT input = new INPUT();
INPUT[] arg = (INPUT[])input.toArray(1);

Alternatively, you can simply declare an alternate method mapping for SendInput:

DWORD SendInput(int nInputs, INPUT pInputs, int cbSize);

However, there may be something else going on (permissions, perhaps? see MS notes on UIPI), since your example ought to work (at least with a single array element).

EDIT: the Union.setType() answer is indeed the correct one.

like image 3
technomage Avatar answered Oct 06 '22 12:10

technomage