【问题标题】:get mouse type in java using jna使用jna在java中获取鼠标类型
【发布时间】:2017-12-04 13:12:30
【问题描述】:

感谢@deFreitas

我正在尝试在java 中创建远程控制程序。 我的问题是我使用robot 类的屏幕截图从远程计算机获取图像,因此我看不到远程光标。 我知道我可以在屏幕截图上绘制光标图像,但是如何获取全局光标类型。

我为此搜索了很多,我得到的最接近的是这段代码:

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();

}

但我不明白如何从 HCursor 类中获取光标类型... 有没有办法获取类型甚至光标位图¿

编辑: 我找到了这个功能:

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

但我不知道该给它什么类型。我看到的每个网站都加载图像或特定的光标类型……

【问题讨论】:

    标签: java cursor jna


    【解决方案1】:

    有可能,基本上你需要GetCursorInfoLoadImage

    BOOL GetCursorInfo(PCURSORINFO pci)
    

    它获取当前光标句柄并将其存储在PCURSORINFO.hCursor 中,这是实际的光标,但没有指示器知道它是什么类型,请注意它是 Windows 而非 JNA 限制。无论如何,如果你使用

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

    它将返回一个给定游标类型 ID 的句柄 here a list 以及所有可用的游标 ID。这样,您可以使用LoadImage 加载所有游标,然后只需对GetCursorInfo 结果进行等于,匹配的结果就是实际的游标类型。这是一个使用 JNA 的工作 JAVA 程序

    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:并非所有可能的光标都有可用的资源ID(如放大,缩小),这是因为系统默认光标为15,其他是软件创建的自定义光标(如chrome , firefox) 这样windows就无法识别它是什么类型的光标。

    Jna 版本

    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'
    

    【讨论】:

    • 成功了!非常感谢。您没有写的一件事是需要最新版本的 jna。非常感谢它真的帮助了我☺
    • 我注意到您添加了注释://您可以使用此处打印的地址来映射其他光标,例如 ALL_SCROLL 这是什么意思?我尝试查看打印的数据,但它打印出不同的代码。例如:对于 NORMAL 光标,它会打印 0x10003,即十进制的 65539,与 NORMAL 光标的代码不同,你能解释一下吗?
    • 对不起,在我进行测试以通过地址 (0x10003) 而不是代码匹配之前,但它不起作用。例如,放大光标在 chrome 和 firefox 中有不同的参考。如果您查看this example,它会更有意义
    • 谢谢,现在我明白了。我现在用java的自定义光标尝试了它,每次运行程序时它都会为光标提供不同的地址。不可能映射所有游标,我认为最好保留基本的系统游标……再次感谢,我真的很感激☺
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    • 1970-01-01
    相关资源
    最近更新 更多