/* Name: imsample Copyright: Copyright (C) 2003-2017 SIL International. Documentation: Description: Create Date: 24 Oct 2012 Modified Date: 24 Oct 2012 Authors: mcdurdin Related Files: Dependencies: Bugs: Todo: Notes: History: 24 Oct 2012 - mcdurdin - I3481 - V9.0 - Eliminate unsafe calls in C++ */ #define STRICT #include #include #include "imlib.h" HWND hwnd; HWND hwndChild; HINSTANCE hinst; UINT wm_keymanim_close = 0, wm_keymanim_contextchanged; BOOL FIMWindowUse = FALSE; BOOL FIMWindowAlwaysVisible = FALSE; BOOL FIMWindowActive = FALSE; struct rule { int contextlen; WCHAR *context; WCHAR key; int outputlen; BOOL drawvalid; WCHAR *outputs[10]; // max ten outputs }; struct group { char name[32]; int nrules; rule *rules; }; struct keyboard { char name[128]; LOGFONT font; HFONT hFont; int maxoutputs; int ngroups; int gridx, gridy; group *groups; }; rule *currule = NULL; keyboard *keyboards = NULL, *curkbd = NULL; int nkeyboards; //BOOL FWindow, FWindowAlways, FInWindow = FALSE; LRESULT CALLBACK IMSampleChildWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK IMSampleWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMReloadConfig(PSTR keyboardname); void WriteRegSetting(PSTR text, int value); int ReadRegSetting(PSTR text); bool RegKeyExits(PSTR text); void UnloadRules(PSTR KeyboardName); BOOL LoadRules(PSTR KeyboardName); void DeleteKeyboard(PSTR keyboardname); void CreateKeyboard(PSTR keyboardname); void CreateRegistryKeys(); /************************************************************************************************************ * DLL entry functions ************************************************************************************************************/ BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { return TRUE; } extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMDestroy(PSTR keyboardname) { UnregisterClass("KM_IMSample", hinst); DeleteKeyboard(keyboardname); DestroyWindow(hwnd); UnloadRules(keyboardname); currule = NULL; curkbd = NULL; FIMWindowActive = FALSE; return TRUE; } extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMInit(PSTR keyboardname) { WNDCLASS wc; wm_keymanim_close = RegisterWindowMessage("WM_KEYMANIM_CLOSE"); wm_keymanim_contextchanged = RegisterWindowMessage("WM_KEYMANIM_CONTEXTCHANGED"); hinst = GetModuleHandle(NULL); if(!GetClassInfo(hinst, "KM_IMSample", &wc)) { wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;// | CS_SAVEBITS; wc.lpfnWndProc = (WNDPROC) IMSampleWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hinst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "KM_IMSample"; if(!RegisterClass(&wc)) return FALSE; wc.lpfnWndProc = (WNDPROC) IMSampleChildWndProc; wc.lpszClassName = "KM_IMSampleChild"; if(!RegisterClass(&wc)) return FALSE; } POINT pt; pt.x = ReadRegSetting("imsample x"); pt.y = ReadRegSetting("imsample y"); hwnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, "KM_IMSample", "Keyman Sample IM", WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, pt.x, pt.y, 200, 120, 0, NULL, hinst, NULL); if(!hwnd) return FALSE; return KeymanIMReloadConfig(keyboardname); } extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMReloadConfig(PSTR keyboardname) { currule = NULL; curkbd = NULL; FIMWindowActive = FALSE; CreateRegistryKeys(); FIMWindowUse = ReadRegSetting("ShowIMWindow"); FIMWindowAlwaysVisible = ReadRegSetting("ShowIMWindowAlways"); if(!PrepIM()) return FALSE; CreateKeyboard(keyboardname); LoadRules(keyboardname); if(!FIMWindowUse || !FIMWindowAlwaysVisible) (*KMHideIM)(); return TRUE; } /************************************************************************************************************ * IM Events ************************************************************************************************************/ extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMActivate(PSTR keyboardname) { currule = NULL; curkbd = NULL; FIMWindowActive = FALSE; if(!PrepIM()) return FALSE; if(FIMWindowUse && FIMWindowAlwaysVisible) (*KMDisplayIM)(hwnd, TRUE); int kbi; char kbdname[260]; if(!(*KMGetActiveKeyboard)(kbdname, 256)) return FALSE; for(kbi = 0; kbi < nkeyboards; kbi++) if(!_stricmp(keyboards[kbi].name, kbdname)) break; if(kbi == nkeyboards) return FALSE; curkbd = &keyboards[kbi]; return TRUE; } extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMDeactivate(PSTR keyboardname) { currule = NULL; curkbd = NULL; FIMWindowActive = FALSE; if(!PrepIM()) return FALSE; (*KMHideIM)(); return TRUE; } /************************************************************************************************************ * Window management functions ************************************************************************************************************/ void FinishEdit() { FIMWindowActive = FALSE; currule = NULL; PostMessage(hwndChild, WM_USER+200, 0, 0); PostMessage(hwnd, wm_keymanim_close, 1, !FIMWindowAlwaysVisible); if(FIMWindowAlwaysVisible) (*KMDisplayIM)(hwnd, TRUE); } LRESULT CALLBACK IMSampleWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { RECT rect; POINTS pt; LRESULT lResult; PAINTSTRUCT ps; HDC hDC; // Handle standard IM functions -- such as window activation, etc. if(IMDefWindowProc(hwnd, msg, wParam, lParam, &lResult)) return lResult; if(msg == wm_keymanim_contextchanged) PostMessage(hwndChild, WM_USER+200, 0, 0); switch(msg) { case WM_CREATE: pt.x = ReadRegSetting("imsample x"); pt.y = ReadRegSetting("imsample y"); if(pt.x > 0 && pt.y > 0) SetWindowPos(hwnd, 0, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); GetClientRect(hwnd, &rect); hwndChild = CreateWindowEx(WS_EX_CLIENTEDGE, "KM_IMSampleChild", "", WS_BORDER | WS_CHILD | /*WS_HSCROLL |*/ WS_VSCROLL | WS_VISIBLE, 2, 2, rect.right - 2, rect.bottom - 2, hwnd, 0, hinst, NULL); PostMessage(hwndChild, WM_USER+200, 0, 0); return 0; case WM_SHOWWINDOW: if(wParam) PostMessage(hwndChild, WM_USER+200, 0, 0); break; case WM_DESTROY: GetWindowRect(hwnd, &rect); WriteRegSetting("imsample x", rect.left); WriteRegSetting("imsample y", rect.top); return 0; case WM_KEYDOWN: if(!FIMWindowActive || !currule) return 0; if(wParam == VK_ESCAPE || wParam == VK_BACK) FinishEdit(); return 0; case WM_CHAR: if(!FIMWindowActive || !currule) return 0; if(wParam >= '1' && wParam <= '9') { wParam -= '1'; if(!currule->outputs[wParam]) return 0; (*KMSetOutput)(currule->outputs[wParam], currule->contextlen); FinishEdit(); } return 0; case WM_SIZE: MoveWindow(hwndChild, 2, 2, LOWORD(lParam) - 2, HIWORD(lParam) - 2, TRUE); return 0; case WM_PAINT: hDC = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); FillRect(hDC, &rect, GetSysColorBrush(COLOR_BTNFACE)); EndPaint(hwnd, &ps); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } struct { int cellcount, visiblecolcount, visiblerowcount, xi, yi; } wz; void CalcScrollSize() { RECT rect; if(!curkbd) { wz.cellcount = 0; return; } if (!curkbd->groups) { wz.cellcount = 0; return; } GetClientRect(hwndChild, &rect); if(FIMWindowActive && currule) for(wz.cellcount = 0; wz.cellcount < 10; wz.cellcount++) { if(!currule->outputs[wz.cellcount]) break; } else { WCHAR buf[48]; if(!(*KMGetContext)(buf, 48)) buf[0] = 0; int buflen = (int)wcslen(buf); wz.cellcount = 0; int i; for(i = 0; i < curkbd->groups[0].nrules; i++) { rule *r = &curkbd->groups[0].rules[i]; r->drawvalid = r->contextlen == 0 || (buflen >= r->contextlen && !wcscmp(buf+(buflen-r->contextlen), r->context)); if(r->drawvalid) wz.cellcount++; } } wz.visiblecolcount = (curkbd->gridx != 0 ? rect.right / curkbd->gridx : rect.right); wz.visiblerowcount = (curkbd->gridy != 0 ? rect.bottom / curkbd->gridy : rect.bottom); wz.xi = (wz.visiblecolcount !=0 ) ? (wz.cellcount-1) % wz.visiblecolcount : 2; wz.yi = (wz.visiblecolcount !=0 ) ? (wz.cellcount-1) / wz.visiblecolcount : 2; SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; si.nMin = 0; si.nMax = max(0, wz.yi - wz.visiblerowcount + 1); si.nPage = wz.visiblerowcount-1; si.nPos = 0; SetScrollInfo(hwndChild, SB_VERT, &si, FALSE); } LRESULT CALLBACK IMSampleChildWndProc(HWND hwndChild, UINT msg, WPARAM wParam, LPARAM lParam) { static int cx, cy; RECT rect; POINTS pt; PAINTSTRUCT ps; HDC hDC; int n, nPos; LRESULT lResult; switch(msg) { case WM_NCHITTEST: lResult = DefWindowProc(hwndChild, msg, wParam, lParam); if(lResult != HTCLIENT && lResult != HTVSCROLL && lResult != HTHSCROLL) return HTNOWHERE; return lResult; case WM_MOUSEACTIVATE: return MA_NOACTIVATE; case WM_SIZE: case WM_USER+200: CalcScrollSize(); InvalidateRect(hwndChild, NULL, TRUE); return 0; case WM_LBUTTONUP: if(!PrepIM()) return DefWindowProc(hwndChild, msg, wParam, lParam); if(!curkbd) return 0; if (!curkbd->groups) { return 0; } GetClientRect(hwndChild, &rect); pt = MAKEPOINTS(lParam); pt.x /= cx; pt.y /= cy; n = pt.y*(rect.right/cx) + pt.x; if(!FIMWindowActive || !currule) { int i, j; for(i = 0, j = 0; i < curkbd->groups[0].nrules; i++) if(curkbd->groups[0].rules[i].drawvalid) { if(j == n) break; j++; } if(i == curkbd->groups[0].nrules) return 0; currule = &curkbd->groups[0].rules[i]; FIMWindowActive = TRUE; PostMessage(hwndChild, WM_USER+200, 0, 0); (*KMDisplayIM)(hwnd, FALSE); } else { if(n > 9) return 0; if(!currule->outputs[n]) return 0; (*KMSetOutput)(currule->outputs[n], currule->contextlen); FinishEdit(); } return 0; case WM_VSCROLL: nPos = HIWORD(wParam); if(nPos == 0 && LOWORD(wParam) != SB_THUMBTRACK && LOWORD(wParam) != SB_THUMBPOSITION) nPos = GetScrollPos(hwndChild, SB_VERT); switch(LOWORD(wParam)) { case SB_BOTTOM: nPos = wz.yi - wz.visiblerowcount + 1; break; case SB_ENDSCROLL: break; case SB_LINEDOWN: nPos++; break; case SB_LINEUP: nPos--; break; case SB_PAGEDOWN: nPos += wz.visiblerowcount - 1; break; case SB_PAGEUP: nPos -= wz.visiblerowcount - 1; break; case SB_THUMBPOSITION: break; case SB_THUMBTRACK: break; case SB_TOP: nPos = 0; break; } if(nPos < 0) nPos = 0; if(nPos > wz.yi - wz.visiblerowcount + 1) nPos = wz.yi - wz.visiblerowcount + 1; SetScrollPos(hwndChild, SB_VERT, nPos, TRUE); InvalidateRect(hwndChild, NULL, TRUE); UpdateWindow(hwndChild); return 0; case WM_PAINT: if (!curkbd || !curkbd->hFont || !curkbd->groups || !PrepIM()) { return DefWindowProc(hwndChild, msg, wParam, lParam); } int vpos = GetScrollPos(hwndChild, SB_VERT) * curkbd->gridy; hDC = BeginPaint(hwndChild, &ps); GetClientRect(hwndChild, &rect); if(curkbd) { HFONT hOldFont = (HFONT) SelectObject(hDC, curkbd->hFont); cx = curkbd->gridx; cy = curkbd->gridy; int i; for(i = 0; i < wz.visiblecolcount; i++) { MoveToEx(hDC, (i+1)*cx, -vpos + 0, NULL); if(i <= wz.xi || wz.yi > 0) LineTo(hDC, (i+1)*cx, -vpos + (i <= wz.xi ? cy * (wz.yi+1) : cy * wz.yi)+1); } for(i = 0; i <= wz.yi; i++) { MoveToEx(hDC, 0, -vpos + (i+1)*cy, NULL); LineTo(hDC, (i < wz.yi ? cx * wz.visiblecolcount : cx * (wz.xi+1))+1, -vpos + (i+1)*cy); } if(FIMWindowActive && currule) { int i, x, y; for(i = 0, x = 0, y = 0; i < 10; i++) { if(!currule->outputs[i]) break; char buf[2]; buf[0] = i+'1'; buf[1] = 0; SelectObject(hDC, GetStockObject(SYSTEM_FONT)); TextOut(hDC, x * cx + 1, -vpos + y * cy+1, buf, 1); SelectObject(hDC, curkbd->hFont); SIZE sz2; GetTextExtentPoint32W(hDC, currule->outputs[i], (int)wcslen(currule->outputs[i]), &sz2); TextOutW(hDC, x * cx + (cx-sz2.cx)/2, -vpos + (y+1) * cy - sz2.cy - 2, currule->outputs[i], (int)wcslen(currule->outputs[i])); if(++x >= wz.visiblecolcount) { x = 0; y++; } } } else { SelectObject(hDC, curkbd->hFont); int i,x,y; for(i = 0, x = 0, y = 0; i < curkbd->groups[0].nrules; i++) { rule *r = &curkbd->groups[0].rules[i]; if(!r->drawvalid) continue; SIZE sz2; GetTextExtentPoint32W(hDC, &r->key, 1, &sz2); TextOutW(hDC, x * cx + (cx-sz2.cx)/2, -vpos + (y+1) * cy - sz2.cy - 2, &r->key, 1); if(++x >= wz.visiblecolcount) { x = 0; y++; } } } SelectObject(hDC, hOldFont); } else Rectangle(hDC, -1, -1, rect.right + 1, rect.bottom + 1); /*char str[128]; wsprintf(str, "%d %d %d %d", wz.xi, wz.yi, wz.visiblecolcount, wz.visiblerowcount); TextOut(hDC, 0, 0, str, strlen(str));*/ EndPaint(hwndChild, &ps); return 0; } return DefWindowProc(hwndChild, msg, wParam, lParam); } BOOL FindRule(group *g, rule **rp, WCHAR KeyChar) { if (!g || !rp) { return FALSE; } WCHAR buf[48]; if(!(*KMGetContext)(buf, 48)) return FALSE; rule *r = g->rules; int buflen = (int)wcslen(buf); int i; for(i = 0; i < g->nrules; i++) { if(r[i].key == KeyChar && buflen >= r[i].contextlen && !wcscmp(buf+(buflen-r[i].contextlen), r[i].context)) { *rp = &r[i]; return TRUE; } } return FALSE; } BOOL PostKey(WCHAR KeyChar, WORD KeyStroke) { if(KeyChar != 0) { WCHAR buf[2]; buf[0] = KeyChar; buf[1] = 0; (*KMSetOutput)(buf, 0); } else { if(KeyStroke == VK_BACK) (*KMQueueAction)(QIT_BACK, 0); else (*KMQueueAction)(QIT_VKEYDOWN, KeyStroke); } return TRUE; } extern "C" BOOL __declspec(dllexport) WINAPI DFWindow(HWND hwndFocus, WORD KeyStroke, WCHAR KeyChar, DWORD shiftFlags) { if(!curkbd) return FALSE; if (!curkbd->groups) { return FALSE; } if(!FindRule(&curkbd->groups[0], &currule, KeyChar)) { if(FIMWindowAlwaysVisible) PostMessage(hwndChild, WM_USER+200, 0, 0); //UpdateWindow(hwndChild); return PostKey(KeyChar, KeyStroke); } FIMWindowActive = TRUE; PostMessage(hwndChild, WM_USER+200, 0, 0); (*KMDisplayIM)(hwnd, FALSE); return TRUE; } extern "C" BOOL __declspec(dllexport) WINAPI DFText(HWND hwndFocus, WORD KeyStroke, WCHAR KeyChar, DWORD shiftFlags) { WCHAR buf[32]; if (!curkbd || !curkbd->groups) { return FALSE; } if(!currule) { if(!FindRule(&curkbd->groups[0], &currule, KeyChar)) { PostKey(KeyChar, KeyStroke); return TRUE; } else { (*KMSetOutput)(L"[", 0); for(int j = 0; currule->outputs[j]; j++) { if(j>0) (*KMSetOutput)(L" ", 0); buf[0] = j+'1'; buf[1] = 0; (*KMSetOutput)(buf, 0); (*KMSetOutput)(currule->outputs[j], 0); } (*KMSetOutput)(L"]", 0); } } else if(KeyChar >= '1' && KeyChar <= '9') { KeyChar -= '1'; if(currule->outputs[KeyChar]) { (*KMSetOutput)(currule->outputs[KeyChar], currule->outputlen); currule = NULL; } } else if(KeyStroke == VK_BACK || KeyStroke == VK_ESCAPE) { (*KMSetOutput)(L"", currule->outputlen); currule = NULL; } return TRUE; } extern "C" BOOL __declspec(dllexport) WINAPI DF(HWND hwndFocus, WORD KeyStroke, WCHAR KeyChar, DWORD shiftFlags) { if(!PrepIM()) return FALSE; if(FIMWindowUse) return DFWindow(hwndFocus, KeyStroke, KeyChar, shiftFlags); else return DFText(hwndFocus, KeyStroke, KeyChar, shiftFlags); } /************************************************************************************************************ * IM Configuration ************************************************************************************************************/ extern "C" BOOL __declspec(dllexport) WINAPI KeymanIMConfigure(PSTR keyboardname, HWND hwndParent) { int n = MessageBox(hwndParent, "Do you want to have a menu window?", "IMSample", MB_YESNOCANCEL); switch(n) { case IDYES: n = MessageBox(hwndParent, "Do you want to have the menu window always open?", "IMSample", MB_YESNOCANCEL); switch(n) { case IDYES: WriteRegSetting("ShowIMWindowAlways", 1); break; case IDNO: WriteRegSetting("ShowIMWindowAlways", 0); break; default: return TRUE; } WriteRegSetting("ShowIMWindow", 1); break; case IDNO: WriteRegSetting("ShowIMWindow", 0); break; } return TRUE; } void WriteRegSetting(PSTR text, int value) { HKEY hkey; if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Keyman\\Keyman Engine\\Active Keyboards\\imsample", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS) { RegSetValueEx(hkey, text, 0, REG_DWORD, (PBYTE) &value, 4); RegCloseKey(hkey); } } int ReadRegSetting(PSTR text) { HKEY hkey; if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Keyman\\Keyman Engine\\Active Keyboards\\imsample", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS) { unsigned long value, sz = 4, tp = REG_DWORD; RegQueryValueEx(hkey, text, 0, &tp, (PBYTE) &value, &sz); RegCloseKey(hkey); return value; } return 0; } bool RegKeyExits(PSTR text) { HKEY hkey; bool result = false; if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Keyman\\Keyman Engine\\Active Keyboards\\imsample", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS) { unsigned long value, sz = 4, tp = REG_DWORD; if (RegQueryValueEx(hkey, text, 0, &tp, (PBYTE) &value, &sz) == ERROR_SUCCESS) { result = true; } RegCloseKey(hkey); } return result; } char *strtokquoted(char *str, char *token, char *quotes) { //slow-n-ugly but quick to write ;-) static char *buf = NULL; if(!str) if(!buf) return NULL; else str = buf; char *q = str; if(!*q) return q; while(strchr(token, *q)) q++; if(strchr(quotes, *q)) //quoted substring { char *r = strchr(q+1, *q); if(!r) return NULL; // unterminated quotes r++; if(!strchr(token, *r)) return NULL; // close of quoted string does not culminate in token if(*r != 0) { *r++ = 0; while(*r != 0 && strchr(token, *r)) r++; } if(*r == 0) buf = NULL; else buf = r; return q; } else { char *r = q; while(!strchr(token, *r) && *r != 0) r++; if(*r != 0) { *r++ = 0; while(*r != 0 && strchr(token, *r)) r++; } if(*r == 0) buf = NULL; else buf = r; return q; } } PWSTR newempty() { PWSTR buf = new WCHAR[1]; buf[0] = 0; return buf; } PWSTR extstr(char *p) { if(*p == '"' || *p == '\'') { p++; char *q = strchr(p, *(p-1)); if(!q) return newempty(); if(q == p) return newempty(); *q = 0; int n = MultiByteToWideChar(CP_ACP, 0, p, (int)strlen(p), NULL, 0); PWCHAR buf = new WCHAR[n+1]; MultiByteToWideChar(CP_ACP, 0, p, (int)strlen(p), buf, n); buf[n] = 0; return buf; } else { WCHAR buf[64]; int i = 0, n; while(*p) { switch(*p) { case ' ': p++; break; case 'U': case 'u': p++; if(*p != '+') return newempty(); case 'x': case 'X': p++; n = strtol(p, &p, 16); if(!p) return newempty(); buf[i++] = n; break; case 'd': case 'D': p++; n = strtol(p, &p, 10); if(!p) return newempty(); buf[i++] = n; break; default: return newempty(); } } buf[i] = 0; PWSTR p = new WCHAR[i+1]; wcscpy_s(p, i+1, buf); // I3481 return p; } } void UnloadRules(PSTR KeyboardName) { int nkbi; for(nkbi = 0; nkbi < nkeyboards; nkbi++) if(!_stricmp(KeyboardName, keyboards[nkbi].name)) break; if(nkbi == nkeyboards) return; keyboard *kbi = &keyboards[nkbi]; if(kbi->hFont) DeleteObject(kbi->hFont); kbi->hFont = NULL; if (kbi->groups == NULL) { return; } int i; for(i = 0; i < kbi->ngroups; i++) { for(int j = 0; j < kbi->groups[i].nrules; j++) { delete kbi->groups[i].rules[j].context; for(int k = 0; k < 10; k++) if(kbi->groups[i].rules[j].outputs[k]) delete kbi->groups[i].rules[j].outputs[k]; } if(kbi->groups[i].nrules > 0) delete kbi->groups[i].rules; } if(kbi->ngroups > 0) delete kbi->groups; kbi->ngroups = 0; kbi->groups = NULL; } BOOL LoadRules(PSTR KeyboardName) { BOOL FGroups = FALSE, FRules = FALSE, FConfig = FALSE; char str[512]; int nkbi, lfpixelsy; UnloadRules(KeyboardName); // Free existing rule base for(nkbi = 0; nkbi < nkeyboards; nkbi++) if(!_stricmp(KeyboardName, keyboards[nkbi].name)) break; if(nkbi == nkeyboards) return FALSE; keyboard *kbi = &keyboards[nkbi]; kbi->maxoutputs = 0; kbi->ngroups = 0; HDC hDC = GetDC(GetDesktopWindow()); SetMapMode(hDC, MM_TEXT); lfpixelsy = GetDeviceCaps(hDC, LOGPIXELSY); ReleaseDC(GetDesktopWindow(), hDC); kbi->font.lfHeight = -MulDiv(10, lfpixelsy, 72); kbi->font.lfWidth = 0; kbi->font.lfEscapement = 0; kbi->font.lfOrientation = 0; kbi->font.lfWeight = FW_NORMAL; kbi->font.lfItalic = FALSE; kbi->font.lfUnderline = FALSE; kbi->font.lfStrikeOut = FALSE; kbi->font.lfCharSet = DEFAULT_CHARSET; kbi->font.lfOutPrecision = OUT_DEFAULT_PRECIS; kbi->font.lfClipPrecision = CLIP_DEFAULT_PRECIS; kbi->font.lfQuality = DEFAULT_QUALITY; kbi->font.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; strcpy_s(kbi->font.lfFaceName, _countof(kbi->font.lfFaceName), "Arial"); // I3481 char drive[_MAX_DRIVE], dir[_MAX_DIR], buf[260]; if(!(*KMGetKeyboardPath)(KeyboardName, buf, 260)) return FALSE; _splitpath_s(buf, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0); // I3481 _makepath_s(buf, _countof(buf), drive, dir, "imsample", ".txt"); // I3481 FILE *fp = NULL; if(fopen_s(&fp, buf, "rt") != 0) return FALSE; // I3481 if(!fp) return FALSE; while(fgets(str, 512, fp)) { if(strchr(str, '\n')) *strchr(str, '\n') = 0; if(str[0] == '#' || str[0] == 0) continue; if(str[0] == '[') { FConfig = FALSE; FGroups = FALSE; FRules = FALSE; if(!_stricmp(str, "[config]")) FConfig = TRUE; else if(!_stricmp(str, "[groups]")) FGroups = TRUE; else if(!_stricmp(str, "[rules]")) FRules = TRUE; } else if(FConfig) { char *tokcontext = NULL; char *p = strtok_s(str, "= ", &tokcontext); if(!p) continue; // I3481 char *q = strtok_s(NULL, "\n", &tokcontext); if(!q) continue; // I3481 if(!_stricmp(p, "font")) { strncpy_s(kbi->font.lfFaceName, _countof(kbi->font.lfFaceName), q, LF_FACESIZE-1); kbi->font.lfFaceName[LF_FACESIZE-1] = 0; } else if(!_stricmp(p, "size")) { int n = atoi(q); if(n == 0) n = 10; kbi->font.lfHeight = -MulDiv(n, lfpixelsy, 72); } else if(!_stricmp(p, "gridx")) kbi->gridx = atoi(q); else if(!_stricmp(p, "gridy")) kbi->gridy = atoi(q); } else if(FGroups) { group *g2; g2 = new group[kbi->ngroups+1]; if(kbi->ngroups > 0) { memcpy(g2, kbi->groups, sizeof(group)*kbi->ngroups); delete kbi->groups; } kbi->groups = g2; kbi->groups[kbi->ngroups].rules = NULL; kbi->groups[kbi->ngroups].nrules = 0; strncpy_s(kbi->groups[kbi->ngroups].name, _countof(kbi->groups[kbi->ngroups].name), str, 31); // I3481 kbi->groups[kbi->ngroups++].name[31] = 0; } else if(FRules) { int i; PSTR pgroup = strtokquoted(str, ", \t", "\"\'"); if(!pgroup) continue; // silently fail on that line [for now] PSTR pcontext = strtokquoted(NULL, ", \t", "\"\'"); if(!pcontext) continue; PSTR pkey = strtokquoted(NULL, ", \t", "\"\'"); if(!pkey) continue; PSTR poutput = strtokquoted(NULL, ", \t", "\"\'"); if(!poutput) continue; // must be at least one output for(i = 0; i < kbi->ngroups; i++) if(!_stricmp(kbi->groups[i].name, pgroup)) break; if(i == kbi->ngroups) continue; if((kbi->groups[i].nrules % 10) == 0) { rule *r2 = new rule[kbi->groups[i].nrules+10]; if(kbi->groups[i].nrules > 0) { memcpy(r2, kbi->groups[i].rules, sizeof(rule)*kbi->groups[i].nrules); delete kbi->groups[i].rules; } kbi->groups[i].rules = r2; } rule *r2 = &kbi->groups[i].rules[kbi->groups[i].nrules++]; r2->context = extstr(pcontext); r2->contextlen = (int)wcslen(r2->context); PWSTR pp = extstr(pkey); r2->key = pp[0]; delete pp; i = 0; r2->outputlen = 1; while(poutput && i < 10) { r2->outputs[i++] = extstr(poutput); r2->outputlen += (int)wcslen(r2->outputs[i-1]) + 2; poutput = strtokquoted(NULL, ", ", "\"\'"); } if(i > kbi->maxoutputs) kbi->maxoutputs = i; for(; i < 10; i++) r2->outputs[i] = NULL; } // fail silently on unrecognised lines } fclose(fp); kbi->hFont = CreateFontIndirect(&kbi->font); return TRUE; } void DeleteKeyboard(PSTR keyboardname) { int nkbi; for(nkbi = 0; nkbi < nkeyboards; nkbi++) if(!_stricmp(keyboardname, keyboards[nkbi].name)) break; if(nkbi == nkeyboards) return; if(nkbi < nkeyboards) memmove(&keyboards[nkbi], &keyboards[nkbi+1], sizeof(keyboard)*(nkeyboards-nkbi-1)); nkeyboards--; if(nkeyboards == 0) { delete keyboards; keyboards = NULL; } } void CreateKeyboard(PSTR keyboardname) { int nkbi; for(nkbi = 0; nkbi < nkeyboards; nkbi++) if(!_stricmp(keyboardname, keyboards[nkbi].name)) break; if(nkbi == nkeyboards) { keyboard *kb2 = new keyboard[nkeyboards + 1]; if(nkeyboards > 0) { memcpy(kb2, keyboards, sizeof(keyboard) * nkeyboards); delete keyboards; } keyboards = kb2; strncpy_s(keyboards[nkeyboards].name, _countof(keyboards[nkeyboards].name), keyboardname, 127); // I3481 keyboards[nkeyboards].name[127] = 0; keyboards[nkeyboards].groups = NULL; keyboards[nkeyboards].hFont = NULL; nkeyboards++; } } // Write default values if keys are not found void CreateRegistryKeys() { if(!RegKeyExits("imsample x")) { WriteRegSetting("imsample x", 50); } if(!RegKeyExits("imsample y")) { WriteRegSetting("imsample y", 50); } if(!RegKeyExits("ShowIMWindow")) { WriteRegSetting("ShowIMWindow", 1); } if(!RegKeyExits("ShowIMWindowAlways")) { WriteRegSetting("ShowIMWindowAlways", 1); } }