mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 12:26:32 +00:00
1162 lines
30 KiB
C
1162 lines
30 KiB
C
/*
|
|
* PROJECT: ReactOS Build Tools [Keyboard Layout Compiler]
|
|
* LICENSE: BSD - See COPYING.BSD in the top level directory
|
|
* FILE: tools/kbdtool/parser.c
|
|
* PURPOSE: Parsing Logic
|
|
* PROGRAMMERS: ReactOS Foundation
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "kbdtool.h"
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
/* Internal parser data about everything that was parsed */
|
|
CHAR gBuf[256];
|
|
CHAR gKBDName[10];
|
|
CHAR gCopyright[256];
|
|
CHAR gDescription[256];
|
|
CHAR gCompany[256];
|
|
CHAR gLocaleName[256];
|
|
CHAR gVKeyName[32];
|
|
ULONG gID = 0;
|
|
ULONG gKbdLayoutVersion;
|
|
LAYOUT g_Layout;
|
|
ULONG gLineCount;
|
|
|
|
/* Table of keywords the parser recognizes */
|
|
PCHAR KeyWordList[KEYWORD_COUNT] =
|
|
{
|
|
"KBD",
|
|
"VERSION",
|
|
"COPYRIGHT",
|
|
"COMPANY",
|
|
"LOCALENAME",
|
|
"MODIIFERS",
|
|
"SHIFTSTATE",
|
|
"ATTRIBUTES",
|
|
"LAYOUT",
|
|
"DEADKEY",
|
|
"LIGATURE",
|
|
"KEYNAME",
|
|
"KEYNAME_EXT",
|
|
"KEYNAME_DEAD",
|
|
"DESCRIPTIONS",
|
|
"LANGUAGENAMES",
|
|
"ENDKBD",
|
|
};
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
ULONG
|
|
isKeyWord(PCHAR p)
|
|
{
|
|
ULONG i;
|
|
|
|
/* Check if we know this keyword */
|
|
for (i = 0; i < KEYWORD_COUNT; i++) if (strcmp(KeyWordList[i], p) == 0) break;
|
|
|
|
/* If we didn't find anything, i will be KEYWORD_COUNT, which is invalid */
|
|
return i;
|
|
}
|
|
|
|
PCHAR
|
|
getVKName(IN ULONG VirtualKey,
|
|
IN BOOLEAN Prefix)
|
|
{
|
|
ULONG i;
|
|
|
|
/* Loop for standard virtual key */
|
|
if (((VirtualKey >= 'A') && (VirtualKey <= 'Z')) ||
|
|
((VirtualKey >= '0') && (VirtualKey <= '9')))
|
|
{
|
|
/* Fill out the name */
|
|
gVKeyName[0] = '\'';
|
|
gVKeyName[1] = VirtualKey;
|
|
gVKeyName[2] = '\'';
|
|
gVKeyName[3] = '\0';
|
|
return gVKeyName;
|
|
}
|
|
|
|
/* Check if a prefix is required */
|
|
if (Prefix)
|
|
{
|
|
/* Add it */
|
|
strcpy(gVKeyName, "VK_");
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, don't add anything */
|
|
strcpy(gVKeyName, "");
|
|
}
|
|
|
|
/* Loop all virtual keys */
|
|
for (i = 0; i < 36; i++)
|
|
{
|
|
/* Check if this key matches */
|
|
if (VKName[i].VirtualKey == VirtualKey)
|
|
{
|
|
/* Copy the key's name into the buffer */
|
|
strcat(gVKeyName, VKName[i].Name);
|
|
return gVKeyName;
|
|
}
|
|
}
|
|
|
|
/* If we got here, then we failed, so print out an error name */
|
|
strcpy(gVKeyName, "#ERROR#");
|
|
return gVKeyName;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
UCHAR
|
|
getCharacterInfo(IN PCHAR State,
|
|
OUT PULONG EntryChar,
|
|
OUT PCHAR LigatureChar)
|
|
{
|
|
ULONG Length;
|
|
ULONG CharInfo = CHAR_NORMAL_KEY;
|
|
UCHAR StateChar;
|
|
ULONG CharCode;
|
|
|
|
/* Calculate the length of the state */
|
|
Length = strlen(State);
|
|
|
|
/* Check if this is at least a simple key state */
|
|
if (Length > 1)
|
|
{
|
|
/* Read the first character and check if it's a dead key */
|
|
StateChar = State[Length - 1];
|
|
if (StateChar == '@')
|
|
{
|
|
/* This is a dead key */
|
|
CharInfo = CHAR_DEAD_KEY;
|
|
}
|
|
else if (StateChar == '%')
|
|
{
|
|
/* This is another key */
|
|
CharInfo = CHAR_OTHER_KEY;
|
|
}
|
|
}
|
|
|
|
/* Check if this is a numerical key state */
|
|
if ((Length - 1) >= 2)
|
|
{
|
|
/* Scan for extended character code entry */
|
|
if ((sscanf(State, "%6x", &CharCode) == 1) &&
|
|
(((Length == 5) && (State[0] == '0')) ||
|
|
((Length == 6) && ((State[0] == '0') && (State[1] == '0')))))
|
|
{
|
|
/* Handle a ligature key */
|
|
CharInfo = CHAR_LIGATURE_KEY;
|
|
|
|
/* Not yet handled */
|
|
printf("Ligatured character entries not yet supported!\n");
|
|
exit(1);
|
|
}
|
|
else
|
|
{
|
|
/* Get the normal character entry */
|
|
if (sscanf(State, "%4x", &CharCode) == 1)
|
|
{
|
|
/* Does the caller want the key? */
|
|
if (EntryChar) *EntryChar = CharCode;
|
|
}
|
|
else
|
|
{
|
|
/* The entry is totally invalid */
|
|
if (Verbose) printf("An unparseable character entry '%s' was found.\n", State);
|
|
if (EntryChar) *EntryChar = 0;
|
|
CharInfo = CHAR_INVALID_KEY;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Save the key if the caller requested it */
|
|
if (EntryChar) *EntryChar = *State;
|
|
}
|
|
|
|
/* Return the type of character this is */
|
|
return CharInfo;
|
|
}
|
|
|
|
BOOLEAN
|
|
NextLine(PCHAR LineBuffer,
|
|
ULONG BufferSize,
|
|
FILE *File)
|
|
{
|
|
PCHAR p, pp;
|
|
|
|
/* Scan each line */
|
|
while (fgets(LineBuffer, BufferSize, File))
|
|
{
|
|
/* Remember it */
|
|
gLineCount++;
|
|
|
|
/* Reset the pointer at the beginning of the line */
|
|
p = LineBuffer;
|
|
|
|
/* Now bypass all whitespace (and tabspace) */
|
|
while ((*p) && ((*p == ' ') || (*p == '\t'))) p++;
|
|
|
|
/* If this is an old-style comment, skip the line */
|
|
if (*p == ';') continue;
|
|
|
|
/* Otherwise, check for new-style comment */
|
|
pp = strstr(p, "//");
|
|
if (pp)
|
|
{
|
|
/* We have a comment, so terminate there (unless the whole line is one) */
|
|
if (pp == p) continue;
|
|
*pp = '\0';
|
|
}
|
|
else
|
|
{
|
|
/* No comment, so find the new line and terminate there */
|
|
p = strchr(p, '\n');
|
|
if (p) *p = '\0';
|
|
}
|
|
|
|
/* We have a line! */
|
|
return TRUE;
|
|
}
|
|
|
|
/* No line found */
|
|
return FALSE;
|
|
}
|
|
|
|
ULONG
|
|
SkipLines(VOID)
|
|
{
|
|
ULONG KeyWord;
|
|
CHAR KeyWordChars[32];
|
|
|
|
/* Scan each line, skipping it if it's not a keyword */
|
|
while (NextLine(gBuf, sizeof(gBuf), gfpInput))
|
|
{
|
|
/* Read a single word */
|
|
if (sscanf(gBuf, "%s", KeyWordChars) == 1)
|
|
{
|
|
/* If the word is a keyword, stop skipping lines */
|
|
KeyWord = isKeyWord(KeyWordChars);
|
|
if (KeyWord < KEYWORD_COUNT) return KeyWord;
|
|
}
|
|
}
|
|
|
|
/* We skipped all the possible lines, not finding anything */
|
|
return KEYWORD_COUNT;
|
|
}
|
|
|
|
ULONG
|
|
DoKBD(VOID)
|
|
{
|
|
/* On Unicode files, we need to find the Unicode marker (FEEF) */
|
|
ASSERT(UnicodeFile == FALSE);
|
|
|
|
/* Initial values */
|
|
*gKBDName = '\0';
|
|
*gDescription = '\0';
|
|
|
|
/* Scan for the values */
|
|
if (sscanf(gBuf, "KBD %8s \"%40[^\"]\" %d", gKBDName, gDescription, &gID) < 2)
|
|
{
|
|
/* Couldn't find them */
|
|
printf("Unable to read keyboard name or description.\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Debug only */
|
|
DPRINT1("KBD Name: [%8s] Description: [%40s] ID: [%d]\n", gKBDName, gDescription, gID);
|
|
return SkipLines();
|
|
}
|
|
|
|
ULONG
|
|
DoVERSION(VOID)
|
|
{
|
|
/* Scan for the value */
|
|
if (sscanf(gBuf, "VERSION %d", &gKbdLayoutVersion) < 1)
|
|
{
|
|
/* Couldn't find them */
|
|
printf("Unable to read keyboard version information.\n");
|
|
}
|
|
|
|
/* Debug only */
|
|
DPRINT1("VERSION [%d]\n", gKbdLayoutVersion);
|
|
return SkipLines();
|
|
}
|
|
|
|
ULONG
|
|
DoCOPYRIGHT(VOID)
|
|
{
|
|
/* Initial values */
|
|
*gCopyright = '\0';
|
|
|
|
/* Scan for the value */
|
|
if (sscanf(gBuf, "COPYRIGHT \"%40[^\"]\"", gCopyright) < 1)
|
|
{
|
|
/* Couldn't find them */
|
|
printf("Unable to read the specified COPYRIGHT string.\n");
|
|
}
|
|
|
|
/* Debug only */
|
|
DPRINT1("COPYRIGHT [%40s]\n", gCopyright);
|
|
return SkipLines();
|
|
}
|
|
|
|
ULONG
|
|
DoCOMPANY(VOID)
|
|
{
|
|
/* Initial values */
|
|
*gCompany = '\0';
|
|
|
|
/* Scan for the value */
|
|
if (sscanf(gBuf, "COMPANY \"%85[^\"]\"", gCompany) < 1)
|
|
{
|
|
/* Couldn't find them */
|
|
printf("Unable to read the specified COMPANY name.\n");
|
|
}
|
|
|
|
/* Debug only */
|
|
DPRINT1("COMPANY [%85s]\n", gCompany);
|
|
return SkipLines();
|
|
}
|
|
|
|
ULONG
|
|
DoLOCALENAME(VOID)
|
|
{
|
|
/* Initial values */
|
|
*gLocaleName = '\0';
|
|
|
|
/* Scan for the value */
|
|
if (sscanf(gBuf, "LOCALENAME \"%40[^\"]\"", gLocaleName) < 1)
|
|
{
|
|
/* Couldn't find them */
|
|
printf("Unable to read the specified COPYRIGHT string.\n");
|
|
}
|
|
|
|
/* Debug only */
|
|
DPRINT1("LOCALENAME [%40s]\n", gLocaleName);
|
|
return SkipLines();
|
|
}
|
|
|
|
ULONG
|
|
DoDESCRIPTIONS(IN PKEYNAME* DescriptionData)
|
|
{
|
|
ULONG KeyWord = 0;
|
|
CHAR Token[32];
|
|
ULONG LanguageCode;
|
|
PCHAR p, pp;
|
|
PKEYNAME Description;
|
|
|
|
/* Assume nothing */
|
|
*DescriptionData = 0;
|
|
|
|
/* Start scanning */
|
|
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 scan for the language code */
|
|
if (sscanf(Token, " %4x", &LanguageCode) != 1)
|
|
{
|
|
/* Skip */
|
|
printf("An invalid LANGID was specified.\n");
|
|
continue;
|
|
}
|
|
|
|
/* Now get the actual description */
|
|
if (sscanf(gBuf, " %*4x %s[^\n]", Token) != 1)
|
|
{
|
|
/* Skip */
|
|
printf("A language description is missing.\n");
|
|
continue;
|
|
}
|
|
|
|
/* Get the description string and find the ending */
|
|
p = strstr(gBuf, Token);
|
|
pp = strchr(p, '\n');
|
|
if (!pp) pp = strchr(p, '\r');
|
|
|
|
/* Terminate the description string here */
|
|
if (pp) *pp = 0;
|
|
|
|
/* Now allocate the description */
|
|
Description = malloc(sizeof(KEYNAME));
|
|
if (!Description)
|
|
{
|
|
/* Fail */
|
|
printf("Unable to allocate the KEYNAME struct (out of memory?).\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Fill out the structure */
|
|
Description->Code = LanguageCode;
|
|
Description->Name = strdup(p);
|
|
Description->Next = NULL;
|
|
|
|
/* Debug only */
|
|
DPRINT1("LANGID: [%4x] Description: [%s]\n", Description->Code, Description->Name);
|
|
|
|
/* Point to it and advance the pointer */
|
|
*DescriptionData = Description;
|
|
DescriptionData = &Description->Next;
|
|
}
|
|
|
|
/* We are done */
|
|
return KeyWord;
|
|
}
|
|
|
|
ULONG
|
|
DoLANGUAGENAMES(IN PKEYNAME* LanguageData)
|
|
{
|
|
ULONG KeyWord = 0;
|
|
CHAR Token[32];
|
|
ULONG LanguageCode;
|
|
PCHAR p, pp;
|
|
PKEYNAME Language;
|
|
|
|
/* Assume nothing */
|
|
*LanguageData = 0;
|
|
|
|
/* Start scanning */
|
|
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 scan for the language code */
|
|
if (sscanf(Token, " %4x", &LanguageCode) != 1)
|
|
{
|
|
/* Skip */
|
|
printf("An invalid LANGID was specified.\n");
|
|
continue;
|
|
}
|
|
|
|
/* Now get the actual language */
|
|
if (sscanf(gBuf, " %*4x %s[^\n]", Token) != 1)
|
|
{
|
|
/* Skip */
|
|
printf("A language name is missing\n");
|
|
continue;
|
|
}
|
|
|
|
/* Get the language string and find the ending */
|
|
p = strstr(gBuf, Token);
|
|
pp = strchr(p, '\n');
|
|
if (!pp) pp = strchr(p, '\r');
|
|
|
|
/* Terminate the language string here */
|
|
if (pp) *pp = 0;
|
|
|
|
/* Now allocate the language */
|
|
Language = malloc(sizeof(KEYNAME));
|
|
if (!Language)
|
|
{
|
|
/* Fail */
|
|
printf("Unable to allocate the KEYNAME struct (out of memory?).\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Fill out the structure */
|
|
Language->Code = LanguageCode;
|
|
Language->Name = strdup(p);
|
|
Language->Next = NULL;
|
|
|
|
/* Debug only */
|
|
DPRINT1("LANGID: [%4x] Name: [%s]\n", Language->Code, Language->Name);
|
|
|
|
/* Point to it and advance the pointer */
|
|
*LanguageData = Language;
|
|
LanguageData = &Language->Next;
|
|
}
|
|
|
|
/* We are done */
|
|
return KeyWord;
|
|
}
|
|
|
|
ULONG
|
|
DoKEYNAME(IN PKEYNAME* KeyNameData)
|
|
{
|
|
ULONG KeyWord = 0;
|
|
CHAR Token[32];
|
|
ULONG CharacterCode;
|
|
PCHAR p, pp;
|
|
PKEYNAME KeyName;
|
|
|
|
/* Assume nothing */
|
|
*KeyNameData = 0;
|
|
|
|
/* Start scanning */
|
|
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 scan for the character code */
|
|
if (sscanf(Token, " %4x", &CharacterCode) != 1)
|
|
{
|
|
/* Skip */
|
|
printf("An invalid character code was specified.\n");
|
|
continue;
|
|
}
|
|
|
|
/* Now get the actual key name */
|
|
if (sscanf(gBuf, " %*4x %s[^\n]", Token) != 1)
|
|
{
|
|
/* Skip */
|
|
printf("A key name is missing\n");
|
|
continue;
|
|
}
|
|
|
|
/* Get the key name string and find the ending */
|
|
p = strstr(gBuf, Token);
|
|
pp = strchr(p, '\n');
|
|
if (!pp) pp = strchr(p, '\r');
|
|
|
|
/* Terminate the key name string here */
|
|
if (pp) *pp = 0;
|
|
|
|
/* Now allocate the language */
|
|
KeyName = malloc(sizeof(KEYNAME));
|
|
if (!KeyName)
|
|
{
|
|
/* Fail */
|
|
printf("Unable to allocate the KEYNAME struct (out of memory?).\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Fill out the structure */
|
|
KeyName->Code = CharacterCode;
|
|
KeyName->Name = strdup(p);
|
|
KeyName->Next = NULL;
|
|
|
|
/* Debug only */
|
|
DPRINT1("CHARCODE: [%4x] Name: [%s]\n", KeyName->Code, KeyName->Name);
|
|
|
|
/* Point to it and advance the pointer */
|
|
*KeyNameData = KeyName;
|
|
KeyNameData = &KeyName->Next;
|
|
}
|
|
|
|
/* We are done */
|
|
return KeyWord;
|
|
}
|
|
|
|
ULONG
|
|
DoSHIFTSTATE(IN PULONG StateCount,
|
|
IN OUT PULONG ShiftStates)
|
|
{
|
|
ULONG KeyWord;
|
|
ULONG i;
|
|
ULONG ShiftState;
|
|
CHAR Token[32];
|
|
|
|
/* Reset the shift states */
|
|
for (i = 0; i < 8; i++) ShiftStates[i] = -1;
|
|
|
|
/* Start with no states */
|
|
*StateCount = 0;
|
|
|
|
/* Scan for shift states */
|
|
while (NextLine(gBuf, 256, gfpInput))
|
|
{
|
|
/* Search for token */
|
|
if (sscanf(gBuf, "%s", Token) != 1) continue;
|
|
|
|
/* Make sure it's not a keyword */
|
|
KeyWord = isKeyWord(Token);
|
|
if (KeyWord < KEYWORD_COUNT) break;
|
|
|
|
/* Now scan for the shift state */
|
|
if (sscanf(gBuf, " %1s[012367]", Token) != 1)
|
|
{
|
|
/* We failed -- should we warn? */
|
|
if (Verbose) printf("An invalid shift state '%s' was found (use 0, 1, 2, 3, 6, or 7.)\n", Token);
|
|
continue;
|
|
}
|
|
|
|
/* Now read the state */
|
|
ShiftState = atoi(Token);
|
|
|
|
/* Scan existing states */
|
|
for (i = 0; i < *StateCount; i++)
|
|
{
|
|
/* Check for duplicate */
|
|
if ((ShiftStates[i] == ShiftState) && (Verbose))
|
|
{
|
|
/* Warn user */
|
|
printf("The state '%d' was duplicated for this Virtual Key.\n", ShiftStates[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Make sure we won't overflow */
|
|
if (*StateCount < 8)
|
|
{
|
|
/* Save this state */
|
|
ShiftStates[(*StateCount)++] = ShiftState;
|
|
}
|
|
else
|
|
{
|
|
/* Too many states -- should we warn? */
|
|
if (Verbose) printf("There were too many states (you defined %d).\n", *StateCount);
|
|
}
|
|
}
|
|
|
|
/* Debug only */
|
|
DPRINT1("Found %d Shift States: [", *StateCount);
|
|
for (i = 0; i < *StateCount; i++) DPRINT1("%d ", ShiftStates[i]);
|
|
DPRINT1("]\n");
|
|
|
|
/* We are done */
|
|
return KeyWord;
|
|
}
|
|
|
|
ULONG
|
|
DoLIGATURE(PVOID LigatureData)
|
|
{
|
|
printf("LIGATURE support is not yet implemented. Please bug Arch to fix it\n");
|
|
return SkipLines();
|
|
}
|
|
|
|
ULONG
|
|
DoATTRIBUTES(PVOID AttributeData)
|
|
{
|
|
printf("ATTRIBUTES support is not yet implemented. Please bug Arch to fix it\n");
|
|
return SkipLines();
|
|
}
|
|
|
|
ULONG
|
|
DoMODIFIERS(VOID)
|
|
{
|
|
printf("MODIFIERS support is not yet implemented. Please bug Arch to fix it\n");
|
|
return SkipLines();
|
|
}
|
|
|
|
ULONG
|
|
DoDEADKEY(PVOID DeadKeyData)
|
|
{
|
|
printf("DEADKEY support is not yet implemented. Please bug Arch to fix it\n");
|
|
return SkipLines();
|
|
}
|
|
|
|
ULONG
|
|
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;
|
|
ULONG Count;
|
|
BOOLEAN FullEntry;
|
|
CHAR State[8][8];
|
|
ULONG ScanCodeCount = -1;
|
|
PLAYOUTENTRY Entry;
|
|
UCHAR CharacterType;
|
|
CHAR LigatureChar;
|
|
|
|
/* 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 */
|
|
DPRINT1("RAW ENTRY: [%x %s %s]\n", ScanCode, Token, Cap);
|
|
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);
|
|
break;
|
|
}
|
|
else if (ScanCode == CurrentCode)
|
|
{
|
|
/* 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;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* The entry is now processed */
|
|
Entry->Processed = TRUE;
|
|
ScVk[i].Processed = TRUE;
|
|
|
|
/* Get the virtual key from the entry */
|
|
VirtualKey = getVKNum(Token);
|
|
Entry->VirtualKey = VirtualKey;
|
|
DPRINT1("ENTRY: [%x %x %x %s] with ",
|
|
Entry->VirtualKey, Entry->OriginalVirtualKey, Entry->ScanCode, Entry->Name);
|
|
|
|
/* Make sure it's valid */
|
|
if (VirtualKey == 0xFFFF)
|
|
{
|
|
/* Warn the user */
|
|
if (Verbose) printf("An invalid Virtual Key '%s' was defined.\n", Token);
|
|
continue;
|
|
}
|
|
|
|
/* Is this a full entry */
|
|
if (FullEntry)
|
|
{
|
|
/* Do we have SGCAP data? Set cap mode to 2 */
|
|
if (!strcmp(Cap, "SGCAP")) *Cap = '2';
|
|
|
|
/* Read the cap mode */
|
|
if (sscanf(Cap, "%1d[012]", &Entry->Cap) != 1)
|
|
{
|
|
/* Invalid cap mode */
|
|
printf("invalid Cap specified (%s). Must be 0, 1, or 2.\n", Cap);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* Read the states */
|
|
Count = sscanf(gBuf,
|
|
" %*s %*s %*s %s %s %s %s %s %s %s %s",
|
|
State[0],
|
|
State[1],
|
|
State[2],
|
|
State[3],
|
|
State[4],
|
|
State[5],
|
|
State[6],
|
|
State[7]);
|
|
Entry->StateCount = Count;
|
|
DPRINT1("%d STATES: [", Count);
|
|
|
|
/* Check if there are less than 2 states */
|
|
if ((Count < 2) && (FullEntry))
|
|
{
|
|
/* Fail */
|
|
printf("You must have at least 2 characters.\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Loop all states */
|
|
for (i = 0; i < Count; i++)
|
|
{
|
|
/* Check if this is an undefined state */
|
|
DPRINT1("%s ", State[i]);
|
|
if (!strcmp(State[i], "-1"))
|
|
{
|
|
/* No data for this state */
|
|
Entry->CharData[i] = -1;
|
|
continue;
|
|
}
|
|
|
|
/* Otherwise, check what kind of character this is */
|
|
CharacterType = getCharacterInfo(State[i],
|
|
&Entry->CharData[i],
|
|
&LigatureChar);
|
|
if (CharacterType == CHAR_DEAD_KEY)
|
|
{
|
|
/* Save it as such */
|
|
Entry->DeadCharData[i] = 1;
|
|
}
|
|
else if (CharacterType == CHAR_OTHER_KEY)
|
|
{
|
|
/* Save it as such */
|
|
Entry->OtherCharData[i] = 1;
|
|
}
|
|
}
|
|
|
|
/* Check for sanity checks */
|
|
DPRINT1("]\n");
|
|
if (SanityCheck)
|
|
{
|
|
/* Not yet handled... */
|
|
printf("Sanity checks not yet handled!\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Check if we had SGCAP data */
|
|
if (Entry->Cap & 2)
|
|
{
|
|
/* Not yet handled... */
|
|
printf("SGCAP state not yet handled!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* Check if we have found any ScanCode in the file */
|
|
|
|
if (ScanCodeCount == -1)
|
|
{
|
|
printf("No ScanCode found!\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Process the scan code table */
|
|
Entry = &LayoutData->Entry[ScanCodeCount];
|
|
for (i = 0; i < 110; i++)
|
|
{
|
|
/* Get the scan code */
|
|
CurrentCode = ScVk[i].ScanCode;
|
|
if (CurrentCode == 0xFFFF) break;
|
|
|
|
/* Check if this entry had been processed */
|
|
if (ScVk[i].Processed)
|
|
{
|
|
/* Skip it */
|
|
ScVk[i].Processed = FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* Do we have too many? */
|
|
if (++ScanCodeCount >= 110)
|
|
{
|
|
/* Fail */
|
|
printf("ScanCode %02x - too many scancodes here to parse.\n", CurrentCode);
|
|
exit(1);
|
|
}
|
|
|
|
/* Build an entry for it */
|
|
Entry++;
|
|
Entry->ScanCode = CurrentCode;
|
|
Entry->VirtualKey = ScVk[i].VirtualKey;
|
|
Entry->OriginalVirtualKey = ScVk[i].VirtualKey;
|
|
Entry->Name = ScVk[i].Name;
|
|
Entry->Processed = TRUE;
|
|
Entry->LineCount = 0;
|
|
DPRINT1("AUTOMATIC ENTRY: [%x %x %s]\n",
|
|
Entry->VirtualKey, Entry->ScanCode, Entry->Name);
|
|
}
|
|
}
|
|
|
|
/* Skip what's left */
|
|
return KeyWord;
|
|
}
|
|
|
|
ULONG
|
|
DoParsing(VOID)
|
|
{
|
|
ULONG KeyWords[KEYWORD_COUNT];
|
|
ULONG KeyWord;
|
|
ULONG StateCount;
|
|
ULONG ShiftStates[8];
|
|
PKEYNAME DescriptionData = NULL, LanguageData = NULL;
|
|
PKEYNAME KeyNameData = NULL, KeyNameExtData = NULL, KeyNameDeadData = NULL;
|
|
PVOID AttributeData = NULL, LigatureData = NULL, DeadKeyData = NULL;
|
|
|
|
/* Parse keywords */
|
|
gLineCount = 0;
|
|
KeyWord = SkipLines();
|
|
if (KeyWord >= KEYWORD_COUNT)
|
|
{
|
|
/* Invalid keyword count, fail */
|
|
fclose(gfpInput);
|
|
printf("No keywords were found in '%s'.\n", gpszFileName);
|
|
exit(1);
|
|
}
|
|
|
|
/* Now parse the keywords */
|
|
memset(KeyWords, 0, sizeof(KeyWords));
|
|
while (KeyWord < (KEYWORD_COUNT - 1))
|
|
{
|
|
/* Save this keyword */
|
|
KeyWords[KeyWord]++;
|
|
|
|
/* Check for duplicate entires, other than DEADKEY, which is okay */
|
|
if ((KeyWord != 9) && (KeyWords[KeyWord] > 1) && (Verbose))
|
|
{
|
|
/* On a verbose run, warn the user */
|
|
printf("The '%s' keyword appeared multiple times.\n",
|
|
KeyWordList[KeyWord]);
|
|
}
|
|
|
|
/* Now parse this keyword */
|
|
switch (KeyWord)
|
|
{
|
|
/* KBD */
|
|
case 0:
|
|
|
|
DPRINT1("Found KBD section\n");
|
|
KeyWord = DoKBD();
|
|
break;
|
|
|
|
/* VERSION */
|
|
case 1:
|
|
|
|
DPRINT1("Found VERSION section\n");
|
|
KeyWord = DoVERSION();
|
|
break;
|
|
|
|
/* COPYRIGHT */
|
|
case 2:
|
|
|
|
DPRINT1("Found COPYRIGHT section\n");
|
|
KeyWord = DoCOPYRIGHT();
|
|
break;
|
|
|
|
/* COMPANY */
|
|
case 3:
|
|
|
|
DPRINT1("Found COMPANY section\n");
|
|
KeyWord = DoCOMPANY();
|
|
break;
|
|
|
|
/* LOCALENAME */
|
|
case 4:
|
|
|
|
DPRINT1("Found LOCALENAME section\n");
|
|
KeyWord = DoLOCALENAME();
|
|
break;
|
|
|
|
/* MODIFIERS */
|
|
case 5:
|
|
|
|
DPRINT1("Found MODIFIERS section\n");
|
|
KeyWord = DoMODIFIERS();
|
|
break;
|
|
|
|
/* SHIFTSTATE */
|
|
case 6:
|
|
|
|
DPRINT1("Found SHIFTSTATE section\n");
|
|
KeyWord = DoSHIFTSTATE(&StateCount, ShiftStates);
|
|
if (StateCount < 2)
|
|
{
|
|
/* Fail */
|
|
fclose(gfpInput);
|
|
printf("ERROR");
|
|
exit(1);
|
|
}
|
|
break;
|
|
|
|
/* ATTRIBUTES */
|
|
case 7:
|
|
|
|
DPRINT1("Found ATTRIBUTES section\n");
|
|
KeyWord = DoATTRIBUTES(&AttributeData);
|
|
break;
|
|
|
|
/* LAYOUT */
|
|
case 8:
|
|
|
|
DPRINT1("Found LAYOUT section\n");
|
|
KeyWord = DoLAYOUT(&g_Layout,
|
|
&LigatureData,
|
|
ShiftStates,
|
|
StateCount);
|
|
break;
|
|
|
|
/* DEADKEY */
|
|
case 9:
|
|
|
|
DPRINT1("Found DEADKEY section\n");
|
|
KeyWord = DoDEADKEY(&DeadKeyData);
|
|
break;
|
|
|
|
/* LIGATURE */
|
|
case 10:
|
|
|
|
DPRINT1("Found LIGATURE section\n");
|
|
KeyWord = DoLIGATURE(&LigatureData);
|
|
break;
|
|
|
|
/* KEYNAME */
|
|
case 11:
|
|
|
|
DPRINT1("Found KEYNAME section\n");
|
|
KeyWord = DoKEYNAME(&KeyNameData);
|
|
break;
|
|
|
|
/* KEYNAME_EXT */
|
|
case 12:
|
|
|
|
DPRINT1("Found KEYNAME_EXT section\n");
|
|
KeyWord = DoKEYNAME(&KeyNameExtData);
|
|
break;
|
|
|
|
/* KEYNAME_DEAD */
|
|
case 13:
|
|
|
|
DPRINT1("Found KEYNAME_DEAD section\n");
|
|
KeyWord = DoKEYNAME(&KeyNameDeadData);
|
|
break;
|
|
|
|
/* DESCRIPTIONS */
|
|
case 14:
|
|
|
|
DPRINT1("Found DESCRIPTIONS section\n");
|
|
KeyWord = DoDESCRIPTIONS(&DescriptionData);
|
|
break;
|
|
|
|
/* LANGUAGENAMES */
|
|
case 15:
|
|
|
|
DPRINT1("Found LANGUAGENAMES section\n");
|
|
KeyWord = DoLANGUAGENAMES(&LanguageData);
|
|
break;
|
|
|
|
/* ENDKBD */
|
|
case 16:
|
|
|
|
DPRINT1("Found ENDKBD section\n");
|
|
KeyWord = SkipLines();
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* We are done */
|
|
fclose(gfpInput);
|
|
|
|
/* Now enter the output phase */
|
|
return DoOutput(StateCount,
|
|
ShiftStates,
|
|
DescriptionData,
|
|
LanguageData,
|
|
AttributeData,
|
|
DeadKeyData,
|
|
LigatureData,
|
|
KeyNameData,
|
|
KeyNameExtData,
|
|
KeyNameDeadData);
|
|
}
|
|
/* EOF */
|