Start implementing the long task of DoLAYOUT to process the big "meat" of a KLC file...
authorArch Blackmann <ablackmann@svn.reactos.org>
Tue, 3 Nov 2009 22:57:26 +0000 (22:57 +0000)
committerArch Blackmann <ablackmann@svn.reactos.org>
Tue, 3 Nov 2009 22:57:26 +0000 (22:57 +0000)
The tool does some minimal error checking for now, and attempts to begin parsing the LAYOUT section, but fails miserably and the code won't execute unless you've enabled verbose mode. I'm just using this commit as a checkpoint for now.
Also fixed SCVK structure to use the last member as a state flag.
Finally, added definitions for LAYOUTENTRY which will keep track of each row's column's values in the LAYOUT.

svn path=/trunk/; revision=43944

reactos/tools/kbdtool/parser.c

index 4308d25..c292f45 100644 (file)
@@ -26,9 +26,36 @@ typedef struct tagSCVK
     USHORT ScanCode;
     USHORT VirtualKey;
     PCHAR Name;
-    PVOID Reserved;
+    BOOLEAN Processed;
 } SCVK, *PSCVK;
 
+typedef struct tagVKNAME
+{
+    ULONG VirtualKey;
+    PCHAR Name;
+} VKNAME, *PVKNAME;
+
+typedef struct tagLAYOUTENTRY
+{
+    USHORT ScanCode;
+    UCHAR VirtualKey;
+    UCHAR OriginalVirtualKey;
+    UCHAR Cap;
+    ULONG StateCount;
+    ULONG CharData[8];
+    ULONG DeadCharData[8];
+    ULONG OtherCharData[8];
+    struct LAYOUTENTRY* CapData;
+    PCHAR Name;
+    ULONG Processed;
+    ULONG LineCount;
+} LAYOUTENTRY, *PLAYOUTENTRY;
+
+typedef struct tagLAYOUT
+{
+    LAYOUTENTRY Entry[110];
+} LAYOUT, *PLAYOUT;
+
 /* GLOBALS ********************************************************************/
 
 #define KEYWORD_COUNT 17
@@ -44,7 +71,7 @@ CHAR gCompany[256];
 CHAR gLocaleName[256];
 ULONG gID = 0;
 ULONG gKbdLayoutVersion;
-CHAR g_Layout[4096];
+LAYOUT g_Layout;
 ULONG gLineCount;
 PCHAR KeyWordList[KEYWORD_COUNT] =
 {
@@ -70,119 +97,160 @@ PCHAR KeyWordList[KEYWORD_COUNT] =
 /* ISO 110-key Keyboard Scancode to Virtual Key Conversion Table */
 SCVK ScVk[] =
 {
-    {0x02, '1', NULL, NULL},
-    {0x03, '2', NULL, NULL},
-    {0x04, '3', NULL, NULL},
-    {0x05, '4', NULL, NULL},
-    {0x06, '5', NULL, NULL},
-    {0x07, '6', NULL, NULL},
-    {0x08, '7', NULL, NULL},
-    {0x09, '8', NULL, NULL},
-    {0x0a, '9', NULL, NULL},
-    {0x0b, '0', NULL, NULL},
-    {0x0c, 0xbd, NULL, NULL},
-    {0x0d, 0xbb, NULL, NULL},
-    {0x10, 'Q', NULL, NULL},
-    {0x11, 'W', NULL, NULL},
-    {0x12, 'E', NULL, NULL},
-    {0x13, 'R', NULL, NULL},
-    {0x14, 'T', NULL, NULL},
-    {0x15, 'Y', NULL, NULL},
-    {0x16, 'U', NULL, NULL},
-    {0x17, 'I', NULL, NULL},
-    {0x18, 'O', NULL, NULL},
-    {0x19, 'P', NULL, NULL},
-    {0x1a, 0xdb, NULL, NULL},
-    {0x1b, 0xdd, NULL, NULL},
-    {0x1e, 'A', NULL, NULL},
-    {0x1f, 'S', NULL, NULL},
-    {0x20, 'D', NULL, NULL},
-    {0x21, 'F', NULL, NULL},
-    {0x22, 'G', NULL, NULL},
-    {0x23, 'H', NULL, NULL},
-    {0x24, 'J', NULL, NULL},
-    {0x25, 'K', NULL, NULL},
-    {0x26, 'L', NULL, NULL},
-    {0x27, 0xba, NULL, NULL},
-    {0x28, 0xde, NULL, NULL},
-    {0x29, 0xc0, NULL, NULL},
-    {0x2b, 0xdc, NULL, NULL},
-    {0x2c, 'Z', NULL, NULL},
-    {0x2d, 'X', NULL, NULL},
-    {0x2e, 'C', NULL, NULL},
-    {0x2f, 'V', NULL, NULL},
-    {0x30, 'B', NULL, NULL},
-    {0x31, 'N', NULL, NULL},
-    {0x32, 'M', NULL, NULL},
-    {0x33, 0xbc, NULL, NULL},
-    {0x34, 0xbe, NULL, NULL},
-    {0x35, 0xbf, NULL, NULL},
-    {0x53, 0x6e, NULL, NULL},
-    {0x56, 0xe2, NULL, NULL},
-    {0x73, 0xc1, NULL, NULL},
-    {0x7e, 0xc2, NULL, NULL},
-    {0xe010, 0xb1, "Speedracer: Previous Track", NULL},
-    {0xe019, 0xb0, "Speedracer: Next Track", NULL},
-    {0xe01d, 0xa3, "RControl", NULL},
-    {0xe020, 0xad, "Speedracer: Volume Mute", NULL},
-    {0xe021, 0xb7, "Speedracer: Launch App 2", NULL},
-    {0xe022, 0xb3, "Speedracer: Media Play/Pause", NULL},
-    {0xe024, 0xb2, "Speedracer: Media Stop", NULL},
-    {0xe02e, 0xae, "Speedracer: Volume Up", NULL},
-    {0xe030, 0xaf, "Speedracer: Volume Down", NULL},
-    {0xe032, 0xac, "Speedracer: Browser Home", NULL},
-    {0xe035, 0x6f, "Numpad Divide", NULL},
-    {0xe037, 0x2c, "Snapshot", NULL},
-    {0xe038, 0xa5, "RMenu", NULL},
-    {0xe047, 0x24, "Home", NULL},
-    {0xe048, 0x26, "Up", NULL},
-    {0xe049, 0x21, "Prior", NULL},
-    {0xe04b, 0x25, "Left", NULL},
-    {0xe04d, 0x27, "Right", NULL},
-    {0xe04f, 0x23, "End", NULL},
-    {0xe050, 0x28, "Down", NULL},
-    {0xe051, 0x22, "Next", NULL},
-    {0xe052, 0x2d, "Insert", NULL},
-    {0xe053, 0x2e, "Delete", NULL},
-    {0xe05b, 0x5b, "Left Win", NULL},
-    {0xe05c, 0x5c, "Right Win", NULL},
-    {0xe05d, 0x5d, "Application", NULL},
-    {0xe05e, 0xff, "Power", NULL},
-    {0xe05f, 0x5f, "Speedracer: Sleep", NULL},
-    {0xe060, 0xff, "BAD SCANCODE", NULL},
-    {0xe061, 0xff, "BAD SCANCODE", NULL},
-    {0xe065, 0xaa, "Speedracer: Browser Search", NULL},
-    {0xe066, 0xab, "Speedracer: Browser Favorites", NULL},
-    {0xe067, 0xa8, "Speedracer: Browser Refresh", NULL},
-    {0xe068, 0xa9, "Speedracer: Browser Stop", NULL},
-    {0xe069, 0xa7, "Speedracer: Browser Foward", NULL},
-    {0xe06a, 0xa6, "Speedracer: Browser Back", NULL},
-    {0xe06b, 0xb6, "Speedracer: Launch App 1", NULL},
-    {0xe06c, 0xb4, "Speedracer: Launch Mail", NULL},
-    {0xe06d, 0xb5, "Speedracer: Launch Media Selector", NULL},
-    {0x53, 0x6e, NULL, NULL},
-    {0x0e, 0x08, NULL, NULL},
-    {0x01, 0x1b, NULL, NULL},
-    {0xe01c, 0x0d, "Numpad Enter", NULL},
-    {0x1c, 0x0d, NULL, NULL},
-    {0x39, 0x20, NULL, NULL},
-    {0xe046, 0x03, "Break (Ctrl + Pause)", NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL},
-    {0xFFFF, 0x00, NULL, NULL}
+    {0x02, '1', NULL, FALSE},
+    {0x03, '2', NULL, FALSE},
+    {0x04, '3', NULL, FALSE},
+    {0x05, '4', NULL, FALSE},
+    {0x06, '5', NULL, FALSE},
+    {0x07, '6', NULL, FALSE},
+    {0x08, '7', NULL, FALSE},
+    {0x09, '8', NULL, FALSE},
+    {0x0a, '9', NULL, FALSE},
+    {0x0b, '0', NULL, FALSE},
+    {0x0c, 0xbd, NULL, FALSE},
+    {0x0d, 0xbb, NULL, FALSE},
+    {0x10, 'Q', NULL, FALSE},
+    {0x11, 'W', NULL, FALSE},
+    {0x12, 'E', NULL, FALSE},
+    {0x13, 'R', NULL, FALSE},
+    {0x14, 'T', NULL, FALSE},
+    {0x15, 'Y', NULL, FALSE},
+    {0x16, 'U', NULL, FALSE},
+    {0x17, 'I', NULL, FALSE},
+    {0x18, 'O', NULL, FALSE},
+    {0x19, 'P', NULL, FALSE},
+    {0x1a, 0xdb, NULL, FALSE},
+    {0x1b, 0xdd, NULL, FALSE},
+    {0x1e, 'A', NULL, FALSE},
+    {0x1f, 'S', NULL, FALSE},
+    {0x20, 'D', NULL, FALSE},
+    {0x21, 'F', NULL, FALSE},
+    {0x22, 'G', NULL, FALSE},
+    {0x23, 'H', NULL, FALSE},
+    {0x24, 'J', NULL, FALSE},
+    {0x25, 'K', NULL, FALSE},
+    {0x26, 'L', NULL, FALSE},
+    {0x27, 0xba, NULL, FALSE},
+    {0x28, 0xde, NULL, FALSE},
+    {0x29, 0xc0, NULL, FALSE},
+    {0x2b, 0xdc, NULL, FALSE},
+    {0x2c, 'Z', NULL, FALSE},
+    {0x2d, 'X', NULL, FALSE},
+    {0x2e, 'C', NULL, FALSE},
+    {0x2f, 'V', NULL, FALSE},
+    {0x30, 'B', NULL, FALSE},
+    {0x31, 'N', NULL, FALSE},
+    {0x32, 'M', NULL, FALSE},
+    {0x33, 0xbc, NULL, FALSE},
+    {0x34, 0xbe, NULL, FALSE},
+    {0x35, 0xbf, NULL, FALSE},
+    {0x53, 0x6e, NULL, FALSE},
+    {0x56, 0xe2, NULL, FALSE},
+    {0x73, 0xc1, NULL, FALSE},
+    {0x7e, 0xc2, NULL, FALSE},
+    {0xe010, 0xb1, "Speedracer: Previous Track", FALSE},
+    {0xe019, 0xb0, "Speedracer: Next Track", FALSE},
+    {0xe01d, 0xa3, "RControl", FALSE},
+    {0xe020, 0xad, "Speedracer: Volume Mute", FALSE},
+    {0xe021, 0xb7, "Speedracer: Launch App 2", FALSE},
+    {0xe022, 0xb3, "Speedracer: Media Play/Pause", FALSE},
+    {0xe024, 0xb2, "Speedracer: Media Stop", FALSE},
+    {0xe02e, 0xae, "Speedracer: Volume Up", FALSE},
+    {0xe030, 0xaf, "Speedracer: Volume Down", FALSE},
+    {0xe032, 0xac, "Speedracer: Browser Home", FALSE},
+    {0xe035, 0x6f, "Numpad Divide", FALSE},
+    {0xe037, 0x2c, "Snapshot", FALSE},
+    {0xe038, 0xa5, "RMenu", FALSE},
+    {0xe047, 0x24, "Home", FALSE},
+    {0xe048, 0x26, "Up", FALSE},
+    {0xe049, 0x21, "Prior", FALSE},
+    {0xe04b, 0x25, "Left", FALSE},
+    {0xe04d, 0x27, "Right", FALSE},
+    {0xe04f, 0x23, "End", FALSE},
+    {0xe050, 0x28, "Down", FALSE},
+    {0xe051, 0x22, "Next", FALSE},
+    {0xe052, 0x2d, "Insert", FALSE},
+    {0xe053, 0x2e, "Delete", FALSE},
+    {0xe05b, 0x5b, "Left Win", FALSE},
+    {0xe05c, 0x5c, "Right Win", FALSE},
+    {0xe05d, 0x5d, "Application", FALSE},
+    {0xe05e, 0xff, "Power", FALSE},
+    {0xe05f, 0x5f, "Speedracer: Sleep", FALSE},
+    {0xe060, 0xff, "BAD SCANCODE", FALSE},
+    {0xe061, 0xff, "BAD SCANCODE", FALSE},
+    {0xe065, 0xaa, "Speedracer: Browser Search", FALSE},
+    {0xe066, 0xab, "Speedracer: Browser Favorites", FALSE},
+    {0xe067, 0xa8, "Speedracer: Browser Refresh", FALSE},
+    {0xe068, 0xa9, "Speedracer: Browser Stop", FALSE},
+    {0xe069, 0xa7, "Speedracer: Browser Foward", FALSE},
+    {0xe06a, 0xa6, "Speedracer: Browser Back", FALSE},
+    {0xe06b, 0xb6, "Speedracer: Launch App 1", FALSE},
+    {0xe06c, 0xb4, "Speedracer: Launch Mail", FALSE},
+    {0xe06d, 0xb5, "Speedracer: Launch Media Selector", FALSE},
+    {0x53, 0x6e, NULL, FALSE},
+    {0x0e, 0x08, NULL, FALSE},
+    {0x01, 0x1b, NULL, FALSE},
+    {0xe01c, 0x0d, "Numpad Enter", FALSE},
+    {0x1c, 0x0d, NULL, FALSE},
+    {0x39, 0x20, NULL, FALSE},
+    {0xe046, 0x03, "Break (Ctrl + Pause)", FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE},
+    {0xFFFF, 0x00, NULL, FALSE}
 };
 
+VKNAME VKName[] =
+{
+    {0x08, "BACK"},
+    {0x03, "CANCEL"},
+    {0x1b, "ESCAPE"},
+    {0x0d, "RETURN"},
+    {0x20, "SPACE"},
+    {0x6e, "DECIMAL"},
+    {0xba, "OEM_1"},
+    {0xbb, "OEM_PLUS"},
+    {0xbc, "OEM_COMMA"},
+    {0xbd, "OEM_MINUS"},
+    {0xbe, "OEM_PERIOD"},
+    {0xbf, "OEM_2"},
+    {0xc0, "OEM_3"},
+    {0xdb, "OEM_4"},
+    {0xdc, "OEM_5"},
+    {0xdd, "OEM_6"},
+    {0xde, "OEM_7"},
+    {0xdf, "OEM_8"},
+    {0xe2, "OEM_102"},
+    {0xc1, "ABNT_C1"},
+    {0xc2, "ABNT_C2"},
+    {0x10, "SHIFT"},
+    {0xa0, "LSHIFT"},
+    {0xa1, "RSHIFT"},
+    {0x12, "MENU"},
+    {0xa4, "LMENU"},
+    {0xa5, "RMENU"},
+    {0x11, "CONTROL"},
+    {0xa2, "LCONTROL"},
+    {0xa3, "RCONTROL"},
+    {0x6c, "SEPARATOR"},
+    {0xe4, "ICO_00"},
+    {0x2e, "DELETE"},
+    {0x2d, "INSERT"},
+    {0xe5, "GROUPSHIFT"},
+    {0xe6, "RGROUPSHIFT"}
+};
+
+
 /* FUNCTIONS ******************************************************************/
 
 ULONG
@@ -197,6 +265,52 @@ isKeyWord(PCHAR p)
     return i;
 }
 
+ULONG
+getVKNum(IN PCHAR p)
+{
+    ULONG Length;
+    ULONG i;
+    ULONG KeyNumber;
+    
+    /* Compute the length of the string */
+    Length = strlen(p);
+    if (!Length) return -1;
+    
+    /* Check if this is is a simple key */
+    if (Length == 1)
+    {
+        /* If it's a number, return it now */
+        if ((*p >= '0') && (*p <= '9')) return *p;
+
+        /* Otherwise, convert the letter to upper case */
+        *p = toupper(*p);
+        
+        /* And make sure it's a valid letter */
+        if ((*p >= 'A') && (*p <='Z')) return *p;
+        
+        /* Otherwise, fail */
+        return -1;
+    }
+
+    /* Otherwise, scan our virtual key names */
+    for (i = 0; i < 36; i++)
+    {
+        /* Check if we have a match */
+        if (!strcmp(VKName[i].Name, p)) return VKName[i].VirtualKey;
+    }
+    
+    /*  Check if this is a hex string */
+    if ((*p == '0') && ((*(p + 1) == 'x') || (*(p + 1) == 'X')))
+    {
+        /* Get the key number from the hex string */
+        *(p + 1) = 'x';
+        if (sscanf(p, "0x%x", &KeyNumber) == 1) return KeyNumber;
+    }
+
+    /* No hope: fail */
+    return -1;
+}
+
 BOOLEAN
 NextLine(PCHAR LineBuffer,
          ULONG BufferSize,
@@ -680,11 +794,131 @@ DoDEADKEY(PVOID DeadKeyData)
 }
 
 ULONG
-DoLAYOUT(IN PVOID LayoutData,
+DoLAYOUT(IN PLAYOUT LayoutData,
          IN PVOID LigatureData,
          IN PULONG ShiftStates,
          IN ULONG StateCount)
 {
+    CHAR Token[32];
+    CHAR Cap[8];
+    ULONG KeyWord;
+    ULONG ScanCode, CurrentCode;
+    ULONG TokenCount;
+    ULONG VirtualKey;
+    ULONG i;
+    BOOLEAN FullEntry;
+    ULONG ScanCodeCount = -1;
+    PLAYOUTENTRY Entry;
+    
+    /* Only attempt this is Verbose is enabled (FOR DEBUGGING ONLY) */
+    if (!Verbose) return SkipLines();
+    
+    /* Zero out the layout */
+    memset(LayoutData, 0, sizeof(LAYOUT));
+    
+    /* Read each line */
+    Entry = &LayoutData->Entry[0];
+    while (NextLine(gBuf, 256, gfpInput))
+    {
+        /* Search for token */
+        if (sscanf(gBuf, "%s", Token) != 1) continue;
+        
+        /* Make sure it's not just a comment */
+        if (*Token == ';') continue;
+        
+        /* Make sure it's not a keyword */
+        KeyWord = isKeyWord(Token);
+        if (KeyWord < KEYWORD_COUNT) break;
+        
+        /* Now read the entry */
+        TokenCount = sscanf(gBuf, " %x %s %s", &ScanCode, Token, Cap);
+        if (TokenCount == 3)
+        {
+            /* Full entry with cap */
+            FullEntry = TRUE;
+        }
+        else if (TokenCount != 2)
+        {
+            /* Fail, invalid LAYOUT entry */
+            printf("There are not enough columns in the layout list.\n");
+            exit(1);
+        }
+        else
+        {
+            /* Simplified layout with no cap */
+            FullEntry = FALSE;
+        }
+        
+        /* One more */
+        Entry++;
+        if (++ScanCodeCount >= 110)
+        {
+            /* Too many! */
+            printf("ScanCode %02x - too many scancodes here to parse.\n", ScanCode);
+            exit(1);
+        }
+        
+        /* Fill out this entry */
+        Entry->ScanCode = ScanCode;
+        Entry->LineCount = gLineCount;
+        
+        /* Loop scancode table */
+        for (i = 0; i < 110; i++)
+        {
+            /* Get the current code */
+            CurrentCode = ScVk[i].ScanCode;
+            if (CurrentCode == 0xFFFF)
+            {
+                /* New code */
+                if (Verbose) printf("A new scancode is being defined: 0x%2X, %s\n", Entry->ScanCode, Token);
+                
+                /* Fill out the entry */
+                Entry->VirtualKey = getVKNum(Token);
+                goto FillEntry;
+            }
+            
+            /* If we found it, process it */
+            if (ScanCode == CurrentCode) break;
+        }
+        
+        /* Make sure we didn't already process it */
+        if (ScVk[i].Processed)
+        {
+            /* Fail */
+            printf("Scancode %X was previously defined.\n", ScanCode);
+            exit(1);
+        }
+        
+        /* Check if there is a valid virtual key */
+        if (ScVk[i].VirtualKey == 0xFFFF)
+        {
+            /* Fail */
+            printf("The Scancode you tried to use (%X) is reserved.\n", ScanCode);
+            exit(1);
+        }
+        
+        /* Fill out the entry */
+        Entry->OriginalVirtualKey = ScVk[i].VirtualKey;
+        Entry->Name = ScVk[i].Name;
+        
+FillEntry:
+        Entry->Processed = TRUE;
+        ScVk[i].Processed = TRUE;
+        
+        /* Get the virtual key from the entry */
+        VirtualKey = getVKNum(Token);
+        Entry->VirtualKey = VirtualKey;
+        
+        /* Make sure it's valid */
+        if (VirtualKey == 0xFFFF)
+        {
+            /* Warn the user */
+            if (Verbose) printf("An invalid Virtual Key '%s' was defined.\n", Token);
+            continue;
+        }
+    }
+    
+    /* Skip what's left */
     return SkipLines();
 }