-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
User32 extensions to support Keyboard related functionality. #1063
Conversation
Extend User32 signatures. Introduce utility function for convenient use of LoadString and enum for all defined Win32 VK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left some comments inline. Please also add an entry to CHANGES.md
.
*/ | ||
public final int code; | ||
/** This VK may be used to map to a unicode codepoint in a Keyboard Layout. */ | ||
public final boolean mappable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does this info come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is based on own investigation. I understand that this might be borderline to include here, but it is such a useful bit of information. I can refactor the code to leave it out if you consider it out-of-policy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gave this a second thought and went for a feasible alternative. I have taken out mappable member and introduced User32Util.WIN32VK_MAPPABLE, a set of the mappable virtual keys. This makes the enum clean (based purely on header definitions) and keeps the information in a concise way as a useful utility.
* @return the VK enum instance. | ||
*/ | ||
public static Win32VK fromValue(final int code) { | ||
if (code < 0 || code > 0xFF) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason to special case this? The fall through to line 300 should catch it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.
* Virtual Keys, Standard Set | ||
*/ | ||
VK_LBUTTON(0x01, false), VK_RBUTTON(0x02, false), VK_CANCEL(0x03, true), VK_MBUTTON(0x04, false), /* | ||
* NOT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lines 15-19 look strange (indent?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
/* | ||
* Virtual Keys, Standard Set | ||
*/ | ||
VK_LBUTTON(0x01, false), VK_RBUTTON(0x02, false), VK_CANCEL(0x03, true), VK_MBUTTON(0x04, false), /* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please define one enum per line - its difficult to see where one entry ends and the next starts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.
/** | ||
* Handle to a input locale identifier (formerly called keyboard layout handle). | ||
*/ | ||
public static class HKL extends HANDLE { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The definition of HKL should be in the file matching its header - that would be WTypes.java. I'm not sure if HANDLE is the correct super class. The C definition is typedef void *HKL
. There is also the question: where does the information about the internal structure (embedded language identifier and device handle) come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HKL is defined as DECLARE_HANDLE(HKL);
in minwindef.h
So it should be defined same way as e.g. HINSTANCE
in the same file.
I have moved it to WinDef.java
.
The internal structure is described in the Javadoc of GetKeyboardLayout
, which is taken from official docs.
* If the function finds no key that translates to the passed character | ||
* code, both the low-order and high-order bytes contain -1. | ||
*/ | ||
short VkKeyScanEx(char ch, HKL dwhkl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is problematic - there are to definitions for this function:
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-vkkeyscanexw
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-vkkeyscanexa
At this point I would consider to explicitly map
short VkKeyScanExW(char ch, HKL dwhkl);
short VkKeyScanExA(byte ch, HKL dwhkl);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.
* character value, depending on the value of uCode and uMapType. If | ||
* there is no translation, the return value is zero. | ||
*/ | ||
UINT MapVirtualKeyEx(UINT uCode, UINT uMapType, HKL dwhkl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UINT is defined to be 32 bit wide (https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types) it might be substituted with an int.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UINT is extensively used in User32. I have it there for consistency with the remainder of the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User32 is old, the current calling parameters will not change to keep the API stable. If there is a good reason to use an UINT
I'm good with it. One thing UINT
can represent, that int can't is the unsignedness. So if the values need to be ordered a UINT
might be better.
* extended error information, call GetLastError. | ||
* | ||
*/ | ||
int LoadString(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int cchBufferMax); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'lpBufferis
LPTSTRand thus changes depending whether or not the unicode version is called. I would use a
Pointer` and add a convinience function to decode it. Have a look at this:
com.sun.jna.platform.win32.Kernel32Util.expandEnvironmentStrings(String)
there memory is allocated based on characters and read based on the unicode settings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pointer - OK.
There is already a convenience function using the more common way to call this function.
if (0 == x) { | ||
throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); | ||
} | ||
return new String(lpBuffer.getValue().getCharArray(0, x)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks suspicious. As written above, you could get a non unicde value, than you are interested in the byte array. And the Native#toString
functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pointer.getString() and Pointer.getWideString() cannot be used as the returned buffer might not be null terminated.
I am now distinguishing between Unicode and non-unicode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your work. In general this looks good. I left a few comments inline. One think I'd like to see before merging are unittests for the new functions. I learned the hard way, that they help.
@@ -2001,4 +2003,83 @@ public String toString() { | |||
* or 22 kHz PCM. | |||
*/ | |||
public int CF_WAVE = 12; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please correct the indention. There is not "one right" indention style for JNA, but in most cases 4 spaces per indention level is correct. Tabs are normally not used.
/** | ||
* Bitmask for the SHIFT key modifier. | ||
*/ | ||
int MODIFIER_SHIFT_MASK = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where do the "MODIFIER_*" constants from? I could not find in my headers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are in the documentation of the function. I have extracted them as constants.
/** | ||
* Handle to a input locale identifier (formerly called keyboard layout handle). | ||
*/ | ||
public static class HKL extends HANDLE { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reindent (4 spaces per ident level)
/** | ||
* Set of {@link Win32VK} members that can be mapped to a UniCode code point via a keyboard layout. | ||
*/ | ||
public static final EnumSet<Win32VK> WIN32VK_MAPPABLE = EnumSet.of(Win32VK.VK_BACK, Win32VK.VK_TAB, Win32VK.VK_CLEAR, Win32VK.VK_RETURN, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I'm not mistaken the WIN32VK_MAPPABLE
property is derived, as is the introducedVersion
in the Win32VK
enum. You pulled one out. I have no strong feelings either way, if you want to reintegrate the mappable property from the first revision, I would be ok with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the mappable property like this. Very convenvient to use and clearly distinguished header values vs. "other known" values.
introducedVersion is part of the header (IFDEF), so it should be in the enum.
* character value, depending on the value of uCode and uMapType. If | ||
* there is no translation, the return value is zero. | ||
*/ | ||
UINT MapVirtualKeyEx(UINT uCode, UINT uMapType, HKL dwhkl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User32 is old, the current calling parameters will not change to keep the API stable. If there is a good reason to use an UINT
I'm good with it. One thing UINT
can represent, that int can't is the unsignedness. So if the values need to be ordered a UINT
might be better.
* the high word contains a device handle to the physical layout of the | ||
* keyboard. | ||
*/ | ||
HKL GetKeyboardLayout(DWORD idThread); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment below for my reasoning (comment on UINT)
I have added the tests and also applied some minor cosmetics. I have not found a source formatting definition. Please create one and then the source base can be reformatted in a tidy matter. I got rid of the tabs. Hope this can be closed now. Keve |
I added some more changes - see here: https://github.com/matthiasblaesing/jna/commits/pr-1063 |
Looked at your changes. All fine with me. Indeed the non-English locale was a good one... Cheers, |
Merged as 07adbff |
Extend User32 signatures. Introduce utility function for convenient use
of LoadString and enum for all defined Win32 VK.