2857 lines
84 KiB
C
2857 lines
84 KiB
C
/******************************* Module Header *******************************\
|
|
* Module Name: KBDTXT2C.C
|
|
*
|
|
* Copyright (c) 1985-2001, Microsoft Corporation
|
|
*
|
|
* History:
|
|
* 1995-03-26 a-KChang
|
|
* 1997-06-13 GregoryW v2.00 BiDi Support
|
|
* 1997-06-19 IanJa v2.01 Add ATTRIBUTES section
|
|
* 1998-03-04 IanJa v3.0 Add dead key composition can be dead char too
|
|
* (Useful for CAN/CSA, Serge Caron @ Attachmate
|
|
* and a customer of Eliyas Yakub's)
|
|
* 1998-05-01 HiroYama v3.01 -k switch to make fallback layout for win32k.sys
|
|
* 1998-05-08 IanJa v3.02 new E1 scancodes allowed
|
|
* 1998-05-19 v-thief v3.03 Add IA64 support. Implies that the data arrays
|
|
* are located in the long data section.
|
|
* Uses IA64 compiler specific pragmas.
|
|
* data_seg() is not explicit enough.
|
|
* 1998-05-20 v-thief v3.04 For the fallback layout in win32k.sys, we are
|
|
* not relocating the data in long data section.
|
|
* 1998-10-29 WKwok v3.05 Specify VER_LANGNEUTRAL in RC.
|
|
* 1998-12-03 IanJa v3.06 Add SpeedRacer VKs, include strid.h
|
|
* 1999-01-12 IanJa v3.07 check for dup VKs, beautify, improve VkKeyScan
|
|
* 1999-01-28 v-thief v3.08 fixed IA64 warnings for .data section. The new
|
|
* IA64 compiler defaults to a "long" attribute
|
|
* for this known section.
|
|
* 1999-02-11 IanJa v3.09 check for dup chars (for VkKeyScanEx's sake)
|
|
* 1999-03-25 IanJa v3.10 no more vkoem.h (get VKs from winuser.h)
|
|
* 1999-03-31 IanJa v3.11 comment out spurious DumpLayoutEntry() call
|
|
* 2001-06-28 Hiroyama v3.12 fix the upper case warnings etc..
|
|
putting the sanity check in "-W".
|
|
\*****************************************************************************/
|
|
|
|
#include <windows.h>
|
|
#include <winuserp.h>
|
|
#include "kbdx.h"
|
|
|
|
DWORD gVersion = 3;
|
|
DWORD gSubVersion = 12;
|
|
|
|
char *KeyWord[] = { /* used by isKeyWord() */
|
|
"KBD", /* 0 */
|
|
"VERSION", /* 1 */
|
|
"MODIFIERS", /* 2 */
|
|
"SHIFTSTATE", /* 3 */
|
|
"ATTRIBUTES", /* 4 */
|
|
"LAYOUT", /* 5 */
|
|
"DEADKEY", /* 6 */
|
|
"LIGATURE", /* 7 */
|
|
"KEYNAME", /* 8 */
|
|
"KEYNAME_EXT", /* 9 */
|
|
"KEYNAME_DEAD", /* 10 */
|
|
"ENDKBD", /* 11 */
|
|
};
|
|
#define KEYWORD_KBD 0
|
|
#define KEYWORD_VERSION 1
|
|
#define KEYWORD_MODIFIERS 2
|
|
#define KEYWORD_SHIFTSTATE 3
|
|
#define KEYWORD_ATTRIBUTES 4
|
|
#define KEYWORD_LAYOUT 5
|
|
#define KEYWORD_DEADKEY 6
|
|
#define KEYWORD_LIGATURE 7
|
|
#define KEYWORD_KEYNAME 8
|
|
#define KEYWORD_KEYNAME_EXT 9
|
|
#define KEYWORD_KEYNAME_DEAD 10
|
|
#define KEYWORD_ENDKBD 11
|
|
|
|
|
|
#define NUMKEYWORD ( sizeof(KeyWord) / sizeof(char*) )
|
|
|
|
#define NOT_KEYWORD 999 /* a number bigger than NUMKEYWORD */
|
|
|
|
#define DEADKEYCODE 6 /* only DEADKEY can have multiple entries */
|
|
|
|
VKEYNAME VKName[] = { /* used only by virtual keys other than 0-9 and A-Z */
|
|
{VK_BACK, "BACK" },
|
|
{VK_CANCEL, "CANCEL" },
|
|
{VK_ESCAPE, "ESCAPE" },
|
|
{VK_RETURN, "RETURN" },
|
|
{VK_SPACE, "SPACE" },
|
|
{VK_DECIMAL, "DECIMAL" },
|
|
{VK_OEM_1, "OEM_1" },
|
|
{VK_OEM_PLUS, "OEM_PLUS" },
|
|
{VK_OEM_COMMA, "OEM_COMMA" },
|
|
{VK_OEM_MINUS, "OEM_MINUS" },
|
|
{VK_OEM_PERIOD, "OEM_PERIOD" },
|
|
{VK_OEM_2, "OEM_2" },
|
|
{VK_OEM_3, "OEM_3" },
|
|
{VK_OEM_4, "OEM_4" },
|
|
{VK_OEM_5, "OEM_5" },
|
|
{VK_OEM_6, "OEM_6" },
|
|
{VK_OEM_7, "OEM_7" },
|
|
{VK_OEM_8, "OEM_8" },
|
|
{VK_OEM_102, "OEM_102" },
|
|
{0xC1, "ABNT_C1" },
|
|
{0xC2, "ABNT_C2" },
|
|
{VK_SHIFT, "SHIFT" },
|
|
{VK_LSHIFT, "LSHIFT" },
|
|
{VK_RSHIFT, "RSHIFT" },
|
|
{VK_MENU, "MENU" },
|
|
{VK_LMENU, "LMENU" },
|
|
{VK_RMENU, "RMENU" },
|
|
{VK_CONTROL, "CONTROL" },
|
|
{VK_LCONTROL, "LCONTROL" },
|
|
{VK_RCONTROL, "RCONTROL" },
|
|
{VK_SEPARATOR, "SEPARATOR" },
|
|
{VK_ICO_00, "ICO_00" },
|
|
{VK_DELETE, "DELETE" },
|
|
{VK_INSERT, "INSERT" },
|
|
{VK_GROUPSHIFT, "GROUPSHIFT" },
|
|
{VK_RGROUPSHIFT,"RGROUPSHIFT"},
|
|
};
|
|
|
|
#define NUMVKNAME ( sizeof(VKName) / sizeof(VKEYNAME) )
|
|
|
|
/*
|
|
* Default ScanCode-VirtualKey relation
|
|
*
|
|
* Includes a comment string used only for E0 prefixed scancodes and
|
|
* then only as a comment for aE0VscToVk[] entries in the output .C file
|
|
*
|
|
* This does not have to be ordered by scancode or virtual key code.
|
|
* The order *does* affect VkKeyScan[Ex] - each aVkToWch*[] table is
|
|
* ordered according to the order of the entries in this table.
|
|
*
|
|
*
|
|
* Scan VKey comment
|
|
* ==== ========= =======
|
|
*/
|
|
SC_VK ScVk[] = {
|
|
{0x02, 0x31, NULL}, /* 1 */
|
|
{0x03, 0x32, NULL}, /* 2 */
|
|
{0x04, 0x33, NULL}, /* 3 */
|
|
{0x05, 0x34, NULL}, /* 4 */
|
|
{0x06, 0x35, NULL}, /* 5 */
|
|
{0x07, 0x36, NULL}, /* 6 */
|
|
{0x08, 0x37, NULL}, /* 7 */
|
|
{0x09, 0x38, NULL}, /* 8 */
|
|
{0x0a, 0x39, NULL}, /* 9 */
|
|
{0x0b, 0x30, NULL}, /* 0 */
|
|
{0x0c, 0xbd, NULL}, /* OEM_MINUS */
|
|
{0x0d, 0xbb, NULL}, /* OEM_PLUS */
|
|
{0x10, 0x51, NULL}, /* Q */
|
|
{0x11, 0x57, NULL}, /* W */
|
|
{0x12, 0x45, NULL}, /* E */
|
|
{0x13, 0x52, NULL}, /* R */
|
|
{0x14, 0x54, NULL}, /* T */
|
|
{0x15, 0x59, NULL}, /* Y */
|
|
{0x16, 0x55, NULL}, /* U */
|
|
{0x17, 0x49, NULL}, /* I */
|
|
{0x18, 0x4f, NULL}, /* O */
|
|
{0x19, 0x50, NULL}, /* P */
|
|
{0x1a, 0xdb, NULL}, /* OEM_4 */
|
|
{0x1b, 0xdd, NULL}, /* OEM_6 */
|
|
{0x1e, 0x41, NULL}, /* A */
|
|
{0x1f, 0x53, NULL}, /* S */
|
|
{0x20, 0x44, NULL}, /* D */
|
|
{0x21, 0x46, NULL}, /* F */
|
|
{0x22, 0x47, NULL}, /* G */
|
|
{0x23, 0x48, NULL}, /* H */
|
|
{0x24, 0x4a, NULL}, /* J */
|
|
{0x25, 0x4b, NULL}, /* K */
|
|
{0x26, 0x4c, NULL}, /* L */
|
|
{0x27, 0xba, NULL}, /* OEM_1 */
|
|
{0x28, 0xde, NULL}, /* OEM_7 */
|
|
{0x29, 0xc0, NULL}, /* OEM_3 */
|
|
{0x2b, 0xdc, NULL}, /* OEM_5 */
|
|
{0x2c, 0x5a, NULL}, /* Z */
|
|
{0x2d, 0x58, NULL}, /* X */
|
|
{0x2e, 0x43, NULL}, /* C */
|
|
{0x2f, 0x56, NULL}, /* V */
|
|
{0x30, 0x42, NULL}, /* B */
|
|
{0x31, 0x4e, NULL}, /* N */
|
|
{0x32, 0x4d, NULL}, /* M */
|
|
{0x33, 0xbc, NULL}, /* OEM_COMMA */
|
|
{0x34, 0xbe, NULL}, /* OEM_PERIOD */
|
|
{0x35, 0xbf, NULL}, /* OEM_2 */
|
|
{0x56, 0xe2, NULL}, /* OEM_102 */
|
|
{0x73, 0xc1, NULL}, /* ABNT_C1 */
|
|
{0x7e, 0xc2, NULL}, /* ABNT_C2 */
|
|
|
|
|
|
// extended scancodes
|
|
// The comment is only as a comment for aE0VscToVk[] entries
|
|
// in the output .C file
|
|
{0xE010, VK_MEDIA_PREV_TRACK, "Speedracer: Previous Track" },
|
|
{0xE019, VK_MEDIA_NEXT_TRACK, "Speedracer: Next Track" },
|
|
{0xE01D, VK_RCONTROL , "RControl" },
|
|
{0xE020, VK_VOLUME_MUTE , "Speedracer: Volume Mute" },
|
|
{0xE021, VK_LAUNCH_APP2 , "Speedracer: Launch App 2" },
|
|
{0xE022, VK_MEDIA_PLAY_PAUSE, "Speedracer: Media Play/Pause" },
|
|
{0xE024, VK_MEDIA_STOP , "Speedracer: Media Stop" },
|
|
{0xE02E, VK_VOLUME_DOWN , "Speedracer: Volume Down" },
|
|
{0xE030, VK_VOLUME_UP , "Speedracer: Volume Up" },
|
|
{0xE032, VK_BROWSER_HOME , "Speedracer: Browser Home" },
|
|
{0xE035, VK_DIVIDE , "Numpad Divide" },
|
|
{0xE037, VK_SNAPSHOT , "Snapshot" },
|
|
{0xE038, VK_RMENU , "RMenu" },
|
|
{0xE047, VK_HOME , "Home" },
|
|
{0xE048, VK_UP , "Up" },
|
|
{0xE049, VK_PRIOR , "Prior" },
|
|
{0xE04B, VK_LEFT , "Left" },
|
|
{0xE04D, VK_RIGHT , "Right" },
|
|
{0xE04F, VK_END , "End" },
|
|
{0xE050, VK_DOWN , "Down" },
|
|
{0xE051, VK_NEXT , "Next" },
|
|
{0xE052, VK_INSERT , "Insert" },
|
|
{0xE053, VK_DELETE , "Delete" },
|
|
{0xE05B, VK_LWIN , "Left Win" },
|
|
{0xE05C, VK_RWIN , "Right Win" },
|
|
{0xE05D, VK_APPS , "Application" },
|
|
|
|
// reserved (VKey == 0xff)
|
|
{0xE05E, 0xff , "Power" },
|
|
{0xE05F, VK_SLEEP , "Speedracer: Sleep" },
|
|
{0xE060, 0xff , "BAD SCANCODE" }, // break would be 0xE0
|
|
{0xE061, 0xff , "BAD SCANCODE" }, // break would be 0xE1
|
|
|
|
// available for adding extended scancodes (VKey == 0x00)
|
|
{0xE065, VK_BROWSER_SEARCH , "Speedracer: Browser Search" },
|
|
{0xE066, VK_BROWSER_FAVORITES , "Speedracer: Browser Favorites" },
|
|
{0xE067, VK_BROWSER_REFRESH , "Speedracer: Browser Refresh" },
|
|
{0xE068, VK_BROWSER_STOP , "Speedracer: Browser Stop" },
|
|
{0xE069, VK_BROWSER_FORWARD , "Speedracer: Browser Forward" },
|
|
{0xE06A, VK_BROWSER_BACK , "Speedracer: Browser Back" },
|
|
{0xE06B, VK_LAUNCH_APP1 , "Speedracer: Launch App 1" },
|
|
{0xE06C, VK_LAUNCH_MAIL , "Speedracer: Launch Mail" },
|
|
{0xE06D, VK_LAUNCH_MEDIA_SELECT, "Speedracer: Launch Media Selector"},
|
|
|
|
// These come near the end for VkKeyScan...
|
|
{0x53, VK_DECIMAL, NULL }, /* Numpad Decimal */
|
|
{0x0e, VK_BACK, NULL }, /* Backspace */
|
|
{0x01, VK_ESCAPE, NULL }, /* Escape */
|
|
{0xE01C, VK_RETURN, "Numpad Enter" },
|
|
{0x1c, VK_RETURN, NULL }, /* Enter */
|
|
{0x39, VK_SPACE, NULL }, /* Space */
|
|
{0xE046, VK_CANCEL, "Break (Ctrl + Pause)" },
|
|
|
|
// ...but the 0xffff entries (for new scancodes) must come last
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
{0xffff, 0x00, NULL },
|
|
|
|
};
|
|
|
|
#define NUMSCVK ( sizeof(ScVk) / sizeof(SC_VK) )
|
|
|
|
typedef struct {
|
|
UINT Vk;
|
|
char *pszModBits;
|
|
} MODIFIERS, *PMODIFIERS;
|
|
|
|
MODIFIERS Modifiers[] = {
|
|
{ VK_SHIFT, "KBDSHIFT" },
|
|
{ VK_CONTROL, "KBDCTRL" },
|
|
{ VK_MENU, "KBDALT" },
|
|
{ 0, NULL },
|
|
{ 0, NULL },
|
|
{ 0, NULL },
|
|
{ 0, NULL },
|
|
{ 0, NULL },
|
|
{ 0, NULL },
|
|
{ 0, NULL },
|
|
{ 0, NULL },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
char* StateLabel[] = {
|
|
"", /* 0 */
|
|
"Shift", /* 1 */
|
|
" Ctrl", /* 2 */
|
|
"S+Ctrl", /* 3 */
|
|
" Alt", /* 4:not used */
|
|
"Shift+Alt", /* 5:not used */
|
|
" Ctl+Alt", /* 6 */
|
|
"S+Ctl+Alt", /* 7 */
|
|
" X1 ", /* 8 */
|
|
"S+ X1 ", /* 9 */
|
|
" C+ X1 ", /* 10 */
|
|
"S+C+ X1 ", /* 11 */
|
|
" A+X1 ", /* 12 */
|
|
"S+ A+X1 ", /* 13 */
|
|
" C+A+X1 ", /* 14 */
|
|
"S+C+A+X1 ", /* 15 */
|
|
" X2", /* 16 */
|
|
"S+ X2", /* 17 */
|
|
" C+ X2", /* 18 */
|
|
"S+C+ X2", /* 19 */
|
|
" A+ X2", /* 20 */
|
|
"S+ A+ X2", /* 21 */
|
|
" C+A+ X2", /* 22 */
|
|
"S+C+A+ X2", /* 23 */
|
|
" X1+X2", /* 24 */
|
|
"S+ X1+X2", /* 25 */
|
|
" C+ X1+X2", /* 26 */
|
|
"S+C+ X1+X2", /* 27 */
|
|
" A+X1+X2", /* 28 */
|
|
"S+ A+X1+X2", /* 29 */
|
|
" C+A+X1+X2", /* 30 */
|
|
"S+C+A+X1+X2", /* 31 */
|
|
" X3", /* 32 */
|
|
"S+ X3", /* 33 */
|
|
" C+ X3", /* 34 */
|
|
"S+C+ X3", /* 35 */
|
|
" A+ X3", /* 36 */
|
|
"S+ A+ X3", /* 37 */
|
|
" C+A+ X3", /* 38 */
|
|
"S+C+A+ X3", /* 39 */
|
|
" X1+ X3", /* 40 */
|
|
"S+ X1+ X3", /* 41 */
|
|
" C+ X1+ X3", /* 42 */
|
|
"S+C+ X1+ X3", /* 43 */
|
|
" A+X1+ X3", /* 44 */
|
|
"S+ A+X1+ X3", /* 45 */
|
|
" C+A+X1+ X3", /* 46 */
|
|
"S+C+A+X1+ X3", /* 47 */
|
|
" X2+X3", /* 48 */
|
|
"S+ X2+X3", /* 49 */
|
|
" C+ X2+X3", /* 50 */
|
|
"S+C+ X2+X3", /* 51 */
|
|
" A+ X2+X3", /* 52 */
|
|
"S+ A+ X2+X3", /* 53 */
|
|
" C+A+ X2+X3", /* 54 */
|
|
"S+C+A+ X2+X3", /* 55 */
|
|
" X1+X2+X3", /* 56 */
|
|
"S+ X1+X2+X3", /* 57 */
|
|
" C+ X1+X2+X3", /* 58 */
|
|
"S+C+ X1+X2+X3", /* 59 */
|
|
" A+X1+X2+X3", /* 60 */
|
|
"S+ A+X1+X2+X3", /* 61 */
|
|
" C+A+X1+X2+X3", /* 62 */
|
|
"S+C+A+X1+X2+X3", /* 63 */
|
|
"unexpected", /* 64 */
|
|
"unexpected", /* 65 */
|
|
};
|
|
|
|
/*************************************************************\
|
|
* forward declarations *
|
|
\*************************************************************/
|
|
BOOL NextLine(char *Buf, DWORD cchBuf, FILE *fIn);
|
|
int SkipLines(void);
|
|
int isKeyWord(char *s);
|
|
int getVKNum(char *pVK);
|
|
char *getVKName(int VK, BOOL prefixVK_);
|
|
int doKBD();
|
|
int doMODIFIERS();
|
|
int doSHIFTSTATE(int *nState, int aiState[]);
|
|
int doATTRIBUTES(char *szAttrs);
|
|
int doLAYOUT(KEYLAYOUT Layout[], int aiState[], int nState);
|
|
int doDEADKEY(PDEADKEY *ppDeadKey);
|
|
int doLIGATURE(PLIGATURE *ppLigature);
|
|
int doKEYNAME(PKEYNAME *ppKeyName);
|
|
int kbd_h(KEYLAYOUT Layout[]);
|
|
int kbd_rc(void);
|
|
int kbd_def(void);
|
|
char *WChName(int WC, int Zero);
|
|
VOID __cdecl Error(const char *Text, ... );
|
|
ULONG __cdecl Warning(int nLine, const char *Text, ... );
|
|
VOID DumpLayoutEntry(PKEYLAYOUT pLayout);
|
|
BOOL MergeState(KEYLAYOUT[], int Vk, WCHAR, WCHAR, WCHAR, int aiState[], int nState);
|
|
|
|
int kbd_c(int nState,
|
|
int aiState[],
|
|
char * szAttrs,
|
|
KEYLAYOUT Layout[],
|
|
PDEADKEY pDeadKey,
|
|
PLIGATURE pLigature,
|
|
PKEYNAME pKeyName,
|
|
PKEYNAME pKeyNameExt,
|
|
PKEYNAME pKeyNameDead);
|
|
void PrintNameTable(FILE *pOut, PKEYNAME pKN, BOOL bDead);
|
|
|
|
/*************************************************************\
|
|
* Global variables
|
|
\*************************************************************/
|
|
BOOL verbose = FALSE;
|
|
BOOL fallback_driver = FALSE;
|
|
BOOL sanity_check = FALSE;
|
|
FILE *gfpInput;
|
|
char gBuf[LINEBUFSIZE];
|
|
int gLineCount;
|
|
LPSTR gpszFileName;
|
|
char gVKeyName[WORDBUFSIZE];
|
|
char gKBDName[MAXKBDNAME];
|
|
char gDescription[LINEBUFSIZE];
|
|
int gID = 0;
|
|
char gCharName[WORDBUFSIZE];
|
|
|
|
struct tm *Now;
|
|
time_t Clock;
|
|
|
|
|
|
void usage()
|
|
{
|
|
fprintf(stderr, "Usage: KbdTool [-v] [-k] file\n");
|
|
fprintf(stderr, "\t[-?] display this message\n");
|
|
fprintf(stderr, "\t[-v] verbose diagnostics/warnings\n");
|
|
fprintf(stderr, "\t[-k] builds kbd layout for embedding in the kernel\n");
|
|
fprintf(stderr, "\t[-W] performs sanity check\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/*************************************************************\
|
|
* Main
|
|
\*************************************************************/
|
|
int _cdecl main(int argc, char** argv)
|
|
{
|
|
int c;
|
|
int i;
|
|
int nKW[NUMKEYWORD]; /* keep track of KeyWord read to prevent duplicates */
|
|
int iKW;
|
|
int nState; /* number of states */
|
|
int aiState[MAXSTATES];
|
|
char szAttrs[128] = "\0";
|
|
int nTotal = 0;
|
|
int nFailH = 0;
|
|
int nFailC = 0;
|
|
int nFailRC = 0;
|
|
int nFailDEF = 0;
|
|
|
|
KEYLAYOUT Layout[NUMSCVK];
|
|
PDEADKEY pDeadKey = NULL;
|
|
PLIGATURE pLigature = NULL;
|
|
PKEYNAME pKeyName = NULL;
|
|
PKEYNAME pKeyNameExt = NULL;
|
|
PKEYNAME pKeyNameDead = NULL;
|
|
|
|
printf("\nKbdTool v%d.%02d - convert keyboard text file to C file\n\n",
|
|
gVersion, gSubVersion);
|
|
|
|
while ((c = getopt(argc, argv, "vkW?")) != EOF) {
|
|
switch (c) {
|
|
case 'v':
|
|
verbose = TRUE;
|
|
break;
|
|
case 'k': // means 'kernel'
|
|
fallback_driver = TRUE;
|
|
break;
|
|
case 'W': // Turn on warning
|
|
sanity_check = TRUE;
|
|
break;
|
|
case '?':
|
|
default:
|
|
usage();
|
|
// never reaches here
|
|
}
|
|
}
|
|
|
|
if (optind == argc) {
|
|
usage();
|
|
// never reaches here
|
|
}
|
|
argv = argv + optind;
|
|
|
|
while (*argv) {
|
|
nTotal++;
|
|
gpszFileName = *argv;
|
|
if ((gfpInput = fopen(*argv, "rt")) == NULL) {
|
|
Error("can't open for read\n");
|
|
nFailH++;
|
|
nFailC++;
|
|
nFailRC++;
|
|
nFailDEF++;
|
|
argv++;
|
|
continue;
|
|
}
|
|
printf("%-23s:\n", *argv);
|
|
|
|
/* initialize for each input file */
|
|
for (i = 0; i < NUMKEYWORD; i++) {
|
|
nKW[i]=0;
|
|
}
|
|
gLineCount = 0;
|
|
/**********************************/
|
|
|
|
if ((iKW = SkipLines()) >= NUMKEYWORD) {
|
|
fclose(gfpInput);
|
|
Error("no keyword found\n");
|
|
nFailH++;
|
|
nFailC++;
|
|
nFailRC++;
|
|
nFailDEF++;
|
|
continue;
|
|
}
|
|
|
|
while (iKW < NUMKEYWORD - 1) {
|
|
nKW[iKW]++;
|
|
if (iKW != DEADKEYCODE && nKW[iKW] > 1 && verbose) {
|
|
Warning(0, "duplicate %s", KeyWord[iKW]);
|
|
}
|
|
|
|
switch (iKW) {
|
|
case KEYWORD_KBD:
|
|
|
|
iKW = doKBD();
|
|
break;
|
|
|
|
case KEYWORD_VERSION: // ignored for now
|
|
|
|
iKW = SkipLines();
|
|
break;
|
|
|
|
case KEYWORD_MODIFIERS:
|
|
|
|
iKW = doMODIFIERS();
|
|
break;
|
|
|
|
case KEYWORD_SHIFTSTATE:
|
|
|
|
iKW = doSHIFTSTATE(&nState, aiState);
|
|
if (nState < 2) {
|
|
fclose(gfpInput);
|
|
Error("must have at least 2 states\n");
|
|
nFailH++;
|
|
nFailC++;
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case KEYWORD_ATTRIBUTES:
|
|
iKW = doATTRIBUTES(szAttrs);
|
|
break;
|
|
|
|
case KEYWORD_LAYOUT:
|
|
|
|
if ((iKW = doLAYOUT(Layout, aiState, nState)) == -1) {
|
|
fclose(gfpInput);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* add layout checking later */
|
|
|
|
break;
|
|
|
|
case KEYWORD_DEADKEY:
|
|
|
|
if ((iKW = doDEADKEY(&pDeadKey)) == -1) {
|
|
fclose(gfpInput);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
break;
|
|
|
|
case KEYWORD_LIGATURE:
|
|
|
|
if ((iKW = doLIGATURE(&pLigature)) == -1) {
|
|
fclose(gfpInput);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
break;
|
|
|
|
case KEYWORD_KEYNAME:
|
|
|
|
if ((iKW = doKEYNAME(&pKeyName)) == -1) {
|
|
fclose(gfpInput);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
break;
|
|
|
|
case KEYWORD_KEYNAME_EXT:
|
|
|
|
if ((iKW = doKEYNAME(&pKeyNameExt)) == -1) {
|
|
fclose(gfpInput);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
break;
|
|
|
|
case KEYWORD_KEYNAME_DEAD:
|
|
|
|
if ((iKW = doKEYNAME(&pKeyNameDead)) == -1) {
|
|
fclose(gfpInput);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
fclose(gfpInput);
|
|
|
|
/* add later : checking for LAYOUT & DEADKEY */
|
|
|
|
time(&Clock);
|
|
Now = localtime(&Clock);
|
|
|
|
if (!fallback_driver && kbd_h(Layout) == FAILURE) {
|
|
nFailH++;
|
|
}
|
|
|
|
if (!fallback_driver && kbd_rc() != SUCCESS) {
|
|
nFailRC++;
|
|
}
|
|
|
|
if (kbd_c(nState, aiState, szAttrs, Layout,
|
|
pDeadKey, pLigature, pKeyName, pKeyNameExt, pKeyNameDead) == FAILURE) {
|
|
nFailC++;
|
|
}
|
|
|
|
if (!fallback_driver && kbd_def() != SUCCESS) {
|
|
nFailDEF++;
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
argv++;
|
|
}
|
|
|
|
printf("\n %13d ->% 12d %12d %12d %12d\n",
|
|
nTotal, nTotal - nFailH, nTotal - nFailRC,
|
|
nTotal - nFailC, nTotal - nFailDEF);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* Check keyword
|
|
* Return: 0 - 8 for valid keyword
|
|
* 9 for invalid keyword
|
|
\*************************************************************/
|
|
int isKeyWord(char *s)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < NUMKEYWORD; i++)
|
|
{
|
|
if(_strcmpi(KeyWord[i], s) == 0)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return NOT_KEYWORD;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* Skip lines till a valid keyword is available
|
|
* Return: 0 - 8 for valid keyword
|
|
* 9 for invalid keyword
|
|
\*************************************************************/
|
|
int SkipLines()
|
|
{
|
|
int iKW;
|
|
char KW[WORDBUFSIZE];
|
|
|
|
while (NextLine(gBuf, LINEBUFSIZE, gfpInput))
|
|
{
|
|
if(sscanf(gBuf, "%s", KW) == 1)
|
|
{
|
|
if((iKW = isKeyWord(KW)) < NUMKEYWORD)
|
|
{
|
|
return iKW;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NUMKEYWORD;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* Convert Virtual Key name to integer
|
|
* Return : -1 if fail
|
|
\*************************************************************/
|
|
int getVKNum(char *pVK)
|
|
{
|
|
int i, len;
|
|
|
|
len = strlen(pVK);
|
|
|
|
if (len < 1) {
|
|
return -1;
|
|
}
|
|
|
|
if (len == 1) {
|
|
if (*pVK >= '0' && *pVK <= '9') {
|
|
return *pVK;
|
|
}
|
|
|
|
*pVK = (char)toupper(*pVK);
|
|
if (*pVK >= 'A' && *pVK <='Z') {
|
|
return *pVK;
|
|
}
|
|
} else {
|
|
for (i = 0; i < NUMVKNAME; i++) {
|
|
if(_strcmpi(VKName[i].pName, pVK) == 0) {
|
|
return VKName[i].VKey;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Hey! It's unknown! Perhaps it is a new one, in which
|
|
* case it must be of the form 0xNN
|
|
*/
|
|
if (pVK[0] == '0' &&
|
|
(pVK[1] == 'x' || pVK[1] == 'X')) {
|
|
pVK[1] = 'x';
|
|
if (sscanf(pVK, "0x%x", &i) == 1) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* Convert VK integer to name and store it in gVKeyName
|
|
\*************************************************************/
|
|
char *getVKName(int VK, BOOL prefixVK_)
|
|
{
|
|
int i;
|
|
char *s;
|
|
|
|
s = gVKeyName;
|
|
|
|
if((VK >= 'A' && VK <= 'Z') || (VK >= '0' && VK <= '9'))
|
|
{
|
|
*s++ = '\'';
|
|
*s++ = (char)VK;
|
|
*s++ = '\'';
|
|
*s = '\0';
|
|
return gVKeyName;
|
|
}
|
|
|
|
if(prefixVK_)
|
|
{
|
|
strcpy(gVKeyName, "VK_");
|
|
}
|
|
else
|
|
{
|
|
strcpy(gVKeyName, "");
|
|
}
|
|
|
|
for(i = 0; i < NUMVKNAME; i++)
|
|
{
|
|
if(VKName[i].VKey == VK)
|
|
{
|
|
strcat(s, VKName[i].pName);
|
|
return gVKeyName;
|
|
}
|
|
}
|
|
|
|
strcpy(gVKeyName, "#ERROR#");
|
|
return gVKeyName;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* KBD section
|
|
* read in gKBDName and gDescription if any
|
|
* Return : next keyword
|
|
\*************************************************************/
|
|
int doKBD()
|
|
{
|
|
char *p;
|
|
|
|
*gKBDName = '\0';
|
|
*gDescription = '\0';
|
|
|
|
if (sscanf(gBuf, "KBD %5s \"%40[^\"]\" %d", gKBDName, gDescription, &gID) < 2)
|
|
{
|
|
// if (sscanf(gBuf, "KBD %5s ;%40[^\n]", gKBDName, gDescription) < 2)
|
|
// {
|
|
Error("unrecognized keyword");
|
|
// }
|
|
}
|
|
|
|
return (SkipLines());
|
|
}
|
|
|
|
/****************************************************************************\
|
|
* MODIFIERS section [OPTIONAL]
|
|
* Additions to the standard MODIFIERS CharModifiers section.
|
|
* Useful now for adding RCONTROL shiftstates (eg: CAN/CSA prototype)
|
|
* Useful in future for KBDGRPSELTAP keys that flip the kbd into an alternate
|
|
* layout until the next character is produced (then reverts to main layout).
|
|
*
|
|
* Example of syntax is
|
|
* MODIFIERS
|
|
* RCONTROL 8
|
|
* RSHIFT KBDGRPSELTAP
|
|
* I hope to be able to extend this to allow key combos as KBDGRPSELTAP, since
|
|
* the CAN/CSA keyboard may want to have RShift+AltGr flip into the alternate
|
|
* layout (group 2 character set) in addition to just RCtrl, since some terminal
|
|
* emulators use the RCtrl key as an "Enter" key.
|
|
\****************************************************************************/
|
|
int doMODIFIERS()
|
|
{
|
|
int i = 3;
|
|
int iKW = NOT_KEYWORD;
|
|
char achModifier[WORDBUFSIZE];
|
|
char achModBits[LINEBUFSIZE];
|
|
|
|
while(NextLine(gBuf, LINEBUFSIZE, gfpInput)) {
|
|
if (sscanf(gBuf, "%s", achModifier) != 1) {
|
|
continue;
|
|
}
|
|
|
|
if ((iKW = isKeyWord(achModifier)) < NUMKEYWORD) {
|
|
break;
|
|
}
|
|
|
|
if (sscanf(gBuf, " %s %[^;\n]", achModifier, achModBits) < 2) {
|
|
Warning(0, "poorly formed MODIFIER entry");
|
|
break;
|
|
}
|
|
|
|
Modifiers[i].Vk = getVKNum(achModifier);
|
|
Modifiers[i].pszModBits = _strdup(achModBits); // never freed!
|
|
|
|
if (++i > (sizeof(Modifiers)/sizeof(Modifiers[0]))) {
|
|
Warning(0, "Too many MODIFIER entries");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return iKW;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* SHIFTSTATE section
|
|
* read number of states and each state
|
|
* return : next keyword
|
|
\*************************************************************/
|
|
int doSHIFTSTATE(int *nState, int* aiState)
|
|
{
|
|
int i;
|
|
int iKW;
|
|
int iSt;
|
|
char Tmp[WORDBUFSIZE];
|
|
|
|
for(i = 0; i < MAXSTATES; i++)
|
|
{
|
|
aiState[i] = -1;
|
|
}
|
|
|
|
*nState = 0;
|
|
while(NextLine(gBuf, LINEBUFSIZE, gfpInput))
|
|
{
|
|
if(sscanf(gBuf, "%s", Tmp) != 1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if((iKW = isKeyWord(Tmp)) < NUMKEYWORD)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(sscanf(gBuf, " %2s[012367]", Tmp) != 1)
|
|
{
|
|
if (verbose) {
|
|
Warning(0, "invalid state");
|
|
}
|
|
continue; /* add printf error later */
|
|
}
|
|
|
|
iSt = atoi(Tmp);
|
|
for (i = 0; i < *nState; i++) {
|
|
if (aiState[i] == iSt && verbose) {
|
|
Warning(0, "duplicate state %d", iSt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*nState < MAXSTATES) {
|
|
aiState[(*nState)++] = iSt;
|
|
} else {
|
|
if (verbose) {
|
|
Warning(0, "too many states %d", *nState);
|
|
}
|
|
}
|
|
}
|
|
|
|
return iKW;
|
|
}
|
|
|
|
/****************************************************************************\
|
|
* ATTRIBUTES section [OPTIONAL]
|
|
*
|
|
* Example of syntax is
|
|
* ATTRIBUTES
|
|
* LRM_RLM
|
|
* SHIFTLOCK
|
|
* ALTGR
|
|
*
|
|
* These convert to
|
|
* KLLF_LRM_RLM (layout generates LRM/RLM 200E/200F with L/RShift+BackSpace)
|
|
* KLLF_SHIFTLOCK (Capslock only turns CapsLock on, Shift turns it off)
|
|
* KLLF_ALTGR (this is normally inferred by number of states > 5)
|
|
*
|
|
\****************************************************************************/
|
|
char *Attribute[] = {
|
|
"LRM_RLM" ,
|
|
"SHIFTLOCK",
|
|
"ALTGR"
|
|
};
|
|
|
|
#define NUMATTR (sizeof(Attribute) / sizeof(Attribute[0]))
|
|
|
|
/*
|
|
* Returns next key word encountered, and places in szAttr:
|
|
* empty string ("") or
|
|
* something like "KLLF_SHIFTLOCK" or "KLLF_SHIFTLOCK | KLLF_LRM_RLM"
|
|
*/
|
|
int doATTRIBUTES(char *szAttrs)
|
|
{
|
|
int iKW = NOT_KEYWORD;
|
|
int i;
|
|
char achAttribute[WORDBUFSIZE];
|
|
|
|
szAttrs[0] = '\0';
|
|
|
|
while (NextLine(gBuf, LINEBUFSIZE, gfpInput)) {
|
|
if (sscanf(gBuf, "%s", achAttribute) != 1) {
|
|
continue;
|
|
}
|
|
|
|
if ((iKW = isKeyWord(achAttribute)) < NUMKEYWORD) {
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < NUMATTR; i++) {
|
|
if (_strcmpi(Attribute[i], achAttribute) == 0) {
|
|
if (szAttrs[0] != '\0') {
|
|
strcat(szAttrs, " | ");
|
|
}
|
|
strcat(szAttrs, "KLLF_");
|
|
strcat(szAttrs, Attribute[i]);
|
|
}
|
|
}
|
|
|
|
if (szAttrs[0] == '\0') {
|
|
Warning(0, "poorly formed ATTRIBUTES entry");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return iKW;
|
|
}
|
|
|
|
/**********************************************************************\
|
|
* GetCharacter
|
|
* Scans the string in p to return a character value and type
|
|
* syntax in p is:
|
|
* xxxx four hex digits, may be followed by a @ or %
|
|
* eg: 00e8, 00AF@, aaaa%
|
|
* c a character, may be followed with @ or %
|
|
* eg: x, ^@, %%
|
|
* -1 not a character
|
|
*
|
|
* return : character value (0xFFFF if badly formed)
|
|
* type of character in pdwType
|
|
* 0 plain char (ends with neither @ nor %)
|
|
* CHARTYPE_DEAD dead char (ends with @)
|
|
* CHARTYPE_LIG ligature (ends with %)
|
|
* CHARTYPE_BAD badly formed character value, exit.
|
|
*
|
|
\**********************************************************************/
|
|
|
|
#define CHARTYPE_DEAD 1
|
|
#define CHARTYPE_LIG 2
|
|
#define CHARTYPE_BAD 3
|
|
|
|
WCHAR GetCharacter(unsigned char *p, DWORD *pdwType)
|
|
{
|
|
int Len;
|
|
DWORD dwCh;
|
|
|
|
*pdwType = 0;
|
|
|
|
// if the last char is @ or % it is dead or ligature
|
|
if (Len = strlen(p) - 1) {
|
|
if (*(p + Len) == '@') {
|
|
*pdwType = CHARTYPE_DEAD;
|
|
} else if (*(p + Len) == '%') {
|
|
*pdwType = CHARTYPE_LIG;
|
|
}
|
|
}
|
|
|
|
if (Len < 2) {
|
|
return *p;
|
|
} else if (sscanf(p, "%4x", &dwCh) != 1) {
|
|
if (verbose) {
|
|
Warning(0, "LAYOUT error %s", p);
|
|
}
|
|
*pdwType = CHARTYPE_BAD;
|
|
return 0;
|
|
} else {
|
|
return (WCHAR)dwCh;
|
|
}
|
|
}
|
|
|
|
int WToUpper(int wch)
|
|
{
|
|
WCHAR src[1] = { (WCHAR)wch };
|
|
WCHAR result[1];
|
|
|
|
if (LCMapStringW(0, LCMAP_UPPERCASE, src, 1, result, 1) == 0) {
|
|
return L'\0';
|
|
}
|
|
|
|
return result[0];
|
|
}
|
|
|
|
|
|
/*************************************************************\
|
|
* LAYOUT section
|
|
* return : next keyword
|
|
* -1 if memory problem
|
|
\*************************************************************/
|
|
int doLAYOUT(KEYLAYOUT Layout[], int aiState[], int nState)
|
|
{
|
|
int i, idx, iCtrlState;
|
|
BOOL fHasCharacters;
|
|
int iKW;
|
|
int Len;
|
|
USHORT Scan;
|
|
DWORD WChr;
|
|
char Cap[MAXWCLENGTH];
|
|
unsigned char WC[MAXSTATES][MAXWCLENGTH];
|
|
char Tmp[WORDBUFSIZE];
|
|
int i1, i2;
|
|
int iScVk;
|
|
|
|
memset(Layout, 0, NUMSCVK * sizeof(KEYLAYOUT));
|
|
|
|
// Initialize layout entries
|
|
for (idx = 0; idx < NUMSCVK; idx++) {
|
|
Layout[idx].defined = FALSE;
|
|
Layout[idx].nState = 0;
|
|
}
|
|
|
|
/*
|
|
* Accumulate layout entries in the order they are read
|
|
*/
|
|
idx = -1;
|
|
while (NextLine(gBuf, LINEBUFSIZE, gfpInput)) {
|
|
|
|
if (sscanf(gBuf, " %s", Tmp) != 1 || *Tmp == ';') {
|
|
continue;
|
|
}
|
|
|
|
if ((iKW = isKeyWord(Tmp)) < NUMKEYWORD) {
|
|
break;
|
|
}
|
|
|
|
i = sscanf(gBuf, " %x %s %s", &Scan, Tmp, Cap);
|
|
if (i == 3) {
|
|
fHasCharacters = TRUE;
|
|
} else if (i == 2) {
|
|
fHasCharacters = FALSE;
|
|
} else {
|
|
Error("not enough entries on line");
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* We have found an Entry
|
|
*/
|
|
idx++;
|
|
if (idx >= NUMSCVK) {
|
|
Error("ScanCode %02x - too many scancodes", Scan);
|
|
return -1;
|
|
}
|
|
Layout[idx].Scan = Scan;
|
|
Layout[idx].nLine = gLineCount;
|
|
|
|
/*
|
|
* Find and use the Default values for this Scan
|
|
*/
|
|
for (iScVk = 0; iScVk < NUMSCVK; iScVk++) {
|
|
if (ScVk[iScVk].Scan == 0xffff) {
|
|
// We didn't find a match (the 0xffff entries come last)
|
|
Warning(0, "defining new scancode 0x%2X, %s", Scan, Tmp);
|
|
Layout[idx].VKey = (unsigned char)getVKNum(Tmp);
|
|
Layout[idx].defined = TRUE;
|
|
ScVk[iScVk].bUsed = TRUE;
|
|
break;
|
|
}
|
|
if (Scan == ScVk[iScVk].Scan) {
|
|
if (ScVk[iScVk].bUsed == TRUE) {
|
|
Error("Scancode %X was previously defined", Scan);
|
|
return -1;
|
|
}
|
|
if (ScVk[iScVk].VKey == 0xff) {
|
|
Error("Scancode %X is reserved", Scan);
|
|
return -1;
|
|
}
|
|
// Save the default VK for generating kbd*.h
|
|
Layout[idx].VKeyDefault = ScVk[iScVk].VKey;
|
|
Layout[idx].VKeyName = ScVk[iScVk].VKeyName;
|
|
Layout[idx].defined = TRUE;
|
|
ScVk[iScVk].bUsed = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
iScVk = 0xFFFF; // finished with iScVk for now
|
|
|
|
if ((Layout[idx].VKey = (unsigned char)getVKNum(Tmp)) == -1) {
|
|
if (verbose) {
|
|
Warning(0, "invalid VK %s", Tmp);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (fHasCharacters) {
|
|
if(_strcmpi(Cap, "SGCAP") == 0) {
|
|
*Cap = '2';
|
|
}
|
|
if(sscanf(Cap, "%1d[012]", &(Layout[idx].Cap)) != 1) {
|
|
Error("invalid Cap %s", Cap);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if ((Layout[idx].nState = sscanf(gBuf,
|
|
" %*s %*s %*s %s %s %s %s %s %s %s %s",
|
|
WC[0], WC[1], WC[2], WC[3], WC[4], WC[5], WC[6], WC[7])) < 2)
|
|
{
|
|
if (fHasCharacters) {
|
|
Error("must have at least 2 characters");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < Layout[idx].nState; i++) {
|
|
DWORD dwCharType;
|
|
|
|
if (_strcmpi(WC[i], "-1") == 0) {
|
|
Layout[idx].WCh[i] = -1;
|
|
continue;
|
|
}
|
|
|
|
Layout[idx].WCh[i] = GetCharacter(WC[i], &dwCharType);
|
|
if (dwCharType == CHARTYPE_DEAD) {
|
|
Layout[idx].DKy[i] = 1;
|
|
} else if (dwCharType == CHARTYPE_LIG) {
|
|
Layout[idx].LKy[i] = 1;
|
|
} else if (dwCharType == CHARTYPE_BAD) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (sanity_check && Layout[idx].nState > 0) {
|
|
int nAltGr, nShiftAltGr;
|
|
|
|
/*
|
|
* Check that characters a-z and A-Z are on VK_A - VK_Z
|
|
* N.b. maybe overactive warnings for the intl layouts.
|
|
*/
|
|
if (((Layout[idx].WCh[0] >= 'a') && (Layout[idx].WCh[0] <= 'z')) ||
|
|
((Layout[idx].WCh[1] >= 'A') && (Layout[idx].WCh[1] <= 'Z'))) {
|
|
if ((Layout[idx].VKey != _toupper(Layout[idx].WCh[0])) && (Layout[idx].VKey != Layout[idx].WCh[1])) {
|
|
Warning(0, "VK_%s (0x%2x) does not match %c %c",
|
|
Tmp, Layout[idx].VKey, Layout[idx].WCh[0], Layout[idx].WCh[1]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check that CAPLOKALTGR is set appropriately
|
|
*/
|
|
nAltGr = 0;
|
|
nShiftAltGr = 0;
|
|
for (i = 0; i < nState; i++) {
|
|
if (aiState[i] == (KBDCTRL | KBDALT)) {
|
|
nAltGr = i;
|
|
} else if (aiState[i] == (KBDCTRL | KBDALT | KBDSHIFT)) {
|
|
nShiftAltGr = i;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check only if nShiftAltGr has a valid character; i.e. not zero, nor a dead key.
|
|
*/
|
|
if (nAltGr && nShiftAltGr && Layout[idx].WCh[nShiftAltGr] && Layout[idx].WCh[nShiftAltGr] != -1) {
|
|
if (Layout[idx].WCh[nShiftAltGr] != WToUpper(Layout[idx].WCh[nAltGr])) {
|
|
if (Layout[idx].Cap & CAPLOKALTGR) {
|
|
Warning(0, "VK_%s (0x%2x) [Shift]AltGr = [%2x],%2x should not be CAPLOKALTGR?",
|
|
Tmp, Layout[idx].VKey,
|
|
Layout[idx].WCh[nAltGr], Layout[idx].WCh[nShiftAltGr]);
|
|
}
|
|
} else if (Layout[idx].WCh[nShiftAltGr] != Layout[idx].WCh[nAltGr]) {
|
|
/*
|
|
* If the character is completely same, no need for CAPLOKALTGR.
|
|
*/
|
|
if ((Layout[idx].Cap & CAPLOKALTGR) == 0) {
|
|
Warning(0, "VK_%s (0x%2x) [Shift]AltGr = [%2x],%2x should be CAPLOKALTGR?",
|
|
Tmp, Layout[idx].VKey,
|
|
Layout[idx].WCh[nAltGr], Layout[idx].WCh[nShiftAltGr]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* SGCAP: read the next line */
|
|
if (Layout[idx].Cap & 0x02) {
|
|
if((Layout[idx].pSGCAP = malloc( sizeof(KEYLAYOUT) )) == NULL)
|
|
{
|
|
Error("can't allocate SGCAP struct");
|
|
return -1;
|
|
}
|
|
memset(Layout[idx].pSGCAP, 0, sizeof(KEYLAYOUT));
|
|
|
|
if (NextLine(gBuf, LINEBUFSIZE, gfpInput) &&
|
|
(Layout[idx].pSGCAP->nState = sscanf(gBuf, " -1 -1 0 %s %s %s %s %s %s %s %s",
|
|
WC[0], WC[1], WC[2], WC[3], WC[4], WC[5], WC[6], WC[7])) != 0) {
|
|
// DumpLayoutEntry(&Layout[idx]);
|
|
for (i = 0; i < Layout[idx].pSGCAP->nState; i++) {
|
|
if (_strcmpi(WC[i], "-1") == 0) {
|
|
Layout[idx].pSGCAP->WCh[i] = -1;
|
|
continue;
|
|
}
|
|
|
|
if ((Len = strlen(WC[i]) - 1) > 0 && *WC[i + Len] == '@') {
|
|
Layout[idx].pSGCAP->DKy[i] = 1; /* it is a dead key */
|
|
}
|
|
|
|
if (Len == 0) {
|
|
Layout[idx].pSGCAP->WCh[i] = *WC[i];
|
|
} else {
|
|
if (sscanf(WC[i], "%4x", &WChr) != 1) {
|
|
if (verbose) {
|
|
Warning(0, "SGCAP LAYOUT error %s", WC[i]);
|
|
}
|
|
continue;
|
|
} else {
|
|
Layout[idx].pSGCAP->WCh[i] = WChr;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
Error("invalid SGCAP");
|
|
}
|
|
}
|
|
|
|
// DumpLayoutEntry(&Layout[idx]);
|
|
}
|
|
|
|
/*
|
|
* Pick up any unused ScVk[] entries (defaults)
|
|
*/
|
|
for (iScVk = 0; iScVk < NUMSCVK; iScVk++) {
|
|
// if we reach 0xffff, we have come to the end.
|
|
if (ScVk[iScVk].Scan == 0xffff) {
|
|
break;
|
|
}
|
|
if (!ScVk[iScVk].bUsed) {
|
|
idx++;
|
|
if (idx >= NUMSCVK) {
|
|
Error("ScanCode %02x - too many scancodes", ScVk[iScVk].Scan);
|
|
return -1;
|
|
}
|
|
Layout[idx].Scan = ScVk[iScVk].Scan;
|
|
Layout[idx].VKey = ScVk[iScVk].VKey;
|
|
Layout[idx].VKeyDefault = ScVk[iScVk].VKey;
|
|
Layout[idx].VKeyName = ScVk[iScVk].VKeyName;
|
|
Layout[idx].defined = TRUE;
|
|
Layout[idx].nLine = 0;
|
|
// DumpLayoutEntry(&Layout[idx]);
|
|
} else {
|
|
ScVk[iScVk].bUsed = FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now make sure some standard Ctrl characters are present
|
|
*/
|
|
MergeState(Layout, VK_BACK, L'\b', L'\b', 0x007f, aiState, nState);
|
|
MergeState(Layout, VK_CANCEL, 0x0003, 0x0003, 0x0003, aiState, nState);
|
|
MergeState(Layout, VK_ESCAPE, 0x001b, 0x001b, 0x001b, aiState, nState);
|
|
MergeState(Layout, VK_RETURN, L'\r', L'\r', L'\n', aiState, nState);
|
|
MergeState(Layout, VK_SPACE, L' ', L' ', L' ', aiState, nState);
|
|
|
|
/*
|
|
* Check VK not duplicated
|
|
*/
|
|
|
|
for (idx = 0; idx < NUMSCVK; idx++) {
|
|
for (i = idx + 1; i < NUMSCVK; i++) {
|
|
if (Layout[idx].VKey == Layout[i].VKey) {
|
|
if (Layout[idx].VKey == 0xFF) {
|
|
// undefined extended and non-extended versions of the same key
|
|
continue;
|
|
}
|
|
if ((BYTE)Layout[idx].Scan == (BYTE)Layout[i].Scan) {
|
|
// extended and non-extended versions of the same key
|
|
continue;
|
|
}
|
|
Error("VK_%s (%02x) found at scancode %02x and %02x",
|
|
getVKName(Layout[idx].VKey, 0), Layout[idx].VKey, Layout[idx].Scan, Layout[i].Scan);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Find duplicated characters and warn of VkKeyScanEx results
|
|
*/
|
|
if (verbose) {
|
|
for (i1 = 0; i1 < NUMSCVK; i1++) {
|
|
for (i2 = i1 + 1; i2 < NUMSCVK; i2++) {
|
|
int ich1, ich2;
|
|
for (ich1 = 0; ich1 < Layout[i1].nState; ich1++) {
|
|
if (Layout[i1].WCh[ich1] == -1) {
|
|
// there may be many WCH_NONEs (padding, or empty holes)
|
|
continue;
|
|
}
|
|
if (Layout[i1].WCh[ich1] < 0x20) {
|
|
// Don't care about Ctrl chars.
|
|
// these are usually duplicated eg: Ctrl-M == Return, etc.
|
|
continue;
|
|
}
|
|
if ((Layout[i1].VKey == VK_DECIMAL) || (Layout[i2].VKey == VK_DECIMAL)) {
|
|
// kbdtool has put VK_DECIMAL at the end just for VkKeyScanEx
|
|
// It is usually period or comma, and we prefer to get those
|
|
// from the main section of the keyboard.
|
|
continue;
|
|
}
|
|
for (ich2 = 0; ich2 < Layout[i2].nState; ich2++) {
|
|
if (Layout[i1].WCh[ich1] == Layout[i2].WCh[ich2]) {
|
|
char achVK1[40];
|
|
char achVK2[40];
|
|
strncpy(achVK1, getVKName(Layout[i1].VKey, TRUE), sizeof(achVK1));
|
|
strncpy(achVK2, getVKName(Layout[i2].VKey, TRUE), sizeof(achVK2));
|
|
Warning(Layout[i1].nLine,
|
|
"%04x is on %s and %s",
|
|
Layout[i1].WCh[ich1],
|
|
achVK1, achVK2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return iKW;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* DEADKEY section
|
|
* return : next keyword
|
|
* -1 if memory problem
|
|
\*************************************************************/
|
|
int doDEADKEY(PDEADKEY *ppDeadKey)
|
|
{
|
|
char Tmp[WORDBUFSIZE];
|
|
int iKW;
|
|
DEADKEY *pDeadKey;
|
|
PDEADTRANS pDeadTrans;
|
|
PDEADTRANS *ppDeadTrans;
|
|
DWORD dw;
|
|
static PDEADKEY pLastDeadKey;
|
|
int iLen;
|
|
DWORD dwCharType;
|
|
|
|
|
|
if (sscanf(gBuf, " DEADKEY %s", Tmp) != 1) {
|
|
Warning(0, "missing dead key");
|
|
return SkipLines();
|
|
}
|
|
|
|
|
|
/* add later : check if dw is in Layout*/
|
|
|
|
if((pDeadKey = (DEADKEY*) malloc( sizeof(DEADKEY) )) == NULL)
|
|
{
|
|
Error("can't allocate DEADKEY struct");
|
|
return -1;
|
|
}
|
|
|
|
pDeadKey->Dead = GetCharacter(Tmp, &dwCharType);
|
|
if (dwCharType != 0) {
|
|
Error("DEADKEY character value badly formed");
|
|
return -1;
|
|
}
|
|
|
|
pDeadKey->pNext = NULL;
|
|
pDeadKey->pDeadTrans = NULL;
|
|
|
|
/*
|
|
* Link into end of list (maintaining original order)
|
|
*/
|
|
if (*ppDeadKey) {
|
|
ppDeadKey = &(pLastDeadKey->pNext);
|
|
}
|
|
*ppDeadKey = pDeadKey;
|
|
pLastDeadKey = pDeadKey;
|
|
// ppDeadKey = &(pDeadKey->pNext);
|
|
|
|
|
|
ppDeadTrans = &(pDeadKey->pDeadTrans);
|
|
while(NextLine(gBuf, LINEBUFSIZE, gfpInput))
|
|
{
|
|
if (sscanf(gBuf, " %s", Tmp) != 1 || *Tmp == ';') {
|
|
continue;
|
|
}
|
|
|
|
if((iKW = isKeyWord(Tmp)) < NUMKEYWORD)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// get base character
|
|
dw = GetCharacter(Tmp, &dwCharType);
|
|
if (dwCharType != 0) {
|
|
Error("DEADKEY %x: base character value badly formed", pDeadKey->Dead);
|
|
return -1;
|
|
}
|
|
|
|
/* add later : check dw */
|
|
|
|
if((pDeadTrans = (DEADTRANS *) malloc( sizeof(DEADTRANS) )) == NULL)
|
|
{
|
|
Error("can't allocate DEADTRANS struct");
|
|
return -1;
|
|
}
|
|
memset(pDeadTrans, 0, sizeof(DEADTRANS));
|
|
|
|
pDeadTrans->pNext = NULL;
|
|
pDeadTrans->Base = dw;
|
|
pDeadTrans->uFlags = 0;
|
|
|
|
/*
|
|
* Link to end of list (maintaining original order)
|
|
*/
|
|
*ppDeadTrans = pDeadTrans;
|
|
ppDeadTrans = &(pDeadTrans->pNext);
|
|
|
|
if (sscanf(gBuf, " %*s %s", Tmp) != 1) {
|
|
if (verbose) {
|
|
Warning(0, "missing deadtrans key");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
pDeadTrans->WChar = GetCharacter(Tmp, &dwCharType);
|
|
if (dwCharType == CHARTYPE_DEAD) {
|
|
pDeadTrans->uFlags |= 0x0001; // DKF_DEAD in oak\inc\kbd.h
|
|
} else if (dwCharType != 0) {
|
|
Error("DEADKEY character value badly formed");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return iKW;
|
|
}
|
|
|
|
static int gMaxLigature = 0;
|
|
|
|
/*************************************************************\
|
|
* LIGATURE section
|
|
* return : next keyword
|
|
* -1 if memory problem
|
|
\*************************************************************/
|
|
int doLIGATURE(PLIGATURE *ppLigature)
|
|
{
|
|
int i;
|
|
int iKW;
|
|
DWORD WChr;
|
|
char Mod[MAXWCLENGTH];
|
|
unsigned char WC[MAXLIGATURES+1][MAXWCLENGTH];
|
|
char Tmp[WORDBUFSIZE];
|
|
LIGATURE *pLigature;
|
|
static PLIGATURE pLastLigature;
|
|
|
|
while(NextLine(gBuf, LINEBUFSIZE, gfpInput))
|
|
{
|
|
if(sscanf(gBuf, " %s", Tmp) != 1 || *Tmp == ';')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if((iKW = isKeyWord(Tmp)) < NUMKEYWORD)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(sscanf(gBuf, " %s %s", Tmp, Mod) != 2)
|
|
{
|
|
if(verbose)
|
|
{
|
|
Warning(0, "invalid LIGATURE");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if((pLigature = (LIGATURE*) malloc( sizeof(LIGATURE) )) == NULL)
|
|
{
|
|
Error("can't allocate LIGATURE struct");
|
|
return -1;
|
|
}
|
|
pLigature->pNext = NULL;
|
|
|
|
if((pLigature->VKey = (unsigned char)getVKNum(Tmp)) == -1)
|
|
{
|
|
if(verbose)
|
|
{
|
|
Warning(0, "invalid VK %s", Tmp);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if(sscanf(Mod, "%1d[012367]", &(pLigature->Mod)) != 1)
|
|
{
|
|
if(verbose)
|
|
{
|
|
Warning(0, "invalid Mod %s", Mod);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* We're currently limited to MAXLIGATURES characters per
|
|
* ligature. In order to support more characters per ligature,
|
|
* increase this define (in kbdx.h).
|
|
*/
|
|
if((pLigature->nCharacters = \
|
|
sscanf(gBuf, " %*s %*s %s %s %s %s %s %s", \
|
|
&WC[0], &WC[1], &WC[2], &WC[3], &WC[4], &WC[5])) < 2)
|
|
{
|
|
if(verbose)
|
|
{
|
|
Warning(0, "must have at least 2 characters");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (pLigature->nCharacters > MAXLIGATURES)
|
|
{
|
|
if(verbose)
|
|
{
|
|
Warning(0, "exceeded maximum # of characters for ligature");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
for(i = 0; i < pLigature->nCharacters; i++)
|
|
{
|
|
DWORD dwCharType;
|
|
|
|
pLigature->WCh[i] = GetCharacter(WC[i], &dwCharType);
|
|
if (dwCharType != 0) {
|
|
if(verbose) {
|
|
Warning(0, "LIGATURE error %s", WC[i]);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Link into end of list (maintaining original order)
|
|
*/
|
|
if (*ppLigature) {
|
|
ppLigature = &(pLastLigature->pNext);
|
|
}
|
|
*ppLigature = pLigature;
|
|
pLastLigature = pLigature;
|
|
|
|
gMaxLigature = max(pLigature->nCharacters, gMaxLigature);
|
|
}
|
|
|
|
return iKW;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* KEYNAME, KEYNAME_EXT, KEYNAME_DEAD sections
|
|
* return : next keyword
|
|
* -1 if memory problem
|
|
\*************************************************************/
|
|
int doKEYNAME(PKEYNAME *ppKeyName)
|
|
{
|
|
KEYNAME *pKN;
|
|
int iKW;
|
|
char Tmp[WORDBUFSIZE];
|
|
int Char;
|
|
char *p;
|
|
char *q;
|
|
|
|
*ppKeyName = NULL;
|
|
|
|
while(NextLine(gBuf, LINEBUFSIZE, gfpInput))
|
|
{
|
|
if(sscanf(gBuf, " %s", Tmp) != 1 || *Tmp == ';')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if((iKW = isKeyWord(Tmp)) < NUMKEYWORD)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(sscanf(Tmp, " %4x", &Char) != 1)
|
|
{
|
|
if(verbose)
|
|
{
|
|
Warning(0, "invalid char code");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* add later : check Scan code */
|
|
|
|
if(sscanf(gBuf, " %*4x %s[^\n]", Tmp) != 1)
|
|
{
|
|
if(verbose)
|
|
{
|
|
Warning(0, "missing name");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
p = strstr(gBuf, Tmp);
|
|
if((q = strchr(p, '\n')) != NULL)
|
|
{
|
|
*q = '\0';
|
|
}
|
|
|
|
if((pKN = (void*) malloc( sizeof(KEYNAME) )) == NULL)
|
|
{
|
|
Error("can't allocate KEYNAME struct");
|
|
return -1;
|
|
}
|
|
|
|
pKN->Code = Char;
|
|
pKN->pName = _strdup(p);
|
|
pKN->pNext = NULL;
|
|
|
|
/*
|
|
* Link to end of list (maintaining original order)
|
|
*/
|
|
*ppKeyName = pKN;
|
|
ppKeyName = &(pKN->pNext);
|
|
}
|
|
|
|
return iKW;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* write kbd*.rc *
|
|
\*************************************************************/
|
|
int kbd_rc(void)
|
|
{
|
|
char OutName[FILENAMESIZE];
|
|
char kbdname[MAXKBDNAME];
|
|
FILE *pOut;
|
|
|
|
strcpy(OutName, "KBD");
|
|
strcat(OutName, gKBDName);
|
|
strcat(OutName, ".RC");
|
|
|
|
strcpy(kbdname, gKBDName);
|
|
_strlwr(kbdname);
|
|
|
|
printf(" %12s", OutName);
|
|
if((pOut = fopen(OutName, "wt")) == NULL)
|
|
{
|
|
printf(": can't open for write; ");
|
|
return FAILURE;
|
|
}
|
|
|
|
fprintf(pOut,
|
|
"#include <windows.h>\n"
|
|
"#include <ntverp.h>\n"
|
|
"\n"
|
|
"#define VER_FILETYPE VFT_DLL\n"
|
|
"#define VER_FILESUBTYPE VFT2_DRV_KEYBOARD\n" );
|
|
|
|
fprintf(pOut,
|
|
"#define VER_FILEDESCRIPTION_STR \"%s Keyboard Layout\"\n", gDescription);
|
|
|
|
fprintf(pOut,
|
|
"#define VER_INTERNALNAME_STR \"kbd%s (%d.%d)\"\n",
|
|
kbdname, gVersion, gSubVersion);
|
|
|
|
fprintf(pOut,
|
|
"#define VER_ORIGINALFILENAME_STR \"kbd%s.dll\"\n", kbdname);
|
|
|
|
fprintf(pOut,
|
|
"\n"
|
|
"#define VER_LANGNEUTRAL\n"
|
|
"#include \"common.ver\"\n");
|
|
|
|
fclose(pOut);
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* write kbd*.def *
|
|
\*************************************************************/
|
|
int kbd_def(void)
|
|
{
|
|
char OutName[FILENAMESIZE];
|
|
FILE *pOut;
|
|
|
|
strcpy(OutName, "KBD");
|
|
strcat(OutName, gKBDName);
|
|
strcat(OutName, ".DEF");
|
|
|
|
printf(" %12s", OutName);
|
|
if((pOut = fopen(OutName, "wt")) == NULL)
|
|
{
|
|
printf(": can't open for write; ");
|
|
return FAILURE;
|
|
}
|
|
|
|
fprintf(pOut,
|
|
"LIBRARY KBD%s\n"
|
|
"\n"
|
|
"EXPORTS\n"
|
|
" KbdLayerDescriptor @1\n", gKBDName);
|
|
|
|
fclose(pOut);
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* write kbd*.h *
|
|
\*************************************************************/
|
|
int kbd_h(KEYLAYOUT Layout[])
|
|
{
|
|
char OutName[FILENAMESIZE];
|
|
FILE *pOut;
|
|
|
|
int nDiff = 0;
|
|
int idx;
|
|
|
|
|
|
strcpy(OutName, "KBD");
|
|
strcat(OutName, gKBDName);
|
|
strcat(OutName, ".H");
|
|
|
|
printf(" %12s ", OutName);
|
|
if((pOut = fopen(OutName, "wt")) == NULL)
|
|
{
|
|
printf(": can't open for write; ");
|
|
return FAILURE;
|
|
}
|
|
|
|
fprintf(pOut,"/****************************** Module Header ******************************\\\n"
|
|
"* Module Name: %s\n*\n* keyboard layout header for %s\n"
|
|
"*\n"
|
|
"* Copyright (c) 1985-2001, Microsoft Corporation\n"
|
|
"*\n"
|
|
"* Various defines for use by keyboard input code.\n*\n* History:\n"
|
|
"*\n"
|
|
"* created by KBDTOOL v%d.%02d %s*\n"
|
|
"\\***************************************************************************/\n\n"
|
|
, OutName, gDescription, gVersion, gSubVersion, asctime(Now));
|
|
|
|
fprintf(pOut,"/*\n"
|
|
" * kbd type should be controlled by cl command-line argument\n"
|
|
" */\n"
|
|
"#define KBD_TYPE 4\n\n"
|
|
"/*\n"
|
|
"* Include the basis of all keyboard table values\n"
|
|
"*/\n"
|
|
"#include \"kbd.h\"\n"
|
|
// "#include \"strid.h\"\n" --- do this in v3.07
|
|
);
|
|
|
|
fprintf(pOut,"/***************************************************************************\\\n"
|
|
"* The table below defines the virtual keys for various keyboard types where\n"
|
|
"* the keyboard differ from the US keyboard.\n"
|
|
"*\n"
|
|
"* _EQ() : all keyboard types have the same virtual key for this scancode\n"
|
|
"* _NE() : different virtual keys for this scancode, depending on kbd type\n"
|
|
"*\n"
|
|
"* +------+ +----------+----------+----------+----------+----------+----------+\n"
|
|
"* | Scan | | kbd | kbd | kbd | kbd | kbd | kbd |\n"
|
|
"* | code | | type 1 | type 2 | type 3 | type 4 | type 5 | type 6 |\n"
|
|
"\\****+-------+_+----------+----------+----------+----------+----------+----------+*/\n\n");
|
|
|
|
for (idx = 0; idx < NUMSCVK; idx++) {
|
|
if (Layout[idx].defined && (Layout[idx].VKey != Layout[idx].VKeyDefault))
|
|
{
|
|
char ch;
|
|
switch (Layout[idx].Scan & 0xFF00) {
|
|
case 0xE100:
|
|
ch = 'Y';
|
|
break;
|
|
|
|
case 0xE000:
|
|
ch = 'X';
|
|
break;
|
|
|
|
case 0x0000:
|
|
ch = 'T';
|
|
break;
|
|
|
|
default:
|
|
Error("Weird scancode value %04x: expected xx, E0xx or E1xx",
|
|
(Layout[idx].Scan & 0xFF00));
|
|
return FAILURE;
|
|
}
|
|
|
|
fprintf(pOut,
|
|
"#undef %c%02X\n"
|
|
"#define %c%02X _EQ(%43s%23s\n",
|
|
ch, LOBYTE(Layout[idx].Scan),
|
|
ch, LOBYTE(Layout[idx].Scan), getVKName(Layout[idx].VKey, 0), ")");
|
|
}
|
|
}
|
|
|
|
fprintf(pOut,"\n");
|
|
fclose(pOut);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*************************************************************\
|
|
* Convert a Unicode value to a text string
|
|
* Zero = 0 : return 'A'; 0x????
|
|
* 1 : return A ; \x????
|
|
* return : ptr to gCharName where result is stored
|
|
\*************************************************************/
|
|
char *WChName(int WC, int Zero)
|
|
{
|
|
char *s;
|
|
|
|
if(WC == -1)
|
|
{
|
|
strcpy(gCharName, "WCH_NONE");
|
|
}
|
|
else if(WC > 0x1F && WC < 0x7F)
|
|
{
|
|
s = gCharName;
|
|
|
|
if(Zero == 0)
|
|
{
|
|
*s++ = '\'';
|
|
}
|
|
|
|
if(WC == '\"' || WC == '\'' || WC == '\\')
|
|
{
|
|
*s++ = '\\';
|
|
}
|
|
|
|
*s++ = (char)WC;
|
|
|
|
if(Zero == 0)
|
|
{
|
|
*s++ = '\'';
|
|
}
|
|
|
|
*s = '\0';
|
|
}
|
|
else
|
|
{
|
|
switch (WC) {
|
|
case L'\r':
|
|
strcpy(gCharName, "'\\r'");
|
|
break;
|
|
case L'\n':
|
|
strcpy(gCharName, "'\\n'");
|
|
break;
|
|
case L'\b':
|
|
strcpy(gCharName, "'\\b'");
|
|
break;
|
|
default:
|
|
if(Zero == 0) {
|
|
sprintf(gCharName, "0x%04x", WC);
|
|
} else {
|
|
sprintf(gCharName, "\\x%04x", WC);
|
|
}
|
|
}
|
|
}
|
|
|
|
return gCharName;
|
|
}
|
|
|
|
void PrintNameTable(
|
|
FILE *pOut,
|
|
PKEYNAME pKN,
|
|
BOOL bDead)
|
|
{
|
|
char *p;
|
|
char *q;
|
|
int k;
|
|
char ExtraLine[LINEBUFSIZE];
|
|
|
|
while (pKN)
|
|
{
|
|
KEYNAME *pKNOld;
|
|
p = ExtraLine;
|
|
q = pKN->pName;
|
|
|
|
if (strncmp(q, "IDS_", 4) == 0) {
|
|
strcpy(p, "(LPWSTR)");
|
|
strcat(p, q);
|
|
} else {
|
|
*p++ = 'L';
|
|
if( *q != '\"' ) {
|
|
*p++ = '\"';
|
|
}
|
|
|
|
while(*q)
|
|
{
|
|
if( *q == '\\' && ( *(q+1) == 'x' || *(q+1) == 'X' ) )
|
|
{
|
|
while( *q == '\\' && ( *(q+1) == 'x' || *(q+1) == 'X' ) )
|
|
{
|
|
for(k = 0; *q && k < 6; k++)
|
|
{
|
|
*p++ = *q++;
|
|
}
|
|
}
|
|
if( *q )
|
|
{
|
|
*p++ = '\"';
|
|
*p++ = ' ';
|
|
*p++ = 'L';
|
|
*p++ = '\"';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*p++ = *q++;
|
|
}
|
|
}
|
|
|
|
if( *(p - 1) != '\"' )
|
|
{
|
|
*p++ = '\"';
|
|
}
|
|
*p++ = '\0';
|
|
}
|
|
|
|
if (bDead) {
|
|
fprintf(pOut," L\"%s\"\t%s,\n", WChName(pKN->Code, 1), ExtraLine);
|
|
} else {
|
|
fprintf(pOut," 0x%02x, %s,\n", pKN->Code, ExtraLine);
|
|
}
|
|
|
|
pKNOld = pKN;
|
|
pKN = pKN->pNext;
|
|
|
|
/*
|
|
* Free the memory (why bother???)
|
|
*/
|
|
free(pKNOld->pName);
|
|
free(pKNOld);
|
|
}
|
|
|
|
if (bDead) {
|
|
fprintf(pOut," NULL\n");
|
|
} else {
|
|
fprintf(pOut," 0 , NULL\n");
|
|
}
|
|
}
|
|
|
|
/*************************************************************\
|
|
* write kbd*.c *
|
|
\*************************************************************/
|
|
int kbd_c(
|
|
int nState,
|
|
int aiState[],
|
|
char * szAttrs,
|
|
KEYLAYOUT Layout[],
|
|
PDEADKEY pDeadKey,
|
|
PLIGATURE pLigature,
|
|
PKEYNAME pKeyName,
|
|
PKEYNAME pKeyNameExt,
|
|
PKEYNAME pKeyNameDead)
|
|
{
|
|
char OutName[13];
|
|
char ExtraLine[LINEBUFSIZE];
|
|
char Tmp[WORDBUFSIZE];
|
|
char *p;
|
|
char *q;
|
|
FILE *pOut;
|
|
int MaxSt;
|
|
int aiSt[MAXSTATES];
|
|
int idx, idxSt, j, k, m;
|
|
DWORD dwEmptyTables = 0; // bitmask of empty VK_TO_WCHARS tables
|
|
|
|
KEYNAME *pKN;
|
|
DEADTRANS *pDeadTrans;
|
|
|
|
char *Cap[] = {
|
|
"0",
|
|
"CAPLOK",
|
|
"SGCAPS",
|
|
"CAPLOK | SGCAPS",
|
|
"CAPLOKALTGR",
|
|
"CAPLOK | CAPLOKALTGR"
|
|
};
|
|
|
|
strcpy(OutName, "KBD");
|
|
strcat(OutName, gKBDName);
|
|
strcat(OutName, ".C");
|
|
|
|
printf(" %12s", OutName);
|
|
|
|
if((pOut = fopen(OutName, "wt")) == NULL)
|
|
{
|
|
printf(": can't open for write\n");
|
|
return FAILURE;
|
|
}
|
|
|
|
fprintf(pOut,"/***************************************************************************\\\n"
|
|
"* Module Name: %s\n*\n* keyboard layout for %s\n"
|
|
"*\n"
|
|
"* Copyright (c) 1985-2001, Microsoft Corporation\n"
|
|
"*\n"
|
|
"* History:\n"
|
|
"* KBDTOOL v%d.%02d - Created %s"
|
|
"\\***************************************************************************/\n\n",
|
|
OutName, gDescription, gVersion, gSubVersion, asctime(Now)
|
|
);
|
|
|
|
if (fallback_driver) {
|
|
fprintf(pOut, "#include \"precomp.h\"\n");
|
|
}
|
|
else {
|
|
fprintf(pOut, "#include <windows.h>\n"
|
|
"#include \"kbd.h\"\n"
|
|
"#include \"kbd%s.h\"\n\n",
|
|
gKBDName);
|
|
}
|
|
|
|
if ( fallback_driver ) {
|
|
|
|
fprintf(pOut,"#pragma data_seg(\"%s\")\n"
|
|
"#define ALLOC_SECTION_LDATA"
|
|
#ifdef LATER
|
|
" const"
|
|
#endif
|
|
"\n\n",
|
|
".kbdfallback" );
|
|
|
|
}
|
|
else {
|
|
|
|
fprintf(pOut,"#if defined(_M_IA64)\n"
|
|
"#pragma section(\"%s\")\n"
|
|
"#define ALLOC_SECTION_LDATA __declspec(allocate(\"%s\"))\n"
|
|
"#else\n"
|
|
"#pragma data_seg(\"%s\")\n"
|
|
"#define ALLOC_SECTION_LDATA\n"
|
|
"#endif\n\n",
|
|
".data",
|
|
".data",
|
|
".data");
|
|
|
|
}
|
|
|
|
fprintf(pOut,"/***************************************************************************\\\n"
|
|
"* ausVK[] - Virtual Scan Code to Virtual Key conversion table for %s\n"
|
|
"\\***************************************************************************/\n\n"
|
|
,gDescription);
|
|
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA USHORT ausVK[] = {\n"
|
|
" T00, T01, T02, T03, T04, T05, T06, T07,\n"
|
|
" T08, T09, T0A, T0B, T0C, T0D, T0E, T0F,\n"
|
|
" T10, T11, T12, T13, T14, T15, T16, T17,\n"
|
|
" T18, T19, T1A, T1B, T1C, T1D, T1E, T1F,\n"
|
|
" T20, T21, T22, T23, T24, T25, T26, T27,\n"
|
|
" T28, T29, T2A, T2B, T2C, T2D, T2E, T2F,\n"
|
|
" T30, T31, T32, T33, T34, T35,\n\n");
|
|
|
|
fprintf(pOut," /*\n"
|
|
" * Right-hand Shift key must have KBDEXT bit set.\n"
|
|
" */\n"
|
|
" T36 | KBDEXT,\n\n"
|
|
" T37 | KBDMULTIVK, // numpad_* + Shift/Alt -> SnapShot\n\n"
|
|
" T38, T39, T3A, T3B, T3C, T3D, T3E,\n"
|
|
" T3F, T40, T41, T42, T43, T44,\n\n");
|
|
|
|
fprintf(pOut," /*\n"
|
|
" * NumLock Key:\n"
|
|
" * KBDEXT - VK_NUMLOCK is an Extended key\n"
|
|
" * KBDMULTIVK - VK_NUMLOCK or VK_PAUSE (without or with CTRL)\n"
|
|
" */\n"
|
|
" T45 | KBDEXT | KBDMULTIVK,\n\n"
|
|
" T46 | KBDMULTIVK,\n\n");
|
|
|
|
fprintf(pOut," /*\n"
|
|
" * Number Pad keys:\n"
|
|
" * KBDNUMPAD - digits 0-9 and decimal point.\n"
|
|
" * KBDSPECIAL - require special processing by Windows\n"
|
|
" */\n"
|
|
" T47 | KBDNUMPAD | KBDSPECIAL, // Numpad 7 (Home)\n"
|
|
" T48 | KBDNUMPAD | KBDSPECIAL, // Numpad 8 (Up),\n"
|
|
" T49 | KBDNUMPAD | KBDSPECIAL, // Numpad 9 (PgUp),\n"
|
|
" T4A,\n"
|
|
" T4B | KBDNUMPAD | KBDSPECIAL, // Numpad 4 (Left),\n"
|
|
" T4C | KBDNUMPAD | KBDSPECIAL, // Numpad 5 (Clear),\n"
|
|
" T4D | KBDNUMPAD | KBDSPECIAL, // Numpad 6 (Right),\n"
|
|
" T4E,\n"
|
|
" T4F | KBDNUMPAD | KBDSPECIAL, // Numpad 1 (End),\n"
|
|
" T50 | KBDNUMPAD | KBDSPECIAL, // Numpad 2 (Down),\n"
|
|
" T51 | KBDNUMPAD | KBDSPECIAL, // Numpad 3 (PgDn),\n"
|
|
" T52 | KBDNUMPAD | KBDSPECIAL, // Numpad 0 (Ins),\n"
|
|
" T53 | KBDNUMPAD | KBDSPECIAL, // Numpad . (Del),\n\n");
|
|
|
|
fprintf(pOut," T54, T55, T56, T57, T58, T59, T5A, T5B,\n"
|
|
" T5C, T5D, T5E, T5F, T60, T61, T62, T63,\n"
|
|
" T64, T65, T66, T67, T68, T69, T6A, T6B,\n"
|
|
" T6C, T6D, T6E, T6F, T70, T71, T72, T73,\n"
|
|
" T74, T75, T76, T77, T78, T79, T7A, T7B,\n"
|
|
" T7C, T7D, T7E\n\n"
|
|
"};\n\n");
|
|
|
|
//
|
|
// Output E0-prefixed (extended) scancodes
|
|
//
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA VSC_VK aE0VscToVk[] = {\n");
|
|
for (idx = 0; idx < NUMSCVK; idx++) {
|
|
// skip keys that are not E0 extended
|
|
if ((Layout[idx].Scan & 0xFF00) != 0xE000) {
|
|
continue;
|
|
}
|
|
// if not undefined (Scan 0xffff) and not reserved (VKey 0xff)
|
|
if ((Layout[idx].Scan != 0xffff) && (Layout[idx].VKey != 0xff)) {
|
|
fprintf(pOut," { 0x%02X, X%02X | KBDEXT }, // %s\n",
|
|
Layout[idx].Scan & 0xFF, Layout[idx].Scan & 0xFF, Layout[idx].VKeyName);
|
|
}
|
|
}
|
|
fprintf(pOut," { 0, 0 }\n"
|
|
"};\n\n");
|
|
|
|
// Output 0xE1-prefixed scancodes
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA VSC_VK aE1VscToVk[] = {\n");
|
|
for (idx = 0; idx < NUMSCVK; idx++) {
|
|
// skip keys that are not E1 extended
|
|
if ((Layout[idx].Scan & 0xFF00) != 0xE100) {
|
|
continue;
|
|
}
|
|
// if not undefined (Scan 0xffff) and not reserved (VKey 0xff)
|
|
if ((Layout[idx].Scan != 0xffff) && (Layout[idx].VKey != 0xff)) {
|
|
fprintf(pOut," { 0x%02X, Y%02X | KBDEXT }, // %s\n",
|
|
Layout[idx].Scan & 0xFF, Layout[idx].Scan & 0xFF,
|
|
Layout[idx].VKeyName);
|
|
}
|
|
}
|
|
fprintf(pOut," { 0x1D, Y1D }, // Pause\n"
|
|
" { 0 , 0 }\n"
|
|
"};\n\n");
|
|
|
|
fprintf(pOut,"/***************************************************************************\\\n"
|
|
"* aVkToBits[] - map Virtual Keys to Modifier Bits\n"
|
|
"*\n"
|
|
"* See kbd.h for a full description.\n"
|
|
"*\n"
|
|
"* %s Keyboard has only three shifter keys:\n"
|
|
"* SHIFT (L & R) affects alphabnumeric keys,\n"
|
|
"* CTRL (L & R) is used to generate control characters\n"
|
|
"* ALT (L & R) used for generating characters by number with numpad\n"
|
|
"\\***************************************************************************/\n"
|
|
,gDescription);
|
|
|
|
// if (we get an RCONTROL, change VK_CONTROL to be VK_LCONTROL) { same for RMENU, RSHIFT?
|
|
// } CAN/CSA tap selection....
|
|
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA VK_TO_BIT aVkToBits[] = {\n");
|
|
for (idx = 0; Modifiers[idx].Vk != 0; idx++) {
|
|
fprintf(pOut, " { %-12s, %-12s },\n",
|
|
getVKName(Modifiers[idx].Vk, TRUE),
|
|
Modifiers[idx].pszModBits);
|
|
}
|
|
fprintf(pOut, " { 0 , 0 }\n};\n\n");
|
|
|
|
fprintf(pOut,"/***************************************************************************\\\n"
|
|
"* aModification[] - map character modifier bits to modification number\n"
|
|
"*\n"
|
|
"* See kbd.h for a full description.\n"
|
|
"*\n"
|
|
"\\***************************************************************************/\n\n");
|
|
|
|
for (idxSt = 0; idxSt < MAXSTATES; idxSt++) {
|
|
aiSt[idxSt] = -1;
|
|
}
|
|
|
|
MaxSt = 1;
|
|
for (idxSt = 0; idxSt < MAXSTATES && aiState[idxSt] > -1; idxSt++) {
|
|
aiSt[aiState[idxSt]] = idxSt;
|
|
if (aiState[idxSt] > MaxSt) {
|
|
MaxSt = aiState[idxSt];
|
|
}
|
|
}
|
|
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA MODIFIERS CharModifiers = {\n"
|
|
" &aVkToBits[0],\n"
|
|
" %d,\n"
|
|
" {\n"
|
|
" // Modification# // Keys Pressed\n"
|
|
" // ============= // =============\n"
|
|
,MaxSt);
|
|
|
|
for (idxSt = 0; idxSt <= MaxSt; idxSt++) {
|
|
int iMod;
|
|
BOOL bNeedPlus;
|
|
if(aiSt[idxSt] == -1) {
|
|
fprintf(pOut," SHFT_INVALID, // ");
|
|
} else if(idxSt == MaxSt) {
|
|
fprintf(pOut," %d // ", aiSt[idxSt]);
|
|
} else {
|
|
fprintf(pOut," %d, // ", aiSt[idxSt]);
|
|
}
|
|
|
|
bNeedPlus = FALSE;
|
|
for (iMod = 0; (1 << iMod) <= idxSt; iMod++) {
|
|
if (bNeedPlus) {
|
|
fprintf(pOut, "+ ");
|
|
bNeedPlus = FALSE;
|
|
}
|
|
if ((1 << iMod) & idxSt) {
|
|
char achModifier[50];
|
|
strcpy(achModifier, getVKName(Modifiers[iMod].Vk, TRUE));
|
|
for (j = 4; (j < 50) && (achModifier[j] != '\0'); j++) {
|
|
achModifier[j] = (char)tolower(achModifier[j]);
|
|
}
|
|
fprintf(pOut, "%s ", &achModifier[3]);
|
|
bNeedPlus = TRUE;
|
|
}
|
|
}
|
|
fprintf(pOut, "\n");
|
|
}
|
|
|
|
fprintf(pOut," }\n"
|
|
"};\n\n");
|
|
|
|
fprintf(pOut,"/***************************************************************************\\\n"
|
|
"*\n"
|
|
"* aVkToWch2[] - Virtual Key to WCHAR translation for 2 shift states\n"
|
|
"* aVkToWch3[] - Virtual Key to WCHAR translation for 3 shift states\n"
|
|
"* aVkToWch4[] - Virtual Key to WCHAR translation for 4 shift states\n");
|
|
|
|
for (idxSt = 5; idxSt < MaxSt; idxSt++) {
|
|
fprintf(pOut,
|
|
"* aVkToWch%d[] - Virtual Key to WCHAR translation for %d shift states\n",
|
|
idxSt, idxSt);
|
|
}
|
|
|
|
fprintf(pOut,"*\n"
|
|
"* Table attributes: Unordered Scan, null-terminated\n"
|
|
"*\n"
|
|
"* Search this table for an entry with a matching Virtual Key to find the\n"
|
|
"* corresponding unshifted and shifted WCHAR characters.\n"
|
|
"*\n"
|
|
"* Special values for VirtualKey (column 1)\n"
|
|
"* 0xff - dead chars for the previous entry\n"
|
|
"* 0 - terminate the list\n"
|
|
"*\n"
|
|
"* Special values for Attributes (column 2)\n"
|
|
"* CAPLOK bit - CAPS-LOCK affect this key like SHIFT\n"
|
|
"*\n"
|
|
"* Special values for wch[*] (column 3 & 4)\n"
|
|
"* WCH_NONE - No character\n"
|
|
"* WCH_DEAD - Dead Key (diaresis) or invalid (US keyboard has none)\n"
|
|
"* WCH_LGTR - Ligature (generates multiple characters)\n"
|
|
"*\n"
|
|
"\\***************************************************************************/\n\n");
|
|
|
|
for (idxSt = 2; idxSt <= nState; idxSt++) {
|
|
/*
|
|
* Quickly check if this table would actually be empty.
|
|
* An empty table (containing just zero terminator) is pointless.
|
|
* Also it will go into the .bss section, which we would have to merge
|
|
* into the .data section with a linker flag, else NT wouldn't load it
|
|
* (bug #120244 - IanJa)
|
|
*/
|
|
BOOL bEmpty;
|
|
|
|
bEmpty = TRUE;
|
|
if (idxSt == 2) {
|
|
// Special case for TAB ADD DIVIDE MULTIPLY SUBTRACT (below)
|
|
bEmpty = FALSE;
|
|
} else {
|
|
for (j = 0; j < NUMSCVK; j++) {
|
|
if (Layout[j].nState == idxSt) {
|
|
bEmpty = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (bEmpty) {
|
|
fprintf(stderr, "\ntable %d is empty\n", idxSt);
|
|
dwEmptyTables |= (1 << idxSt);
|
|
continue;
|
|
}
|
|
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA VK_TO_WCHARS%d aVkToWch%d[] = {\n"
|
|
"// | | Shift |"
|
|
,idxSt, idxSt);
|
|
|
|
for (j = 2; j < idxSt; j++) {
|
|
fprintf(pOut,"%-9.9s|", StateLabel[aiState[j]]);
|
|
}
|
|
|
|
fprintf(pOut,"\n// |=========|=========|");
|
|
for(j = 2; j < idxSt; j++) {
|
|
fprintf(pOut,"=========|");
|
|
}
|
|
fprintf(pOut,"\n");
|
|
|
|
for (j = 0; j < NUMSCVK; j++) {
|
|
if (idxSt != Layout[j].nState) {
|
|
continue;
|
|
}
|
|
fprintf(pOut," {%-13s,%-7s", \
|
|
getVKName(Layout[j].VKey, 1), Cap[Layout[j].Cap]);
|
|
|
|
*ExtraLine = '\0';
|
|
|
|
for (k = 0; k < idxSt; k++) {
|
|
if (pDeadKey != NULL && Layout[j].DKy[k] == 1) {
|
|
/*
|
|
* it is a dead key
|
|
*/
|
|
if (*ExtraLine == '\0') {
|
|
strcpy(ExtraLine, " {0xff ,0 ");
|
|
if (Layout[j].Cap != 2) {
|
|
/*
|
|
* Not SGCap
|
|
*/
|
|
for (m = 0; m < k; m++) {
|
|
strcat(ExtraLine, ",WCH_NONE ");
|
|
}
|
|
} else {
|
|
/*
|
|
* added for a new kbdCZ that has both SGCap and WCH_DEAD
|
|
*/
|
|
for (m = 0; m < k; m++ ) {
|
|
if (Layout[j].pSGCAP->WCh[m] == 0) {
|
|
strcat( ExtraLine, ",WCH_NONE " );
|
|
} else {
|
|
sprintf( Tmp, ",%-9s", WChName( Layout[j].pSGCAP->WCh[m], 0 ) );
|
|
strcat( ExtraLine, Tmp );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sprintf(Tmp,",%-9s", WChName(Layout[j].WCh[k], 0));
|
|
strcat(ExtraLine, Tmp);
|
|
fprintf(pOut,",WCH_DEAD ");
|
|
|
|
} else if(Layout[j].LKy[k] == 1) {
|
|
/*
|
|
* it is a ligature key
|
|
*/
|
|
if (pLigature == NULL) {
|
|
Error("Ligature entry with no LIGATURE table");
|
|
fclose(pOut);
|
|
return FAILURE;
|
|
}
|
|
fprintf(pOut,",WCH_LGTR ");
|
|
if (*ExtraLine != '\0') {
|
|
strcat(ExtraLine, ",WCH_NONE ");
|
|
}
|
|
} else {
|
|
fprintf(pOut,",%-9s", WChName(Layout[j].WCh[k], 0));
|
|
if (*ExtraLine != '\0') {
|
|
strcat(ExtraLine, ",WCH_NONE ");
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(pOut,"},\n");
|
|
|
|
if (*ExtraLine != '\0') {
|
|
fprintf(pOut,"%s},\n", ExtraLine);
|
|
continue; /* skip if WCH_DEAD */
|
|
}
|
|
|
|
/*
|
|
* skip if not SGCAP
|
|
*/
|
|
if (Layout[j].Cap != 2) {
|
|
continue;
|
|
}
|
|
|
|
if (Layout[j].pSGCAP == NULL) {
|
|
fclose(pOut);
|
|
Error("failed SGCAP error");
|
|
return FAILURE;
|
|
}
|
|
|
|
fprintf(pOut," {%-13s,0 ", getVKName(Layout[j].VKey, 1));
|
|
|
|
for (k = 0; k < Layout[j].pSGCAP->nState; k++) {
|
|
fprintf(pOut,",%-9s", WChName(Layout[j].pSGCAP->WCh[k], 0));
|
|
}
|
|
|
|
fprintf(pOut,"},\n");
|
|
|
|
free (Layout[j].pSGCAP);
|
|
}
|
|
|
|
/*
|
|
* These entries appear last to make VkKeyScan[Ex] results match
|
|
* Windows 95/98. See DRIVERS\KEYBOARD\WIN3.1\TAB4.INC (under
|
|
* \\redrum\w98slmRO\proj\dos\src)
|
|
*/
|
|
if (idxSt == 2) {
|
|
fprintf(pOut," {VK_TAB ,0 ,'\\t' ,'\\t' },\n"
|
|
" {VK_ADD ,0 ,'+' ,'+' },\n"
|
|
" {VK_DIVIDE ,0 ,'/' ,'/' },\n"
|
|
" {VK_MULTIPLY ,0 ,'*' ,'*' },\n"
|
|
" {VK_SUBTRACT ,0 ,'-' ,'-' },\n");
|
|
}
|
|
|
|
fprintf(pOut," {0 ,0 ");
|
|
for (k = 0; k < idxSt; k++) {
|
|
fprintf(pOut,",0 ");
|
|
}
|
|
fprintf(pOut,"}\n"
|
|
"};\n\n");
|
|
}
|
|
|
|
fprintf(pOut,"// Put this last so that VkKeyScan interprets number characters\n"
|
|
"// as coming from the main section of the kbd (aVkToWch2 and\n"
|
|
"// aVkToWch5) before considering the numpad (aVkToWch1).\n\n"
|
|
"static ALLOC_SECTION_LDATA VK_TO_WCHARS1 aVkToWch1[] = {\n"
|
|
" { VK_NUMPAD0 , 0 , '0' },\n"
|
|
" { VK_NUMPAD1 , 0 , '1' },\n"
|
|
" { VK_NUMPAD2 , 0 , '2' },\n"
|
|
" { VK_NUMPAD3 , 0 , '3' },\n"
|
|
" { VK_NUMPAD4 , 0 , '4' },\n"
|
|
" { VK_NUMPAD5 , 0 , '5' },\n"
|
|
" { VK_NUMPAD6 , 0 , '6' },\n"
|
|
" { VK_NUMPAD7 , 0 , '7' },\n"
|
|
" { VK_NUMPAD8 , 0 , '8' },\n"
|
|
" { VK_NUMPAD9 , 0 , '9' },\n"
|
|
" { 0 , 0 , '\\0' }\n"
|
|
"};\n\n");
|
|
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA VK_TO_WCHAR_TABLE aVkToWcharTable[] = {\n");
|
|
|
|
for (idxSt = 3; idxSt <= nState; idxSt++) {
|
|
if ((dwEmptyTables & (1 << idxSt)) == 0) {
|
|
fprintf(pOut,
|
|
" { (PVK_TO_WCHARS1)aVkToWch%d, %d, sizeof(aVkToWch%d[0]) },\n",
|
|
idxSt, idxSt, idxSt);
|
|
}
|
|
}
|
|
fprintf(pOut," { (PVK_TO_WCHARS1)aVkToWch2, 2, sizeof(aVkToWch2[0]) },\n"
|
|
" { (PVK_TO_WCHARS1)aVkToWch1, 1, sizeof(aVkToWch1[0]) },\n"
|
|
" { NULL, 0, 0 },\n"
|
|
"};\n\n");
|
|
|
|
fprintf(pOut,"/***************************************************************************\\\n"
|
|
"* aKeyNames[], aKeyNamesExt[] - Virtual Scancode to Key Name tables\n"
|
|
"*\n"
|
|
"* Table attributes: Ordered Scan (by scancode), null-terminated\n"
|
|
"*\n"
|
|
"* Only the names of Extended, NumPad, Dead and Non-Printable keys are here.\n"
|
|
"* (Keys producing printable characters are named by that character)\n"
|
|
"\\***************************************************************************/\n\n");
|
|
|
|
if (pKeyName != NULL) {
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA VSC_LPWSTR aKeyNames[] = {\n");
|
|
PrintNameTable(pOut, pKeyName, FALSE);
|
|
fprintf(pOut,"};\n\n");
|
|
}
|
|
|
|
if (pKeyNameExt != NULL) {
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA VSC_LPWSTR aKeyNamesExt[] = {\n");
|
|
PrintNameTable(pOut, pKeyNameExt, FALSE);
|
|
fprintf(pOut,"};\n\n");
|
|
}
|
|
|
|
if (pKeyNameDead != NULL) {
|
|
if (pDeadKey == NULL) {
|
|
fprintf(pOut,"/*** No dead key defined, dead key names ignored ! ***\\\n\n");
|
|
}
|
|
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA DEADKEY_LPWSTR aKeyNamesDead[] = {\n");
|
|
PrintNameTable(pOut, pKeyNameDead, TRUE);
|
|
fprintf(pOut,"};\n\n");
|
|
|
|
if(pDeadKey == NULL) {
|
|
fprintf(pOut,"\\*****************************************************/\n\n");
|
|
}
|
|
}
|
|
|
|
if (pDeadKey != NULL) {
|
|
PDEADKEY pDeadKeyTmp = pDeadKey;
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA DEADKEY aDeadKey[] = {\n");
|
|
while (pDeadKeyTmp != NULL) {
|
|
PDEADKEY pDeadKeyOld;
|
|
pDeadTrans = pDeadKeyTmp->pDeadTrans;
|
|
while (pDeadTrans != NULL) {
|
|
PDEADTRANS pDeadTransOld;
|
|
fprintf(pOut," DEADTRANS( ");
|
|
if (strlen(WChName(pDeadTrans->Base, 0)) == 3) {
|
|
fprintf(pOut,"L%-6s, ", WChName(pDeadTrans->Base, 0));
|
|
} else {
|
|
fprintf(pOut,"%-7s, ", WChName(pDeadTrans->Base, 0));
|
|
}
|
|
|
|
if (strlen(WChName(pDeadKeyTmp->Dead, 0)) == 3) {
|
|
fprintf(pOut,"L%-6s, ", WChName(pDeadKeyTmp->Dead, 0));
|
|
} else {
|
|
fprintf(pOut,"%-7s, ", WChName(pDeadKeyTmp->Dead, 0));
|
|
}
|
|
|
|
if (strlen(WChName(pDeadTrans->WChar, 0)) == 3) {
|
|
fprintf(pOut,"L%-6s, ", WChName(pDeadTrans->WChar, 0));
|
|
} else {
|
|
fprintf(pOut,"%-7s, ", WChName(pDeadTrans->WChar, 0));
|
|
}
|
|
fprintf(pOut,"0x%04x),\n", pDeadTrans->uFlags);
|
|
|
|
pDeadTransOld = pDeadTrans;
|
|
pDeadTrans = pDeadTrans->pNext;
|
|
free(pDeadTransOld);
|
|
}
|
|
fprintf(pOut,"\n");
|
|
|
|
pDeadKeyOld = pDeadKeyTmp;
|
|
pDeadKeyTmp = pDeadKeyTmp->pNext;
|
|
free(pDeadKeyOld);
|
|
}
|
|
|
|
fprintf(pOut," 0, 0\n");
|
|
fprintf(pOut,"};\n\n");
|
|
}
|
|
|
|
if (pLigature != NULL) {
|
|
PLIGATURE pLigatureTmp = pLigature;
|
|
fprintf(pOut,"static ALLOC_SECTION_LDATA LIGATURE%d aLigature[] = {\n", gMaxLigature);
|
|
while (pLigatureTmp != NULL) {
|
|
PLIGATURE pLigatureOld;
|
|
|
|
fprintf(pOut," {%-13s,%-7d", \
|
|
getVKName(pLigatureTmp->VKey, 1), pLigatureTmp->Mod);
|
|
|
|
for (k = 0; k < gMaxLigature; k++) {
|
|
if (k < pLigatureTmp->nCharacters) {
|
|
fprintf(pOut,",%-9s", WChName(pLigatureTmp->WCh[k], 0));
|
|
} else {
|
|
fprintf(pOut,",WCH_NONE ");
|
|
}
|
|
}
|
|
fprintf(pOut,"},\n");
|
|
|
|
pLigatureOld = pLigatureTmp;
|
|
pLigatureTmp = pLigatureTmp->pNext;
|
|
free(pLigatureOld);
|
|
}
|
|
fprintf(pOut," {%-13d,%-7d", 0, 0);
|
|
for (k = 0; k < gMaxLigature; k++) {
|
|
fprintf(pOut,",%-9d", 0);
|
|
}
|
|
fprintf(pOut,"}\n};\n\n");
|
|
}
|
|
|
|
if (!fallback_driver) {
|
|
fprintf(pOut, "static ");
|
|
}
|
|
fprintf(pOut,"ALLOC_SECTION_LDATA KBDTABLES KbdTables%s = {\n"
|
|
" /*\n"
|
|
" * Modifier keys\n"
|
|
" */\n"
|
|
" &CharModifiers,\n\n"
|
|
" /*\n"
|
|
" * Characters tables\n"
|
|
" */\n"
|
|
" aVkToWcharTable,\n\n"
|
|
" /*\n"
|
|
" * Diacritics\n"
|
|
" */\n",
|
|
fallback_driver ? "Fallback" : "");
|
|
|
|
if (pDeadKey != NULL) {
|
|
fprintf(pOut," aDeadKey,\n\n");
|
|
} else {
|
|
fprintf(pOut," NULL,\n\n");
|
|
}
|
|
|
|
fprintf(pOut," /*\n"
|
|
" * Names of Keys\n"
|
|
" */\n");
|
|
|
|
if (pKeyName != NULL) {
|
|
fprintf(pOut," aKeyNames,\n");
|
|
} else {
|
|
fprintf(pOut," NULL,\n");
|
|
}
|
|
|
|
if (pKeyNameExt != NULL) {
|
|
fprintf(pOut," aKeyNamesExt,\n");
|
|
} else {
|
|
fprintf(pOut," NULL,\n");
|
|
}
|
|
|
|
if (pDeadKey != NULL && pKeyNameDead != NULL) {
|
|
fprintf(pOut," aKeyNamesDead,\n\n");
|
|
} else {
|
|
fprintf(pOut," NULL,\n\n");
|
|
}
|
|
|
|
fprintf(pOut," /*\n"
|
|
" * Scan codes to Virtual Keys\n"
|
|
" */\n"
|
|
" ausVK,\n"
|
|
" sizeof(ausVK) / sizeof(ausVK[0]),\n"
|
|
" aE0VscToVk,\n"
|
|
" aE1VscToVk,\n\n"
|
|
" /*\n"
|
|
" * Locale-specific special processing\n"
|
|
" */\n");
|
|
|
|
|
|
if (MaxSt > 5) {
|
|
if (szAttrs[0] != '\0') {
|
|
strcat(szAttrs, " | ");
|
|
}
|
|
strcat(szAttrs, "KLLF_ALTGR");
|
|
} else if (szAttrs[0] == '\0') {
|
|
strcpy(szAttrs, "0");
|
|
}
|
|
|
|
fprintf(pOut," MAKELONG(%s, KBD_VERSION),\n\n", szAttrs);
|
|
|
|
fprintf(pOut," /*\n"
|
|
" * Ligatures\n"
|
|
" */\n"
|
|
" %d,\n", gMaxLigature);
|
|
if (pLigature != NULL) {
|
|
fprintf(pOut," sizeof(aLigature[0]),\n");
|
|
fprintf(pOut," (PLIGATURE1)aLigature\n");
|
|
} else {
|
|
fprintf(pOut," 0,\n");
|
|
fprintf(pOut," NULL\n");
|
|
}
|
|
|
|
fprintf(pOut, "};\n\n");
|
|
if (!fallback_driver) {
|
|
fprintf(pOut,"PKBDTABLES KbdLayerDescriptor(VOID)\n"
|
|
"{\n"
|
|
" return &KbdTables;\n"
|
|
"}\n");
|
|
|
|
}
|
|
fclose(pOut);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* read next (content-containing) line from input file
|
|
* Consumes lines the are empty, or contain just comments.
|
|
*
|
|
* Buf - contains the new line.
|
|
* (A nul character is inserted before any comment portion)
|
|
* cchBuf - provides number of characters in Buf
|
|
* gLineCount - Incremented for each line read (including skipped lines)
|
|
*
|
|
* Returns TRUE - if new line is returned in Buf
|
|
* FALSE - if end of file was reached
|
|
\*****************************************************************************/
|
|
|
|
BOOL NextLine(char *Buf, DWORD cchBuf, FILE *fIn)
|
|
{
|
|
char *p;
|
|
char *pComment;
|
|
|
|
while (fgets(Buf, cchBuf, fIn) != NULL) {
|
|
gLineCount++;
|
|
p = Buf;
|
|
|
|
// skip leading white spaces
|
|
while( *p && (*p == ' ' || *p == '\t')) {
|
|
p++;
|
|
}
|
|
|
|
if (*p == ';') {
|
|
// This line is purely comment, so skip it
|
|
continue;
|
|
}
|
|
|
|
if ((pComment = strstr(p, "//")) != NULL) {
|
|
if (pComment == p) {
|
|
// This line is purely comment, so skip it
|
|
continue;
|
|
}
|
|
|
|
// separate comment portion from content-containing portion
|
|
*pComment = '\0';
|
|
|
|
} else {
|
|
|
|
// remove newline at the end
|
|
if ((p = strchr(p, '\n')) != NULL) {
|
|
*p = '\0';
|
|
}
|
|
}
|
|
|
|
// We are returning a content-containing line
|
|
return TRUE;
|
|
}
|
|
|
|
// we reached the end of the file
|
|
return FALSE;
|
|
}
|
|
|
|
VOID __cdecl Error(const char *Text, ... )
|
|
{
|
|
char Temp[1024];
|
|
va_list valist;
|
|
|
|
va_start(valist, Text);
|
|
vsprintf(Temp,Text,valist);
|
|
printf("\n%s(%d): error : %s\n", gpszFileName, gLineCount, Temp);
|
|
va_end(valist);
|
|
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
ULONG __cdecl Warning(int nLine, const char *Text, ... )
|
|
{
|
|
char Temp[1024];
|
|
va_list valist;
|
|
|
|
if (nLine == 0) {
|
|
nLine = gLineCount;
|
|
}
|
|
va_start(valist, Text);
|
|
vsprintf(Temp,Text,valist);
|
|
printf("%s(%d): warning : %s\n", gpszFileName, nLine, Temp);
|
|
va_end(valist);
|
|
|
|
return 0;
|
|
}
|
|
|
|
VOID DumpLayoutEntry(PKEYLAYOUT pLayout)
|
|
{
|
|
printf("Scan %2x, VK %2x, VKDef %2x, Cap %d, nState %d, defined %x\n",
|
|
pLayout->Scan,
|
|
pLayout->VKey,
|
|
pLayout->VKeyDefault,
|
|
pLayout->Cap,
|
|
pLayout->nState,
|
|
pLayout->defined
|
|
);
|
|
printf("WCh[] = %x, %x, %x, %x, %x, %x, %x, %x, %x\n",
|
|
pLayout->WCh[0], pLayout->WCh[1],
|
|
pLayout->WCh[2], pLayout->WCh[3],
|
|
pLayout->WCh[4], pLayout->WCh[5],
|
|
pLayout->WCh[6], pLayout->WCh[7],
|
|
pLayout->WCh[8]);
|
|
printf("DKy[] = %x, %x, %x, %x, %x, %x, %x, %x, %x\n",
|
|
pLayout->DKy[0], pLayout->DKy[1],
|
|
pLayout->DKy[2], pLayout->DKy[3],
|
|
pLayout->DKy[4], pLayout->DKy[5],
|
|
pLayout->DKy[6], pLayout->DKy[7],
|
|
pLayout->DKy[8]);
|
|
printf("LKy[] = %x, %x, %x, %x, %x, %x, %x, %x, %x\n",
|
|
pLayout->LKy[0], pLayout->LKy[1],
|
|
pLayout->LKy[2], pLayout->LKy[3],
|
|
pLayout->LKy[4], pLayout->LKy[5],
|
|
pLayout->LKy[6], pLayout->LKy[7],
|
|
pLayout->LKy[8]);
|
|
printf("pSGCAP = %p\n", pLayout->pSGCAP);
|
|
printf("VKeyName = %s\n", pLayout->VKeyName);
|
|
}
|
|
|
|
|
|
/*
|
|
* Helper routine to make sure Backspace, Enter, Esc, Space and Cancel
|
|
* have the right characters.
|
|
* If they aren't defined by the input file, this is where we set their
|
|
* default values.
|
|
*/
|
|
BOOL MergeState(
|
|
KEYLAYOUT Layout[],
|
|
int Vk,
|
|
WCHAR wchUnshifted,
|
|
WCHAR wchShifted,
|
|
WCHAR wchCtrl,
|
|
int aiState[],
|
|
int nState)
|
|
{
|
|
static int idxCtrl = -1;
|
|
int idxSt, idx;
|
|
PKEYLAYOUT pLayout = NULL;
|
|
|
|
// which state is Ctrl?
|
|
if (idxCtrl == -1) {
|
|
for (idxSt = 0; idxSt < nState; idxSt++) {
|
|
if (aiState[idxSt] == KBDCTRL) {
|
|
idxCtrl = idxSt;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (idxCtrl == -1) {
|
|
Error("No Ctrl state");
|
|
}
|
|
|
|
// find the VK we want to merge
|
|
for (idx = 0; idx < NUMSCVK; idx++) {
|
|
if (Layout[idx].VKey == Vk) {
|
|
pLayout = &Layout[idx];
|
|
break;
|
|
}
|
|
}
|
|
if (pLayout == NULL) {
|
|
Error("No VK %2x state", Vk);
|
|
}
|
|
|
|
/*
|
|
* Now merge the default values in
|
|
*/
|
|
|
|
// printf("BEFORE ====================\n");
|
|
// DumpLayoutEntry(pLayout);
|
|
|
|
if (pLayout->WCh[0] == 0) {
|
|
pLayout->WCh[0] = wchUnshifted;
|
|
}
|
|
if (pLayout->WCh[1] == 0) {
|
|
pLayout->WCh[1] = wchShifted;
|
|
}
|
|
if (pLayout->WCh[idxCtrl] == 0) {
|
|
pLayout->WCh[idxCtrl] = wchCtrl;
|
|
}
|
|
|
|
// pad empty slots with WCH_NONE
|
|
for (idxSt = pLayout->nState; idxSt < idxCtrl; idxSt++) {
|
|
if (pLayout->WCh[idxSt] == 0) {
|
|
pLayout->WCh[idxSt] = -1; // WCH_NONE
|
|
}
|
|
}
|
|
if (pLayout->nState <= idxCtrl) {
|
|
pLayout->nState = idxCtrl + 1;
|
|
}
|
|
|
|
pLayout->defined = TRUE;
|
|
|
|
// printf("AFTER ===================\n");
|
|
// DumpLayoutEntry(pLayout);
|
|
// printf("=========================\n\n");
|
|
|
|
return TRUE;
|
|
}
|