9

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!).

ios coder
  • 1
  • 4
  • 31
  • 91
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373

3 Answers3

11

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));
    ...
}
edwardw
  • 12,652
  • 3
  • 40
  • 51
3

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.

technomage
  • 9,861
  • 2
  • 26
  • 40
2
input.input.mi.dwFlags = new DWORD(0);

You didn't specify any of the mouse input flags, so there was no mouse input.

Neil
  • 54,642
  • 8
  • 60
  • 72