Search code examples
javawinapijnalparam

Is there something like MAKELPARAM in Java / JNA?


I would like to realize the code taken from this answer and simulate a click without simulating mouse movement inside non-java app window. I know about JNA which, in theory, should have all WinAPI functions. The latest JNA version is 5.6.0 but I didn't find something similar to MAKELPARAM.

POINT pt;
    pt.x = 30; // This is your click coordinates
    pt.y = 30;

HWND hWnd = WindowFromPoint(pt);
LPARAM lParam = MAKELPARAM(pt.x, pt.y);
PostMessage(hWnd, WM_RBUTTONDOWN, MK_RBUTTON, lParam);
PostMessage(hWnd, WM_RBUTTONUP, MK_RBUTTON, lParam);

Does anyone know if there is something similar in Java or JNA?

Please do not suggest Java Robot. I have tried it, but unfortunately the mouse cursor moves (disappears) by about a milliseconds from the starting position to the point where you need to click and back to the starting position.

public void performClick(int x, int y) {
        Point origLoc = MouseInfo.getPointerInfo().getLocation();
        robot.mouseMove(x, y);
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
        robot.mouseMove(origLoc.x, origLoc.y);
    }

Solution

  • Short answer:

    No, but you can easily do it yourself.

    Long answer:

    As you said, "JNA ... in theory, should have all WinAPI functions." What is important to recognize is that there are two components to JNA, the core functionality that allows Java to interface with native (C) code via libffi, contained in the jna artifact; and the user-contributed platform mappings (including many WinAPI mappings) in jna-platform. So JNA has the ability to map anything in WinAPI but someone needs to contribute it to the project to share their work with others.

    Now regarding MAKELPARAM, it is simply a macro. You can see the source code for it here:

    #define MAKELPARAM(l, h)      ((LPARAM)(DWORD)MAKELONG(l, h))
    

    It calls the MAKELONG macro with (WORD) inputs l and h, casts that to a DWORD, and further casts that to a LPARAM.

    The MAKELONG macro is defined in Windef.h:

    #define MAKELONG(a, b)      ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))
    

    JNA does have the LPARAM type mapped, present in the WinDef class. It takes a long argument to the constructor.

    So you must simply take two 16-bit values l and h, map them to the rightmost 32 bits of a long, and send that long to the LPARAM constructor.

    So the solution you seek is:

    // int args are needed for unsigned 16-bit values
    public static WinDef.LPARAM makeLParam(int l, int h) {
        // note the high word bitmask must include L
        return new WinDef.LPARAM((l & 0xffff) | (h & 0xffffL) << 16);
    }