static void Main(string[] args) { const string sBanner = "/*\r\n\r\n" + "This include file for Password Safe support of all keyboards supported\r\n" + "by Windows was created by the \"Password Safe - Keyboard Data Generator\" program\r\n" + "kblgen V{0} on a Windows 7 64-bit RC system with all keyboard layouts installed on\r\n" + "{1:u}.\r\n\r\n" + "The \"Password Safe - Keyboard Data Generator\" program is a modified version of\r\n" + "code published by Michael Kaplan in his series of MSDN Blogs \"Sorting it all Out,\r\n" + "Getting all you can out of a keyboard layout\" (Part 0 to Part 9b) between \r\n" + "March 23 and April 13, 2006.\r\n\r\n" + "See http://blogs.msdn.com/michkap/archive/2006/04/13/575500.aspx\r\n\r\n" + " *** PLEASE DO NOT EDIT THIS FILE DIRECTLY ***\r\n\r\n" + "*/\r\n"; string version = Application.ProductVersion; List<kbd_layout> kbd_layout_list = new List<kbd_layout>(); GetKeyboardsOnMachine(ref kbd_layout_list); int cKeyboards = GetKeyboardLayoutList(0, null); IntPtr[] rghkl = new IntPtr[cKeyboards]; GetKeyboardLayoutList(cKeyboards, rghkl); DateTime dateTime = DateTime.Now; CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture; TextInfo textInfo = cultureInfo.TextInfo; List<string> Char_List = new List<string>(); List<int> Char_Use_Count = new List<int>(); List<string> Multi2Char_List = new List<string>(); List<int> Multi2Char_Use_Count = new List<int>(); List<string> Multi3Char_List = new List<string>(); List<int> Multi3Char_Use_Count = new List<int>(); List<string> Multi4Char_List = new List<string>(); List<int> Multi4Char_Use_Count = new List<int>(); List<char> DeadKey_List = new List<char>(); List<int> DeadKey_Use_Count = new List<int>(); List<string> KLID_Exclude_List = new List<string>(); // The first four handled specially via XML KLID_Exclude_List.Add("00000404"); // Chinese (Simplified) KLID_Exclude_List.Add("00000411"); // Japanese KLID_Exclude_List.Add("00000412"); // Korean KLID_Exclude_List.Add("00000804"); // Chinese (Traditional) // Can't display characters using MS Arial Unicode font KLID_Exclude_List.Add("0000045A"); // Syriac KLID_Exclude_List.Add("00000465"); // Divehi Phonetic KLID_Exclude_List.Add("00010465"); // Divehi Typewriter // Not shown on MS web page of Keyboard Layouts (although in Vista/Windows 7) KLID_Exclude_List.Add("0000042F"); // Macedonian (Fyrom) KLID_Exclude_List.Add("0000044C"); // Malayalam KLID_Exclude_List.Add("0000044D"); // Assamese - INSCRIPT KLID_Exclude_List.Add("00000453"); // Khmer KLID_Exclude_List.Add("00000454"); // Lao KLID_Exclude_List.Add("0000045B"); // Sinhala KLID_Exclude_List.Add("00000461"); // Nepali KLID_Exclude_List.Add("00000463"); // Pashto (Afghanistan) KLID_Exclude_List.Add("0000046D"); // Bashkir KLID_Exclude_List.Add("0000046E"); // Luxembourgish KLID_Exclude_List.Add("0000046F"); // Greenlandic KLID_Exclude_List.Add("00000480"); // Uighur KLID_Exclude_List.Add("00000485"); // Yakut KLID_Exclude_List.Add("00000850"); // Mongolian (Mongolian Script) KLID_Exclude_List.Add("0000085D"); // Inuktitut - Latin KLID_Exclude_List.Add("00010416"); // Portuguese (Brazilian Abnt2) KLID_Exclude_List.Add("0001042E"); // Sorbian Extended KLID_Exclude_List.Add("0001042F"); // Macedonian (Fyrom) - Standard KLID_Exclude_List.Add("0001045A"); // Syriac Phonetic KLID_Exclude_List.Add("0001045B"); // Sinhala - wij KLID_Exclude_List.Add("0001045D"); // Inuktitut - Naqittaut KLID_Exclude_List.Add("00010401"); // Arabic (102) KLID_Exclude_List.Add("00020401"); // Arabic (102) AZERTY KLID_Exclude_List.Add("00020402"); // Bulgarian (Phonetic Layout) // Others KLID_Exclude_List.Add("0000043A"); // Maltese 47-Key KLID_Exclude_List.Add("0001043A"); // Maltese 48-Key KLID_Exclude_List.Add("00000451"); // Tibetan (Prc) KLID_Exclude_List.Add("00000C04"); // Chinese (Traditional, Hong Kong S.A.R.) - US Keyboard KLID_Exclude_List.Add("00001004"); // Chinese (Simplified, Singapore) - US Keyboard KLID_Exclude_List.Add("00001404"); // Chinese (Traditional, Macao S.A.R.) - Us Keyboard // Don't support Dvorak keyboard KLID_Exclude_List.Add("00010409"); // United States-Dvorak KLID_Exclude_List.Add("00030409"); // United States-Dvorak for left hand KLID_Exclude_List.Add("00040409"); // United States-Dvorak for right hand KLID_Exclude_List.Add("00050409"); // US English Table for IBM Arabic 238_L const int IDS_PHYSICAL = 8200; const int IDS_BASE = IDS_PHYSICAL + 1; string strKorean = "00000000"; string strJapanese = "00000000"; int max_rows = 0; int iCountMain = 0; int iCount = 0; int inumKLID2MC2 = 0; int inumKLID2MC3 = 0; int inumKLID2MC4 = 0; int iCountMC2 = 0; int iCountMC3 = 0; int iCountMC4 = 0; int iCountDK = -1; int iMC2_Offset = -1; int iMC3_Offset = -1; int iMC4_Offset = -1; int iDK_Offset = -1; // Initialise Char_List with most used entry // NOTE: This MUST be the first entry as offset == 0 is used in the DLL // to determine is there are any valid characters to be displayed in // this quartet int iOffset = 0; Char_List.Add(" 0x0000, 0x0000, 0x0000, 0x0000"); Char_Use_Count.Add(0); StreamWriter sw_log = new StreamWriter("log.txt"); StreamWriter sw_OSK_KLID2VKBDX_Table = new StreamWriter("OSK_KLID2VKBDX_Table.inc"); sw_OSK_KLID2VKBDX_Table.WriteLine(sBanner, version, dateTime); string Cmd_arg = ""; bool bAll = false, bXML_Only = false; sw_OSK_KLID2VKBDX_Table.WriteLine("static const st_IKLID2VKBD IKLID2VKBD[] = {"); if (args.Length > 0) { Cmd_arg = args[0].ToUpper(); if (Cmd_arg.CompareTo("ALL") == 0) bAll = true; else if (Cmd_arg.CompareTo("XML-ONLY") == 0) { bXML_Only = true; kbd_layout_list.Clear(); } } if (Cmd_arg.Length > 0 && !bAll && !bXML_Only) { sw_OSK_KLID2VKBDX_Table.WriteLine(" {{0x{0}, &VKBD_{0}}}, // {1,4}", Cmd_arg, iCountMain); iCountMain++; } else { int i = -1; foreach (kbd_layout kbl in kbd_layout_list) { i++; // Exclude Dvorak keyboard or those requiring an IME + a few others // Unless command argument 'all' specified if (!bAll && KLID_Exclude_List.Contains(kbl.Key)) continue; sw_OSK_KLID2VKBDX_Table.WriteLine(" {{0x{0}, &VKBD_{0}}}, // {1,4}", kbl.Key, iCountMain); iCountMain++; } } StreamWriter sw_OSK_KB_Data = new StreamWriter("OSK_KB_Data.inc"); sw_OSK_KB_Data.WriteLine(sBanner, version, dateTime); StreamWriter sw_OSK_KB_KLID2SCSS2MC2Data = new StreamWriter("OSK_KB_KLID2SCSS2MC2Data.inc"); sw_OSK_KB_KLID2SCSS2MC2Data.WriteLine(sBanner, version, dateTime); StreamWriter sw_OSK_KB_KLID2SCSS2MC3Data = new StreamWriter("OSK_KB_KLID2SCSS2MC3Data.inc"); sw_OSK_KB_KLID2SCSS2MC3Data.WriteLine(sBanner, version, dateTime); StreamWriter sw_OSK_KB_KLID2SCSS2MC4Data = new StreamWriter("OSK_KB_KLID2SCSS2MC4Data.inc"); sw_OSK_KB_KLID2SCSS2MC4Data.WriteLine(sBanner, version, dateTime); StreamWriter sw_OSK_KB_SCSS2MC2Data = new StreamWriter("OSK_KB_SCSS2MC2Data.inc"); sw_OSK_KB_SCSS2MC2Data.WriteLine(sBanner, version, dateTime); StreamWriter sw_OSK_KB_SCSS2MC3Data = new StreamWriter("OSK_KB_SCSS2MC3Data.inc"); sw_OSK_KB_SCSS2MC3Data.WriteLine(sBanner, version, dateTime); StreamWriter sw_OSK_KB_SCSS2MC4Data = new StreamWriter("OSK_KB_SCSS2MC4Data.inc"); sw_OSK_KB_SCSS2MC4Data.WriteLine(sBanner, version, dateTime); StreamWriter sw_OSK_Define_DeadKey_DataMaps = new StreamWriter("OSK_Define_DeadKey_DataMaps.inc"); sw_OSK_Define_DeadKey_DataMaps.WriteLine(sBanner, version, dateTime); StreamWriter sw_OSK_Insert_DeadKey_DataMaps = new StreamWriter("OSK_Insert_DeadKey_DataMaps.inc"); sw_OSK_Insert_DeadKey_DataMaps.WriteLine(sBanner, version, dateTime); StreamWriter sw_OSK_DeadKey_Data = new StreamWriter("OSK_DeadKey_Data.inc"); sw_OSK_DeadKey_Data.WriteLine(sBanner, version, dateTime); StreamWriter sw_VKresource = new StreamWriter("VKresource3.inc"); sw_VKresource.WriteLine(sBanner, version, dateTime); sw_VKresource.WriteLine("#define IDS_VKB_PHYSICAL {0,4}\r\n", IDS_PHYSICAL); sw_VKresource.WriteLine("#define IDS_VKB_BASE {0,4}\r\n", IDS_PHYSICAL + 1); StreamWriter sw_VKPasswordSafe3 = new StreamWriter("VKPasswordSafe3.inc"); sw_VKPasswordSafe3.WriteLine(sBanner, version, dateTime); sw_OSK_KB_KLID2SCSS2MC2Data.WriteLine("\r\nstatic const st_IKLID2SCSS2MC MC2[] = {"); sw_OSK_KB_KLID2SCSS2MC3Data.WriteLine("\r\nstatic const st_IKLID2SCSS2MC MC3[] = {"); sw_OSK_KB_KLID2SCSS2MC4Data.WriteLine("\r\nstatic const st_IKLID2SCSS2MC MC4[] = {"); foreach (kbd_layout kbl in kbd_layout_list) { if (!bAll && Cmd_arg.Length > 0 && Cmd_arg != kbl.Key) { continue; } else { // Don't include excluded keyboards if (!bAll && KLID_Exclude_List.Contains(kbl.Key)) continue; } IntPtr hkl = LoadKeyboardLayout(kbl.Key, KLF_NOTELLSHELL); if (iCount % 10 == 0) sw_VKPasswordSafe3.WriteLine("\r\nSTRINGTABLE\r\nBEGIN"); if (iCount == 0) sw_VKPasswordSafe3.WriteLine(" IDS_VKB_PHYSICAL \"- Physical -\""); Console.WriteLine("Processing Keyboard Layout - {0}:{1}", kbl.Key, kbl.Name); sw_log.WriteLine("Processing Keyboard Layout - {0}:{1}", kbl.Key, kbl.Name); sw_OSK_KB_Data.WriteLine("// Keyboard Layouts - {0}:{1}", kbl.Key, kbl.Name); sw_OSK_KB_Data.WriteLine("static st_IVKBD VKBD_{0} = {{", kbl.Key); int ires = IDS_BASE + iCount; sw_VKresource.WriteLine("#define IDS_VKB_{0} {1,4}", kbl.Key, ires); sw_VKPasswordSafe3.WriteLine(" IDS_VKB_{0} \"{1}\"", kbl.Key, kbl.Name); iCount++; if (iCount % 10 == 0) sw_VKPasswordSafe3.WriteLine("END"); Loader.RCtrlVk = KeysEx.None; KeysEx[] lpKeyState = new KeysEx[256]; VirtualKey[] rgKey = new VirtualKey[256]; List<DeadKey> alDead = new List<DeadKey>(); // Scroll through the Scan Code (SC) values and get the valid Virtual Key (VK) // values in it. Then, store the SC in each valid VK so it can act as both a // flag that the VK is valid, and it can store the SC value. for (uint sc = 0x01; sc <= 0x7f; sc++) { VirtualKey key = new VirtualKey(hkl, sc); if (key.VK != 0) { rgKey[(uint)key.VK] = key; } } // add the special keys that do not get added from the code above for (KeysEx ke = KeysEx.VK_NUMPAD0; ke <= KeysEx.VK_NUMPAD9; ke++) { rgKey[(uint)ke] = new VirtualKey(hkl, ke); } rgKey[(uint)KeysEx.VK_DIVIDE] = new VirtualKey(hkl, KeysEx.VK_DIVIDE); rgKey[(uint)KeysEx.VK_CANCEL] = new VirtualKey(hkl, KeysEx.VK_CANCEL); rgKey[(uint)KeysEx.VK_DECIMAL] = new VirtualKey(hkl, KeysEx.VK_DECIMAL); // See if there is a special shift state added for (KeysEx vk = KeysEx.None; vk <= KeysEx.VK_OEM_CLEAR; vk++) { uint sc = VirtualKey.MapVirtualKeyEx((uint)vk, 0, hkl); uint vkL = VirtualKey.MapVirtualKeyEx(sc, 1, hkl); uint vkR = VirtualKey.MapVirtualKeyEx(sc, 3, hkl); if ((vkL != vkR) && ((uint)vk != vkL)) { switch (vk) { case KeysEx.VK_LCONTROL: case KeysEx.VK_RCONTROL: case KeysEx.VK_LSHIFT: case KeysEx.VK_RSHIFT: case KeysEx.VK_LMENU: case KeysEx.VK_RMENU: break; default: Loader.RCtrlVk = vk; break; } } } for (uint iKey = 0; iKey < rgKey.Length; iKey++) { if (rgKey[iKey] != null) { StringBuilder sbBuffer; // Scratchpad we use many places for (ShiftState ss = ShiftState.Base; ss <= Loader.MaxShiftState; ss++) { if (ss == ShiftState.Menu || ss == ShiftState.ShftMenu) { // Alt and Shift+Alt don't work, so skip them continue; } for (int caps = 0; caps <= 1; caps++) { ClearKeyboardBuffer((uint)KeysEx.VK_DECIMAL, rgKey[(uint)KeysEx.VK_DECIMAL].SC, hkl); FillKeyState(lpKeyState, ss, (caps!= 0)); sbBuffer = new StringBuilder(10); int rc = ToUnicodeEx((uint)rgKey[iKey].VK, rgKey[iKey].SC, lpKeyState, sbBuffer, sbBuffer.Capacity, 0, hkl); if (rc > 0) { if (sbBuffer.Length == 0) { // Someone defined NULL on the keyboard; let's coddle them rgKey[iKey].SetShiftState(ss, "\u0000", false, (caps != 0)); } else { if ((rc == 1) && (ss == ShiftState.LCtrl || ss == ShiftState.ShftLCtrl) && ((int)rgKey[iKey].VK == ((uint)sbBuffer[0] + 0x40))) { // ToUnicodeEx has an internal knowledge about those // VK_A ~ VK_Z keys to produce the control characters, // when the conversion rule is not provided in keyboard // layout files continue; } rgKey[iKey].SetShiftState(ss, sbBuffer.ToString().Substring(0, rc), false, (caps != 0)); } } else if (rc < 0) { rgKey[iKey].SetShiftState(ss, sbBuffer.ToString().Substring(0, 1), true, (caps != 0)); // It's a dead key; let's flush out whats stored in the keyboard state. ClearKeyboardBuffer((uint)KeysEx.VK_DECIMAL, rgKey[(uint)KeysEx.VK_DECIMAL].SC, hkl); DeadKey dk = null; for (int iDead = 0; iDead < alDead.Count; iDead++) { dk = (DeadKey)alDead[iDead]; if (dk.DeadCharacter == rgKey[iKey].GetShiftState(ss, caps != 0)[0]) { break; } dk = null; } if (dk == null) { alDead.Add(ProcessDeadKey(iKey, ss, lpKeyState, rgKey, caps == 1, hkl)); } } } } } } foreach (IntPtr i in rghkl) { if (hkl == i) { hkl = IntPtr.Zero; break; } } if (hkl != IntPtr.Zero) { UnloadKeyboardLayout(hkl); } // Okay, now we can dump the layout int numrows = 0; int inumMC2 = 0; int inumMC3 = 0; int inumMC4 = 0; for (uint iKey = 0; iKey < rgKey.Length; iKey++) { if (rgKey[iKey] == null || rgKey[iKey].IsEmpty || rgKey[iKey].VK == KeysEx.VK_CANCEL || rgKey[iKey].VK == KeysEx.VK_BACK || rgKey[iKey].VK == KeysEx.VK_TAB || rgKey[iKey].VK == KeysEx.VK_RETURN || rgKey[iKey].VK == KeysEx.VK_ESCAPE || rgKey[iKey].VK == KeysEx.VK_MULTIPLY || rgKey[iKey].VK == KeysEx.VK_ADD || rgKey[iKey].VK == KeysEx.VK_SUBTRACT || rgKey[iKey].VK == KeysEx.VK_DECIMAL || rgKey[iKey].VK == KeysEx.VK_DIVIDE || (rgKey[iKey].VK >= KeysEx.VK_NUMPAD0 && rgKey[iKey].VK <= KeysEx.VK_NUMPAD9)) { continue; } numrows++; } max_rows = max_rows > numrows ? max_rows : numrows; sw_OSK_KB_Data.Write(" {0}, {1}", ires, numrows); for (uint iKey = 0; iKey < rgKey.Length; iKey++) { if (rgKey[iKey] == null || rgKey[iKey].IsEmpty || rgKey[iKey].VK == KeysEx.VK_CANCEL || rgKey[iKey].VK == KeysEx.VK_BACK || rgKey[iKey].VK == KeysEx.VK_TAB || rgKey[iKey].VK == KeysEx.VK_RETURN || rgKey[iKey].VK == KeysEx.VK_ESCAPE || rgKey[iKey].VK == KeysEx.VK_MULTIPLY || rgKey[iKey].VK == KeysEx.VK_ADD || rgKey[iKey].VK == KeysEx.VK_SUBTRACT || rgKey[iKey].VK == KeysEx.VK_DECIMAL || rgKey[iKey].VK == KeysEx.VK_DIVIDE || (rgKey[iKey].VK >= KeysEx.VK_NUMPAD0 && rgKey[iKey].VK <= KeysEx.VK_NUMPAD9)) { continue; } else { int ichar1, ichar2, ichar3, ichar4; string header = rgKey[iKey].GetRowHeader; string chars1 = rgKey[iKey].Get_Standard_Chars1; ichar1 = Char_List.IndexOf(chars1); if (ichar1 == -1) { Char_List.Add(chars1); iOffset++; ichar1 = iOffset; Char_Use_Count.Add(1); } else Char_Use_Count[ichar1] = Char_Use_Count[ichar1] + 1; string chars2 = rgKey[iKey].Get_Standard_Chars2; ichar2 = Char_List.IndexOf(chars2); if (ichar2 == -1) { Char_List.Add(chars2); iOffset++; ichar2 = iOffset; Char_Use_Count.Add(1); } else Char_Use_Count[ichar2] = Char_Use_Count[ichar2] + 1; string chars3 = rgKey[iKey].Get_Standard_Chars3; ichar3 = Char_List.IndexOf(chars3); if (ichar3 == -1) { Char_List.Add(chars3); iOffset++; ichar3 = iOffset; Char_Use_Count.Add(1); } else Char_Use_Count[ichar3] = Char_Use_Count[ichar3] + 1; string chars4 = rgKey[iKey].Get_Standard_Chars4; ichar4 = Char_List.IndexOf(chars4); if (ichar4 == -1) { Char_List.Add(chars4); iOffset++; ichar4 = iOffset; Char_Use_Count.Add(1); } else Char_Use_Count[ichar4] = Char_Use_Count[ichar4] + 1; if (rgKey[iKey].Get_Multi_Chars_Count > 0) { List<st_multi_chars> Multi_Chars_List = rgKey[iKey].Get_Multi_Chars_List; for (int i = 0; i < Multi_Chars_List.Count; i++) { int index; switch (Multi_Chars_List[i].num) { case 2: if (inumMC2 == 0) { sw_OSK_KB_KLID2SCSS2MC2Data.WriteLine(" {{ 0x{0}, &vctSCSS2MC2_{0} }}, // {1,4}", kbl.Key, inumKLID2MC2); sw_OSK_KB_SCSS2MC2Data.WriteLine("\r\nstatic const st_SCSS2Offset dtaSCSS2MC2_{0}[] = {{", kbl.Key); inumKLID2MC2++; } index = Multi2Char_List.IndexOf(Multi_Chars_List[i].mchars); if (index == -1) { Multi2Char_List.Add(Multi_Chars_List[i].mchars); iMC2_Offset++; index = iMC2_Offset; iCountMC2++; Multi2Char_Use_Count.Add(1); } else { Multi2Char_Use_Count[index] = Multi2Char_Use_Count[index] + 1; } sw_OSK_KB_SCSS2MC2Data.WriteLine(" {{ 0x{0:x4}, {1,3} }}, // {2,4}", Multi_Chars_List[i].scss, index, inumMC2); inumMC2++; break; case 3: if (inumMC3 == 0) { sw_OSK_KB_KLID2SCSS2MC3Data.WriteLine(" {{ 0x{0}, &vctSCSS2MC3_{0} }}, // {1,4}", kbl.Key, inumKLID2MC3); sw_OSK_KB_SCSS2MC3Data.WriteLine("\r\nstatic const st_SCSS2Offset dtaSCSS2MC3_{0}[] = {{", kbl.Key); inumKLID2MC3++; } index = Multi3Char_List.IndexOf(Multi_Chars_List[i].mchars); if (index == -1) { Multi3Char_List.Add(Multi_Chars_List[i].mchars); iMC3_Offset++; index = iMC3_Offset; iCountMC3++; Multi3Char_Use_Count.Add(1); } else { Multi3Char_Use_Count[index] = Multi3Char_Use_Count[index] + 1; } sw_OSK_KB_SCSS2MC3Data.WriteLine(" {{ 0x{0:x4}, {1,3} }}, // {2,4}", Multi_Chars_List[i].scss, index, inumMC3); inumMC3++; break; case 4: if (inumMC4 == 0) { sw_OSK_KB_KLID2SCSS2MC4Data.WriteLine(" {{ 0x{0}, &vctSCSS2MC4_{0} }}, // {1,4}", kbl.Key, inumKLID2MC4); sw_OSK_KB_SCSS2MC4Data.WriteLine("\r\nstatic const st_SCSS2Offset dtaSCSS2MC4_{0}[] = {{", kbl.Key); inumKLID2MC4++; } index = Multi4Char_List.IndexOf(Multi_Chars_List[i].mchars); if (index == -1) { Multi4Char_List.Add(Multi_Chars_List[i].mchars); iMC4_Offset++; index = iMC4_Offset; iCountMC4++; Multi4Char_Use_Count.Add(1); } else { Multi4Char_Use_Count[index] = Multi4Char_Use_Count[index] + 1; } sw_OSK_KB_SCSS2MC4Data.WriteLine(" {{ 0x{0:x4}, {1,3} }}, // {2,4}", Multi_Chars_List[i].scss, index, inumMC4); inumMC4++; break; } } } sw_OSK_KB_Data.Write(",\r\n {0} {1,4}, {2,4}, {3,4}, {4,4}", header, ichar1, ichar2, ichar3, ichar4); } } if (inumMC2 > 0) { sw_OSK_KB_SCSS2MC2Data.WriteLine("};\r\n"); sw_OSK_KB_SCSS2MC2Data.WriteLine("static const Vct_ISCSS2MC vctSCSS2MC2_{0}(dtaSCSS2MC2_{0},", kbl.Key); sw_OSK_KB_SCSS2MC2Data.Write(" "); sw_OSK_KB_SCSS2MC2Data.WriteLine("dtaSCSS2MC2_{0} + {1});", kbl.Key, inumMC2); } if (inumMC3 > 0) { sw_OSK_KB_SCSS2MC3Data.WriteLine("};\r\n"); sw_OSK_KB_SCSS2MC3Data.WriteLine("static const Vct_ISCSS2MC vctSCSS2MC3_{0}(dtaSCSS2MC3_{0},", kbl.Key); sw_OSK_KB_SCSS2MC3Data.Write(" "); sw_OSK_KB_SCSS2MC3Data.WriteLine("dtaSCSS2MC3_{0} + {1});", kbl.Key, inumMC3); } if (inumMC4 > 0) { sw_OSK_KB_SCSS2MC4Data.WriteLine("};\r\n"); sw_OSK_KB_SCSS2MC4Data.WriteLine("static const Vct_ISCSS2MC vctSCSS2MC4_{0}(dtaSCSS2MC4_{0},", kbl.Key); sw_OSK_KB_SCSS2MC4Data.Write(" "); sw_OSK_KB_SCSS2MC4Data.WriteLine("dtaSCSS2MC4_{0} + {1});", kbl.Key, inumMC4); } if (alDead.Count > 0) { sw_OSK_Define_DeadKey_DataMaps.WriteLine(" static Map_IDK2SCSSCC m_map_IDK2SCSSCC_{0};", kbl.Key); } bool bFirst = alDead.Count > 0; foreach (DeadKey dk in alDead) { if (bFirst) { sw_OSK_DeadKey_Data.WriteLine("\r\n//\r\n// Keyboard {0} - {1} deadkeys\r\n//", kbl.Key, kbl.Name); sw_OSK_Insert_DeadKey_DataMaps.WriteLine("\r\n m_mapIKLID2DK2SCSSCC.insert(std::make_pair(0x{0}, &m_map_IDK2SCSSCC_{0}));", kbl.Key); bFirst = false; } char wcdk; int index; uint scss = 0; // Initialise enumerator dk.GetDeadKeyInfo(ref scss, out wcdk); sw_OSK_DeadKey_Data.WriteLine("\r\n// Deadkey 0x{0:x4}", ((ushort)dk.DeadCharacter).ToString("x4")); sw_OSK_DeadKey_Data.WriteLine("static const st_IDKSCSS2Offset dtaDeadkey_{0}_x{1}[{2}] = {{", kbl.Key, ((ushort)dk.DeadCharacter).ToString("x4"), dk.Count); int inumDK = 0; for (int id = 0; id < dk.Count; id++) { scss = 1; dk.GetDeadKeyInfo(ref scss, out wcdk); if (scss == 0) continue; iCountDK++; index = DeadKey_List.IndexOf(wcdk); if (index == -1) { DeadKey_List.Add(wcdk); iDK_Offset++; index = iDK_Offset; DeadKey_Use_Count.Add(1); } else { DeadKey_Use_Count[index] = DeadKey_Use_Count[index] + 1; } byte sc = (byte)((scss & 0xFF00) >> 8); byte ss = (byte)(scss & 0xFF); sw_OSK_DeadKey_Data.WriteLine(" {{ 0x{0:x2}, 0x{1:x2}, {2,4} }}, // {3,4}", sc, ss, index, inumDK++); } sw_OSK_DeadKey_Data.WriteLine("};\r\n"); sw_OSK_DeadKey_Data.WriteLine("static const Vct_IDeadkeys vctDeadkey_{0}_x{1}(dtaDeadkey_{0}_x{1},", kbl.Key, ((ushort)dk.DeadCharacter).ToString("x4")); sw_OSK_DeadKey_Data.Write(" "); sw_OSK_DeadKey_Data.WriteLine("dtaDeadkey_{0}_x{1} + {2});", kbl.Key, ((ushort)dk.DeadCharacter).ToString("x4"), dk.Count); sw_OSK_Insert_DeadKey_DataMaps.WriteLine(" m_map_IDK2SCSSCC_{0}.insert(std::make_pair(0x{1:x4}, &vctDeadkey_{0}_x{1}));", kbl.Key, ((ushort)dk.DeadCharacter).ToString("x4")); } sw_OSK_KB_Data.WriteLine("\r\n};"); sw_OSK_KB_Data.WriteLine(); } // If caller specified a KLID - don't do XML as well if (Cmd_arg.Length > 0 && !bAll && !bXML_Only) goto finish_up; // Process XML Custom keyboards // Expects 2 files in this executable's directory: // user_keyboard.xml and user_keyboards.xsd // See these for details of their format if (!File.Exists("user_keyboards.xml") || !File.Exists("user_keyboards.xsd")) { sw_log.WriteLine("Either or both of the files 'user_keyboards.xml/xsd' are missing"); sw_log.WriteLine("No processing of User Keyboards via a XML file will be performed."); goto finish_up; } ProcessXML xml_vld = new ProcessXML("user_keyboards.xsd"); xml_vld.DoXML(true, "user_keyboards.xml"); if (xml_vld.Results.Count > 0) { sw_log.WriteLine("Processing User Keyboards input via XML file encountered errors:"); foreach (string res in xml_vld.Results) { sw_log.WriteLine("{0}", res); } } if (xml_vld.Results.Count == 0) { sw_log.WriteLine("Processing User Keyboards input via XML file:"); xml_vld.DoXML(false, "user_keyboards.xml"); foreach (st_XML_Keyboard xmlkbd in xml_vld.XMLKeyboards) { // Check unique kbd_layout kbl = new kbd_layout(); string sKey = xmlkbd.KLID.ToUpper(); string sName = xmlkbd.Name; if (kbd_layout_list.Exists(delegate(kbd_layout kblX) {return kblX.Key == sKey;})) { sw_log.WriteLine("Duplicate KLID '{0}' encountered. This keyboard has not been processed.", sKey); continue; } if (kbd_layout_list.Exists(delegate(kbd_layout kblX) {return kblX.Name == sName;})) { sw_log.WriteLine("Duplicate Keyboard Name '{0}' encountered. This keyboard has not been processed.", sName); continue; } kbl.Key = sKey; kbl.Name = sName; kbd_layout_list.Add(kbl); sw_OSK_KLID2VKBDX_Table.WriteLine(" {{0x{0}, &VKBD_{0}}}, // {1,4}", xmlkbd.KLID, iCountMain); iCountMain++; Console.WriteLine("Processing Keyboard Layout - {0}:{1}", xmlkbd.KLID, xmlkbd.Name); sw_log.WriteLine("Processing Keyboard Layout - {0}:{1}", xmlkbd.KLID, xmlkbd.Name); sw_OSK_KB_Data.WriteLine("// Keyboard Layouts - {0}:{1}", xmlkbd.KLID, xmlkbd.Name); sw_OSK_KB_Data.WriteLine("static st_IVKBD VKBD_{0} = {{", xmlkbd.KLID); int ires = IDS_BASE + iCount; sw_VKresource.WriteLine("#define IDS_VKB_{0} {1,4}", xmlkbd.KLID, ires); sw_VKPasswordSafe3.WriteLine(" IDS_VKB_{0} \"{1}\"", xmlkbd.KLID, xmlkbd.Name); // Remember 2 special keyboards for later if (xmlkbd.Name == "Korean") strKorean = xmlkbd.KLID; if (xmlkbd.Name == "Japanese") strJapanese = xmlkbd.KLID; iCount++; max_rows = max_rows > xmlkbd.KeyData.Count ? max_rows : xmlkbd.KeyData.Count; sw_OSK_KB_Data.Write(" {0}, {1}", ires, xmlkbd.KeyData.Count); for (int i = 0; i < xmlkbd.KeyData.Count; i++) { int ichar1, ichar2, ichar3, ichar4; ichar1 = Char_List.IndexOf(xmlkbd.KeyData[i].chars1); if (ichar1 == -1) { Char_List.Add(xmlkbd.KeyData[i].chars1); iOffset++; ichar1 = iOffset; Char_Use_Count.Add(1); } else Char_Use_Count[ichar1] = Char_Use_Count[ichar1] + 1; ichar2 = Char_List.IndexOf(xmlkbd.KeyData[i].chars2); if (ichar2 == -1) { Char_List.Add(xmlkbd.KeyData[i].chars2); iOffset++; ichar2 = iOffset; Char_Use_Count.Add(1); } else Char_Use_Count[ichar2] = Char_Use_Count[ichar2] + 1; ichar3 = Char_List.IndexOf(xmlkbd.KeyData[i].chars3); if (ichar3 == -1) { Char_List.Add(xmlkbd.KeyData[i].chars3); iOffset++; ichar3 = iOffset; Char_Use_Count.Add(1); } else Char_Use_Count[ichar3] = Char_Use_Count[ichar3] + 1; ichar4 = Char_List.IndexOf(xmlkbd.KeyData[i].chars4); if (ichar4 == -1) { Char_List.Add(xmlkbd.KeyData[i].chars4); iOffset++; ichar4 = iOffset; Char_Use_Count.Add(1); } else Char_Use_Count[ichar4] = Char_Use_Count[ichar4] + 1; sw_OSK_KB_Data.Write(",\r\n 0x" + xmlkbd.KeyData[i].sc + ", 0,"); sw_OSK_KB_Data.Write(" {0,4}, {1,4}, {2,4}, {3,4}", ichar1, ichar2, ichar3, ichar4); } sw_OSK_KB_Data.WriteLine("\r\n};"); sw_OSK_KB_Data.WriteLine(); } } finish_up: sw_OSK_KLID2VKBDX_Table.WriteLine("};"); if (iCountMC2 < 1) sw_OSK_KB_KLID2SCSS2MC2Data.WriteLine(" {0, NULL} // Dummy"); sw_OSK_KB_KLID2SCSS2MC2Data.WriteLine("};"); if (iCountMC3 < 1) sw_OSK_KB_KLID2SCSS2MC3Data.WriteLine(" {0, NULL} // Dummy"); sw_OSK_KB_KLID2SCSS2MC3Data.WriteLine("};"); if (iCountMC4 < 1) sw_OSK_KB_KLID2SCSS2MC4Data.WriteLine(" {0, NULL} // Dummy"); sw_OSK_KB_KLID2SCSS2MC4Data.WriteLine("};"); // Write out the standard and extended arrays sw_OSK_KB_Data.WriteLine("static const wchar_t wc_Chars[{0}][4] = {{", iOffset + 1); for (int i = 0; i < iOffset; i++) { sw_OSK_KB_Data.WriteLine(" {{{0}}}, // {1,4}; Use Count = {2,5}", Char_List[i], i, Char_Use_Count[i]); } if (iOffset > 0) sw_OSK_KB_Data.WriteLine(" {{{0}}} // {1,4}; Use Count = {2,5}", Char_List[iOffset], iOffset, Char_Use_Count[iOffset]); else sw_OSK_KB_Data.WriteLine(" {0, 0, 0, 0} // Dummy"); sw_OSK_KB_Data.WriteLine("};\r\n"); int isize; isize = (iMC2_Offset) < 0 ? 1 : (iMC2_Offset + 1); sw_OSK_KB_SCSS2MC2Data.WriteLine("\r\nstatic const wchar_t wcMC2[{0}][2] = {{", isize); if (Multi2Char_List.Count > 0) { for (int i = 0; i < iMC2_Offset; i++) { sw_OSK_KB_SCSS2MC2Data.WriteLine(" {{{0}}}, // {1,4}; Use Count = {2,3}", Multi2Char_List[i], i, Multi2Char_Use_Count[i]); } sw_OSK_KB_SCSS2MC2Data.WriteLine(" {{{0}}} // {1,4}; Use Count = {2,3}", Multi2Char_List[iMC2_Offset], iMC2_Offset, Multi2Char_Use_Count[iMC2_Offset]); } else { sw_OSK_KB_SCSS2MC2Data.WriteLine(" {0, 0} // Dummy"); } sw_OSK_KB_SCSS2MC2Data.WriteLine("};"); isize = (iMC3_Offset) < 0 ? 1 : (iMC3_Offset + 1); sw_OSK_KB_SCSS2MC3Data.WriteLine("\r\nstatic const wchar_t wcMC3[{0}][3] = {{", isize); if (Multi3Char_List.Count > 0) { for (int i = 0; i < iMC3_Offset; i++) { sw_OSK_KB_SCSS2MC3Data.WriteLine(" {{{0}}}, // {1,4}; Use Count = {2,3}", Multi3Char_List[i], i, Multi3Char_Use_Count[i]); } sw_OSK_KB_SCSS2MC3Data.WriteLine(" {{{0}}} // {1,4}; Use Count = {2,3}", Multi3Char_List[iMC3_Offset], iMC3_Offset, Multi3Char_Use_Count[iMC3_Offset]); } else { sw_OSK_KB_SCSS2MC3Data.WriteLine(" {0, 0, 0} // Dummy"); } sw_OSK_KB_SCSS2MC3Data.WriteLine("};"); isize = (iMC4_Offset) < 0 ? 1 : (iMC4_Offset + 1); sw_OSK_KB_SCSS2MC4Data.WriteLine("\r\nstatic const wchar_t wcMC4[{0}][4] = {{", isize); if (Multi4Char_List.Count > 0) { for (int i = 0; i < iMC4_Offset; i++) { sw_OSK_KB_SCSS2MC4Data.WriteLine(" {{{0}}}, // {1,4}; Use Count = {2,3}", Multi4Char_List[i], i, Multi4Char_Use_Count[i]); } sw_OSK_KB_SCSS2MC4Data.WriteLine(" {{{0}}} // {1,4}; Use Count = {2,3}", Multi4Char_List[iMC4_Offset], iMC4_Offset, Multi4Char_Use_Count[iMC4_Offset]); } else { sw_OSK_KB_SCSS2MC4Data.WriteLine(" {0, 0, 0, 0} // Dummy"); } sw_OSK_KB_SCSS2MC4Data.WriteLine("};"); isize = (iDK_Offset) < 0 ? 1 : (iDK_Offset + 1); sw_OSK_DeadKey_Data.WriteLine("\r\nstatic const wchar_t wcDK[{0}] = {{", isize); if (DeadKey_List.Count > 0) { for (int i = 0; i < iDK_Offset; i++) { sw_OSK_DeadKey_Data.WriteLine(" {{ 0x{0:x4} }}, // {1,4}; Use Count = {2,3}", ((ushort)DeadKey_List[i]).ToString("x4"), i, DeadKey_Use_Count[i]); } sw_OSK_DeadKey_Data.WriteLine(" {{ 0x{0:x4} }} // {1,4}; Use Count = {2,3}", ((ushort)DeadKey_List[iDK_Offset]).ToString("x4"), iDK_Offset, DeadKey_Use_Count[iDK_Offset]); } else { sw_OSK_DeadKey_Data.WriteLine(" {0} // Dummy"); } sw_OSK_DeadKey_Data.WriteLine("};"); StreamWriter sw_OSK_voskeys = new StreamWriter("OSK_voskeys.inc"); sw_OSK_voskeys.WriteLine(sBanner, version, dateTime); sw_OSK_voskeys.WriteLine("#define NUM_KEYBOARDS {0,4}", iCount); sw_OSK_voskeys.WriteLine("#define MAX_ROWS {0,4}", max_rows); sw_OSK_voskeys.WriteLine(); sw_OSK_voskeys.WriteLine("#define NUM_UNIQUE_SC {0,4}", iOffset + 1); sw_OSK_voskeys.WriteLine("#define NUM_UNIQUE_MC2 {0,4}", iMC2_Offset + 1); sw_OSK_voskeys.WriteLine("#define NUM_UNIQUE_MC3 {0,4}", iMC3_Offset + 1); sw_OSK_voskeys.WriteLine("#define NUM_UNIQUE_MC4 {0,4}", iMC4_Offset + 1); sw_OSK_voskeys.WriteLine("#define NUM_UNIQUE_DK {0,4}", iDK_Offset + 1); sw_OSK_voskeys.WriteLine(); sw_OSK_voskeys.WriteLine("#define NUM_MC2 {0,4}", inumKLID2MC2); sw_OSK_voskeys.WriteLine("#define NUM_MC3 {0,4}", inumKLID2MC3); sw_OSK_voskeys.WriteLine("#define NUM_MC4 {0,4}", inumKLID2MC4); sw_OSK_voskeys.WriteLine(); sw_OSK_voskeys.WriteLine("#define KOREAN_KBD 0x" + strKorean); sw_OSK_voskeys.WriteLine("#define JAPANESE_KBD 0x" + strJapanese); if (iCount % 10 != 0) sw_VKPasswordSafe3.WriteLine("END"); sw_VKresource.WriteLine(); // Close files sw_OSK_KLID2VKBDX_Table.Close(); sw_OSK_Define_DeadKey_DataMaps.Close(); sw_OSK_Insert_DeadKey_DataMaps.Close(); sw_OSK_DeadKey_Data.Close(); sw_OSK_voskeys.Close(); sw_OSK_KB_Data.Close(); sw_OSK_KB_KLID2SCSS2MC2Data.Close(); sw_OSK_KB_KLID2SCSS2MC3Data.Close(); sw_OSK_KB_KLID2SCSS2MC4Data.Close(); sw_OSK_KB_SCSS2MC2Data.Close(); sw_OSK_KB_SCSS2MC3Data.Close(); sw_OSK_KB_SCSS2MC4Data.Close(); sw_VKPasswordSafe3.Close(); sw_VKresource.Close(); sw_log.Close(); }
// The keyboard layout private static DeadKey ProcessDeadKey( uint iKeyDead, // The index into the VirtualKey of the dead key ShiftState shiftStateDead, // The shiftstate that contains the dead key KeysEx[] lpKeyStateDead, // The key state for the dead key VirtualKey[] rgKey, // Our array of dead keys bool fCapsLock, // Was the caps lock key pressed? IntPtr hkl) { KeysEx[] lpKeyState = new KeysEx[256]; DeadKey deadKey = new DeadKey(rgKey[iKeyDead].GetShiftState(shiftStateDead, fCapsLock)[0]); for (uint iKey = 0; iKey < rgKey.Length; iKey++) { if (rgKey[iKey] != null) { StringBuilder sbBuffer = new StringBuilder(10); // Scratchpad we use many places for (ShiftState ss = ShiftState.Base; ss <= Loader.MaxShiftState; ss++) { int rc = 0; if (ss == ShiftState.Menu || ss == ShiftState.ShftMenu) { // Alt and Shift+Alt don't work, so skip them continue; } for (int caps = 0; caps <= 1; caps++) { // First the dead key while (rc >= 0) { // We know that this is a dead key coming up, otherwise // this function would never have been called. If we do // *not* get a dead key then that means the state is // messed up so we run again and again to clear it up. // Risk is technically an infinite loop but per Hiroyama // that should be impossible here. rc = ToUnicodeEx((uint)rgKey[iKeyDead].VK, rgKey[iKeyDead].SC, lpKeyStateDead, sbBuffer, sbBuffer.Capacity, 0, hkl); } // Now fill the key state for the potential base character FillKeyState(lpKeyState, ss, (caps != 0)); sbBuffer = new StringBuilder(10); rc = ToUnicodeEx((uint)rgKey[iKey].VK, rgKey[iKey].SC, lpKeyState, sbBuffer, sbBuffer.Capacity, 0, hkl); if (rc == 1) { // That was indeed a base character for our dead key. // And we now have a composite character. Let's run // through one more time to get the actual base // character that made it all possible? char combchar = sbBuffer[0]; sbBuffer = new StringBuilder(10); rc = ToUnicodeEx((uint)rgKey[iKey].VK, rgKey[iKey].SC, lpKeyState, sbBuffer, sbBuffer.Capacity, 0, hkl); char basechar = sbBuffer[0]; if (deadKey.DeadCharacter == combchar) { // Since the combined character is the same as the dead key, // we must clear out the keyboard buffer. ClearKeyboardBuffer((uint)KeysEx.VK_DECIMAL, rgKey[(uint)KeysEx.VK_DECIMAL].SC, hkl); } if ((((ss == ShiftState.LCtrl) || (ss == ShiftState.ShftLCtrl)) && (char.IsControl(basechar))) || (basechar.Equals(combchar))) { // ToUnicodeEx has an internal knowledge about those // VK_A ~ VK_Z keys to produce the control characters, // when the conversion rule is not provided in keyboard // layout files // Additionally, dead key state is lost for some of these // character combinations, for unknown reasons. // Therefore, if the base character and combining are equal, // and its a CTRL or CTRL+SHIFT state, and a control character // is returned, then we do not add this "dead key" (which // is not really a dead key). continue; } if (caps == 0 && (ss == ShiftState.Base || ss == ShiftState.Shft)) deadKey.AddDeadKeyRow(rgKey[iKey].SC, caps, ss, combchar); } else if (rc > 1) { // Not a valid dead key combination, sorry! We just ignore it. } else if (rc < 0) { // It's another dead key, so we ignore it (other than to flush it from the state) ClearKeyboardBuffer((uint)KeysEx.VK_DECIMAL, rgKey[(uint)KeysEx.VK_DECIMAL].SC, hkl); } } } } } return deadKey; }