0

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.

According to Microsoft:

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.

(source)

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.

Zhro
  • 2,546
  • 2
  • 29
  • 39

4 Answers4

1

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.

Anders
  • 97,548
  • 12
  • 110
  • 164
  • Identifying the scan code by monitoring the input messages you referenced counts as user intervention. I want to find the scan code without the user having to press a key first. – Zhro Jul 05 '18 at 01:57
  • "The scan code depends on the hardware" is not accurate in this context. A physical key is identified as Enter only if the keyboard layout (purely a software construct) maps that particular scan code to VK_RETURN. Different hardware cannot give the Enter or Numpad Enter key a different scan code than expected by the keyboard layout (software), because that would prevent it from being recognized as Enter. On the other hand, a different (perhaps custom) keyboard layout can map any scan code to VK_RETURN, regardless of what the key physically appears to be. – Lexikos Oct 12 '19 at 03:21
  • @Lexikos The point is, don't hardcode scancodes in high level code, that is why VK_ exists. – Anders Oct 12 '19 at 06:13
  • @Anders It is a poor point, based on false reasoning. Your suggestion to check bit 24 in combination with `VK_RETURN` is a good one (although bit 24 is *derived from the scan code* and may be set for scan codes other than Numpad Enter in a custom layout), but that doesn't make the rest of your answer any more accurate. *That* is the point of my comment. – Lexikos Oct 12 '19 at 21:40
1

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:

  1. Change the labels visible on the keys but keep the scan codes in the same physical positions. For the function of each key to match its label, the user must choose, install or create the correct keyboard layout in software.
  2. Physically move keys, or assign pre-established scan codes to different physical positions. The OS doesn't know or care where any key is physically; it just maps scan codes to virtual keycodes based on the current keyboard layout.

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.

Lexikos
  • 987
  • 6
  • 16
0

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?

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
0

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.

DJm00n
  • 1,083
  • 5
  • 18