xref: /reactos/sdk/tools/kbdtool/output.c (revision 53221834)
1 /*
2  * PROJECT:         ReactOS Build Tools [Keyboard Layout Compiler]
3  * LICENSE:         BSD - See COPYING.BSD in the top level directory
4  * FILE:            tools/kbdtool/output.c
5  * PURPOSE:         Output Logic (Source Builder)
6  * PROGRAMMERS:     ReactOS Foundation
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "kbdtool.h"
12 
13 /* GLOBALS ********************************************************************/
14 
15 ULONG gStringIdForDescriptions = 1000;
16 ULONG gStringIdForLanguageNames = 1100;
17 ULONG gStringIdForLocaleName = 1200;
18 time_t Clock;
19 struct tm *Now;
20 CHAR gCharName[32];
21 
22 /* FUNCTIONS ******************************************************************/
23 
24 PCHAR
25 WChName(IN ULONG Char,
26         IN BOOLEAN AddZero)
27 {
28     PCHAR p;
29 
30     /* Check for invalid character */
31     if (Char == -1)
32     {
33         /* No name */
34         strcpy(gCharName, "WCH_NONE");
35     }
36     else if ((Char > 31) && (Char < 128))
37     {
38         /* Use our global buffer */
39         p = gCharName;
40 
41         /* Add the first quote unless this was a zero-string */
42         if (!AddZero) *p++ = '\'';
43 
44         /* Now replace any other quote or comment character with a slash */
45         if ((Char == '\"') || (Char == '\'') || (Char == '\\')) *p++ = '\\';
46 
47         /* Now plug in the character */
48         *p++ = Char;
49 
50         /* And add the terminating quote, unless this was a zero-string */
51         if (!AddZero) *p++ = '\'';
52 
53         /* Terminate the buffer */
54         *p = '\0';
55     }
56     else
57     {
58         /* Handle special cases */
59         if (Char == '\b')
60         {
61             /* Bell */
62             strcpy(gCharName, "'\\b'");
63         }
64         else if (Char == '\n')
65         {
66             /* New line */
67             strcpy(gCharName, "'\\n'");
68         }
69         else if (Char == '\r')
70         {
71             /* Return */
72             strcpy(gCharName, "'\\r'");
73         }
74         else if (!AddZero)
75         {
76             /* Char value, in hex */
77             sprintf(gCharName, "0x%04x", Char);
78         }
79         else
80         {
81             /* Char value, C-style */
82             sprintf(gCharName, "\\x%04x", Char);
83         }
84     }
85 
86     /* Return the name */
87     return gCharName;
88 }
89 
90 VOID
91 PrintNameTable(FILE* FileHandle,
92                PKEYNAME KeyName,
93                BOOL DeadKey)
94 {
95     CHAR CharBuffer[255];
96     PKEYNAME NextName;
97     PCHAR Name, Buffer;
98     ULONG i;
99 
100     /* Loop all key names */
101     while (KeyName)
102     {
103         /* Go to the next key name */
104         NextName = KeyName->Next;
105 
106         /* Remember the name and our buffer address */
107         Name = KeyName->Name;
108         Buffer = CharBuffer;
109 
110         /* Check if it's an IDS name */
111         if (strncmp(Name, "IDS_", 4))
112         {
113             /* No, so start parsing it. First, handle initial quote */
114             if (*Name != '\"') *Buffer++ = '\"';
115 
116             /* Next, parse the name */
117             while (*Name)
118             {
119                 /* Check if this is a C-style hex string */
120                 if ((*Name != '\\') || ((*(Name + 1) != 'x') && (*(Name + 1) != 'X')))
121                 {
122                     /* It's not, so just copy straight into our buffer */
123                     *Buffer++ = *Name++;
124                 }
125                 else
126                 {
127                     /* Continue scanning as long as this is a C-style hex string */
128                     while ((*Name == '\\') && ((*(Name + 1) == 'x') || (*(Name + 1) == 'X')))
129                     {
130                         /* Copy 6 characters */
131                         for (i = 0; (*Name) && (i < 6); i++) *Buffer++ = *Name++;
132                     }
133 
134                     /* Check if we still have something at the end */
135                     if (*Name)
136                     {
137                         /* Terminate our buffer */
138                         *Buffer++ = '\"';
139                         *Buffer++ = ' ';
140                         *Buffer++ = 'L';
141                         *Buffer++ = '\"';
142                     }
143                 }
144             }
145 
146             /*  Check for terminating quote */
147             if (*(Buffer - 1) != '\"') *Buffer++ = '\"';
148 
149             /* Terminate the buffer */
150             *Buffer++ = '\0';
151         }
152         else
153         {
154             /* Not yet supported */
155             printf("IDS Entries not yet handled!\n");
156             exit(1);
157         }
158 
159         /* Is this a dead key? */
160         if (DeadKey)
161         {
162             /* Not yet handled */
163             printf("Dead keys not yet handled\n");
164             exit(1);
165         }
166         else
167         {
168             /* Print the entry */
169             fprintf(FileHandle, "    0x%02x,    L%s,\n", KeyName->Code, CharBuffer);
170         }
171 
172         /* Cleanup allocation */
173         free(KeyName->Name);
174         free(KeyName);
175 
176         /* Move on */
177         KeyName = NextName;
178     }
179 
180     /* Is this a dead key? */
181     if (DeadKey)
182     {
183         /* Not yet handled */
184         printf("Dead keys not yet handled\n");
185         exit(1);
186     }
187     else
188     {
189         /* Terminate the table */
190         fprintf(FileHandle, "    0   ,    NULL\n");
191     }
192 }
193 
194 BOOLEAN
195 kbd_h(IN PLAYOUT Layout)
196 {
197     CHAR OutputFile[13];
198     FILE *FileHandle;
199     ULONG i;
200     CHAR UndefChar;
201     USHORT SubCode;
202 
203     /* Build the keyboard name */
204     strcpy(OutputFile, gKBDName);
205     strcat(OutputFile, ".H");
206 
207     /* Open it */
208     FileHandle = fopen(OutputFile, "wt");
209     if (!FileHandle)
210     {
211         /* Fail */
212         printf(" %12s : can't open for write.\n", OutputFile);
213         return FALSE;
214     }
215 
216     /* Print the module header */
217     fprintf(FileHandle,
218             "/****************************** Module Header ******************************\\\n"
219             "* Module Name: %s\n*\n* keyboard layout header\n"
220             "*\n"
221             "* Copyright (c) 2009, ReactOS Foundation\n"
222             "*\n"
223             "* Various defines for use by keyboard input code.\n*\n* History:\n"
224             "*\n"
225             "* created by KBDTOOL v%d.%02d %s*\n"
226             "\\***************************************************************************/\n\n",
227             OutputFile,
228             gVersion,
229             gSubVersion,
230             asctime(Now));
231 
232     /* Print out the includes and defines */
233     fprintf(FileHandle,
234             "/*\n"
235             " * kbd type should be controlled by cl command-line argument\n"
236             " *\\n"
237             "#define KBD_TYPE 4\n\n"
238             "/*\n"
239             "* Include the basis of all keyboard table values\n"
240             "*/\n"
241             "#include \"kbd.h\"\n");
242 
243     /* Now print out the virtual key conversion table */
244     fprintf(FileHandle,
245             "/***************************************************************************\\\n"
246             "* The table below defines the virtual keys for various keyboard types where\n"
247             "* the keyboard differ from the US keyboard.\n"
248             "*\n"
249             "* _EQ() : all keyboard types have the same virtual key for this scancode\n"
250             "* _NE() : different virtual keys for this scancode, depending on kbd type\n"
251             "*\n"
252             "*     +------+ +----------+----------+----------+----------+----------+----------+\n"
253             "*     | Scan | |    kbd   |    kbd   |    kbd   |    kbd   |    kbd   |    kbd   |\n"
254             "*     | code | |   type 1 |   type 2 |   type 3 |   type 4 |   type 5 |   type 6 |\n"
255             "\\****+-------+_+----------+----------+----------+----------+----------+----------+*/\n\n");
256 
257     /* Loop all keys */
258     for (i = 0; i < 110; i++)
259     {
260         /* Check if we processed this key */
261         if (Layout->Entry[i].Processed)
262         {
263             /* Check if it redefined a virtual key */
264             if (Layout->Entry[i].VirtualKey != Layout->Entry[i].OriginalVirtualKey)
265             {
266                 /* Do we have a subcode? */
267                 SubCode = Layout->Entry[i].ScanCode & 0xFF00;
268                 if (SubCode)
269                 {
270                     /* Which kind is it? */
271                     if (SubCode == 0xE000)
272                     {
273                         /* Extended 0 */
274                         UndefChar = 'X';
275                     }
276                     else
277                     {
278                         /* Illegal */
279                         if (SubCode != 0xE100)
280                         {
281                             /* Unrecognized */
282                             printf("Weird scancode value %04x: expected xx, E0xx, or E1xx\n", SubCode);
283                             exit(1);
284                         }
285 
286                         /* Extended 1 */
287                         UndefChar = 'Y';
288                     }
289                 }
290                 else
291                 {
292                     /* Normal key */
293                     UndefChar = 'T';
294                 }
295 
296                 /* Print out the virtual key redefinition */
297                 fprintf(FileHandle,
298                         "#undef %c%02X\n#define %c%02X _EQ(%43s%23s\n",
299                         UndefChar,
300                         Layout->Entry[i].ScanCode,
301                         UndefChar,
302                         Layout->Entry[i].ScanCode,
303                         getVKName(Layout->Entry[i].VirtualKey, 0),
304                         ")");
305             }
306         }
307     }
308 
309     /* Cleanup and close */
310     fprintf(FileHandle,"\n");
311     fclose(FileHandle);
312 
313     /* We made it */
314     return TRUE;
315 }
316 
317 BOOLEAN
318 kbd_rc(IN PKEYNAME DescriptionData,
319        IN PKEYNAME LanguageData)
320 {
321     CHAR OutputFile[13];
322     CHAR InternalName[13];
323     CHAR TimeBuffer[5];
324     FILE *FileHandle;
325     ULONG Length;
326     PCHAR p;
327     PKEYNAME NextDescription, NextLanguage;
328 
329     /* Build the keyboard name and internal name */
330     strcpy(OutputFile, gKBDName);
331     strcat(OutputFile, ".RC");
332     strcpy(InternalName, gKBDName);
333     for (p = InternalName; *p; p++) *p = tolower(*p);
334 
335     /* Open it */
336     FileHandle = fopen(OutputFile, "wb");
337     if (!FileHandle)
338     {
339         /* Fail */
340         printf(" %12s : can't open for write.\n", OutputFile);
341         return FALSE;
342     }
343 
344     /* Check if we have copyright */
345     Length = strlen(gCopyright);
346     if (!Length)
347     {
348         /* Set time string */
349         strftime(TimeBuffer, 5, "%Y", Now);
350 
351         /* Add copyright character */
352         strcpy(gCopyright, "(C)");
353 
354         /* Add the year */
355         strcat(gCopyright, TimeBuffer);
356 
357         /* Add blank company */
358         strcat(gCopyright, " ");
359     }
360 
361     /* Write the resource file header */
362     fprintf(FileHandle,
363             "#include \"winver.h\"\r\n"
364             "1 VERSIONINFO\r\n"
365             " FILEVERSION       1,0,%d,%d\r\n"
366             " PRODUCTVERSION    1,0,%d,%d\r\n"
367             " FILEFLAGSMASK 0x3fL\r\n"
368             " FILEFLAGS 0x0L\r\n"
369             "FILEOS 0x40004L\r\n"
370             " FILETYPE VFT_DLL\r\n"
371             " FILESUBTYPE VFT2_DRV_KEYBOARD\r\n"
372             "BEGIN\r\n"
373             "    BLOCK \"StringFileInfo\"\r\n"
374             "    BEGIN\r\n"
375             "        BLOCK \"000004B0\"\r\n"
376             "        BEGIN\r\n"
377             "            VALUE \"CompanyName\",     \"%s\\0\"\r\n"
378             "            VALUE \"FileDescription\", \"%s Keyboard Layout\\0\"\r\n"
379             "            VALUE \"FileVersion\",     \"1, 0, %d, %d\\0\"\r\n",
380             gVersion,
381             gSubVersion,
382             gVersion,
383             gSubVersion,
384             gCompany,
385             gDescription,
386             gVersion,
387             gSubVersion);
388 
389     /* Continue writing it */
390     fprintf(FileHandle,
391             "            VALUE \"InternalName\",    \"%s (%d.%d)\\0\"\r\n"
392             "            VALUE \"ProductName\",\"%s\\0\"\r\n"
393             "            VALUE \"Release Information\",\"%s\\0\"\r\n"
394             "            VALUE \"LegalCopyright\",  \"%s\\0\"\r\n"
395             "            VALUE \"OriginalFilename\",\"%s\\0\"\r\n"
396             "            VALUE \"ProductVersion\",  \"1, 0, %d, %d\\0\"\r\n"
397             "        END\r\n"
398             "    END\r\n"
399             "    BLOCK \"VarFileInfo\"\r\n"
400             "    BEGIN\r\n"
401             "        VALUE \"Translation\", 0x0000, 0x04B0\r\n"
402             "    END\r\n"
403             "END\r\n",
404             InternalName,
405             gVersion,
406             gSubVersion,
407             "Created by ReactOS KbdTool",
408             "Created by ReactOS KbdTool",
409             gCopyright,
410             InternalName,
411             gVersion,
412             gSubVersion);
413 
414     /* Now check if we have a locale name */
415     Length = strlen(gLocaleName);
416     if (Length)
417     {
418         /* Write the stringtable header */
419         fprintf(FileHandle,
420                 "\r\nSTRINGTABLE DISCARDABLE\r\nLANGUAGE %d, %d\r\n",
421                 9,
422                 1);
423         fprintf(FileHandle, "BEGIN\r\n");
424 
425         /* Language or locale? */
426         if (strchr(gLocaleName, '\"'))
427         {
428             /* Write the language name */
429             fprintf(FileHandle, "    %d    %s\r\n", gStringIdForLanguageNames, gLocaleName);
430         }
431         else
432         {
433             /* Write the locale name */
434             fprintf(FileHandle, "    %d    \"%s\"\r\n", gStringIdForLocaleName, gLocaleName);
435         }
436 
437         /* Terminate the entry */
438         fprintf(FileHandle, "END\r\n\r\n");
439     }
440 
441     /* Check for description information */
442     while (DescriptionData)
443     {
444         /* Remember the next pointer */
445         NextDescription = DescriptionData->Next;
446 
447         /* Write the header */
448         fprintf(FileHandle,
449                 "\r\nSTRINGTABLE DISCARDABLE\r\nLANGUAGE %d, %d\r\n",
450                 DescriptionData->Code & 0x3FF,
451                 DescriptionData->Code >> 10);
452         fprintf(FileHandle, "BEGIN\r\n");
453 
454         /* Quoted string or not? */
455         if (strchr(DescriptionData->Name, '\"'))
456         {
457             /* Write the description name */
458             fprintf(FileHandle, "    %d    %s\r\n", gStringIdForDescriptions, DescriptionData->Name);
459         }
460         else
461         {
462             /* Write the description name */
463             fprintf(FileHandle, "    %d    \"%s\"\r\n", gStringIdForDescriptions, DescriptionData->Name);
464         }
465 
466         /* Terminate the entry */
467         fprintf(FileHandle, "END\r\n\r\n");
468 
469         /* Free the allocation */
470         free(DescriptionData->Name);
471         free(DescriptionData);
472 
473         /* Move to the next entry */
474         DescriptionData = NextDescription;
475     }
476 
477     /* Check for language information */
478     while (LanguageData)
479     {
480         /* Remember the next pointer */
481         NextLanguage = LanguageData->Next;
482 
483         /* Write the header */
484         fprintf(FileHandle,
485                 "\r\nSTRINGTABLE DISCARDABLE\r\nLANGUAGE %d, %d\r\n",
486                 LanguageData->Code & 0x3FF,
487                 LanguageData->Code >> 10);
488         fprintf(FileHandle, "BEGIN\r\n");
489 
490         /* Quoted string or not? */
491         if (strchr(LanguageData->Name, '\"'))
492         {
493             /* Write the language name */
494             fprintf(FileHandle, "    %d    %s\r\n", gStringIdForLanguageNames, LanguageData->Name);
495         }
496         else
497         {
498             /* Write the language name */
499             fprintf(FileHandle, "    %d    \"%s\"\r\n", gStringIdForLanguageNames, LanguageData->Name);
500         }
501 
502         /* Terminate the entry */
503         fprintf(FileHandle, "END\r\n\r\n");
504 
505         /* Free the allocation */
506         free(LanguageData->Name);
507         free(LanguageData);
508 
509         /* Move to the next entry */
510         LanguageData = NextLanguage;
511     }
512 
513     /* We're done! */
514     fclose(FileHandle);
515     return TRUE;
516 }
517 
518 BOOLEAN
519 kbd_def(VOID)
520 {
521     CHAR OutputFile[13];
522     FILE *FileHandle;
523 
524     /* Build the keyboard name and internal name */
525     strcpy(OutputFile, gKBDName);
526     strcat(OutputFile, ".DEF");
527 
528     /* Open it */
529     FileHandle = fopen(OutputFile, "wt");
530     if (!FileHandle)
531     {
532         /* Fail */
533         printf(" %12s : can't open for write.\n", OutputFile);
534         return FALSE;
535     }
536 
537     /* Write the file exports */
538     fprintf(FileHandle,
539             "LIBRARY %s\n\n"
540             "EXPORTS\n"
541             "    KbdLayerDescriptor @1\n",
542             gKBDName);
543 
544     /* Clean up */
545     fclose(FileHandle);
546     return TRUE;
547 }
548 
549 BOOLEAN
550 kbd_c(IN ULONG StateCount,
551       IN PULONG ShiftStates,
552       IN PVOID AttributeData,
553       IN PLAYOUT Layout,
554       IN PVOID DeadKeyData,
555       IN PVOID LigatureData,
556       IN PKEYNAME KeyNameData,
557       IN PKEYNAME KeyNameExtData,
558       IN PKEYNAME KeyNameDeadData)
559 {
560     CHAR OutputFile[13];
561     CHAR KeyNameBuffer[50];
562     CHAR LineBuffer[256];
563     BOOLEAN NeedPlus;
564     FILE *FileHandle;
565     ULONG States[8];
566     ULONG i, j, k;
567     ULONG HighestState;
568     PVKNAME Entry;
569     PCHAR p;
570 
571     /* Build the keyboard name and internal name */
572     strcpy(OutputFile, gKBDName);
573     strcat(OutputFile, ".C");
574 
575     /* Open it */
576     FileHandle = fopen(OutputFile, "wt");
577     if (!FileHandle)
578     {
579         /* Fail */
580         printf(" %12s : can't open for write.\n", OutputFile);
581         return FALSE;
582     }
583 
584     /* Print the header */
585     fprintf(FileHandle,
586             "/***************************************************************************\\\n"
587             "* Module Name: %s\n*\n* keyboard layout\n"
588             "*\n"
589             "* Copyright (c) 2009, ReactOS Foundation\n"
590             "*\n"
591             "* History:\n"
592             "* KBDTOOL v%d.%02d - Created  %s"
593             "\\***************************************************************************/\n\n",
594             OutputFile,
595             gVersion,
596             gSubVersion,
597             asctime(Now));
598 
599     /* What kind of driver is this? */
600     if (FallbackDriver)
601     {
602         /* Fallback only */
603         fprintf(FileHandle, "#include \"precomp.h\"\n");
604     }
605     else
606     {
607         /* Add the includes */
608         fprintf(FileHandle,
609                 "#include <windows.h>\n"
610                 "#include \"kbd.h\"\n"
611                 "#include \"%s.h\"\n\n",
612                 gKBDName);
613     }
614 
615     /* What kind of driver is this? */
616     if (FallbackDriver)
617     {
618         /* Only one section */
619         fprintf(FileHandle,
620                 "#pragma data_seg(\"%s\")\n#define ALLOC_SECTION_LDATA\n\n",
621                 ".kbdfallback");
622     }
623     else
624     {
625         /* Section and attributes depend on architecture */
626         fprintf(FileHandle,
627                 "#if defined(_M_IA64)\n"
628                 "#pragma section(\"%s\")\n"
629                 "#define ALLOC_SECTION_LDATA __declspec(allocate(\"%s\"))\n"
630                 "#else\n"
631                 "#pragma data_seg(\"%s\")\n"
632                 "#define ALLOC_SECTION_LDATA\n"
633                 "#endif\n\n",
634                 ".data",
635                 ".data",
636                 ".data");
637     }
638 
639     /* Scan code to virtual key conversion table header */
640     fprintf(FileHandle,
641             "/***************************************************************************\\\n"
642             "* ausVK[] - Virtual Scan Code to Virtual Key conversion table\n"
643             "\\***************************************************************************/\n\n");
644 
645     /* Table begin */
646     fprintf(FileHandle,
647             "static ALLOC_SECTION_LDATA USHORT ausVK[] = {\n"
648             "    T00, T01, T02, T03, T04, T05, T06, T07,\n"
649             "    T08, T09, T0A, T0B, T0C, T0D, T0E, T0F,\n"
650             "    T10, T11, T12, T13, T14, T15, T16, T17,\n"
651             "    T18, T19, T1A, T1B, T1C, T1D, T1E, T1F,\n"
652             "    T20, T21, T22, T23, T24, T25, T26, T27,\n"
653             "    T28, T29, T2A, T2B, T2C, T2D, T2E, T2F,\n"
654             "    T30, T31, T32, T33, T34, T35,\n\n");
655 
656     /* Table continue */
657     fprintf(FileHandle,
658             "    /*\n"
659             "     * Right-hand Shift key must have KBDEXT bit set.\n"
660             "     */\n"
661             "    T36 | KBDEXT,\n\n"
662             "    T37 | KBDMULTIVK,               // numpad_* + Shift/Alt -> SnapShot\n\n"
663             "    T38, T39, T3A, T3B, T3C, T3D, T3E,\n"
664             "    T3F, T40, T41, T42, T43, T44,\n\n");
665 
666     /* Table continue */
667     fprintf(FileHandle,
668             "    /*\n"
669             "     * NumLock Key:\n"
670             "     *     KBDEXT     - VK_NUMLOCK is an Extended key\n"
671             "     *     KBDMULTIVK - VK_NUMLOCK or VK_PAUSE (without or with CTRL)\n"
672             "     */\n"
673             "    T45 | KBDEXT | KBDMULTIVK,\n\n"
674             "    T46 | KBDMULTIVK,\n\n");
675 
676     /* Numpad table */
677     fprintf(FileHandle,
678             "    /*\n"
679             "     * Number Pad keys:\n"
680             "     *     KBDNUMPAD  - digits 0-9 and decimal point.\n"
681             "     *     KBDSPECIAL - require special processing by Windows\n"
682             "     */\n"
683             "    T47 | KBDNUMPAD | KBDSPECIAL,   // Numpad 7 (Home)\n"
684             "    T48 | KBDNUMPAD | KBDSPECIAL,   // Numpad 8 (Up),\n"
685             "    T49 | KBDNUMPAD | KBDSPECIAL,   // Numpad 9 (PgUp),\n"
686             "    T4A,\n"
687             "    T4B | KBDNUMPAD | KBDSPECIAL,   // Numpad 4 (Left),\n"
688             "    T4C | KBDNUMPAD | KBDSPECIAL,   // Numpad 5 (Clear),\n"
689             "    T4D | KBDNUMPAD | KBDSPECIAL,   // Numpad 6 (Right),\n"
690             "    T4E,\n"
691             "    T4F | KBDNUMPAD | KBDSPECIAL,   // Numpad 1 (End),\n"
692             "    T50 | KBDNUMPAD | KBDSPECIAL,   // Numpad 2 (Down),\n"
693             "    T51 | KBDNUMPAD | KBDSPECIAL,   // Numpad 3 (PgDn),\n"
694             "    T52 | KBDNUMPAD | KBDSPECIAL,   // Numpad 0 (Ins),\n"
695             "    T53 | KBDNUMPAD | KBDSPECIAL,   // Numpad . (Del),\n\n");
696 
697     /* Table finish */
698     fprintf(FileHandle,
699             "    T54, T55, T56, T57, T58, T59, T5A, T5B,\n"
700             "    T5C, T5D, T5E, T5F, T60, T61, T62, T63,\n"
701             "    T64, T65, T66, T67, T68, T69, T6A, T6B,\n"
702             "    T6C, T6D, T6E, T6F, T70, T71, T72, T73,\n"
703             "    T74, T75, T76, T77, T78, T79, T7A, T7B,\n"
704             "    T7C, T7D, T7E\n\n"
705             "};\n\n");
706 
707     /* Key name table header */
708     fprintf(FileHandle, "static ALLOC_SECTION_LDATA VSC_VK aE0VscToVk[] = {\n");
709 
710     /* Loop 110-key table */
711     for (i = 0; i < 110; i++)
712     {
713         /* Check for non-extended keys */
714         if ((Layout->Entry[i].ScanCode & 0xFF00) == 0xE000)
715         {
716             /* Which are valid */
717             if (Layout->Entry[i].ScanCode != 0xFF)
718             {
719                 /* And mapped */
720                 if (Layout->Entry[i].VirtualKey != 0xFF)
721                 {
722                     /* Output them */
723                     fprintf(FileHandle,
724                             "        { 0x%02X, X%02X | KBDEXT              },  // %s\n",
725                             Layout->Entry[i].ScanCode,
726                             Layout->Entry[i].ScanCode,
727                             Layout->Entry[i].Name);
728                 }
729             }
730         }
731     }
732 
733     /* Key name table finish */
734     fprintf(FileHandle, "        { 0,      0                       }\n};\n\n");
735 
736     /* Extended key name table header */
737     fprintf(FileHandle, "static ALLOC_SECTION_LDATA VSC_VK aE1VscToVk[] = {\n");
738 
739     /* Loop 110-key table */
740     for (i = 0; i < 110; i++)
741     {
742         /* Check for extended keys */
743         if ((Layout->Entry[i].ScanCode & 0xFF00) == 0xE100)
744         {
745             /* Which are valid */
746             if (Layout->Entry[i].ScanCode != 0xFF)
747             {
748                 /* And mapped */
749                 if (Layout->Entry[i].VirtualKey != 0xFF)
750                 {
751                     /* Output them */
752                     fprintf(FileHandle,
753                             "        { 0x%02X, Y%02X | KBDEXT            },  // %s\n",
754                             Layout->Entry[i].ScanCode,
755                             Layout->Entry[i].ScanCode,
756                             Layout->Entry[i].Name);
757                 }
758             }
759         }
760     }
761 
762     /* Extended key name table finish */
763     fprintf(FileHandle,
764             "        { 0x1D, Y1D                       },  // Pause\n"
765             "        { 0   ,   0                       }\n};\n\n");
766 
767     /* Modifier table description */
768     fprintf(FileHandle,
769             "/***************************************************************************\\\n"
770             "* aVkToBits[]  - map Virtual Keys to Modifier Bits\n"
771             "*\n"
772             "* See kbd.h for a full description.\n"
773             "*\n"
774             "* The keyboard has only three shifter keys:\n"
775             "*     SHIFT (L & R) affects alphabnumeric keys,\n"
776             "*     CTRL  (L & R) is used to generate control characters\n"
777             "*     ALT   (L & R) used for generating characters by number with numpad\n"
778             "\\***************************************************************************/\n");
779 
780     /* Modifier table header */
781     fprintf(FileHandle, "static ALLOC_SECTION_LDATA VK_TO_BIT aVkToBits[] = {\n");
782 
783     /* Loop modifier table */
784     i = 0;
785     Entry = &Modifiers[0];
786     while (Entry->VirtualKey)
787     {
788         /* Print out entry */
789         fprintf(FileHandle,
790                 "    { %-12s,   %-12s },\n",
791                 getVKName(Entry->VirtualKey, 1),
792                 Entry->Name);
793 
794         /* Move to the next one */
795         Entry = &Modifiers[++i];
796     }
797 
798     /* Modifier table finish */
799     fprintf(FileHandle, "    { 0,          0        }\n};\n\n");
800 
801     /* Modifier conversion table description */
802     fprintf(FileHandle,
803             "/***************************************************************************\\\n"
804             "* aModification[]  - map character modifier bits to modification number\n"
805             "*\n"
806             "* See kbd.h for a full description.\n"
807             "*\n"
808             "\\***************************************************************************/\n\n");
809 
810     /* Zero out local state data */
811     for (i = 0; i < 8; i++) States[i] = -1;
812 
813     /* Find the highest set state */
814     for (HighestState = 1, i = 0; (i < 8) && (ShiftStates[i] != -1); i++)
815     {
816         /* Save all state values */
817         States[ShiftStates[i]] = i;
818         if (ShiftStates[i] > HighestState) HighestState = ShiftStates[i];
819     }
820 
821     /* Modifier conversion table header */
822     fprintf(FileHandle,
823             "static ALLOC_SECTION_LDATA MODIFIERS CharModifiers = {\n"
824             "    &aVkToBits[0],\n"
825             "    %d,\n"
826             "    {\n"
827             "    //  Modification# //  Keys Pressed\n"
828             "    //  ============= // =============\n",
829             HighestState);
830 
831     /* Loop states */
832     for (i = 0; i <= HighestState; i++)
833     {
834         /* Check for invalid state */
835         if (States[i] == -1)
836         {
837             /* Invalid state header */
838             fprintf(FileHandle, "        SHFT_INVALID, // ");
839         }
840         else
841         {
842             /* Is this the last one? */
843             if (i == HighestState)
844             {
845                 /* Last state header */
846                 fprintf(FileHandle, "        %d             // ", States[i]);
847             }
848             else
849             {
850                 /* Normal state header */
851                 fprintf(FileHandle, "        %d,            // ", States[i]);
852             }
853 
854             /* State 1 or higher? */
855             if (i >= 1)
856             {
857                 /* J is the loop variable, K is the double */
858                 for (NeedPlus = 0, j = 0, k = 1; (1u << j) <= i; j++, k = (1 << j))
859                 {
860                     /* Do we need to add a plus? */
861                     if (NeedPlus)
862                     {
863                         /* Add it */
864                         fprintf(FileHandle, "+");
865                         NeedPlus = FALSE;
866                     }
867 
868                     /* Check if it's time to add a modifier */
869                     if (i & k)
870                     {
871                         /* Get the key state name and copy it into our buffer */
872                         strcpy(KeyNameBuffer, getVKName(Modifiers[j].VirtualKey, 1));
873 
874                         /* Go go the 4th char (past the "KBD") and lower name */
875                         for (p = &KeyNameBuffer[4]; *p; p++) *p = tolower(*p);
876 
877                         /* Print it */
878                         fprintf(FileHandle, "%s", &KeyNameBuffer[3]);
879 
880                         /* We'll need a plus sign next */
881                         NeedPlus = TRUE;
882                     }
883                 }
884             }
885 
886             /* Terminate the entry */
887             fprintf(FileHandle, "\n");
888         }
889     }
890 
891 
892     /* Modifier conversion table end */
893     fprintf(FileHandle,"     }\n" "};\n\n");
894 
895     /* Shift state translation table description */
896     fprintf(FileHandle,
897             "/***************************************************************************\\\n"
898             "*\n"
899             "* aVkToWch2[]  - Virtual Key to WCHAR translation for 2 shift states\n"
900             "* aVkToWch3[]  - Virtual Key to WCHAR translation for 3 shift states\n"
901             "* aVkToWch4[]  - Virtual Key to WCHAR translation for 4 shift states\n");
902 
903     /* Check if there's exta shift states */
904     for (i = 5; i < HighestState; i++)
905     {
906         /* Print out extra information */
907         fprintf(FileHandle,
908                 "* aVkToWch%d[]  - Virtual Key to WCHAR translation for %d shift states\n",
909                 i,
910                 i);
911     }
912 
913     /* Shift state translation table description continue */
914     fprintf(FileHandle,
915             "*\n"
916             "* Table attributes: Unordered Scan, null-terminated\n"
917             "*\n"
918             "* Search this table for an entry with a matching Virtual Key to find the\n"
919             "* corresponding unshifted and shifted WCHAR characters.\n"
920             "*\n"
921             "* Special values for VirtualKey (column 1)\n"
922             "*     0xff          - dead chars for the previous entry\n"
923             "*     0             - terminate the list\n"
924             "*\n"
925             "* Special values for Attributes (column 2)\n"
926             "*     CAPLOK bit    - CAPS-LOCK affect this key like SHIFT\n"
927             "*\n"
928             "* Special values for wch[*] (column 3 & 4)\n"
929             "*     WCH_NONE      - No character\n"
930             "*     WCH_DEAD      - Dead Key (diaresis) or invalid (US keyboard has none)\n"
931             "*     WCH_LGTR      - Ligature (generates multiple characters)\n"
932             "*\n"
933             "\\***************************************************************************/\n\n");
934 
935     /* Loop all the states */
936     for (i = 2; i <= StateCount; i++)
937     {
938         /* Check if this something else than state 2 */
939         if (i != 2)
940         {
941             /* Loop all the scan codes */
942             for (j = 0; j < 110; j++)
943             {
944                 /* Check if this is the state for the entry */
945                 if (i == Layout->Entry[j].StateCount) break;
946             }
947         }
948 
949         /* Print the table header */
950         fprintf(FileHandle,
951                 "static ALLOC_SECTION_LDATA VK_TO_WCHARS%d aVkToWch%d[] = {\n"
952                 "//                      |         |  Shift  |",
953                 i,
954                 i);
955 
956         /* Print the correct state label */
957         for (k = 2; k < i; k++) fprintf(FileHandle, "%-9.9s|",
958                                         StateLabel[ShiftStates[k]]);
959 
960         /* Print the next separator */
961         fprintf(FileHandle, "\n//                      |=========|=========|");
962 
963         /* Check for extra states and print their separators too */
964         for (k = 2; k < i; k++) fprintf(FileHandle, "=========|");
965 
966         /* Finalize the separator header */
967         fprintf(FileHandle, "\n");
968 
969         /* Loop all the scan codes */
970         for (j = 0; j < 110; j++)
971         {
972             /* Check if this is the state for the entry */
973             if (i != Layout->Entry[j].StateCount) continue;
974 
975             /* Print out the entry for this key */
976             fprintf(FileHandle,
977                     "  {%-13s,%-7s",
978                     getVKName(Layout->Entry[j].VirtualKey, 1),
979                     CapState[Layout->Entry[j].Cap]);
980 
981             /* Initialize the buffer for this line */
982             *LineBuffer = '\0';
983 
984             /* Loop states */
985             for (k = 0; k < i; k++)
986             {
987                 /* Check for dead key data */
988                 if (DeadKeyData)
989                 {
990                     /* Not yet supported */
991                     printf("Dead key data not supported!\n");
992                     exit(1);
993                 }
994 
995                 /* Check if it's a ligature key */
996                 if (Layout->Entry[j].LigatureCharData[k])
997                 {
998                     /* Not yet supported */
999                     printf("Ligature key data not supported!\n");
1000                     exit(1);
1001                 }
1002 
1003                 /* Print out the WCH_ name */
1004                 fprintf(FileHandle,
1005                         ",%-9s",
1006                         WChName(Layout->Entry[j].CharData[k], 0));
1007 
1008                 /* If we have something on the line buffer by now, add WCH_NONE */
1009                 if (*LineBuffer != '\0') strcpy(LineBuffer, "WCH_NONE ");
1010             }
1011 
1012             /* Finish the line */
1013             fprintf(FileHandle, "},\n");
1014 
1015             /* Do we have any data at all? */
1016             if (*LineBuffer != '\0')
1017             {
1018                 /* Print it, we're done */
1019                 fprintf(FileHandle, "%s},\n", LineBuffer);
1020                 continue;
1021             }
1022 
1023             /* Otherwise, we're done, unless this requires SGCAP data */
1024             if (Layout->Entry[j].Cap != 2) continue;
1025 
1026             /* Not yet supported */
1027             printf("SGCAP not yet supported!\n");
1028             exit(1);
1029         }
1030 
1031         /* Did we only have two states? */
1032         if (i == 2)
1033         {
1034             /* Print out the built-in table */
1035             fprintf(FileHandle,
1036                     "  {VK_TAB       ,0      ,'\\t'     ,'\\t'     },\n"
1037                     "  {VK_ADD       ,0      ,'+'      ,'+'      },\n"
1038                     "  {VK_DIVIDE    ,0      ,'/'      ,'/'      },\n"
1039                     "  {VK_MULTIPLY  ,0      ,'*'      ,'*'      },\n"
1040                     "  {VK_SUBTRACT  ,0      ,'-'      ,'-'      },\n");
1041         }
1042 
1043         /* Terminate the table */
1044         fprintf(FileHandle, "  {0            ,0      ");
1045         for (k = 0; k < i; k++) fprintf(FileHandle, ",0        ");
1046 
1047         /* Terminate the structure */
1048         fprintf(FileHandle, "}\n" "};\n\n");
1049     }
1050 
1051     /* Numpad translation table */
1052     fprintf(FileHandle,
1053             "// Put this last so that VkKeyScan interprets number characters\n"
1054             "// as coming from the main section of the kbd (aVkToWch2 and\n"
1055             "// aVkToWch5) before considering the numpad (aVkToWch1).\n\n"
1056             "static ALLOC_SECTION_LDATA VK_TO_WCHARS1 aVkToWch1[] = {\n"
1057             "    { VK_NUMPAD0   , 0      ,  '0'   },\n"
1058             "    { VK_NUMPAD1   , 0      ,  '1'   },\n"
1059             "    { VK_NUMPAD2   , 0      ,  '2'   },\n"
1060             "    { VK_NUMPAD3   , 0      ,  '3'   },\n"
1061             "    { VK_NUMPAD4   , 0      ,  '4'   },\n"
1062             "    { VK_NUMPAD5   , 0      ,  '5'   },\n"
1063             "    { VK_NUMPAD6   , 0      ,  '6'   },\n"
1064             "    { VK_NUMPAD7   , 0      ,  '7'   },\n"
1065             "    { VK_NUMPAD8   , 0      ,  '8'   },\n"
1066             "    { VK_NUMPAD9   , 0      ,  '9'   },\n"
1067             "    { 0            , 0      ,  '\\0'  }\n"
1068             "};\n\n");
1069 
1070     /* Translation tables header */
1071     fprintf(FileHandle,"static ALLOC_SECTION_LDATA VK_TO_WCHAR_TABLE aVkToWcharTable[] = {\n");
1072 
1073     /* Loop states higher than 3 */
1074     for (i = 3; i <= StateCount; i++)
1075     {
1076         /* Print out the extra tables */
1077         fprintf(FileHandle,
1078                 "    {  (PVK_TO_WCHARS1)aVkToWch%d, %d, sizeof(aVkToWch%d[0]) },\n",
1079                 i,
1080                 i,
1081                 i);
1082     }
1083 
1084     /* Array of translation tables */
1085     fprintf(FileHandle,
1086             "    {  (PVK_TO_WCHARS1)aVkToWch2, 2, sizeof(aVkToWch2[0]) },\n"
1087             "    {  (PVK_TO_WCHARS1)aVkToWch1, 1, sizeof(aVkToWch1[0]) },\n"
1088             "    {                       NULL, 0, 0                    },\n"
1089             "};\n\n");
1090 
1091     /* Scan code to key name conversion table description */
1092     fprintf(FileHandle,
1093             "/***************************************************************************\\\n"
1094             "* aKeyNames[], aKeyNamesExt[]  - Virtual Scancode to Key Name tables\n"
1095             "*\n"
1096             "* Table attributes: Ordered Scan (by scancode), null-terminated\n"
1097             "*\n"
1098             "* Only the names of Extended, NumPad, Dead and Non-Printable keys are here.\n"
1099             "* (Keys producing printable characters are named by that character)\n"
1100             "\\***************************************************************************/\n\n");
1101 
1102     /* Check for key name data */
1103     if (KeyNameData)
1104     {
1105         /* Table header */
1106         fprintf(FileHandle, "static ALLOC_SECTION_LDATA VSC_LPWSTR aKeyNames[] = {\n");
1107 
1108         /* Print table */
1109         PrintNameTable(FileHandle, KeyNameData, FALSE);
1110 
1111         /* Table end */
1112         fprintf(FileHandle, "};\n\n");
1113     }
1114 
1115     /* Check for extended key name data */
1116     if (KeyNameExtData)
1117     {
1118         /* Table header */
1119         fprintf(FileHandle, "static ALLOC_SECTION_LDATA VSC_LPWSTR aKeyNamesExt[] = {\n");
1120 
1121         /* Print table */
1122         PrintNameTable(FileHandle, KeyNameExtData, FALSE);
1123 
1124         /* Table end */
1125         fprintf(FileHandle, "};\n\n");
1126     }
1127 
1128     /* Check for dead key name data */
1129     if (KeyNameDeadData)
1130     {
1131         /* Not yet supported */
1132         printf("Dead key name data not supported!\n");
1133         exit(1);
1134     }
1135 
1136     /* Check for dead key data */
1137     if (DeadKeyData)
1138     {
1139         /* Not yet supported */
1140         printf("Dead key data not supported!\n");
1141         exit(1);
1142     }
1143 
1144     /* Check for ligature data */
1145     if (LigatureData)
1146     {
1147         /* Not yet supported */
1148         printf("Ligature key data not supported!\n");
1149         exit(1);
1150     }
1151 
1152     /* Main keyboard table descriptor type */
1153     fprintf(FileHandle, "static ");
1154 
1155     /* FIXME? */
1156 
1157     /* Main keyboard table descriptor header */
1158     fprintf(FileHandle,
1159             "ALLOC_SECTION_LDATA KBDTABLES KbdTables%s = {\n"
1160             "    /*\n"
1161             "     * Modifier keys\n"
1162             "     */\n"
1163             "    &CharModifiers,\n\n"
1164             "    /*\n"
1165             "     * Characters tables\n"
1166             "     */\n"
1167             "    aVkToWcharTable,\n\n"
1168             "    /*\n"
1169             "     * Diacritics\n"
1170             "     */\n",
1171             FallbackDriver ? "Fallback" : "" );
1172 
1173     /* Descriptor dead key data section */
1174     if (DeadKeyData)
1175     {
1176         fprintf(FileHandle, "    aDeadKey,\n\n");
1177     }
1178     else
1179     {
1180         fprintf(FileHandle, "    NULL,\n\n");
1181     }
1182 
1183     /* Descriptor key name comment */
1184     fprintf(FileHandle,
1185             "    /*\n"
1186             "     * Names of Keys\n"
1187             "     */\n");
1188 
1189     /* Descriptor key name section */
1190     if (KeyNameData)
1191     {
1192         fprintf(FileHandle, "    aKeyNames,\n");
1193     }
1194     else
1195     {
1196         fprintf(FileHandle, "    NULL,\n");
1197     }
1198 
1199     /* Descriptor extended key name section */
1200     if (KeyNameExtData)
1201     {
1202         fprintf(FileHandle, "    aKeyNamesExt,\n");
1203     }
1204     else
1205     {
1206         fprintf(FileHandle, "    NULL,\n");
1207     }
1208 
1209     /* Descriptor dead key name section */
1210     if ((DeadKeyData) && (KeyNameDeadData))
1211     {
1212         fprintf(FileHandle, "    aKeyNamesDead,\n\n");
1213     }
1214     else
1215     {
1216         fprintf(FileHandle, "    NULL,\n\n");
1217     }
1218 
1219     /* Descriptor conversion table section  */
1220     fprintf(FileHandle,
1221             "    /*\n"
1222             "     * Scan codes to Virtual Keys\n"
1223             "     */\n"
1224             "    ausVK,\n"
1225             "    sizeof(ausVK) / sizeof(ausVK[0]),\n"
1226             "    aE0VscToVk,\n"
1227             "    aE1VscToVk,\n\n"
1228             "    /*\n"
1229             "     * Locale-specific special processing\n"
1230             "     */\n");
1231 
1232     /* FIXME: AttributeData and KLLF_ALTGR stuff */
1233 
1234     /* Descriptor locale-specific section */
1235     fprintf(FileHandle, "    MAKELONG(%s, KBD_VERSION),\n\n", "0");  /* FIXME */
1236 
1237     /* Descriptor ligature data comment */
1238     fprintf(FileHandle, "    /*\n     * Ligatures\n     */\n    %d,\n", 0); /* FIXME */
1239 
1240     /* Descriptor ligature data section */
1241     if (!LigatureData)
1242     {
1243         fprintf(FileHandle, "    0,\n");
1244         fprintf(FileHandle, "    NULL\n");
1245     }
1246     else
1247     {
1248         fprintf(FileHandle, "    sizeof(aLigature[0]),\n");
1249         fprintf(FileHandle, "    (PLIGATURE1)aLigature\n");
1250     }
1251 
1252     /* Descriptor finish */
1253     fprintf(FileHandle, "};\n\n");
1254 
1255     /* Keyboard layout callback function */
1256     if (!FallbackDriver) fprintf(FileHandle,
1257                                  "PKBDTABLES KbdLayerDescriptor(VOID)\n"
1258                                  "{\n"
1259                                  "    return &KbdTables;\n"
1260                                  "}\n");
1261 
1262     /* Clean up */
1263     fclose(FileHandle);
1264     return TRUE;
1265 }
1266 
1267 ULONG
1268 DoOutput(IN ULONG StateCount,
1269          IN PULONG ShiftStates,
1270          IN PKEYNAME DescriptionData,
1271          IN PKEYNAME LanguageData,
1272          IN PVOID AttributeData,
1273          IN PVOID DeadKeyData,
1274          IN PVOID LigatureData,
1275          IN PKEYNAME KeyNameData,
1276          IN PKEYNAME KeyNameExtData,
1277          IN PKEYNAME KeyNameDeadData)
1278 {
1279     ULONG FailureCode = 0;
1280 
1281     /* Take the time */
1282     time(&Clock);
1283     Now = localtime(&Clock);
1284 
1285     /* Check if this just a fallback driver*/
1286     if (!FallbackDriver)
1287     {
1288         /* It's not, create header file */
1289         if (!kbd_h(&g_Layout)) FailureCode = 1;
1290 
1291         /* Create the resource file */
1292         if (!kbd_rc(DescriptionData, LanguageData)) FailureCode = 2;
1293     }
1294 
1295     /* Create the C file */
1296     if (!kbd_c(StateCount,
1297                ShiftStates,
1298                AttributeData,
1299                &g_Layout,
1300                DeadKeyData,
1301                LigatureData,
1302                KeyNameData,
1303                KeyNameExtData,
1304                KeyNameDeadData))
1305     {
1306         /* Failed in C file generation */
1307         FailureCode = 3;
1308     }
1309 
1310     /* Check if this just a fallback driver*/
1311     if (!FallbackDriver)
1312     {
1313         /* Generate the definition file */
1314         if (!kbd_def()) FailureCode = 4;
1315     }
1316 
1317     /* Done */
1318     return FailureCode;
1319 }
1320 
1321 
1322 /* EOF */
1323