get mouse type in java using jna

2019-06-02 06:58发布

问题:

SOVED thanks to @deFreitas

I am trying to create remote control program in java. my problem is that I get image from remote computer using screenshot from the robot class and therefore I can not see the remote cursor. I know I can draw image of cursor on the screenshot but how can I get the global cursor type.

I have searched a lot for that and the closest I got was this code:

public interface User32 extends com.sun.jna.Library {
  public static User32 INSTANCE = (User32) com.sun.jna.Native
          .loadLibrary("User32", User33.class);
  public com.sun.jna.platform.win32.WinDef.HCURSOR GetCursor();

}

but I don't understand how to get cursor type from HCursor class… Is there a way to get the type or even the cursor bitmap¿

EDIT: I found this function:

WinNT.HANDLE LoadImage(WinDef.HINSTANCE hinst,
                   String name,
                   int type,
                   int xDesired,
                   int yDesired,
                   int load)

but I don't know whitch type to give it. every website I saw load image or a specific cursor type…

回答1:

It's possible, basically you need GetCursorInfo and LoadImage

BOOL GetCursorInfo(PCURSORINFO pci)

It gets current cursor handle and store it inside PCURSORINFO.hCursor, that's the actual cursor but there is not indicator to know what type it's, note that it is a Windows and not a JNA limitation. Anyway if you use

HANDLE WINAPI LoadImage(...,PCTSTR cursorId,...)

It will return a handle given the cursor type ID, here a list with all available cursor ids. This way you can use LoadImage to load all cursors then just do a equals with GetCursorInfo result, the result which match is the actual cursor type. Here a working JAVA program using JNA

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.*;

import java.io.IOException;
import java.util.*;

/**
 * https://msdn.microsoft.com/pt-br/library/windows/desktop/ms648029(v=vs.85).aspx
 * Test cursors - https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
 * Chromium cursor map -  https://github.com/mageddo/chromium/blob/master/webkit/glue/webcursor_win.cc
 * Load icon example - https://github.com/java-native-access/jna/blob/master/contrib/platform/test/com/sun/jna/platform/win32/GDI32Test.java#L54
 * understanding makeintresource - https://stackoverflow.com/questions/3610565/why-does-makeintresource-work
 * all possible windows error codes - https://msdn.microsoft.com/en-us/library/windows/desktop/ms681386(v=vs.85).aspx
 * Cursor ids - https://msdn.microsoft.com/en-us/library/windows/desktop/ms648391(v=vs.85).aspx
 *
 */
public class Main {

    public static void main(String[] args) throws Exception {
        while(true){
            final Main main = new Main();
            System.out.println(main.getCurrentCursor());
            Thread.sleep(2000);
        }
    }

    private final Map<WinNT.HANDLE, Cursor> cursors;
    private final User32 user32;

    public Main(){
        user32 = User32.INSTANCE;
        cursors = loadCursors();
    }


    /**
     * Load all possible cursors to a map
     */
    private Map<WinNT.HANDLE, Cursor> loadCursors() {
        final Map<WinNT.HANDLE, Cursor> cursors = new HashMap<>();
        for (final Cursor cursor : Cursor.values()) {

            final Memory memory = new Memory(Native.getNativeSize(Long.class, null));
            memory.setLong(0, cursor.getCode());
            final Pointer resource = memory.getPointer(0);
            final WinNT.HANDLE hcursor = this.user32.LoadImageA(
                null, resource, WinUser.IMAGE_CURSOR, 0, 0, WinUser.LR_SHARED
            );
            if(hcursor == null || Native.getLastError() != 0){
                throw new Error("Cursor could not be loaded: " + String.valueOf(Native.getLastError()));
            }

            cursors.put(hcursor, cursor);
        }
        return Collections.unmodifiableMap(cursors);
    }

    public Cursor getCurrentCursor(){
        final CURSORINFO cursorinfo = new CURSORINFO();
        final int success = this.user32.GetCursorInfo(cursorinfo);
        if(success != 1){
            throw new Error("Could not retrieve cursor info: " + String.valueOf(Native.getLastError()));
        }

        // you can use the address printed here to map the others cursors like ALL_SCROLL
        System.out.printf("currentPointer=%s%n", cursorinfo.hCursor);
        // some times cursor can be hidden, in this case it will be null
        if(cursorinfo.hCursor != null && cursors.containsKey(cursorinfo.hCursor)){
            return cursors.get(cursorinfo.hCursor);
        }
        return null;
    }

//  typedef struct {
//      DWORD   cbSize;
//      DWORD   flags;
//      HCURSOR hCursor;
//      POINT   ptScreenPos;
//  } CURSORINFO, *PCURSORINFO, *LPCURSORINFO;
    public static class CURSORINFO extends Structure {

        public int cbSize;
        public int flags;
        public WinDef.HCURSOR hCursor;
        public WinDef.POINT ptScreenPos;

        public CURSORINFO() {
            this.cbSize = Native.getNativeSize(CURSORINFO.class, null);
        }
        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("cbSize", "flags", "hCursor", "ptScreenPos");
        }
    }

    public interface User32 extends com.sun.jna.Library {
        User32 INSTANCE = Native.loadLibrary("User32.dll", User32.class);

        //      BOOL WINAPI GetCursorInfo(
//          _Inout_ PCURSORINFO pci
//      );
        int GetCursorInfo(CURSORINFO cursorinfo);

//      HANDLE WINAPI LoadImage(
//          _In_opt_ HINSTANCE hinst,
//          _In_     LPCTSTR   lpszName,
//          _In_     UINT      uType,
//          _In_     int       cxDesired,
//          _In_     int       cyDesired,
//          _In_     UINT      fuLoad
//      );
        WinNT.HANDLE LoadImageA(
            WinDef.HINSTANCE hinst,
            Pointer lpszName,
            int uType,
            int cxDesired,
            int cyDesired,
            int fuLoad
        );
    }

    public enum Cursor {
        APPSTARTING(32650),
        NORMAL(32512),
        CROSS(32515),
        HAND(32649),
        HELP(32651),
        IBEAM(32513),
        NO(32648),
        SIZEALL(32646),
        SIZENESW(32643),
        SIZENS(32645),
        SIZENWSE(32642),
        SIZEWE(32644),
        UP(32516),
        WAIT(32514),
        PEN(32631)
        ;

        private final int code;

        Cursor(final int code) {
            this.code = code;
        }

        public int getCode() {
            return code;
        }
    }
}

Obs: Not all possible cursors have available resource ids (like zoom in, zoom out), it's because the system default cursors are 15, the anothers are custom cursors created by the software(like chrome, firefox) this way windows cannot identify what kind cursor it's.

Jna version

compile group: 'net.java.dev.jna', name: 'jna', version: '4.5.0'
compile group: 'net.java.dev.jna', name: 'jna-platform', version: '4.5.0'


标签: java cursor jna