Reputation: 2614
I would like to add certain behavior to my program that binds a function to the numpad enter key, if it is present, or bind an alternate key if it is not.
The scan code is the value that the keyboard hardware generates when the user presses a key. It is a device-dependent value that identifies the key pressed, as opposed to the character represented by the key. An application typically ignores scan codes. Instead, it uses the device-independent virtual-key codes to interpret keystroke messages.
I know that on my keyboard it is 0x9C (156), but this is not guaranteed to hold true for all keyboards.
I can't use MapVirtualKey()
with VK_RETURN
and MAPVK_VK_TO_VSC
as this always returns the scan code for the primary return key in the center of the keyboard.
How can I obtain this information without any intervention on the part of the user?
My language is C/C++ and this is for Win32 only.
Upvotes: 0
Views: 1981
Reputation: 1441
As an addition to @Lexikos great answer:
The scan code is the value that the keyboard hardware generates when the user presses a key. It is a device-dependent value that identifies the key pressed, as opposed to the character represented by the key.
This was true in encient days. At least since Windows NT system uses PS/2 Scan Code Set 1 for all keyboard APIs. With some bugs that are specifically supported for backwards compatibility (for example NumLock and Pause scan codes are swapped. They are special.).
Under all Microsoft operating systems, all keyboards actually transmit Scan Code Set 2 values down the wire from the keyboard to the keyboard port. These values are translated to Scan Code Set 1 by the i8042 port chip. The rest of the operating system, and all applications that handle scan codes expect the values to be from Scan Code Set 1. Scan Code Set 3 is not used or required for operation of Microsoft operating systems. (Keyboard Scan Code Specification Revision 1.3a — March 16, 2000)
Because of this some API docs are reffering to scan codes as to virtual scan codes.
Modern USB or Bluetooth keyboard are using HID protocol with its HID Usage IDs to report key presses (see 10 Keyboard/Keypad Page (0x07)
in HID Usage Tables spec for a list of possible keyboard key Usage IDs).
These HID Usages get converted to PS/2 Scan Code Set 1 by kbdclass driver (HID client mapper driver for keyboards) via call to HidP_TranslateUsagesToI8042ScanCodes API. It works according to published spec. So we actually have a published scan code list that is used in Windows. If you're interested in history behind this scan code mess - there is a good page.
There is no way to detect if keypad Enter button is present on particular keyboard hardware.
Upvotes: 1
Reputation: 1067
For Numpad Enter to be recognized as either kind of Enter, the keyboard hardware must send a scan code that maps to VK_RETURN
within the current keyboard layout. Keyboard layout is determined by system settings and the window which is receiving keyboard input (or the user), not by the physical keyboard. It is quite possible that the virtual keyboard layout does not match the physical keyboard (i.e. the labels on the keys don't match their functions).
There are two strategies for allowing different physical keyboard layouts to function correctly:
Both Enter and Numpad Enter are mapped to VK_RETURN
; there is no virtual key code reserved for Numpad Enter, so no way for it to have different scan codes on different keyboard layouts. With strategy #1, any key can be turned into Enter, but not specifically Numpad Enter. With strategy #2, Numpad Enter still has the same scan code as usual.
At the hardware level, Enter sends 0x1C
while Numpad Enter sends 0xE0 0x1C
(source: my own observations and a document by Andries Brouwer). Windows has different ways of reporting this: with bit 24 of WM_KEYDOWN
's lParam
, the LLKHF_EXTENDED
flag for low level keyboard hooks, the RI_KEY_E0
flag for Raw Input, and possibly more.
In short, it is safe to assume that Numpad Enter is 0x1C plus the extended-key flag, since in any other case, it is impossible to identify.
I know that on my keyboard it is 0x9C (156)
I assume that you received this value from DirectInput, which defines an enum constant DIK_NUMPADENTER
with value 0x9C. This value is not a scan code.
Upvotes: 1
Reputation: 25388
Anders makes a good point - I don't know of a way to tell if that key is present on (one of the) keyboard (s) present on any particular system. Also, don't forget about the Onscreen Keyboard and touch devices in general.
Why not simply bind your function to both keys regardless? Do you have a good reason not to do this?
Upvotes: 0
Reputation: 101746
The scan code depends on the hardware, it might not be the same on a different system. There can be more than one scan code that maps to a virtual key. Virtual keys are supposed to be somewhat generic and not tied to the hardware.
You can tell the difference in WM_KEYDOWN
and WM_KEYUP
; WPARAM
is VK_RETURN
and bit 24 is set in LPARAM
when the Enter key on the numpad is used:
Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
GetKeyboardType
can tell you some information about "the keyboard" but since there can be more than one keyboard connected these days you would have to go deeper to find out if there are any keyboards that have the properties you are looking for. Perhaps the SetupAPI knows.
Upvotes: 1