Create a keyboard layout

From ReactOS Wiki
Jump to: navigation, search

The keyboard layouts are dlls loaded in kernel space. The keyboard layouts are a bit strange. The keyboard files have some preprocessor cruft because the constants used in them have no standard definitions. You can find this stuff in the existing keyboard layouts.

They have a data payload and a single entry point that returns a pointer to the keyboard tables.

The structure has these members:

 modifiers -> modifier_keys -> zero terminated mapping from vk to mod bit
ROSDATA VK_TO_BIT modifier_keys[] = {
  { VK_SHIFT,   KSHIFT },
  { VK_CONTROL, KCTRL },
  { VK_MENU,    KALT },
  { 0,          0 }
};
           -> number of bit combinations listed in modifier bits
   6
           -> modifier_bits 
 { 0, 1, 3, 4, SHFT_INVALID, SHFT_INVALID, 2 } /* Modifier bit order, NONE, SHIFT, CTRL, ALT, MENU, SHIFT + MENU, CTRL + MENU */

Each entry in this list is indexed by a shift state (some combination of bits from the modifier keys table), and tells what column in the VK_TO_WCHARS tables that shift state applies to.

 vk_to_wchar_master -> null terminated list of vk_to_wchar tables of varying widths.  the numberpad
 is a special table and is listed last.

Each vk_to_wchar table is identified by a width, telling how many of the columns indexed by the modifier list are present.

Put the new key-to-char entry in the key_to_chars_Xmod, where X is the number of functions the key has in the particular language. The values of the columns other than column 2 are from the ISO10646 Unicode standard. See the tables at http://www.unicode.org/charts/.

ROSDATA VK_TO_WCHARS3 key_to_chars_3mod[] = {
  /* Normal, Shifted, Ctrl */
  /* Legacy (telnet-style) ascii escapes */
  { '3', CAPS, '3', 0xa7, 0xb3 },
  { '7', CAPS, '7', '/', '{' },
  ...
The virtual key '3' responds to capitalization in this language, produces:
  '3'  unshifted (column 2)
  0xa7 Section sign  Shifted      (1) in the modifier bits
  0xb3 Superscript 3 Ctrl+Shift   (3) in the modifier bits (Alt+Gr)

Dead Keys

Many languages have keys on the keyboard which have more than one meaning depending on which key is pressed next. The dead key table tells which keys these are and what the outcomes will be.

ROSDATA DEADKEY dead_key[] = {
 { DEADTRANS(L'a', L'^', 0xE2 /* â */, 0x00) },
 { DEADTRANS(L'e', L'´', 0xE9 /* é */, 0x00) }
}

In this language, '^' followed by 'a' yields 0xe2, "Latin small letter a with circumflex", and an acute accent plus a 'e' results in a 'e' with and acute accent. Feel free to use hexadecimal numbers in place of the real characters if you can't input the correct chars or if you are not sure whether the characters you are inserting are the correct ones. Once again, refer to the Unicode specs.

Dead keys are marked in the vk_to_wchar table by a WCH_DEAD and then are searched by first and second keypress in the dead chars table.

 Followed in the main table by three key name tables (zero terminated)
 1. normal key names
 2. extended key names
 3. dead key names

The tables following these are the meat of the system, scancode to virtual key translation tables. Since there are more keys in the unenhanced key table (the 'beige keys') these are listed as 0x80 entries, indexed by scan code. Empty entries are marked VK_EMPTY.

The e0 and e1 scan code to vk tables are zero-terminated lists of scan codes that follow the special e0 and e1 extended keyboard codes. The first column is the scan code and the second column is an 8-bit virtual key code along with any required modifier bits in the upper byte (normally KEXT). The ext-bit is used by various parts of the keyboard system (for example to distinguish left and right shift and control, and to distinguish the windows keys from the alt keys).

Following these are the local flags:

 MAKELONG(1,1),
 

Change the first argument to control the behavior of certain keys:

1: Right Alt key is AltGr (to produce special characters on most non-US keyboards)

2: Pressing SHIFT will turn off Caps Lock

4: Left and right shift keys set left-to-right/right-to-left marker

Any sum of these is acceptable. Note the following:

  • Due to a bug in ReactOS, setting 1 has no effect at this time. However, under Windows this bit works as described, and a fix for ReactOS is under way.
  • Setting 2 has no effect on ReactOS (or Windows 2000 and up) as this behavior is overridden by a Control Panel setting. However, it does become important if you intend to use your keyboard layout on Windows NT 4.0 and earlier.

The last lines are for ligature tables, which we don't currently support. These tables are used in languages that use scripts such as Devanagari, which have special opening character sequences for the beginning of a sentence. As far as I'm aware, languages based on Cyrillic or Roman alphabets don't use this. It would be great if somebody could help me describe this more fully.

There is a list of virtual key codes available at:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx

Example

Here's a short example of what is needed to be done to add a new keyboard layout:

First make sure you have got a working build environment: http://reactos.com/wiki/index.php/Build_Environment

You will need to know the correct descriptions and abbreviations for your keyboard (e.g. American English, en-US, etc).

The easiest way of creating a new keyboard layout is to copy and then modify an existing layout. The existing layouts can be found in the sources under /dll/keyboard/kbd*.

For the rest of this HOWTO let’s imagine we want to create a Belgian (point) keyboard layout (kbdbe.dll) based on the US keyboard layout.

 Copy /dll/keyboard/kbdus (the layout you're modifying) to /dll/keyboard/kbdbe.

In /dll/keyboard/kbdbe rename the following files:

 kbdus.c to kbdbe.c
 kbdus.spec to kbdbe.spec
 kbdus.rc to kbdbe.rc

Change kbdbe.rc so that it looks like this:

 #define REACTOS_VERSION_DLL
 #define REACTOS_STR_FILE_DESCRIPTION	"ReactOS Belgian (point) Keyboard Layout\0"
 #define REACTOS_STR_INTERNAL_NAME	"kbdbe\0"
 #define REACTOS_STR_ORIGINAL_FILENAME	"kbdbe.dll\0"
 #include <reactos/version.rc>

in kbdbe.spec and CMakeLists.txt

 Search for kbus and change it to kbdbe

in /dll/keyboard/CMakeLists.txt add your directory

 add_subdirectory(kbdbe)

Change kbdbe.c according to the keyboard specifications (yes, this is the main part of the work).

Now we want to make the new layout selectable during setup.

bootdata/hivesys.inf

 Search for "Keyboard Layouts" and add a two-line entry for your new layout.
 Also add appropriate lines in the "NLS Language settings" and "Supported and installed locales"

In order to find the NLS code for your locale you could look in the Registry on a Windows computer under the "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts" keys.

You could also look in the LCID column of the National Language Support (NLS) API Reference in the Microsoft MSDN documentation. (Be sure to select the appropriate operating system before using this web page.)


bootdata/packages/reactos.dff

 Just follow the example of the other /dll/keyboard/kbd* stuff in there. 

In bootdata/txtsetup.sif add the following lines:

Keyboardlayout-section

 00000813 = "Belgian (point)"

Files.KeyboardLayout-section

 00000813 = kbdbe.dll

Now you can compile ReactOS and create your boot CD. Your newly created keyboard layout can be selected when you install ReactOS with your boot CD.

Appendix 1

Here are some keyboard designations that you will come across in the source file.

Клв подредба.png

K1= VK_OEM_1

K2= VK_OEM_2

K3= VK_OEM_3

K4= VK_OEM_4

K5= VK_OEM_5 (This key may have different positions on different keyboards. In en-US keyboard layouts it generates \ and |)

K6= VK_OEM_6

K7= VK_OEM_7

K8= VK_OEM_8

K9= VK_OEM_9

K102= VK_OEM_102 (This key is available only on some new keyboards. In en-US keyboard layouts it generates / and \)

COM= VK_OEM_COMMA

PER= VK_OEM_PERIOD

K-=VK_OEM_MINUS

K+=VK_OEM_PLUS

KBack= VK_BACK

N0=VK_NUMPAD0

N1=VK_NUMPAD1

N2=VK_NUMPAD2

N3=VK_NUMPAD3

N4=VK_NUMPAD4

N5=VK_NUMPAD5

N6=VK_NUMPAD6

N7=VK_NUMPAD7

N8=VK_NUMPAD8

N9=VK_NUMPAD9