The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 4,266 other subscribers

delphi – What is the meaning of the bScan parameter value 0x45 in keybd_event? – Stack Overflow

Posted by jpluimers on 2024/06/06

From a long time go and a project that got cancelled, but maybe in the future I will need a similar thing again: back in the days not all raw key codes were readily documented or converted correctly from winuser.h to other environments (0x45 is the keyboard raw scan code value for VK_NUMLOCK of the Num Lock key).

[Wayback/Archive] delphi – What is the meaning of the bScan parameter value 0x45 in keybd_event? – Stack Overflow (thanks [Wayback/Archive] David Heffernan and [Wayback/Archive] kludg):

Q

[Wayback/Archive] Many examples of using [Wayback/Archive] keybd_event, have the value 0x45 for the bScan parameter.

What is the meaning of that 0x45 value?

I was under the impression [Wayback/Archive] 0x45 was a keyboard scancode, but since it is used for a various number of keys, I’m not so sure about that any more.

My goal is to use keybd_event either from .NET P/Invoke, or from Delphi, and make the types more restrictive (using for instance enums or flagged enums) so my code becomes easier to maintain.

A

It is indeed a scan code and for many keyboards it is the scan code for the NumLock key.

The example code attached to the documentation of keybd_event is an example of how to toggle the NumLock state. And so naturally 0x45 is used as the scan code. My guess is that lots of the other examples that you found simply copied blindly that value from the keybd_event MSDN example. Since [Wayback/Archive] applications typically ignore the scan code and respond to the virtual key code, it usually doesn’t matter what value is passed as the scan code.

Finally, you’ll want to use SendInput rather than keybd_event. The reason being that that former allows you to place a sequence of events in the queue. With keybd_event you place the events in the queue one at a time and it’s possible that your faked events can get interspersed with real events. And that problem is one of the main reasons why SendInput was introduced.

C

Delphi ignores scan code info, ex when generates OnKeyDown event. If somebody needs to extract key scan codes he should handle corresponding windows messages (ex WM_KEYDOWN) directly.

Thanks. I’ll give [Wayback/ArchiveSendInput and [Wayback/ArchiveP/Invoke SendInput a shot. Will get back later on this.

Related:

  • [Wayback/Archive] Keyboard Input Overview – Win32 apps | Microsoft Learn is a very comprehensive page which in depth explains keyboard handling. Read in full. Then read it in full again as it is dense.
  • [Wayback/Archive] keybd_event function (winuser.h) – Win32 apps | Microsoft Docs

    Examples

    The following sample program toggles the NUM LOCK light by using keybd_event with a virtual key of VK_NUMLOCK. It takes a Boolean value that indicates whether the light should be turned off (FALSE) or on (TRUE). The same technique can be used for the CAPS LOCK key (VK_CAPITAL) and the SCROLL LOCK key (VK_SCROLL).

    
       #include <windows.h>
    
       void SetNumLock( BOOL bState )
       {
          BYTE keyState[256];
    
          GetKeyboardState((LPBYTE)&keyState);
          if( (bState && !(keyState[VK_NUMLOCK] & 1)) ||
              (!bState && (keyState[VK_NUMLOCK] & 1)) )
          {
          // Simulate a key press
             keybd_event( VK_NUMLOCK,
                          0x45,
                          KEYEVENTF_EXTENDEDKEY | 0,
                          0 );
    
          // Simulate a key release
             keybd_event( VK_NUMLOCK,
                          0x45,
                          KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
                          0);
          }
       }
    
       void main()
       {
          SetNumLock( TRUE );
       }
    
  • Tables with raw keyboard scan codes are in:
    • [Wayback/Archive] Keyboard inputs – scancodes, raw input, text input, key names | Handmade Network

      How to get scancodes

      First let’s start by saying that you can use both scancodes and virtual keys at the same time. It’s probably a good feature to have both.

      When you receive a WM_KEYDOWNWM_KEYUPWM_SYSKEYDOWNWM_SYSKEYUP message the lParam parameter contains the scancode in the 16 – 23 bits and the 24th bit indicates if the scancode is 1 or 2 bytes (extended). If the scancode is extended, you just need to add 0xE000 or 0xE100.

      There are a few catches:

      • VK_PAUSE will give you a value of 0x45, but when using raw input it is 0xE11D 0x45 (the value in the list)
      • VK_NUMLOCK will give you a value of 0xE045, but when using raw input it is 0x45 (the value in the list)
      • Some keys change the scancode value if shift, alt, control (left or right) or a combination of those keys are pressed. The only visible change in the WM_KEYDOWN… messages are VK_PAUSE that generates 0x0E46 (sc_cancel, or “Break”) when control is pressed and VK_SNAPSHOT (print screen) that will give you a value of 0x54 if alt is pressed. We could use 0x54 and consider it a different key, but windows doesn’t have a text name for the scancode value of 0x54 so I chose to force it to the same value as print screen

      A few things to know:

      • There are no WM_KEYDOWN for the print screen key and so if you hold the key down it’s never repeated
      • There are no break code for “Pause” so I don’t know how the key down/up is expected to work (I remember reading somewhere that the key should be consider up as soon as the down message is sent, but I can’t find it back). Raw input sends “keydown” and “keyup” message, and it appears that the keyup message is sent directly after the keydown message (you can’t hold the key down) so depending on when GetMessage or PeekMessage are called, you may get both a keydown and keyup message “in the same frame”. If you use VK messages most of the time you only get keydown messages, but some times you get a keyup message too
      • According to the Microsoft scancode.doc (links above), pause is the only key that never repeats when held down (Print screen reapeats if you use raw input)
      • The right alt key (Alt Gr which stands for Alternate Graphics) sends a alt message and a control message
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      case WM_SYSKEYDOWN:
      case WM_SYSKEYUP:
      case WM_KEYDOWN:
      case WM_KEYUP: {
      
          unsigned int scancode = ( message.lParam >> 16 ) & 0xff;
          unsigned int extended = ( message.lParam >> 24 ) & 0x1;
      
          if ( extended ) {
      
              if ( scancode != 0x45 ) {
                  scancode |= 0xE000;
              }
      
          } else {
      
              if ( scancode == 0x45 ) {
                  scancode = 0xE11D45;
              } else if ( scancode == 0x54 ) {
                  scancode = 0xE037;
              }
          }
      
          // Get the key state and store it...
      }
    • [Wayback/Archive] PS/2 Keyboard – OSDev Wiki

      Scan codes themselves are sequences of one or more bytes. In some cases the sequence can be as many as 6 bytes (e.g. the Pause/Break key in scan code set 1 generates the sequence 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 when pressed). This situation isn’t really ideal. In general (for later processing) you want to convert these “one or more byte sequences” into a single integer that uniquely identifies a specific key, that can be used effectively in things like lookup tables (without having sparsely used “many GiB” lookup tables).

      Scan Code Set 1:

      0x45 NumberLock pressed

      0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 pause pressed

      Scan Code set 2:

      0x45 0 (zero) pressed

      0xF0, 0x45 0 (zero) released

–jeroen

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.