Skip to content

Commit 07adbff

Browse files
Keve Müllermatthiasblaesing
authored andcommitted
User32 extensions to support Keyboard related functionality.
Extend User32 signatures. Introduce utility function for convenient use of LoadString and enum for all defined Win32 VK.
1 parent 13d6c8a commit 07adbff

9 files changed

Lines changed: 1104 additions & 4 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Features
1212
* [#1061](https://github.com/java-native-access/jna/pull/1061): replace toArray(new T[size]) with toArray(new T[0]) for better performance - [@hc-codersatlas](https://github.com/hc-codersatlas).
1313
* [#1064](https://github.com/java-native-access/jna/pull/1064): Add `c.s.j.p.win32.Kernel32.GetLogicalProcessorInformationEx` function, convenience Util method and supporting structures - [@dbwiddis](https://github.com/dbwiddis).
1414
* [#1065](https://github.com/java-native-access/jna/pull/1065): Add `c.s.j.p.win32.PowrProf#CallNTPowerInformation` and supporting structures - [@dbwiddis](https://github.com/dbwiddis).
15+
* [#1063](https://github.com/java-native-access/jna/pull/1063): Enhance `c.s.j.p.win32.User32` and associated classes to support keyboard related functionality. - [@kevemueller](https://github.com/kevemueller).
1516

1617
Bug Fixes
1718
---------

contrib/platform/src/com/sun/jna/platform/win32/User32.java

Lines changed: 228 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.sun.jna.win32.StdCallLibrary;
3333
import com.sun.jna.win32.W32APIOptions;
3434

35+
3536
/**
3637
* Provides access to the w32 user32 library. Incomplete implementation to
3738
* support demos.
@@ -2484,5 +2485,231 @@ HANDLE SetWinEventHook(int eventMin, int eventMax, HMODULE hmodWinEventProc, Win
24842485
* - with a WM_COPYDATA msg value : wParam is the length of the structure and lParam a pointer to a COPYDATASTRUCT
24852486
*/
24862487
LRESULT SendMessage(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam);
2487-
2488+
2489+
/**
2490+
* Retrieves the input locale identifiers (formerly called keyboard layout
2491+
* handles) corresponding to the current set of input locales in the system. The
2492+
* function copies the identifiers to the specified buffer.
2493+
*
2494+
* @param nBuff The maximum number of handles that the buffer can hold.
2495+
* @param lpList A pointer to the buffer that receives the array of input locale
2496+
* identifiers.
2497+
* @return If the function succeeds, the return value is the number of input
2498+
* locale identifiers copied to the buffer or, if nBuff is zero, the
2499+
* return value is the size, in array elements, of the buffer needed to
2500+
* receive all current input locale identifiers. If the function fails,
2501+
* the return value is zero. To get extended error information, call
2502+
* GetLastError.
2503+
*/
2504+
int GetKeyboardLayoutList(int nBuff, HKL[] lpList);
2505+
2506+
/**
2507+
* Retrieves the active input locale identifier (formerly called the keyboard
2508+
* layout).
2509+
*
2510+
* @param idThread The identifier of the thread to query, or 0 for the current
2511+
* thread.
2512+
* @return The return value is the input locale identifier for the thread. The
2513+
* low word contains a Language Identifier for the input language and
2514+
* the high word contains a device handle to the physical layout of the
2515+
* keyboard.
2516+
*/
2517+
HKL GetKeyboardLayout(int idThread);
2518+
2519+
/**
2520+
* This function retrieves the name of the active keyboard layout.
2521+
*
2522+
* @param pwszKLID [in] Pointer to the buffer of at least {@link #KL_NAMELENGTH}
2523+
* characters that is to receive the name of the keyboard
2524+
* layout, including the terminating null character.
2525+
* @return Nonzero indicates success. Zero indicates failure. To get extended
2526+
* error information, call GetLastError.
2527+
*/
2528+
boolean GetKeyboardLayoutName(char[] pwszKLID);
2529+
2530+
/**
2531+
* Translates a character to the corresponding virtual-key code and shift state.
2532+
* The function translates the character using the input language and physical
2533+
* keyboard layout identified by the input locale identifier.
2534+
*
2535+
* @param ch The character to be translated into a virtual-key code.
2536+
* @param dwhkl Input locale identifier to use for translating the specified
2537+
* code. This parameter can be any input locale identifier
2538+
* previously returned by the {@link #LoadKeyboardLayout()}
2539+
* function.
2540+
* @return If the function succeeds, the low-order byte of the return value
2541+
* contains the virtual-key code and the high-order byte contains the
2542+
* shift state, which can be a combination of the following flag bits.
2543+
* <dl>
2544+
* <dt>1</dt>
2545+
* <dd>Either SHIFT key is pressed. Use
2546+
* {@link WinUser#MODIFIER_SHIFT_MASK}.</dd>
2547+
* <dt>2</dt>
2548+
* <dd>Either CTRL key is pressed. Use
2549+
* {@link WinUser#MODIFIER_CTRL_MASK}.</dd>
2550+
* <dt>4</dt>
2551+
* <dd>Either ALT key is pressed. Use
2552+
* {@link WinUser#MODIFIER_ALT_MASK}.</dd>
2553+
* <dt>8</dt>
2554+
* <dd>The Hankaku key is pressed. Use
2555+
* {@link WinUser#MODIFIER_HANKAKU_MASK}.</dd>
2556+
* <dt>16</dt>
2557+
* <dd>Reserved (defined by the keyboard layout driver). Use
2558+
* {@link WinUser#MODIFIER_RESERVED1_MASK}.</dd>
2559+
* <dt>32</dt>
2560+
* <dd>Reserved (defined by the keyboard layout driver). Use
2561+
* {@link WinUser#MODIFIER_RESERVED2_MASK}.</dd>
2562+
* </dl>
2563+
* If the function finds no key that translates to the passed character
2564+
* code, both the low-order and high-order bytes contain -1.
2565+
*/
2566+
short VkKeyScanExA(byte ch, HKL dwhkl);
2567+
2568+
/**
2569+
* Translates a character to the corresponding virtual-key code and shift state.
2570+
* The function translates the character using the input language and physical
2571+
* keyboard layout identified by the input locale identifier.
2572+
*
2573+
* @param ch The character to be translated into a virtual-key code.
2574+
* @param dwhkl Input locale identifier to use for translating the specified
2575+
* code. This parameter can be any input locale identifier
2576+
* previously returned by the {@link #LoadKeyboardLayout()}
2577+
* function.
2578+
* @return If the function succeeds, the low-order byte of the return value
2579+
* contains the virtual-key code and the high-order byte contains the
2580+
* shift state, which can be a combination of the following flag bits.
2581+
* <dl>
2582+
* <dt>1</dt>
2583+
* <dd>Either SHIFT key is pressed. Use
2584+
* {@link WinUser#MODIFIER_SHIFT_MASK}.</dd>
2585+
* <dt>2</dt>
2586+
* <dd>Either CTRL key is pressed. Use
2587+
* {@link WinUser#MODIFIER_CTRL_MASK}.</dd>
2588+
* <dt>4</dt>
2589+
* <dd>Either ALT key is pressed. Use
2590+
* {@link WinUser#MODIFIER_ALT_MASK}.</dd>
2591+
* <dt>8</dt>
2592+
* <dd>The Hankaku key is pressed. Use
2593+
* {@link WinUser#MODIFIER_HANKAKU_MASK}.</dd>
2594+
* <dt>16</dt>
2595+
* <dd>Reserved (defined by the keyboard layout driver). Use
2596+
* {@link WinUser#MODIFIER_RESERVED1_MASK}.</dd>
2597+
* <dt>32</dt>
2598+
* <dd>Reserved (defined by the keyboard layout driver). Use
2599+
* {@link WinUser#MODIFIER_RESERVED2_MASK}.</dd>
2600+
* </dl>
2601+
* If the function finds no key that translates to the passed character
2602+
* code, both the low-order and high-order bytes contain -1.
2603+
*/
2604+
short VkKeyScanExW(char ch, HKL dwhkl);
2605+
2606+
/**
2607+
* Translates (maps) a virtual-key code into a scan code or character value, or
2608+
* translates a scan code into a virtual-key code. The function translates the
2609+
* codes using the input language and an input locale identifier.
2610+
*
2611+
* @param uCode The virtual-key code or scan code for a key. How this value
2612+
* is interpreted depends on the value of the uMapType
2613+
* parameter. Starting with Windows Vista, the high byte of the
2614+
* uCode value can contain either 0xe0 or 0xe1 to specify the
2615+
* extended scan code.
2616+
* @param uMapType The translation to perform. The value of this parameter
2617+
* depends on the value of the uCode parameter. One of
2618+
* {@link WinUser#MAPVK_VK_TO_CHAR},
2619+
* {@link WinUser#MAPVK_VK_TO_VSC},
2620+
* {@link WinUser#MAPVK_VK_TO_VSC_EX},
2621+
* {@link WinUser#MAPVK_VSC_TO_VK},
2622+
* {@link WinUser#MAPVK_VSC_TO_VK_EX}
2623+
*
2624+
* @param dwhkl Input locale identifier to use for translating the specified
2625+
* code. This parameter can be any input locale identifier
2626+
* previously returned by the {@link #LoadKeyboardLayout()}
2627+
* function.
2628+
* @return The return value is either a scan code, a virtual-key code, or a
2629+
* character value, depending on the value of uCode and uMapType. If
2630+
* there is no translation, the return value is zero.
2631+
*/
2632+
int MapVirtualKeyEx(int uCode, int uMapType, HKL dwhkl);
2633+
2634+
/**
2635+
* Translates the specified virtual-key code and keyboard state to the
2636+
* corresponding Unicode character or characters.
2637+
*
2638+
* @param wVirtKey The virtual-key code to be translated.
2639+
* @param wScanCode The hardware scan code of the key to be translated. The
2640+
* high-order bit of this value is set if the key is up.
2641+
* @param lpKeyState A pointer to a 256-byte array that contains the current
2642+
* keyboard state. Each element (byte) in the array contains
2643+
* the state of one key. If the high-order bit of a byte is
2644+
* set, the key is down.
2645+
* @param pwszBuff The buffer that receives the translated Unicode character
2646+
* or characters. However, this buffer may be returned without
2647+
* being null-terminated even though the variable name
2648+
* suggests that it is null-terminated.
2649+
* @param cchBuff The size, in characters, of the buffer pointed to by the
2650+
* pwszBuff parameter.
2651+
* @param wFlags The behavior of the function. If bit 0 is set, a menu is
2652+
* active. If bit 2 is set, keyboard state is not changed
2653+
* (Windows 10, version 1607 and newer) All other bits
2654+
* (through 31) are reserved.
2655+
* @param dwhkl Input locale identifier to use for translating the
2656+
* specified code. This parameter can be any input locale
2657+
* identifier previously returned by the
2658+
* {@link #LoadKeyboardLayout()} function.
2659+
* @return The function returns one of the following values.
2660+
* <dl>
2661+
* <dt>-1</dt>
2662+
* <dd>The specified virtual key is a dead-key character (accent or
2663+
* diacritic). This value is returned regardless of the keyboard layout,
2664+
* even if several characters have been typed and are stored in the
2665+
* keyboard state. If possible, even with Unicode keyboard layouts, the
2666+
* function has written a spacing version of the dead-key character to
2667+
* the buffer specified by pwszBuff. For example, the function writes
2668+
* the character SPACING ACUTE (0x00B4), rather than the character
2669+
* NON_SPACING ACUTE (0x0301).</dd>
2670+
* <dt>0</dt>
2671+
* <dd>The specified virtual key has no translation for the current
2672+
* state of the keyboard. Nothing was written to the buffer specified by
2673+
* pwszBuff.</dd>
2674+
* <dt>1</dt>
2675+
* <dd>One character was written to the buffer specified by
2676+
* pwszBuff.</dd>
2677+
* <dt>2&le;value</dt>
2678+
* <dd>Two or more characters were written to the buffer specified by
2679+
* pwszBuff. The most common cause for this is that a dead-key character
2680+
* (accent or diacritic) stored in the keyboard layout could not be
2681+
* combined with the specified virtual key to form a single character.
2682+
* However, the buffer may contain more characters than the return value
2683+
* specifies. When this happens, any extra characters are invalid and
2684+
* should be ignored.</dd>
2685+
* </dl>
2686+
*
2687+
*/
2688+
int ToUnicodeEx(int wVirtKey, int wScanCode, byte[] lpKeyState, char[] pwszBuff, int cchBuff, int wFlags,
2689+
HKL dwhkl);
2690+
2691+
/**
2692+
* Loads a string resource from the executable file associated with a specified
2693+
* module, copies the string into a buffer, and appends a terminating null
2694+
* character.
2695+
*
2696+
* @param hInstance A handle to an instance of the module whose executable
2697+
* file contains the string resource. To get the handle to
2698+
* the application itself, call the GetModuleHandle function
2699+
* with NULL.
2700+
* @param uID The identifier of the string to be loaded.
2701+
* @param lpBuffer The buffer is to receive the string. Must be of
2702+
* sufficient length to hold a pointer (8 bytes).
2703+
* @param cchBufferMax The size of the buffer, in characters. The string is
2704+
* truncated and null-terminated if it is longer than the
2705+
* number of characters specified. If this parameter is 0,
2706+
* then lpBuffer receives a read-only pointer to the
2707+
* resource itself.
2708+
* @return If the function succeeds, the return value is the number of
2709+
* characters copied into the buffer, not including the terminating null
2710+
* character, or zero if the string resource does not exist. To get
2711+
* extended error information, call GetLastError.
2712+
*
2713+
*/
2714+
int LoadString(HINSTANCE hInstance, int uID, Pointer lpBuffer, int cchBufferMax);
24882715
}

contrib/platform/src/com/sun/jna/platform/win32/User32Util.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,29 @@
2424
*/
2525

2626
package com.sun.jna.platform.win32;
27+
import com.sun.jna.Memory;
2728
import java.util.Arrays;
2829
import java.util.List;
2930

31+
import com.sun.jna.Native;
32+
import com.sun.jna.Pointer;
3033
import com.sun.jna.platform.win32.WinDef.HINSTANCE;
3134
import com.sun.jna.platform.win32.WinDef.HMENU;
35+
import com.sun.jna.platform.win32.WinDef.HMODULE;
3236
import com.sun.jna.platform.win32.WinDef.HWND;
3337
import com.sun.jna.platform.win32.WinDef.LPVOID;
3438
import com.sun.jna.platform.win32.WinUser.MSG;
3539
import com.sun.jna.platform.win32.WinUser.RAWINPUTDEVICELIST;
3640
import com.sun.jna.ptr.IntByReference;
41+
import com.sun.jna.win32.W32APITypeMapper;
42+
43+
import java.io.UnsupportedEncodingException;
3744
import java.lang.reflect.InvocationHandler;
3845
import java.lang.reflect.InvocationTargetException;
3946
import java.lang.reflect.Method;
4047
import java.util.ArrayList;
4148
import java.util.Collections;
49+
import java.util.EnumSet;
4250
import java.util.concurrent.Callable;
4351
import java.util.concurrent.ExecutionException;
4452
import java.util.concurrent.Future;
@@ -268,4 +276,59 @@ protected boolean getMessageFailed() {
268276
return true;
269277
}
270278
}
279+
280+
/**
281+
* Load a string value from the string table of an executable.
282+
*
283+
* @param location the location, eg. %SystemRoot%\system32\input.dll,-5011
284+
* @return
285+
* @throws UnsupportedEncodingException
286+
*/
287+
public static String loadString(String location) throws UnsupportedEncodingException {
288+
int x = location.lastIndexOf(',');
289+
String moduleName = location.substring(0, x);
290+
int index = Math.abs(Integer.parseInt(location.substring(x + 1)));
291+
String path = Kernel32Util.expandEnvironmentStrings(moduleName);
292+
HMODULE target = Kernel32.INSTANCE.LoadLibraryEx(path, null, Kernel32.LOAD_LIBRARY_AS_DATAFILE);
293+
if (target == null) {
294+
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
295+
}
296+
Pointer lpBuffer = new Memory(Native.POINTER_SIZE);
297+
x = User32.INSTANCE.LoadString(target, index, lpBuffer, 0);
298+
if (0 == x) {
299+
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
300+
}
301+
302+
if (W32APITypeMapper.DEFAULT == W32APITypeMapper.UNICODE) {
303+
return new String(lpBuffer.getPointer(0).getCharArray(0, x));
304+
} else {
305+
return new String(lpBuffer.getPointer(0).getByteArray(0, x), Native.getDefaultStringEncoding());
306+
}
307+
}
308+
309+
/**
310+
* Set of {@link Win32VK} members that can be mapped to a UniCode code point via
311+
* a keyboard layout.
312+
*/
313+
public static final EnumSet<Win32VK> WIN32VK_MAPPABLE = EnumSet.of(Win32VK.VK_BACK, Win32VK.VK_TAB,
314+
Win32VK.VK_CLEAR, Win32VK.VK_RETURN, Win32VK.VK_ESCAPE, Win32VK.VK_SPACE, Win32VK.VK_SELECT,
315+
Win32VK.VK_EXECUTE, Win32VK.VK_0, Win32VK.VK_1, Win32VK.VK_2, Win32VK.VK_3, Win32VK.VK_4, Win32VK.VK_5,
316+
Win32VK.VK_6, Win32VK.VK_7, Win32VK.VK_8, Win32VK.VK_9, Win32VK.VK_A, Win32VK.VK_B, Win32VK.VK_C,
317+
Win32VK.VK_D, Win32VK.VK_E, Win32VK.VK_F, Win32VK.VK_G, Win32VK.VK_H, Win32VK.VK_I, Win32VK.VK_J,
318+
Win32VK.VK_K, Win32VK.VK_L, Win32VK.VK_M, Win32VK.VK_N, Win32VK.VK_O, Win32VK.VK_P, Win32VK.VK_Q,
319+
Win32VK.VK_R, Win32VK.VK_S, Win32VK.VK_T, Win32VK.VK_U, Win32VK.VK_V, Win32VK.VK_W, Win32VK.VK_X,
320+
Win32VK.VK_Y, Win32VK.VK_Z, Win32VK.VK_NUMPAD0, Win32VK.VK_NUMPAD1, Win32VK.VK_NUMPAD2, Win32VK.VK_NUMPAD3,
321+
Win32VK.VK_NUMPAD4, Win32VK.VK_NUMPAD5, Win32VK.VK_NUMPAD6, Win32VK.VK_NUMPAD7, Win32VK.VK_NUMPAD8,
322+
Win32VK.VK_NUMPAD9, Win32VK.VK_MULTIPLY, Win32VK.VK_ADD, Win32VK.VK_SEPARATOR, Win32VK.VK_SUBTRACT,
323+
Win32VK.VK_DECIMAL, Win32VK.VK_DIVIDE, Win32VK.VK_OEM_NEC_EQUAL, Win32VK.VK_OEM_FJ_MASSHOU,
324+
Win32VK.VK_OEM_FJ_TOUROKU, Win32VK.VK_OEM_FJ_LOYA, Win32VK.VK_OEM_FJ_ROYA, Win32VK.VK_OEM_1,
325+
Win32VK.VK_OEM_PLUS, Win32VK.VK_OEM_COMMA, Win32VK.VK_OEM_MINUS, Win32VK.VK_OEM_PERIOD, Win32VK.VK_OEM_2,
326+
Win32VK.VK_OEM_3, Win32VK.VK_RESERVED_C1, Win32VK.VK_RESERVED_C2, Win32VK.VK_OEM_4, Win32VK.VK_OEM_5,
327+
Win32VK.VK_OEM_6, Win32VK.VK_OEM_7, Win32VK.VK_OEM_8, Win32VK.VK_OEM_AX, Win32VK.VK_OEM_102,
328+
Win32VK.VK_ICO_HELP, Win32VK.VK_PROCESSKEY, Win32VK.VK_ICO_CLEAR, Win32VK.VK_PACKET, Win32VK.VK_OEM_RESET,
329+
Win32VK.VK_OEM_JUMP, Win32VK.VK_OEM_PA1, Win32VK.VK_OEM_PA2, Win32VK.VK_OEM_PA3, Win32VK.VK_OEM_WSCTRL,
330+
Win32VK.VK_OEM_CUSEL, Win32VK.VK_OEM_ATTN, Win32VK.VK_OEM_FINISH, Win32VK.VK_OEM_COPY, Win32VK.VK_OEM_AUTO,
331+
Win32VK.VK_OEM_ENLW, Win32VK.VK_OEM_BACKTAB, Win32VK.VK_ATTN, Win32VK.VK_CRSEL, Win32VK.VK_EXSEL,
332+
Win32VK.VK_EREOF, Win32VK.VK_PLAY, Win32VK.VK_ZOOM, Win32VK.VK_NONAME, Win32VK.VK_PA1,
333+
Win32VK.VK_OEM_CLEAR);
271334
}

0 commit comments

Comments
 (0)