[DLL:KEYBOARD] Add Romanian Standard Keyboard layout. (#861)
[reactos.git] / dll / keyboard / kbdrost / kbdrost.c
1 /*
2 * ReactOS Romanian (Standard) Keyboard layout
3 * Copyright (C) 2018 ReactOS
4 * Author: Ștefan Fulea (stefan dot fulea at mail dot com)
5 * License: LGPL, see: LGPL.txt
6 *
7 * Thanks to: http://www.barcodeman.com/altek/mule/scandoc.php
8 * and http://win.tue.nl/~aeb/linux/kbd/scancodes-1.html
9 *
10 * Romanian standard layout as defined in SR 13392:2004 by
11 * Romanian Standards Association (ASRO), with enacted use in
12 * romanian public institutions through Order no. 414/25.09.2006
13 * http://legislatie.just.ro/Public/FormaPrintabila/00000G22CFKNTV3ZAR52IRPL5V03Y1CD
14 *
15 * The combining characters, non-romanian diacritics and other
16 * symbols were taken as reference from Microsoft's demo layout:
17 * https://docs.microsoft.com/en-us/globalization/keyboards/kbdrost.html
18 *
19 * Finally, considering the amount of combining characters unused in Romanian
20 * but present by default in this language's keyboard layouts, I've took the
21 * liberty to add one combining character that it may use but I haven't
22 * encountered as of the time of this writing. The combining comma below,
23 * provides an alternative way of generating romanian S-comma and T-comma
24 * characters and is set as a dead character under letter Q.
25 *
26 */
27
28 #define WIN32_NO_STATUS
29 #include <stdarg.h>
30 #include <windef.h>
31 #include <winuser.h>
32 #include <ndk/kbd.h>
33
34 #ifdef _M_IA64
35 #define ROSDATA static __declspec(allocate(".data"))
36 #else
37 #ifdef _MSC_VER
38 #pragma data_seg(".data")
39 #define ROSDATA static
40 #else
41 #define ROSDATA static __attribute__((section(".data")))
42 #endif
43 #endif
44
45 #define VK_EMPTY 0xff /* The non-existent VK */
46
47 #define KNUMS KBDNUMPAD|KBDSPECIAL /* Special + number pad */
48 #define KMEXT KBDEXT|KBDMULTIVK /* Multi + ext */
49
50 ROSDATA USHORT scancode_to_vk[] =
51 {
52 /* Numbers Row */
53 /* - 00 - */
54 /* 1 ... 2 ... 3 ... 4 ... */
55 VK_EMPTY, VK_ESCAPE, '1', '2',
56 '3', '4', '5', '6',
57 '7', '8', '9', '0',
58 VK_OEM_MINUS, VK_OEM_PLUS, VK_BACK,
59
60 /* - 0f - */
61 /* First Letters Row */
62 VK_TAB, 'Q', 'W', 'E',
63 'R', 'T', 'Y', 'U',
64 'I', 'O', 'P',
65 VK_OEM_4, VK_OEM_6, VK_RETURN,
66
67 /* - 1d - */
68 /* Second Letters Row */
69 VK_LCONTROL,
70 'A', 'S', 'D', 'F',
71 'G', 'H', 'J', 'K',
72 'L', VK_OEM_1, VK_OEM_7, VK_OEM_3,
73 VK_LSHIFT, VK_OEM_5,
74
75 /* - 2c - */
76 /* Third letters row */
77 'Z', 'X', 'C', 'V',
78 'B', 'N', 'M', VK_OEM_COMMA,
79 VK_OEM_PERIOD,VK_OEM_2, VK_RSHIFT,
80
81 /* - 37 - */
82 /* Bottom Row */
83 VK_MULTIPLY, VK_LMENU, VK_SPACE, VK_CAPITAL,
84
85 /* - 3b - */
86 /* F-Keys */
87 VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6,
88 VK_F7, VK_F8, VK_F9, VK_F10,
89
90 /* - 45 - */
91 /* Locks */
92 VK_NUMLOCK | KMEXT,
93 VK_SCROLL | KBDMULTIVK,
94
95 /* - 47 - */
96 /* Number-Pad */
97 VK_HOME | KNUMS, VK_UP | KNUMS, VK_PRIOR | KNUMS, VK_SUBTRACT,
98 VK_LEFT | KNUMS, VK_CLEAR | KNUMS, VK_RIGHT | KNUMS, VK_ADD,
99 VK_END | KNUMS, VK_DOWN | KNUMS, VK_NEXT | KNUMS,
100 VK_INSERT | KNUMS, VK_DELETE | KNUMS,
101
102 /* - 54 - */
103 /* Presumably PrtSc */
104 VK_SNAPSHOT,
105
106 /* - 55 - */
107 /* Oddities, and the remaining standard F-Keys */
108 VK_EMPTY, VK_OEM_102, VK_F11, VK_F12,
109
110 /* - 59 - */
111 VK_CLEAR, VK_EMPTY, VK_EMPTY, VK_EMPTY, VK_EMPTY, /* EREOF */
112 VK_EMPTY, VK_EMPTY, VK_EMPTY, VK_EMPTY, VK_EMPTY, /* ZOOM */
113 VK_HELP,
114
115 /* - 64 - */
116 /* Even more F-Keys (for example, NCR keyboards from the early 90's) */
117 VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, VK_F19, VK_F20,
118 VK_F21, VK_F22, VK_F23,
119
120 /* - 6f - */
121 /* Not sure who uses these codes */
122 VK_EMPTY, VK_EMPTY, VK_EMPTY,
123
124 /* - 72 - */
125 VK_EMPTY, VK_EMPTY, VK_EMPTY, VK_EMPTY,
126
127 /* - 76 - */
128 /* One more f-key */
129 VK_F24,
130
131 /* - 77 - */
132 VK_EMPTY, VK_EMPTY, VK_EMPTY, VK_EMPTY,
133 VK_EMPTY, VK_EMPTY, VK_EMPTY, VK_EMPTY, /* PA1 */
134 VK_EMPTY,
135
136 /* - 80 - */
137 0
138 };
139
140 ROSDATA VSC_VK extcode0_to_vk[] =
141 {
142 { 0x10, VK_MEDIA_PREV_TRACK | KBDEXT },
143 { 0x19, VK_MEDIA_NEXT_TRACK | KBDEXT },
144 { 0x1D, VK_RCONTROL | KBDEXT },
145 { 0x20, VK_VOLUME_MUTE | KBDEXT },
146 { 0x21, VK_LAUNCH_APP2 | KBDEXT },
147 { 0x22, VK_MEDIA_PLAY_PAUSE | KBDEXT },
148 { 0x24, VK_MEDIA_STOP | KBDEXT },
149 { 0x2E, VK_VOLUME_DOWN | KBDEXT },
150 { 0x30, VK_VOLUME_UP | KBDEXT },
151 { 0x32, VK_BROWSER_HOME | KBDEXT },
152 { 0x35, VK_DIVIDE | KBDEXT },
153 { 0x37, VK_SNAPSHOT | KBDEXT },
154 { 0x38, VK_RMENU | KBDEXT },
155 { 0x47, VK_HOME | KBDEXT },
156 { 0x48, VK_UP | KBDEXT },
157 { 0x49, VK_PRIOR | KBDEXT },
158 { 0x4B, VK_LEFT | KBDEXT },
159 { 0x4D, VK_RIGHT | KBDEXT },
160 { 0x4F, VK_END | KBDEXT },
161 { 0x50, VK_DOWN | KBDEXT },
162 { 0x51, VK_NEXT | KBDEXT },
163 { 0x52, VK_INSERT | KBDEXT },
164 { 0x53, VK_DELETE | KBDEXT },
165 { 0x5B, VK_LWIN | KBDEXT },
166 { 0x5C, VK_RWIN | KBDEXT },
167 { 0x5D, VK_APPS | KBDEXT },
168 { 0x5F, VK_SLEEP | KBDEXT },
169 { 0x65, VK_BROWSER_SEARCH | KBDEXT },
170 { 0x66, VK_BROWSER_FAVORITES | KBDEXT },
171 { 0x67, VK_BROWSER_REFRESH | KBDEXT },
172 { 0x68, VK_BROWSER_STOP | KBDEXT },
173 { 0x69, VK_BROWSER_FORWARD | KBDEXT },
174 { 0x6A, VK_BROWSER_BACK | KBDEXT },
175 { 0x6B, VK_LAUNCH_APP1 | KBDEXT },
176 { 0x6C, VK_LAUNCH_MAIL | KBDEXT },
177 { 0x6D, VK_LAUNCH_MEDIA_SELECT | KBDEXT },
178 { 0x1C, VK_RETURN | KBDEXT },
179 { 0x46, VK_CANCEL | KBDEXT },
180 { 0, 0 }
181 };
182
183 ROSDATA VSC_VK extcode1_to_vk[] =
184 {
185 { 0x1d, VK_PAUSE },
186 { 0, 0 }
187 };
188
189 ROSDATA VK_TO_BIT modifier_keys[] =
190 {
191 { VK_SHIFT, KBDSHIFT },
192 { VK_CONTROL, KBDCTRL },
193 { VK_MENU, KBDALT },
194 { 0, 0 }
195 };
196
197 ROSDATA MODIFIERS modifier_bits =
198 {
199 modifier_keys,
200 7,
201 { 0, 1, 2, SHFT_INVALID, SHFT_INVALID, SHFT_INVALID, 3, 4 }
202 /* Modifiers order: NONE, SHIFT, CTRL, ALTGR, SHIFT-ALTGR */
203 };
204
205 ROSDATA VK_TO_WCHARS2 key_to_chars_2mod[] =
206 {
207 /* The alphabet */
208 { 'A', CAPLOK, {'a', 'A'} },
209 { 'B', CAPLOK, {'b', 'B'} },
210 { 'C', CAPLOK, {'c', 'C'} },
211 { 'F', CAPLOK, {'f', 'F'} },
212 { 'G', CAPLOK, {'g', 'G'} },
213 { 'H', CAPLOK, {'h', 'H'} },
214 { 'I', CAPLOK, {'i', 'I'} },
215 { 'J', CAPLOK, {'j', 'J'} },
216 { 'K', CAPLOK, {'k', 'K'} },
217 { 'M', CAPLOK, {'m', 'M'} },
218 { 'N', CAPLOK, {'n', 'N'} },
219 { 'O', CAPLOK, {'o', 'O'} },
220 { 'R', CAPLOK, {'r', 'R'} },
221 { 'T', CAPLOK, {'t', 'T'} },
222 { 'U', CAPLOK, {'u', 'U'} },
223 { 'V', CAPLOK, {'v', 'V'} },
224 { 'W', CAPLOK, {'w', 'W'} },
225 { 'X', CAPLOK, {'x', 'X'} },
226 { 'Y', CAPLOK, {'y', 'Y'} },
227 { 'Z', CAPLOK, {'z', 'Z'} },
228
229 /* Specials */
230 { VK_OEM_2, 0, {'/', '?'} },
231
232 /* Keys that do not have shift states */
233 { VK_TAB, 0, {'\t','\t'} },
234 { VK_ADD, 0, {'+', '+'} },
235 { VK_SUBTRACT, 0, {'-', '-'} },
236 { VK_MULTIPLY, 0, {'*', '*'} },
237 { VK_DIVIDE, 0, {'/', '/'} },
238
239 { 0, 0 }
240 };
241
242 ROSDATA VK_TO_WCHARS3 key_to_chars_3mod[] =
243 {
244 /* Legacy (telnet-style) ascii escapes */
245 { VK_OEM_102, 0, {'\\','|', 0x1c /* FS */} },
246 { VK_BACK, 0, {0x8, 0x8, 0x7F } },
247 { VK_ESCAPE, 0, {0x1b,0x1b,0x1b } },
248 { VK_RETURN, 0, {'\r','\r','\n'} },
249 { VK_SPACE, 0, {' ', ' ', ' '} },
250 { VK_CANCEL, 0, {0x3, 0x3, 0x3} },
251 { 0, 0 }
252 };
253
254 ROSDATA VK_TO_WCHARS4 key_to_chars_4mod[] =
255 {
256 { '1', 0, {'1', '!', WCH_NONE, 0x0303 /* COMBINING TILDE */} },
257 { '2', 0, {'2', '@', WCH_NONE, 0x030C /* COMBINING CARON */} },
258 { '3', 0, {'3', '#', WCH_NONE, 0x0302 /* COMBINING CIRCUMFLEX */} },
259 { '4', 0, {'4', '$', WCH_NONE, 0x0306 /* COMBINING BREVE */} },
260 { '5', 0, {'5', '%', WCH_NONE, 0x030A /* COMBINING RING ABOVE */} },
261 { '6', 0, {'6', '^', WCH_NONE, 0x0328 /* COMBINING OGONEK */} },
262 { '7', 0, {'7', '&', WCH_NONE, 0x0300 /* COMBINING GRAVE ACCENT */} },
263 { '8', 0, {'8', '*', WCH_NONE, 0x0307 /* COMBINING DOT ABOVE */} },
264 { '9', 0, {'9', '(', WCH_NONE, 0x0301 /* COMBINING ACUTE ACCENT */} },
265 { '0', 0, {'0', ')', WCH_NONE, 0x030B /* COMBINING DOUBLE ACUTE ACCENT */} },
266 { 'Q', CAPLOK, {'q', 'Q', WCH_NONE, 0x0326 /* COMBINING COMMA BELOW */} },
267 { 'E', CAPLOK, {'e', 'E', WCH_NONE, 0x20AC /* EURO SIGN */} },
268 { 'P', CAPLOK, {'p', 'P', WCH_NONE, 0x00A7 /* SECTION SIGN */} },
269 { 'S', CAPLOK, {'s', 'S', WCH_NONE, 0x00DF /* LATIN SMALL LETTER SHARP S */} },
270 { 0, 0 }
271 };
272
273 ROSDATA VK_TO_WCHARS5 key_to_chars_5mod[] =
274 {
275 { VK_OEM_3, 0, {0x201E /* DOUBLE QUOTE 99 LOW */, 0x201D /* DOUBLE QUOTE 99 HIGH */, WCH_NONE, '`', '~' } },
276 { VK_OEM_MINUS, 0, {'-', '_', WCH_NONE, 0x0308 /* COMBINING DIAERESIS */, 0x2013 /* EN DASH */} },
277 { VK_OEM_PLUS, 0, {'=', '+', WCH_NONE, 0x0327 /* COMBINING CEDILLA */, 0x00B1 /* PLUS-MINUS SIGN */} },
278 { VK_OEM_4, CAPLOK, {0x0103 /* a BREVE */, 0x0102 /* A BREVE */, 0x1b /* ESC */, '[', '{' } },
279 { VK_OEM_6, CAPLOK, {0x00ee /* i CIRCUMFLEX */, 0x00ce /* I CIRCUMFLEX */, 0x1d /* GS */, ']', '}' } },
280 { 'D', CAPLOK, {'d', 'D', WCH_NONE, 0x0111 /* d WITH STROKE */, 0x0110 /* D WITH STROKE */} },
281 { 'L', CAPLOK, {'l', 'L', WCH_NONE, 0x0142 /* l WITH STROKE */, 0x0141 /* L WITH STROKE */} },
282 { VK_OEM_1, CAPLOK, {0x0219 /* s COMMA */, 0x0218 /* S COMMA */, WCH_NONE, ';', ':' } },
283 { VK_OEM_7, CAPLOK, {0x021B /* t COMMA */, 0x021A /* T COMMA */, WCH_NONE, '\'', '"' } },
284 { VK_OEM_5, CAPLOK, {0x00e2 /* a CIRCUMFLEX */, 0x00c2 /* A CIRCUMFLEX */, 0x1c /* FS */, '\\', '|' } },
285 { VK_OEM_COMMA, 0, {',', ';', WCH_NONE, '<', 0x00AB /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */ } },
286 { VK_OEM_PERIOD, 0, {'.', ':', WCH_NONE, '>', 0x00BB /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */ } },
287 { 0, 0 }
288 };
289
290 ROSDATA VK_TO_WCHARS1 keypad_numbers[] =
291 {
292 { VK_NUMPAD0, 0, {'0'} },
293 { VK_NUMPAD1, 0, {'1'} },
294 { VK_NUMPAD2, 0, {'2'} },
295 { VK_NUMPAD3, 0, {'3'} },
296 { VK_NUMPAD4, 0, {'4'} },
297 { VK_NUMPAD5, 0, {'5'} },
298 { VK_NUMPAD6, 0, {'6'} },
299 { VK_NUMPAD7, 0, {'7'} },
300 { VK_NUMPAD8, 0, {'8'} },
301 { VK_NUMPAD9, 0, {'9'} },
302 { VK_DECIMAL, 0, {','} },
303 { 0, 0 }
304 };
305
306 #define vk_master(n, x) { (PVK_TO_WCHARS1)x, n, sizeof(x[0]) }
307 ROSDATA VK_TO_WCHAR_TABLE vk_to_wchar_master_table[] =
308 {
309 vk_master(2, key_to_chars_2mod),
310 vk_master(3, key_to_chars_3mod),
311 vk_master(4, key_to_chars_4mod),
312 vk_master(5, key_to_chars_5mod),
313 vk_master(1, keypad_numbers),
314 { 0, 0, 0 }
315 };
316
317 ROSDATA VSC_LPWSTR key_names[] =
318 {
319 { 0x01, L"Esc" },
320 { 0x0e, L"Retroștergere" },
321 { 0x0f, L"Tabulator" },
322 { 0x1c, L"Intrare" },
323 { 0x1d, L"Control" },
324 { 0x2a, L"Schimb" },
325 { 0x35, L"/ (num.)" },
326 { 0x36, L"Schimb dreapta" },
327 { 0x37, L"* (num.)" },
328 { 0x38, L"Alt" },
329 { 0x39, L"Spațiu" },
330 { 0x3a, L"MAJUSCULE" },
331 { 0x3b, L"F1" },
332 { 0x3c, L"F2" },
333 { 0x3d, L"F3" },
334 { 0x3e, L"F4" },
335 { 0x3f, L"F5" },
336 { 0x40, L"F6" },
337 { 0x41, L"F7" },
338 { 0x42, L"F8" },
339 { 0x43, L"F9" },
340 { 0x44, L"F10" },
341 { 0x45, L"Pauză" },
342 { 0x46, L"Fix. derulare" },
343 { 0x47, L"7 (num.)" },
344 { 0x48, L"8 (num.)" },
345 { 0x49, L"9 (num.)" },
346 { 0x4a, L"- (num.)" },
347 { 0x4b, L"4 (num.)" },
348 { 0x4c, L"5 (num.)" },
349 { 0x4d, L"6 (num.)" },
350 { 0x4e, L"+ (num.)" },
351 { 0x4f, L"1 (num.)" },
352 { 0x50, L"2 (num.)" },
353 { 0x51, L"3 (num.)" },
354 { 0x52, L"0 (num.)" },
355 { 0x53, L"Sep. zecimal" },
356 { 0x54, L"Sys Req" },
357 { 0x56, L"\\" },
358 { 0x57, L"F11" },
359 { 0x58, L"F12" },
360 { 0x7c, L"F13" },
361 { 0x7d, L"F14" },
362 { 0x7e, L"F15" },
363 { 0x7f, L"F16" },
364 { 0x80, L"F17" },
365 { 0x81, L"F18" },
366 { 0x82, L"F19" },
367 { 0x83, L"F20" },
368 { 0x84, L"F21" },
369 { 0x85, L"F22" },
370 { 0x86, L"F23" },
371 { 0x87, L"F24" },
372 { 0, NULL }
373 };
374
375 ROSDATA VSC_LPWSTR extended_key_names[] =
376 {
377 { 0x1c, L"Intr. numerice" },
378 { 0x1d, L"Control dreapta" },
379 { 0x37, L"Imprimare" },
380 { 0x38, L"Alt dreapta" },
381 { 0x45, L"Fix. numerice" },
382 { 0x46, L"Întrerupere" },
383 { 0x47, L"Acasă" },
384 { 0x48, L"Sus" },
385 { 0x49, L"Pag. sus" },
386 { 0x4b, L"Stânga" },
387 { 0x4c, L"Centru" },
388 { 0x4d, L"Dreapta" },
389 { 0x4f, L"Sfârșit" },
390 { 0x50, L"Jos" },
391 { 0x51, L"Pag. jos" },
392 { 0x52, L"Inserție" },
393 { 0x53, L"Ștergere" },
394 { 0x54, L"Meniu" },
395 { 0x56, L"Ajutor" },
396 { 0x5b, L"Meniu stânga" },
397 { 0x5c, L"Meniu dreapta" },
398 { 0, NULL }
399 };
400
401 ROSDATA DEADKEY_LPWSTR dead_key_names[] =
402 {
403 L"\x0300" L"Accent grav",
404 L"\x0301" L"Accent acut",
405 L"\x0302" L"Circumflex",
406 L"\x0303" L"Tildă",
407 L"\x0306" L"Breve",
408 L"\x0307" L"Suprapunct",
409 L"\x0308" L"Tremă",
410 L"\x030A" L"Supracerc",
411 L"\x030B" L"Accent acut dublu",
412 L"\x030C" L"Caron",
413 L"\x0326" L"Virgulă",
414 L"\x0327" L"Sedilă",
415 L"\x0328" L"Ogonek",
416 NULL
417 };
418
419 #define DEADTRANS(ch, accent, comp, flags) MAKELONG(ch, accent), comp, flags
420 ROSDATA DEADKEY dead_key[] =
421 {
422 /*
423 * combining diacritics: tilde, caron, circumflex,
424 * breve, ring above, ogonek, grave accent, dot above,
425 * acute accent, double acute accent, and comma below
426 */
427 #include "deadkeys/tilde"
428 #include "deadkeys/caron"
429 #include "deadkeys/circumflex"
430 #include "deadkeys/breve"
431 #include "deadkeys/ring_above"
432 #include "deadkeys/ogonek"
433 #include "deadkeys/grave_acc"
434 #include "deadkeys/dot_above"
435 #include "deadkeys/acute_acc"
436 #include "deadkeys/dbl_acute_acc"
437 #include "deadkeys/comma_below"
438
439 { 0, 0 }
440 };
441
442 /* Finally, the master table */
443 ROSDATA KBDTABLES keyboard_layout_table =
444 {
445 /* modifier assignments */
446 &modifier_bits,
447
448 /* character from vk tables */
449 vk_to_wchar_master_table,
450
451 /* diacritical marks */
452 dead_key,
453
454 /* Key names */
455 key_names,
456 extended_key_names,
457 dead_key_names,
458
459 /* scan code to virtual key maps */
460 scancode_to_vk,
461 sizeof(scancode_to_vk) / sizeof(scancode_to_vk[0]),
462 extcode0_to_vk,
463 extcode1_to_vk,
464
465 MAKELONG(KLLF_ALTGR, 1), /* Version 1.0 */
466
467 /* Ligatures (Romanian doesn't have any) */
468 0,
469 0,
470 NULL
471 };
472
473 PKBDTABLES WINAPI KbdLayerDescriptor(VOID)
474 {
475 return &keyboard_layout_table;
476 }