4

Is there a way to programmatically find out what kind of keyboard a computer has (i.e. where keys are located, and what extra keys are present in which locations)?

A little error is acceptable, if the keyboard is very non-standard, but in general, the point is to construct an on-screen keyboard-like application that can dynamically draw the keyboard layout on the screen, with high accuracy.

Braiam
  • 1
  • 11
  • 47
  • 78
user541686
  • 205,094
  • 128
  • 528
  • 886

3 Answers3

5

when connected to a computer, keyboards sends "scan codes" to the operating system. on windows, scan codes are then converted into virtual keys (a hardware independent mapping of the keyboard) then to real characters.

the MapVirtualKeyEx() function of the windows API allows you to translate between scan codes, virtual keys and characters. it should also be able to tell you if a key is non-existing.

together with GetKeyboardLayout() which tells you which keybaord is active at any point in time (keyboard layout can be different for different running applications), it should allow you to build a pretty accurate map of the keyboard.

anyway, have a look at the keyboard input section of the MSDN

i will add that all keyboards have almost the same layout. although there is no way to know where a key is physically located, you can probably guess from the scan code and basic knowledge of your own keyboards.

Adrien Plisson
  • 22,486
  • 6
  • 42
  • 73
  • But in that way You get only the key number the layout has, right? Or that retrieved number includes media buttons? –  Jul 29 '11 at 10:28
4

There is no mechanism by which a keyboard can tell Windows what its physical layout looks like. Easy to see with the Windows version of an on-screen keyboard, osk.exe. It seems to be able to guess the form-factor of the machine (laptop vs desktop) but on my laptop it doesn't match the layout of the keyboard.

Use the osk.exe layout as a template so nobody can complain that yours doesn't match well.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Is there really *no* way to, say, pass data directly to/from the driver to get this info? – user541686 Jan 18 '11 at 05:59
  • 2
    No. Not even the driver cares exactly where a user puts her fingers. – Hans Passant Jan 18 '11 at 06:06
  • This might sound silly, but is there any way to bypass the driver and query the keyboard itself?? (A keyboard equivalent of a SCSI pass-through request, for example?) – user541686 Jan 19 '11 at 02:58
  • Yes, that is silly. You are still missing the point, there is no protocol between the keyboard controller and the driver that passes anything resembling physical layout info. It just sends a simple byte with a scan code number when a key is pressed. – Hans Passant Jan 19 '11 at 07:17
  • Hm... interesting. Wonder why they didn't decide to standardize this info and have the keyboard report it. Thanks for the info! – user541686 Jan 20 '11 at 08:40
1

Update from 2023

There is a new KEYBOARD_EXTENDED_ATTRIBUTES struct and IOCTL_KEYBOARD_QUERY_EXTENDED_ATTRIBUTES IOCTL added in Windows 10 that can return additional keyboard info.

See "15.18 Descriptive Controls" in the recent HID Usage Tables spec. These was from adopted HID Usage Table Review Request 42: Consumer Page Keyboard Assist Controls from 2013.

bool QueryInfo(const ScopedHandle& interfaceHandle)
{
    // https://docs.microsoft.com/windows/win32/api/ntddkbd/ns-ntddkbd-keyboard_extended_attributes

    KEYBOARD_EXTENDED_ATTRIBUTES extended_attributes{ KEYBOARD_EXTENDED_ATTRIBUTES_STRUCT_VERSION_1 };
    DWORD len = 0;

    if (!DeviceIoControl(interfaceHandle.get(), IOCTL_KEYBOARD_QUERY_EXTENDED_ATTRIBUTES, nullptr, 0, &extended_attributes, sizeof(extended_attributes), &len, nullptr))
        return false;

    DCHECK_EQ(len, sizeof(extended_attributes));

    FormFactor = extended_attributes.FormFactor;
    KeyType = extended_attributes.IETFLanguageTagIndex;
    PhysicalLayout = extended_attributes.PhysicalLayout;
    VendorSpecificPhysicalLayout = extended_attributes.VendorSpecificPhysicalLayout;
    IETFLanguageTagIndex = extended_attributes.IETFLanguageTagIndex;
    ImplementedInputAssistControls = extended_attributes.ImplementedInputAssistControls;

    return true;
}

But seems these is not adopted by vendors and my modern Logitech MX keys keyboard returns zero values in these fields..

DJm00n
  • 1,083
  • 5
  • 18