From 0f32515050edd8385d0e41afdb844e1c36c68b92 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Wed, 22 Nov 2023 09:08:55 +0700 Subject: [PATCH 01/14] fix(web): app/webview did not clear deadkeys on context-reset --- common/web/keyboard-processor/src/text/keyboardProcessor.ts | 3 +++ web/src/engine/main/src/keymanEngine.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/common/web/keyboard-processor/src/text/keyboardProcessor.ts b/common/web/keyboard-processor/src/text/keyboardProcessor.ts index 2a2dc0bb70..14e819a56d 100644 --- a/common/web/keyboard-processor/src/text/keyboardProcessor.ts +++ b/common/web/keyboard-processor/src/text/keyboardProcessor.ts @@ -570,6 +570,9 @@ export default class KeyboardProcessor extends EventEmitter { resetContext(target?: OutputTarget) { this.layerId = 'default'; + + // Make sure all deadkeys for the context get cleared properly. + target?.resetContext(); this.keyboardInterface.resetContextCache(); // May be null if it's a keyboard swap. diff --git a/web/src/engine/main/src/keymanEngine.ts b/web/src/engine/main/src/keymanEngine.ts index 99495a263a..5c94b30f48 100644 --- a/web/src/engine/main/src/keymanEngine.ts +++ b/web/src/engine/main/src/keymanEngine.ts @@ -202,6 +202,8 @@ export default class KeymanEngine< this.contextManager.configure({ resetContext: (target) => { + // Could reset the target's deadkeys here, but it's really more of a 'core' task. + // So we delegate that to keyboard-processor. this.core.resetContext(target); }, predictionContext: new PredictionContext(this.core.languageProcessor, this.core.keyboardProcessor), From fb347bba8dfa9418611fc09e100aedaf7f0798f1 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Wed, 22 Nov 2023 15:25:14 +0100 Subject: [PATCH 02/14] chore(linux): Update debian changelog (cherry picked from commit 97d7f3a11c121a45389cdfb2c2eeb565ae612ce7) --- linux/debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux/debian/changelog b/linux/debian/changelog index 1ad0f861fb..431728feb1 100644 --- a/linux/debian/changelog +++ b/linux/debian/changelog @@ -1,3 +1,11 @@ +keyman (16.0.143-1) unstable; urgency=medium + + * Fix failure to build source after successful build (Closes #1046776) + * New upstream release. + * Re-release to Debian + + -- Eberhard Beilharz Wed, 22 Nov 2023 15:24:59 +0100 + keyman (16.0.141-1) unstable; urgency=medium * Work around mips64el build failure (#1041499) From ee1f972b134cecf5f07af282add5483778465f78 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 23 Nov 2023 10:49:58 +1000 Subject: [PATCH 03/14] chore(windows): remove wm_keymandebug messages and functions Fixes #10050. Removes the following unused identifiers: * ::wm_kmdebug * ::wm_keymandebug * AppInt::DebugControlled() * AITIP::WM_KEYMANDEBUG_CANDEBUG * AITIP::WM_KEYMANDEBUG_GETUNICODESTATUS * AITIP::WM_KEYMANDEBUG_GETCONTEXT * AITIP::WM_KEYMANDEBUG_ACTION * AITIP::WM_KEYMANDEBUG_RULEMATCH * AITIP::DebugControlled() * AITIP::IsDebugControlWindow() * AITIP::GetDebugControlWindow() * AITIP::Debug_FillContextBuffer() * AIDEBUGINFO struct * ::FillStoreOffsets() * AIDEBUGKEYINFO struct Removes overloads which are now no-ops: * AITIP::HandleWindow() * AITIP::IsWindowHandled() * AITIP::QueueAction() --- windows/src/engine/keyman32/appint/aiTIP.cpp | 144 ------------------ windows/src/engine/keyman32/appint/aiTIP.h | 25 --- windows/src/engine/keyman32/globals.h | 2 - windows/src/engine/keyman32/k32_globals.cpp | 1 - .../src/engine/keyman32/kmhook_getmessage.cpp | 5 - windows/src/engine/keyman32/kmprocess.cpp | 20 --- 6 files changed, 197 deletions(-) diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index b6f591845b..a7faa7170f 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -234,14 +234,7 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM AITIP::AITIP() { ::AIWin2000Unicode(); // I3574 - FIsDebugControlWindow = FALSE; useLegacy = FALSE; - - WM_KEYMANDEBUG_CANDEBUG = RegisterWindowMessage("WM_KEYMANDEBUG_CANDEBUG"); - WM_KEYMANDEBUG_GETUNICODESTATUS = RegisterWindowMessage("WM_KEYMANDEBUG_GETUNICODESTATUS"); - WM_KEYMANDEBUG_GETCONTEXT = RegisterWindowMessage("WM_KEYMANDEBUG_GETCONTEXT"); - WM_KEYMANDEBUG_ACTION = RegisterWindowMessage("WM_KEYMANDEBUG_ACTION"); - WM_KEYMANDEBUG_RULEMATCH = RegisterWindowMessage("WM_KEYMANDEBUG_RULEMATCH"); } AITIP::~AITIP() { @@ -254,15 +247,6 @@ BOOL AITIP::CanHandleWindow(HWND ahwnd) { return TRUE; // I3574 } -BOOL AITIP::HandleWindow(HWND ahwnd) { - FIsDebugControlWindow = IsDebugControlWindow(ahwnd); - return AIWin2000Unicode::HandleWindow(ahwnd); // I3574 -} - -BOOL AITIP::IsWindowHandled(HWND ahwnd) { - return AIWin2000Unicode::IsWindowHandled(ahwnd); // I3574 -} - BOOL AITIP::IsUnicode() { return TRUE; } @@ -335,11 +319,6 @@ void AITIP::MergeContextWithCache(PWSTR buf, AppContext *local_context) { // I } void AITIP::ReadContext() { - if(DebugControlled()) { - Debug_FillContextBuffer(); - return; - } - WCHAR buf[MAXCONTEXT]; PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) return; @@ -376,44 +355,7 @@ void AITIP::RestoreContextOnly(AppContext *savedContext) { /* Output actions */ -BOOL AITIP::QueueAction(int ItemType, DWORD dwData) { - if(DebugControlled()) { - switch(ItemType) { - case QIT_VKEYDOWN: - if((dwData & QVK_KEYMASK) <= VK__MAX && VKContextReset[(BYTE) dwData]) context->Reset(); // I3438 // I4370 - break; - - case QIT_DEADKEY: - context->Add(UC_SENTINEL); // I4370 - context->Add(CODE_DEADKEY); // I4370 - context->Add((WORD) dwData); // I4370 - break; - - case QIT_CHAR: - context->Add((WORD) dwData); // I4370 - break; - - case QIT_BACK: - if(dwData & BK_BACKSPACE) - while(context->CharIsDeadkey()) context->Delete(); // I4370 - context->Delete(); // I4370 - if(dwData & BK_BACKSPACE) - while(context->CharIsDeadkey()) context->Delete(); // I4370 - break; - } - - SendMessage(GetDebugControlWindow(), WM_KEYMANDEBUG_ACTION, ItemType, dwData); - return TRUE; - } - - return AIWin2000Unicode::QueueAction(ItemType, dwData); // I3575 -} - BOOL AITIP::SendActions() { // I4196 - if(DebugControlled()) { - return TRUE; - } - PKEYMAN64THREADDATA _td = ThreadGlobals(); if(!_td) return FALSE; @@ -504,89 +446,3 @@ DWORD TSFShiftToShift(LPARAM shift) // I3588 if(shift & TF_MOD_RCONTROL) res |= RCTRLFLAG; return res; } - -/* Debug Integration */ - -BOOL AITIP::IsDebugControlWindow(HWND hwnd) -{ - static int WM_KEYMANDEBUG_CANDEBUG = RegisterWindowMessage("WM_KEYMANDEBUG_CANDEBUG"); - DWORD_PTR dwResult; - SendMessageTimeout(hwnd, WM_KEYMANDEBUG_CANDEBUG, 0, 0, SMTO_BLOCK, 50, &dwResult); - return dwResult != 0; -} - -HWND AITIP::GetDebugControlWindow() -{ - if(!FIsDebugControlWindow) return NULL; - return hwnd; -} - -BOOL AITIP::DebugControlled() -{ - return FIsDebugControlWindow; -} - -void AITIP::Debug_FillContextBuffer() -{ - WCHAR buf[MAXCONTEXT]; - if(DebugControlled() && - SendMessage(GetDebugControlWindow(), WM_KEYMANDEBUG_GETCONTEXT, MAXCONTEXT, (LPARAM) buf)) - { - context->Set(buf); // I4370 - SendDebugMessageFormat(0, sdmKeyboard, 0, "AIDebugger::FillContextBuffer(%ls)", buf); - } - else - { - context->Reset(); // I4370 - SendDebugMessageFormat(0, sdmKeyboard, 0, "AIDebugger::FillContextBuffer()-Reset"); - } -} - -#define MAXSTOREOFFSETS 20 - -struct AIDEBUGINFO -{ - int cbSize; - int ItemType; - PWSTR Context, Output; - LPKEY Rule; - LPGROUP Group; - DWORD_PTR Flags; - WORD StoreOffsets[MAXSTOREOFFSETS*2+1]; // pairs--store, char position, terminated by 0xFFFF -}; - -void FillStoreOffsets(AIDEBUGINFO *di) -{ - int i, n; - PWSTR p; - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td) return; - - for(i = n = 0, p = di->Rule->dpContext; *p; p = incxstr(p), i++) - { - if(*p == UC_SENTINEL && (*(p+1) == CODE_ANY || *(p+1) == CODE_NOTANY)) - { - di->StoreOffsets[n++] = *(p+2) - 1; - di->StoreOffsets[n++] = _td->IndexStack[i]; - } - if(*p == UC_SENTINEL && *(p+1) == CODE_INDEX) - { - di->StoreOffsets[n++] = *(p+2) - 1; - di->StoreOffsets[n++] = _td->IndexStack[*(p+3) - 1]; - } - if(n == MAXSTOREOFFSETS*2) break; - } - - if(n < MAXSTOREOFFSETS*2 - 1) - for(p = di->Rule->dpOutput; *p; p = incxstr(p)) - { - if(*p == UC_SENTINEL && *(p+1) == CODE_INDEX) - { - di->StoreOffsets[n++] = *(p+2) - 1; - di->StoreOffsets[n++] = _td->IndexStack[*(p+3) - 1]; - } - if(n == MAXSTOREOFFSETS*2) break; - } - di->StoreOffsets[n] = 0xFFFF; -} diff --git a/windows/src/engine/keyman32/appint/aiTIP.h b/windows/src/engine/keyman32/appint/aiTIP.h index 3c6fd9b698..93c9acd4ab 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.h +++ b/windows/src/engine/keyman32/appint/aiTIP.h @@ -35,30 +35,11 @@ // This can be customised with HKLM\Software\Keyman\Keyman Engine\zap virtual key code #define _VK_PREFIX_DEFAULT 0x0E -struct AIDEBUGKEYINFO -{ - UINT VirtualKey; - DWORD shiftFlags; - WCHAR Character, DeadKeyCharacter; - BOOL IsUp; -}; - class AITIP : public AIWin2000Unicode { private: - int WM_KEYMANDEBUG_CANDEBUG, - WM_KEYMANDEBUG_GETUNICODESTATUS, - WM_KEYMANDEBUG_GETCONTEXT, - WM_KEYMANDEBUG_ACTION, - WM_KEYMANDEBUG_RULEMATCH; - - BOOL FIsDebugControlWindow; - HWND GetDebugControlWindow(); - void Debug_FillContextBuffer(); void MergeContextWithCache(PWSTR buf, AppContext *context); // I4262 - static BOOL IsDebugControlWindow(HWND hwnd); - private: BOOL useLegacy; @@ -69,8 +50,6 @@ public: AITIP(); ~AITIP(); - BOOL DebugControlled(); - /** * Copy the member context * @@ -85,13 +64,9 @@ public: */ void RestoreContextOnly(AppContext *savedContext); - virtual BOOL QueueAction(int ItemType, DWORD dwData); - /* Information functions */ virtual BOOL CanHandleWindow(HWND ahwnd); - virtual BOOL IsWindowHandled(HWND ahwnd); - virtual BOOL HandleWindow(HWND ahwnd); virtual BOOL IsUnicode(); /* Context functions */ diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index 320ef811de..22a0e437e9 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -263,12 +263,10 @@ typedef struct tagKEYMAN64THREADDATA extern UINT wm_keyman, // user message - ignore msg - wm_kmdebug, // " " " " - debugging wm_keyman_control, // messages to main Keyman window - replaces WM_USER+* wm_keyman_control_internal, // messages to all windows to notify of changes to Keyman // I4412 wm_keymankeydown, wm_keymankeyup, - wm_keymandebug, wm_keyman_grabwindowproc, wm_keyman_refresh, wm_kmgetactivekeymanid, diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index 989a787f95..bc500e763d 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -72,7 +72,6 @@ UINT //TODO: consolidate these messages -- they are probably not all required now wm_keyman = 0, // user message - ignore msg // I3594 - wm_kmdebug = 0, // " " " " - debugging wm_keymankeydown = 0, wm_keymankeyup = 0, diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index e129a0b8da..d4d1177ced 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -266,11 +266,6 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) SendDebugMessageFormat(0, sdmInternat, 0, "GetMessage: wm_keymanshift %x %x", mp->wParam, mp->lParam); SelectApplicationIntegration(); if(!_td->app->IsWindowHandled(mp->hwnd)) _td->app->HandleWindow(mp->hwnd); - if(_td->app->DebugControlled()) - { - if(mp->wParam == 1) *Globals::ShiftState() = (DWORD) mp->lParam; - else *Globals::ShiftState() = 0; - } return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); } diff --git a/windows/src/engine/keyman32/kmprocess.cpp b/windows/src/engine/keyman32/kmprocess.cpp index 5772836de2..7e5e807056 100644 --- a/windows/src/engine/keyman32/kmprocess.cpp +++ b/windows/src/engine/keyman32/kmprocess.cpp @@ -138,16 +138,7 @@ BOOL ProcessHook() if(!_td) return FALSE; fOutputKeystroke = FALSE; // TODO: 5442 no longer needs to be global once we use core processor - // - // If we are running in the debugger, don't do a second run through - // - if(_td->app->DebugControlled() && !_td->TIPFUpdateable) { // I4287 - if(_td->state.vkey == VK_ESCAPE || (_td->state.vkey >= VK_PRIOR && _td->state.vkey <= VK_DOWN) || (_td->state.vkey == VK_DELETE)) return FALSE; // I4033 // I4826 // I4845 - else return TRUE; - } - - //app->NoSetShift = FALSE; _td->app->ReadContext(); if(_td->state.msg.message == wm_keymankeydown) { // I4827 @@ -216,17 +207,6 @@ BOOL ProcessHook() } } - if (fOutputKeystroke && _td->app->DebugControlled()) { - // The debug memo does not receive default key events because - // we capture them all here. So we synthesize the key event for - // the debugger. - _td->app->QueueAction(QIT_VSHIFTDOWN, Globals::get_ShiftState()); - _td->app->QueueAction(QIT_VKEYDOWN, _td->state.vkey); - _td->app->QueueAction(QIT_VKEYUP, _td->state.vkey); - _td->app->QueueAction(QIT_VSHIFTUP, Globals::get_ShiftState()); - fOutputKeystroke = FALSE; - } - if(*Globals::hwndIM() == 0 || *Globals::hwndIMAlways()) { _td->app->SetCurrentShiftState(Globals::get_ShiftState()); From df2b258c89ae55ebad79b07cd308662ec242aedf Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 23 Nov 2023 11:22:32 +1000 Subject: [PATCH 04/14] chore(windows): remove legacy LoadKeyboard Fixes #10053. Removes `LoadKeyboard` and related functions used only by it. --- windows/src/engine/keyman32/K32_load.cpp | 776 --------------------- windows/src/engine/keyman32/keymanengine.h | 8 - 2 files changed, 784 deletions(-) diff --git a/windows/src/engine/keyman32/K32_load.cpp b/windows/src/engine/keyman32/K32_load.cpp index 999d8941c9..9917e7edbf 100644 --- a/windows/src/engine/keyman32/K32_load.cpp +++ b/windows/src/engine/keyman32/K32_load.cpp @@ -30,17 +30,6 @@ #include "pch.h" -HBITMAP LoadBitmapFile(LPBYTE data, DWORD sz); -BOOL VerifyKeyboard(LPBYTE filebase); - -#ifdef _WIN64 -LPKEYBOARD CopyKeyboard(PBYTE bufp, PBYTE base, DWORD dwFileSize); -#else -LPKEYBOARD FixupKeyboard(PBYTE bufp, PBYTE base, DWORD dwFileSize); -#endif - -HBITMAP LoadBitmapFileEx(PBYTE filebase); - BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf) { PKEYMAN64THREADDATA _td = ThreadGlobals(); @@ -128,768 +117,3 @@ BOOL LoadlpKeyboard(int i) return TRUE; } - -/* - * Instead of performing a straightforward calculation of the 32 bit - * CRC using a series of logical operations, this program uses the - * faster table lookup method. This routine is called once when the - * program starts up to build the table which will be used later - * when calculating the CRC values. - */ - -#define CRC32_POLYNOMIAL 0xEDB88320L - -unsigned long CRCTable[256]; - -void BuildCRCTable(void) -{ - static BOOL TableBuilt = FALSE; - int i; - int j; - unsigned long crc; - - if(!TableBuilt) - { - for(i = 0; i <= 255; i++) - { - crc = i; - - for(j = 8; j > 0; j--) - if(crc & 1) crc = (crc >> 1) ^ CRC32_POLYNOMIAL; else crc >>= 1; - - CRCTable[i] = crc; - } - } -} - - -/* - * This routine calculates the CRC for a block of data using the - * table lookup method. It accepts an original value for the crc, - * and returns the updated value. - */ - -unsigned long CalculateBufferCRC(unsigned long count, BYTE *p) -{ - unsigned long temp1; - unsigned long temp2; - unsigned long crc = 0xFFFFFFFFL; - - BuildCRCTable(); - - while (count-- != 0) - { - temp1 = ( crc >> 8 ) & 0x00FFFFFFL; - temp2 = CRCTable[((int) crc ^ *p++) & 0xff]; - crc = temp1 ^ temp2; - } - - return crc; -} - -//#define Err(s) - -void Err(char *s) -{ - SendDebugMessageFormat(0, sdmLoad, 0, "LoadKeyboard: %s", s); -} - -BOOL LoadKeyboard(LPSTR fileName, LPKEYBOARD *lpKeyboard) -{ - DWORD sz; - LPBYTE buf; - HANDLE hFile; - LPKEYBOARD kbp; - PBYTE filebase; - - if(!fileName || !lpKeyboard) - { - Err("Bad Filename"); - return FALSE; - } - - hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if(hFile == INVALID_HANDLE_VALUE) - { - Err("Could not open file"); - return FALSE; - } - - sz = GetFileSize(hFile, NULL); - -#ifdef _WIN64 - // allocate enough memory for expanded data structure + original data. - // Expanded data structure is double the size of data on disk (8-byte - // pointers) - on disk the "pointers" are relative to the beginning of - // the file. - // We save the original data at the end of buf; we don't copy strings, so - // those will remain in the location at the end of the buffer. - buf = new BYTE[sz * 3]; -#else - buf = new BYTE[sz]; -#endif - - if(!buf) - { - CloseHandle(hFile); - Err("Not allocmem"); - return FALSE; - } -#ifdef _WIN64 - filebase = buf + sz*2; -#else - filebase = buf; -#endif - - ReadFile(hFile, filebase, sz, &sz, NULL); - CloseHandle(hFile); - - PKEYMAN64THREADDATA _td = ThreadGlobals(); - if (!_td) { - delete[] buf; - return FALSE; - } - - if(*LPDWORD(filebase) != FILEID_COMPILED) - { - delete[] buf; - Err("Invalid file"); - return FALSE; - } - - if(!VerifyKeyboard(filebase)) return FALSE; - -#ifdef _WIN64 - kbp = CopyKeyboard(buf, filebase, sz); -#else - kbp = FixupKeyboard(buf, filebase, sz); -#endif - - if(!kbp) return FALSE; - - if(kbp->dwIdentifier != FILEID_COMPILED) { delete buf; Err("errNotFileID"); return FALSE; } - - kbp->hBitmap = LoadBitmapFileEx(filebase); - - *lpKeyboard = kbp; - - return TRUE; -} - - - -// These next two structs represent how the icon information is stored -// in an ICO file. -typedef struct -{ - BYTE bWidth; // Width of the image - BYTE bHeight; // Height of the image (times 2) - BYTE bColorCount; // Number of colors in image (0 if >=8bpp) - BYTE bReserved; // Reserved - WORD wPlanes; // Color Planes - WORD wBitCount; // Bits per pixel - DWORD dwBytesInRes; // how many bytes in this resource? - DWORD dwImageOffset; // where in the file is this image -} ICONDIRENTRY, *LPICONDIRENTRY; -typedef struct -{ - WORD idReserved; // Reserved - WORD idType; // resource type (1 for icons) - WORD idCount; // how many images? - ICONDIRENTRY idEntries[1]; // the entries for each image -} ICONDIR, *LPICONDIR; - -// The following two structs are for the use of this program in -// manipulating icons. They are more closely tied to the operation -// of this program than the structures listed above. One of the -// main differences is that they provide a pointer to the DIB -// information of the masks. -typedef struct -{ - UINT Width, Height, Colors; // Width, Height and bpp - LPBYTE lpBits; // ptr to DIB bits - DWORD dwNumBytes; // how many bytes? - LPBITMAPINFO lpbi; // ptr to header - LPBYTE lpXOR; // ptr to XOR image bits - LPBYTE lpAND; // ptr to AND image bits -} ICONIMAGE, *LPICONIMAGE; -typedef struct -{ - UINT nNumImages; // How many images? - ICONIMAGE IconImages[1]; // Image entries -} ICONRESOURCE, *LPICONRESOURCE; -/****************************************************************************/ -LPICONRESOURCE ReadIconFromICOFile( PBYTE buf, int sz ); -void FreeIconResource(LPICONRESOURCE lpIR); -HICON MakeIconFromResource( LPICONIMAGE lpIcon ); - -HBITMAP LoadBitmapFile(LPBYTE data, DWORD sz) -{ - BITMAPFILEHEADER *bmfh; - BITMAPINFO *bmi; - HBITMAP hBitmap, hBitmap2, hOldBmp1, hOldBmp2; - HDC hDC, hSrcDC, hSrcDC2; - LPICONRESOURCE lpir = NULL; - - bmfh = (BITMAPFILEHEADER *) data; - - if(bmfh->bfType == 0x4D42) - { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadKeyboard: Bitmap found"); - bmi = (BITMAPINFO *) (data + sizeof(BITMAPFILEHEADER)); - - hDC = GetDC(GetDesktopWindow()); - hSrcDC = CreateCompatibleDC(hDC); - hSrcDC2 = CreateCompatibleDC(hDC); - hBitmap = CreateDIBitmap(hDC, &bmi->bmiHeader, CBM_INIT, data + bmfh->bfOffBits, bmi, DIB_RGB_COLORS); - hBitmap2 = CreateCompatibleBitmap(hDC, 16, 16); - ReleaseDC(GetDesktopWindow(), hDC); - - hOldBmp1 = (HBITMAP) SelectObject(hSrcDC, hBitmap); - hOldBmp2 = (HBITMAP) SelectObject(hSrcDC2, hBitmap2); - BitBlt(hSrcDC2, 0, 0, 16, 16, hSrcDC, 0, 0, SRCCOPY); - SelectObject(hSrcDC, hOldBmp1); - SelectObject(hSrcDC2, hOldBmp2); - DeleteDC(hSrcDC); - DeleteDC(hSrcDC2); - DeleteObject(hBitmap); - } - else - { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadKeyboard: Icon found"); - - lpir = ReadIconFromICOFile(data, sz); - if(!lpir) - { - SendDebugMessageFormat(0, sdmLoad, 0, "LoadKeyboard: icon not loaded"); - return 0; - } - - if(lpir->nNumImages == 0) - { - FreeIconResource(lpir); - return 0; - } - - HICON hIcon = MakeIconFromResource(&lpir->IconImages[0]); - //HICON hIcon = CreateIcon(GetModuleHandle(LIBRARY_NAME), lpir->IconImages[0].Width, lpir->IconImages[0].Height, - // 1, lpir->IconImages[0].Colors, lpir->IconImages[0].lpAND, lpir->IconImages[0].lpXOR); - FreeIconResource(lpir); - - - if(hIcon == 0) - { - DebugLastError("MakeIconFromResource"); - return 0; - } - hDC = GetDC(GetDesktopWindow()); - - hBitmap2 = CreateCompatibleBitmap(hDC, 16, 16); - hSrcDC = CreateCompatibleDC(hDC); - ReleaseDC(GetDesktopWindow(), hDC); - - hOldBmp2 = (HBITMAP) SelectObject(hSrcDC, hBitmap2); - DrawIconEx(hSrcDC, 0, 0, hIcon, 16, 16, 0, NULL, DI_NORMAL); - SelectObject(hSrcDC, hOldBmp2); - DeleteDC(hSrcDC); - - DestroyIcon(hIcon); - - } - return hBitmap2; -} - - - -/**************************************************************************** -* -* FUNCTION: ReadICOHeader -* -* PURPOSE: Reads the header from an ICO file -* -* PARAMS: HANDLE hFile - handle to the file -* -* RETURNS: UINT - Number of images in file, -1 for failure -* -* History: -* July '95 - Created -* -\****************************************************************************/ -UINT ReadICOHeader( PBYTE buf ) -{ - if(*(PWORD)(buf) != 0) return (UINT)-1; - if(*(PWORD)(buf+2) != 1) return (UINT)-1; - return *(PWORD)(buf+4); -} -/* End ReadICOHeader() ****************************************************/ - - - - -/**************************************************************************** -* -* FUNCTION: DIBNumColors -* -* PURPOSE: Calculates the number of entries in the color table. -* -* PARAMS: LPSTR lpbi - pointer to the CF_DIB memory block -* -* RETURNS: WORD - Number of entries in the color table. -* -* History: -* July '95 - Copied -* -\****************************************************************************/ -WORD DIBNumColors( LPSTR lpbi ) -{ - WORD wBitCount; - DWORD dwClrUsed; - - dwClrUsed = ((LPBITMAPINFOHEADER) lpbi)->biClrUsed; - - if (dwClrUsed) - return (WORD) dwClrUsed; - - wBitCount = ((LPBITMAPINFOHEADER) lpbi)->biBitCount; - - switch (wBitCount) - { - case 1: return 2; - case 4: return 16; - case 8: return 256; - } - return 0; -} -/* End DIBNumColors() ******************************************************/ - - - -/**************************************************************************** -* -* FUNCTION: PaletteSize -* -* PURPOSE: Calculates the number of bytes in the color table. -* -* PARAMS: LPSTR lpbi - pointer to the CF_DIB memory block -* -* RETURNS: WORD - number of bytes in the color table -* -* -* History: -* July '95 - Copied -* -\****************************************************************************/ -WORD PaletteSize( LPSTR lpbi ) -{ - return ( DIBNumColors( lpbi ) * sizeof( RGBQUAD ) ); -} -/* End PaletteSize() ********************************************************/ - -/**************************************************************************** -* -* FUNCTION: FindDIBits -* -* PURPOSE: Locate the image bits in a CF_DIB format DIB. -* -* PARAMS: LPSTR lpbi - pointer to the CF_DIB memory block -* -* RETURNS: LPSTR - pointer to the image bits -* -* History: -* July '95 - Copied -* -\****************************************************************************/ -LPSTR FindDIBBits( LPSTR lpbi ) -{ - return ( lpbi + *(LPDWORD)lpbi + PaletteSize( lpbi ) ); -} -/* End FindDIBits() *********************************************************/ - - - -// How wide, in bytes, would this many bits be, DWORD aligned? -#define WIDTHBYTES(bits) ((((bits) + 31)>>5)<<2) - -/**************************************************************************** -* -* FUNCTION: BytesPerLine -* -* PURPOSE: Calculates the number of bytes in one scan line. -* -* PARAMS: LPBITMAPINFOHEADER lpBMIH - pointer to the BITMAPINFOHEADER -* that begins the CF_DIB block -* -* RETURNS: DWORD - number of bytes in one scan line (DWORD aligned) -* -* History: -* July '95 - Created -* -\****************************************************************************/ -DWORD BytesPerLine( LPBITMAPINFOHEADER lpBMIH ) -{ - return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount); -} -/* End BytesPerLine() ********************************************************/ - - -/**************************************************************************** -* -* FUNCTION: AdjustIconImagePointers -* -* PURPOSE: Adjusts internal pointers in icon resource struct -* -* PARAMS: LPICONIMAGE lpImage - the resource to handle -* -* RETURNS: BOOL - TRUE for success, FALSE for failure -* -* History: -* July '95 - Created -* -\****************************************************************************/ -BOOL AdjustIconImagePointers( LPICONIMAGE lpImage ) -{ - // Sanity check - if( lpImage==NULL ) - return FALSE; - // BITMAPINFO is at beginning of bits - lpImage->lpbi = (LPBITMAPINFO)lpImage->lpBits; - // Width - simple enough - lpImage->Width = lpImage->lpbi->bmiHeader.biWidth; - // Icons are stored in funky format where height is doubled - account for it - lpImage->Height = (lpImage->lpbi->bmiHeader.biHeight)/2; - // How many colors? - lpImage->Colors = lpImage->lpbi->bmiHeader.biPlanes * lpImage->lpbi->bmiHeader.biBitCount; - // XOR bits follow the header and color table - lpImage->lpXOR = (LPBYTE) FindDIBBits((LPSTR)lpImage->lpbi); - // AND bits follow the XOR bits - lpImage->lpAND = lpImage->lpXOR + (lpImage->Height*BytesPerLine((LPBITMAPINFOHEADER)(lpImage->lpbi))); - return TRUE; -} -/* End AdjustIconImagePointers() *******************************************/ - -/**************************************************************************** -* -* FUNCTION: ReadIconFromICOFile -* -* PURPOSE: Reads an Icon Resource from an ICO file -* -* PARAMS: LPCTSTR szFileName - Name of the ICO file -* -* RETURNS: LPICONRESOURCE - pointer to the resource, NULL for failure -* -* History: -* July '95 - Created -* -\****************************************************************************/ -LPICONRESOURCE ReadIconFromICOFile( PBYTE buf, int sz ) -{ - UNREFERENCED_PARAMETER(sz); - LPICONRESOURCE lpIR = NULL, lpNew = NULL; - HANDLE hFile = NULL; - //LPRESOURCEPOSINFO lpRPI = NULL; - UINT i; - LPICONDIRENTRY lpIDE = NULL; - - // Allocate memory for the resource structure - if( (lpIR = (LPICONRESOURCE) malloc( sizeof(ICONRESOURCE) )) == NULL ) - { - SendDebugMessageFormat(0, sdmLoad, 0, "Error Allocating Memory"); - return NULL; - } - - // Read in the header - if( (lpIR->nNumImages = ReadICOHeader(buf)) == (UINT)-1 ) - { - SendDebugMessageFormat(0, sdmLoad, 0, "Error Reading File Header"); - free( lpIR ); - return NULL; - } - // Adjust the size of the struct to account for the images - if( (lpNew = (LPICONRESOURCE) realloc( lpIR, sizeof(ICONRESOURCE) + ((lpIR->nNumImages-1) * sizeof(ICONIMAGE)) )) == NULL ) - { - SendDebugMessageFormat(0, sdmLoad, 0, "Error Allocating Memory"); - CloseHandle( hFile ); - free( lpIR ); - return NULL; - } - lpIR = lpNew; - // Store the original name - - // Allocate enough memory for the icon directory entries - if( (lpIDE = (LPICONDIRENTRY) malloc( lpIR->nNumImages * sizeof( ICONDIRENTRY ) ) ) == NULL ) - { - SendDebugMessageFormat(0, sdmLoad, 0, "Error Allocating Memory"); - free( lpIR ); - return NULL; - } - memcpy(lpIDE, buf + 6, lpIR->nNumImages * sizeof( ICONDIRENTRY )); - - // Loop through and read in each image - for( i = 0; i < lpIR->nNumImages; i++ ) - { - // Allocate memory for the resource - if( (lpIR->IconImages[i].lpBits = (LPBYTE) malloc(lpIDE[i].dwBytesInRes)) == NULL ) - { - SendDebugMessageFormat(0, sdmLoad, 0, "Error Allocating Memory"); - free( lpIR ); - free( lpIDE ); - return NULL; - } - lpIR->IconImages[i].dwNumBytes = lpIDE[i].dwBytesInRes; - // Seek to beginning of this image - memcpy(lpIR->IconImages[i].lpBits, buf + lpIDE[i].dwImageOffset, lpIDE[i].dwBytesInRes); - - // Set the internal pointers appropriately - if( ! AdjustIconImagePointers( &(lpIR->IconImages[i]) ) ) - { - SendDebugMessageFormat(0, sdmLoad, 0, "Error Converting to Internal Format"); - free( lpIDE ); - free( lpIR ); - return NULL; - } - } - // Clean up - free( lpIDE ); - //free( lpRPI ); - return lpIR; -} -/* End ReadIconFromICOFile() **********************************************/ - -void FreeIconResource(LPICONRESOURCE lpIR) -{ - for( UINT i = 0; i < lpIR->nNumImages; i++ ) - // Allocate memory for the resource - free(lpIR->IconImages[i].lpBits); - free( lpIR ); -} - -/**************************************************************************** -* -* FUNCTION: MakeIconFromResource -* -* PURPOSE: Makes an HICON from an icon resource -* -* PARAMS: LPICONIMAGE lpIcon - pointer to the icon resource -* -* RETURNS: HICON - handle to the new icon, NULL for failure -* -* History: -* July '95 - Created -* -\****************************************************************************/ -HICON MakeIconFromResource( LPICONIMAGE lpIcon ) -{ - HICON hIcon = NULL; - - // Sanity Check - if( lpIcon == NULL ) - return NULL; - if( lpIcon->lpBits == NULL ) - return NULL; - // Let the OS do the real work :) - hIcon = CreateIconFromResourceEx( lpIcon->lpBits, lpIcon->dwNumBytes, TRUE, 0x00030000, - (*(LPBITMAPINFOHEADER)(lpIcon->lpBits)).biWidth, (*(LPBITMAPINFOHEADER)(lpIcon->lpBits)).biHeight/2, 0 ); - - // It failed, odds are good we're on NT so try the non-Ex way - if( hIcon == NULL ) - { - // We would break on NT if we try with a 16bpp image - if(lpIcon->lpbi->bmiHeader.biBitCount != 16) - { - hIcon = CreateIconFromResource( lpIcon->lpBits, lpIcon->dwNumBytes, TRUE, 0x00030000 ); - } - } - return hIcon; -} -/* End MakeIconFromResource() **********************************************/ - -PWCHAR StringOffset(PBYTE base, DWORD offset) -{ - if(offset == 0) return NULL; - return (PWCHAR)(base + offset); -} - -#ifdef _WIN64 - -/** - CopyKeyboard will copy the data read into bufp from x86-sized structures into - x64-sized structures starting at `base` - * After this function finishes, we still need to keep the original data because - we don't copy the strings - This method is used on 64-bit architectures. -*/ -LPKEYBOARD CopyKeyboard(PBYTE bufp, PBYTE base, DWORD dwFileSize) -{ - UNREFERENCED_PARAMETER(dwFileSize); - - PCOMP_KEYBOARD ckbp = (PCOMP_KEYBOARD) base; - - /* Copy keyboard structure */ - - LPKEYBOARD kbp = (LPKEYBOARD) bufp; - bufp += sizeof(KEYBOARD); - - kbp->dwIdentifier = ckbp->dwIdentifier; - kbp->dwFileVersion = ckbp->dwFileVersion; - kbp->dwCheckSum = ckbp->dwCheckSum; - kbp->xxkbdlayout = ckbp->KeyboardID; - kbp->IsRegistered = ckbp->IsRegistered; - kbp->version = ckbp->version; - kbp->cxStoreArray = ckbp->cxStoreArray; - kbp->cxGroupArray = ckbp->cxGroupArray; - kbp->StartGroup[0] = ckbp->StartGroup[0]; - kbp->StartGroup[1] = ckbp->StartGroup[1]; - kbp->dwFlags = ckbp->dwFlags; - kbp->dwHotKey = ckbp->dwHotKey; - kbp->hBitmap = 0; // will be built later - - kbp->dpStoreArray = (LPSTORE) bufp; - bufp += sizeof(STORE) * kbp->cxStoreArray; - - kbp->dpGroupArray = (LPGROUP) bufp; - bufp += sizeof(GROUP) * kbp->cxGroupArray; - - PCOMP_STORE csp; - LPSTORE sp; - DWORD i; - - for( - csp = (PCOMP_STORE)(base + ckbp->dpStoreArray), sp = kbp->dpStoreArray, i = 0; - i < kbp->cxStoreArray; - i++, sp++, csp++) - { - sp->dwSystemID = csp->dwSystemID; - sp->dpName = StringOffset(base, csp->dpName); - sp->dpString = StringOffset(base, csp->dpString); - } - - PCOMP_GROUP cgp; - LPGROUP gp; - - for( - cgp = (PCOMP_GROUP)(base + ckbp->dpGroupArray), gp = kbp->dpGroupArray, i = 0; - i < kbp->cxGroupArray; - i++, gp++, cgp++) - { - gp->dpName = StringOffset(base, cgp->dpName); - gp->dpKeyArray = cgp->cxKeyArray > 0 ? (LPKEY) bufp : NULL; - gp->cxKeyArray = cgp->cxKeyArray; - bufp += sizeof(KEY) * gp->cxKeyArray; - gp->dpMatch = StringOffset(base, cgp->dpMatch); - gp->dpNoMatch = StringOffset(base, cgp->dpNoMatch); - gp->fUsingKeys = cgp->fUsingKeys; - - PCOMP_KEY ckp; - LPKEY kp; - DWORD j; - - for( - ckp = (PCOMP_KEY)(base + cgp->dpKeyArray), kp = gp->dpKeyArray, j = 0; - j < gp->cxKeyArray; - j++, kp++, ckp++) - { - kp->Key = ckp->Key; - kp->Line = ckp->Line; - kp->ShiftFlags = ckp->ShiftFlags; - kp->dpOutput = StringOffset(base, ckp->dpOutput); - kp->dpContext = StringOffset(base, ckp->dpContext); - } - } - - return kbp; -} - -#else - -/** - Fixup the keyboard by expanding pointers. On disk the pointers are stored relative to the - beginning of the file, but we need real pointers. This method is used on 32-bit architectures. -*/ -LPKEYBOARD FixupKeyboard(PBYTE bufp, PBYTE base, DWORD dwFileSize) -{ - UNREFERENCED_PARAMETER(dwFileSize); - - DWORD i, j; - PCOMP_KEYBOARD ckbp = (PCOMP_KEYBOARD) base; - PCOMP_GROUP cgp; - PCOMP_STORE csp; - PCOMP_KEY ckp; - LPKEYBOARD kbp = (LPKEYBOARD) bufp; - LPSTORE sp; - LPGROUP gp; - LPKEY kp; - - kbp->dpStoreArray = (LPSTORE) (base + ckbp->dpStoreArray); - kbp->dpGroupArray = (LPGROUP) (base + ckbp->dpGroupArray); - -/*if( ckbp->dwBitmapSize > 0 ) - kbp->hBitmap = LoadBitmapFile((buf + ckbp->dpBitmapOffset), ckbp->dwBitmapSize); - else - kbp->hBitmap = NULL; -*/ - - for(sp = kbp->dpStoreArray, csp = (PCOMP_STORE) sp, i = 0; i < kbp->cxStoreArray; i++, sp++, csp++) - { - sp->dpName = StringOffset(base, csp->dpName); - sp->dpString = StringOffset(base, csp->dpString); - } - - for(gp = kbp->dpGroupArray, cgp = (PCOMP_GROUP) gp, i = 0; i < kbp->cxGroupArray; i++, gp++, cgp++) - { - gp->dpName = StringOffset(base, cgp->dpName); - gp->dpKeyArray = cgp->cxKeyArray > 0 ? (LPKEY) (base + cgp->dpKeyArray) : NULL; - gp->dpMatch = StringOffset(base, cgp->dpMatch); - gp->dpNoMatch = StringOffset(base, cgp->dpNoMatch); - - for(kp = gp->dpKeyArray, ckp = (PCOMP_KEY) kp, j = 0; j < gp->cxKeyArray; j++, kp++, ckp++) - { - kp->dpOutput = StringOffset(base, ckp->dpOutput); - kp->dpContext = StringOffset(base, ckp->dpContext); - } - } - - return kbp; -} - -#endif - -HBITMAP LoadBitmapFileEx(PBYTE filebase) -{ - PCOMP_KEYBOARD ckbp = (PCOMP_KEYBOARD) filebase; - - if( ckbp->dwBitmapSize > 0 ) - return LoadBitmapFile(filebase + ckbp->dpBitmapOffset, ckbp->dwBitmapSize); - else - return NULL; -} - - -BOOL VerifyKeyboard(LPBYTE filebase) -{ - DWORD i; - PCOMP_KEYBOARD ckbp = (PCOMP_KEYBOARD) filebase; - PCOMP_STORE csp; - - /* Check file version */ - - if(ckbp->dwFileVersion < VERSION_MIN || - ckbp->dwFileVersion > VERSION_MAX) - { - for(csp = (PCOMP_STORE)(filebase + ckbp->dpStoreArray), i = 0; i < ckbp->cxStoreArray; i++, csp++) { - if(csp->dwSystemID == TSS_COMPILEDVERSION) - { - char buf2[256]; - if(csp->dpString == 0) - wsprintf(buf2, "errWrongFileVersion:NULL"); - else - wsprintf(buf2, "errWrongFileVersion:%10.10ls", StringOffset(filebase, csp->dpString)); - Err(buf2); - return FALSE; - } - } - Err("errWrongFileVersion"); - return FALSE; - } - - return TRUE; -} diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index c563210a76..5803407cc1 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -124,14 +124,7 @@ LRESULT CALLBACK kmnLowLevelKeyboardProc( // I4124 BOOL ReleaseStateMemoryCore(km_core_state** state); BOOL ReleaseKeyboardMemoryCore(km_core_keyboard** kbd); -void PostGETNEXT(HWND hwnd); -BOOL CompareMsg(LPMSG MsgA, LPMSG MsgB); BOOL ProcessHook(); // returns FALSE on error or key not matched [only for AITip] -BOOL ProcessMessage( LPMSG mp ); -BOOL ProcessGroup(LPGROUP gp); -BOOL ContextMatch(LPKEY kkp); -int PostString(PWSTR str, LPMSG mp, LPKEYBOARD lpkb, PWSTR endstr); -BOOL LoadAllKeymanKeyboards(DWORD layout); BOOL IsSysTrayWindow(HWND hwnd); @@ -149,7 +142,6 @@ BOOL SelectKeyboard(DWORD KeymanID); extern "C" DWORD _declspec(dllexport) WINAPI GetActiveKeymanID(); BOOL GetKeyboardFileName(LPSTR kbname, LPSTR buf, int nbuf); -BOOL LoadKeyboard(LPSTR fileName, LPKEYBOARD *lpKeyboard); BOOL LoadlpKeyboard(int i); PSTR wstrtostr(PCWSTR in); From 5224affd38bf3cf97c8e015c2905c47656724f36 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 23 Nov 2023 11:30:57 +1000 Subject: [PATCH 05/14] chore(windows): remove unused globals relating to old keyboard debugging Fixes #10056. Removes: * Globals::miniContext * Globals::miniContextIfLen * Globals::indexStack * Globals::msgbuf * GLOBAL_ContextStackSize * GLOBAL_MsgStackSize * GLOBAL_MaxKeyboards * INI struct (and commented-out usage of this) --- windows/src/engine/keyman32/globals.h | 13 ----- windows/src/engine/keyman32/k32_globals.cpp | 10 ---- windows/src/engine/keyman32/keyman32.cpp | 61 +-------------------- windows/src/engine/keyman32/keymanengine.h | 7 --- 4 files changed, 3 insertions(+), 88 deletions(-) diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index 22a0e437e9..8f1dfc4c90 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -54,10 +54,6 @@ #include -#define GLOBAL_ContextStackSize 80 -#define GLOBAL_MsgStackSize 80 -#define GLOBAL_MaxKeyboards 32 - #include "serialkeyeventclient.h" #include "SharedBuffers.h" @@ -66,8 +62,6 @@ class Globals { public: - //static INI *Ini(); - static HHOOK *hhookGetMessage(); static HHOOK *hhookCallWndProc(); @@ -196,16 +190,9 @@ typedef struct tagKEYMAN64THREADDATA LPINTKEYBOARDINFO lpKeyboards; // keyboard definitions LPINTKEYBOARDINFO lpActiveKeyboard; - // I3616 - LPMSG msgbuf; // Message buffer (alloc at runtime) - int nKeyboards; // nLoadedKeyboards int nLanguages; // I1087 //TODO UNUSED - LPWORD IndexStack; - LPWSTR miniContext; - int miniContextIfLen; - KMSTATE state; AITIP *app; diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index bc500e763d..fb82735377 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -217,9 +217,6 @@ BOOL Globals_ProcessInitialised() #pragma data_seg(".SHARDATA") -//static INI // I3158 // I3524 -// f_Ini = {0}; // KEYMAN.INI options - static HHOOK f_hhookGetMessage = NULL, // GETMESSAGE hook handle f_hhookCallWndProc = NULL; // CALLWNDPROC hook handle @@ -295,8 +292,6 @@ DWORD //static HANDLE f_hLockMutex = 0; -//INI *Globals::Ini() { return &f_Ini; } // I3158 // I3524 - HHOOK *Globals::hhookGetMessage() { return &f_hhookGetMessage; } HHOOK *Globals::hhookCallWndProc() { return &f_hhookCallWndProc; } @@ -427,11 +422,6 @@ BOOL Globals::ResetControllers() // I3092 f_MasterController = NULL; f_MaxControllerThreads = 0; - /* I3158 // I3524 - f_Ini.ContextStackSize = 0; - f_Ini.MaxKeyboards = 0; - f_Ini.MsgStackSize = 0; - */ f_hhookCallWndProc = NULL; f_hhookGetMessage = NULL; #ifndef _WIN64 diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp index 5dfdaab079..9dbd692525 100644 --- a/windows/src/engine/keyman32/keyman32.cpp +++ b/windows/src/engine/keyman32/keyman32.cpp @@ -157,27 +157,9 @@ void UninitDebuggingEx(); BOOL UninitialiseProcess(BOOL Lock) { if(!Globals_ProcessInitialised()) return TRUE; - - ReleaseKeyboards(Lock); - - UninitDebuggingEx(); - - PKEYMAN64THREADDATA _td = ThreadGlobals(); // This is safe because of Globals_ProcessInitialised call above - if(_td) - { - if(_td->msgbuf) delete _td->msgbuf; - _td->msgbuf = NULL; - - if(_td->IndexStack) delete _td->IndexStack; - _td->IndexStack = NULL; - - if (_td->miniContext) delete _td->miniContext; - _td->miniContext = NULL; - - if (_td->msgbuf) delete _td->msgbuf; - _td->msgbuf = NULL; - } - return TRUE; + ReleaseKeyboards(Lock); + UninitDebuggingEx(); + return TRUE; } LONG FStartedInitialise = FALSE; @@ -239,34 +221,8 @@ BOOL InitThread(HWND hwnd) // I2448 - Removed "|| _td->FInitialised" -- this should not be included because sometimes it can be re-initialised. } - // TODO: Check if we are initialising again and don't reallocate memory. This can happen if Keyman is restarted - _td->FInitialising = TRUE; // Control re-entrancy, this is thread safe because the variable is per-thread - _td->IndexStack = new WORD[GLOBAL_ContextStackSize]; //Globals::Ini()->ContextStackSize]; // I3158 // I3524 - if(!_td->IndexStack) - { - SendDebugMessage(hwnd, sdmGlobal, 0, "InitialiseProcess: Failed to allocate memory for IndexStack"); - SetLastError(ERROR_KEYMAN_MEMORY_ALLOCATION_FAILED); // I3143 // I3523 - return FALSE; - } - - _td->miniContext = new WCHAR[GLOBAL_ContextStackSize]; //Globals::Ini()->ContextStackSize]; // I3158 // I3524 - if(!_td->miniContext) - { - SendDebugMessage(hwnd, sdmGlobal, 0, "InitialiseProcess: Failed to allocate memory for miniContext"); - SetLastError(ERROR_KEYMAN_MEMORY_ALLOCATION_FAILED); // I3143 // I3523 - return FALSE; - } - - _td->msgbuf = new MSG[GLOBAL_MsgStackSize]; //Globals::Ini()->MsgStackSize]; // I3158 // I3524 - if(!_td->msgbuf) - { - SendDebugMessage(hwnd, sdmGlobal, 0, "InitialiseProcess: Failed to allocate memory for msgbuf"); - SetLastError(ERROR_KEYMAN_MEMORY_ALLOCATION_FAILED); // I3143 // I3523 - return FALSE; - } - RefreshKeyboards(TRUE); SendDebugMessageFormat(hwnd, sdmGlobal, 0, "--InitialiseProcess LEAVE--"); @@ -316,10 +272,6 @@ BOOL InitialiseProcess(HWND hwnd) DoChangeWindowMessageFilter(); - //GetINIAdvanced(); /* I163x - Fix crash due to memory corruption - Globals::Ini not initialized before use - only appeared to happen on x64? */ // I3158 // I3524 - - SendDebugMessageFormat(hwnd, sdmGlobal, 0, "ContextStackSize: %d", GLOBAL_ContextStackSize); // Globals::Ini()->ContextStackSize); // I3158 // I3524 - return InitThread(hwnd); } @@ -461,13 +413,6 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Initialise(HWND Handle, BOOL return TRUE; } -/*void GetINIAdvanced(void) // I3158 // I3524 -{ - Globals::Ini()->ContextStackSize = 80; - Globals::Ini()->MsgStackSize = 80; - Globals::Ini()->MaxKeyboards = 32; -}*/ - extern "C" BOOL _declspec(dllexport) WINAPI Keyman_StartExit(void) // I3092 { *Globals::Keyman_Shutdown() = TRUE; diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h index 5803407cc1..3c6e2d3aff 100644 --- a/windows/src/engine/keyman32/keymanengine.h +++ b/windows/src/engine/keyman32/keymanengine.h @@ -92,13 +92,6 @@ typedef struct tagINTKEYBOARDINFO km_core_keyboard_imx* lpIMXList; } INTKEYBOARDINFO, * LPINTKEYBOARDINFO; -typedef struct tagINI -{ - int MsgStackSize; - int MaxKeyboards; - int ContextStackSize; -} INI; - typedef struct tagKMSTATE { BOOL NoMatches; From 21e0254c95077bc617cf1f14a5ff7e7383f65e23 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 23 Nov 2023 11:51:22 +1000 Subject: [PATCH 06/14] chore(core): remove vkey output from kmx processor Fixes #10049. vkey output was never supported by Core, so this code effectively was a no-op. --- core/src/kmx/kmx_actions.cpp | 3 --- core/src/kmx/kmx_actions.h | 12 ++++-------- core/src/kmx/kmx_processevent.cpp | 18 +++--------------- core/src/kmx/kmx_processor.cpp | 6 ------ 4 files changed, 7 insertions(+), 32 deletions(-) diff --git a/core/src/kmx/kmx_actions.cpp b/core/src/kmx/kmx_actions.cpp index 4e3f613357..5ea5f4e8a1 100644 --- a/core/src/kmx/kmx_actions.cpp +++ b/core/src/kmx/kmx_actions.cpp @@ -35,9 +35,6 @@ KMX_BOOL KMX_Actions::QueueAction(int ItemType, KMX_DWORD dwData) switch(ItemType) { - case QIT_VKEYDOWN: - break; - case QIT_DEADKEY: m_context->Add(UC_SENTINEL); m_context->Add(CODE_DEADKEY); diff --git a/core/src/kmx/kmx_actions.h b/core/src/kmx/kmx_actions.h index b536a3018a..c2ec61f43e 100644 --- a/core/src/kmx/kmx_actions.h +++ b/core/src/kmx/kmx_actions.h @@ -20,10 +20,10 @@ typedef struct } KMX_Action; // QueueAction ItemTypes -#define QIT_VKEYDOWN 0 -#define QIT_VKEYUP 1 -#define QIT_VSHIFTDOWN 2 -#define QIT_VSHIFTUP 3 +// QIT_VKEYDOWN 0 Not supported by Core, legacy Windows-only, see #10049 +// QIT_VKEYUP 1 Not supported by Core, legacy Windows-only, see #10049 +// QIT_VSHIFTDOWN 2 Not supported by Core, legacy Windows-only, see #10049 +// QIT_VSHIFTUP 3 Not supported by Core, legacy Windows-only, see #10049 #define QIT_CHAR 4 #define QIT_DEADKEY 5 #define QIT_BELL 6 @@ -35,10 +35,6 @@ typedef struct #define QIT_MAX 11 -#define QVK_EXTENDED 0x00010000 // Flag for QIT_VKEYDOWN to indicate an extended key -#define QVK_KEYMASK 0x0000FFFF -#define QVK_FLAGMASK 0xFFFF0000 - class KMX_Actions { private: diff --git a/core/src/kmx/kmx_processevent.cpp b/core/src/kmx/kmx_processevent.cpp index 8e07e963c0..cd0ca7c90c 100644 --- a/core/src/kmx/kmx_processevent.cpp +++ b/core/src/kmx/kmx_processevent.cpp @@ -434,7 +434,7 @@ int KMX_ProcessEvent::PostString(PKMX_WCHAR str, LPKEYBOARD lpkb, PKMX_WCHAR end PKMX_WCHAR p, q, temp; LPSTORE s; int n1, n2; - int i, n, shift; + int i, n; KMX_BOOL FoundUse = FALSE; // TODO: Refactor to use incxstr for(p = str; *p && (p < endstr || !endstr); p++) @@ -443,21 +443,9 @@ int KMX_ProcessEvent::PostString(PKMX_WCHAR str, LPKEYBOARD lpkb, PKMX_WCHAR end switch(*(++p)) { case CODE_EXTENDED: // Start of a virtual key section w/shift codes - p++; - - shift = *p; //(*p<<8) | *(p+1); - m_actions.QueueAction(QIT_VSHIFTDOWN, shift); - - p++; - - m_actions.QueueAction(QIT_VKEYDOWN, *p); - m_actions.QueueAction(QIT_VKEYUP, *p); - - m_actions.QueueAction(QIT_VSHIFTUP, shift); - + p++; // modifier + p++; // vkey p++; // CODE_EXTENDEDEND - ////// CODE_EXTENDEDEND will be incremented by loop - break; case CODE_DEADKEY: // A deadkey to be output diff --git a/core/src/kmx/kmx_processor.cpp b/core/src/kmx/kmx_processor.cpp index bb18db9edd..c72d2fe857 100644 --- a/core/src/kmx/kmx_processor.cpp +++ b/core/src/kmx/kmx_processor.cpp @@ -205,12 +205,6 @@ kmx_processor::internal_process_queued_actions(km_core_state *state) { case QIT_EMIT_KEYSTROKE: state->actions().push_emit_keystroke(); break; - case QIT_VKEYDOWN: - case QIT_VKEYUP: - case QIT_VSHIFTDOWN: - case QIT_VSHIFTUP: - // TODO: eliminate?? - break; case QIT_CHAR: state->context().push_character(a.dwData); state->actions().push_character(a.dwData); From 958fb6a5c9f1201ddb1456b989d8284cd358b6be Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 23 Nov 2023 11:58:41 +1000 Subject: [PATCH 07/14] chore: add comment --- core/src/kmx/kmx_processevent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/kmx/kmx_processevent.cpp b/core/src/kmx/kmx_processevent.cpp index cd0ca7c90c..4b98312c36 100644 --- a/core/src/kmx/kmx_processevent.cpp +++ b/core/src/kmx/kmx_processevent.cpp @@ -443,6 +443,7 @@ int KMX_ProcessEvent::PostString(PKMX_WCHAR str, LPKEYBOARD lpkb, PKMX_WCHAR end switch(*(++p)) { case CODE_EXTENDED: // Start of a virtual key section w/shift codes + // virtual keys in output are not supported p++; // modifier p++; // vkey p++; // CODE_EXTENDEDEND From e983818bda9a2bcfc8758d70ccd0c7b7aaf5285c Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 23 Nov 2023 15:13:56 +1000 Subject: [PATCH 08/14] feat(developer): warn on usage of virtual keys in rule output Fixes #10059. Use of the unsupported and undocumented virtual key output, that doesn't work in recent Keyman versions, at all, now results in a build warning. Only a warning, because it did kinda work in old versions of Keyman. --- .../src/common/include/kmn_compiler_errors.h | 2 ++ .../src/compiler/kmn-compiler-messages.ts | 2 ++ .../warn_virtual_key_in_output.kmn | 9 ++++++++ developer/src/kmc-kmn/test/test-messages.ts | 7 ++++++ developer/src/kmcmplib/src/CompMsg.cpp | 1 + developer/src/kmcmplib/src/Compiler.cpp | 22 +++++++++++++++++++ 6 files changed, 43 insertions(+) create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_virtual_key_in_output.kmn diff --git a/developer/src/common/include/kmn_compiler_errors.h b/developer/src/common/include/kmn_compiler_errors.h index fe7ba11a15..e0bea39549 100644 --- a/developer/src/common/include/kmn_compiler_errors.h +++ b/developer/src/common/include/kmn_compiler_errors.h @@ -240,6 +240,8 @@ #define CHINT_UnreachableRule 0x000010AE +#define CWARN_VirtualKeyInOutput 0x000020AF + #define CERR_BufferOverflow 0x000080C0 #define CERR_Break 0x000080C1 diff --git a/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts b/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts index 2995c8f016..4ad9d02598 100644 --- a/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts +++ b/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts @@ -302,6 +302,8 @@ export class KmnCompilerMessages { static HINT_UnreachableRule = SevHint | 0x0AE; + static WARN_VirtualKeyInOutput = SevWarn | 0x0AF; + static FATAL_BufferOverflow = SevFatal | 0x0C0; static FATAL_Break = SevFatal | 0x0C1; }; diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_virtual_key_in_output.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_virtual_key_in_output.kmn new file mode 100644 index 0000000000..e4919689b1 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/warn_virtual_key_in_output.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'WARN_VirtualKeyInOutput' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c WARN_VirtualKeyInOutput ++ 'a' > [K_BKQUOTE] diff --git a/developer/src/kmc-kmn/test/test-messages.ts b/developer/src/kmc-kmn/test/test-messages.ts index 6970b99741..51e6894daa 100644 --- a/developer/src/kmc-kmn/test/test-messages.ts +++ b/developer/src/kmc-kmn/test/test-messages.ts @@ -87,4 +87,11 @@ describe('CompilerMessages', function () { assert.equal(callbacks.messages[0].message, "Statement 'return' is not currently supported in output for web and touch targets"); }); + // WARN_VirtualKeyInOutput + + it('should generate WARN_VirtualKeyInOutput if a virtual key is found in the output part of a rule', async function() { + await testForMessage(this, ['invalid-keyboards', 'warn_virtual_key_in_output.kmn'], KmnCompilerMessages.WARN_VirtualKeyInOutput); + assert.equal(callbacks.messages[0].message, "Virtual keys are not supported in output"); + }); + }); diff --git a/developer/src/kmcmplib/src/CompMsg.cpp b/developer/src/kmcmplib/src/CompMsg.cpp index 8ab5db81f6..715750d4f2 100644 --- a/developer/src/kmcmplib/src/CompMsg.cpp +++ b/developer/src/kmcmplib/src/CompMsg.cpp @@ -143,6 +143,7 @@ const struct CompilerError CompilerErrors[] = { { CWARN_NulNotFirstStatementInContext , "nul must be the first statement in the context"}, { CWARN_IfShouldBeAtStartOfContext , "if, platform and baselayout should be at start of context (after nul, if present)"}, { CWARN_KeyShouldIncludeNCaps , "Other rules which reference this key include CAPS or NCAPS modifiers, so this rule must include NCAPS modifier to avoid inconsistent matches"}, + { CWARN_VirtualKeyInOutput , "Virtual keys are not supported in output"}, { 0, nullptr } }; diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index e2720f8608..045b1c39ad 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -1331,6 +1331,7 @@ KMX_BOOL CheckContextStatementPositions(PKMX_WCHAR context) { return TRUE; } + /** * Checks if a use() statement is followed by other content in the output of a rule */ @@ -1348,6 +1349,22 @@ KMX_DWORD CheckUseStatementsInOutput(PKMX_WCHAR output) { return CERR_None; } +/** + * Warn if output has virtual keys in it, which is not supported by Core at all, + * but was unofficially supported, but never worked properly, in Keyman for + * Windows for many years + */ +KMX_DWORD CheckVirtualKeysInOutput(PKMX_WCHAR output) { + PKMX_WCHAR p; + for (p = output; *p; p = incxstr(p)) { + if (*p == UC_SENTINEL && *(p + 1) == CODE_EXTENDED) { + AddWarning(CWARN_VirtualKeyInOutput); + break; + } + } + return CERR_None; +} + /** * Adds implicit `context` to start of output of rules for readonly groups */ @@ -1472,6 +1489,11 @@ KMX_DWORD ProcessKeyLineImpl(PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX_BOOL IsUnico return msg; // I4867 } + // Warn if virtual keys are used in the output, as they are unsupported by Core + if ((msg = CheckVirtualKeysInOutput(pklOut)) != CERR_None) { + return msg; + } + if (gp->fReadOnly) { // Ensure no output is made from the rule, and that // use() statements meet required readonly semantics From fb7c19fee4187483762fcedd933a41cc068b238b Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Fri, 17 Nov 2023 17:47:02 +0100 Subject: [PATCH 09/14] chore(core): Add test keyboard for text selection tests Part of #9073. --- .../HISTORY.md | 6 + .../LICENSE.md | 21 + .../README.md | 31 ++ .../source/readme.htm | 24 + .../text_selection_tests_keyboard_9073.ico | Bin 0 -> 1150 bytes ...on_tests_keyboard_9073.keyman-touch-layout | 527 ++++++++++++++++++ .../text_selection_tests_keyboard_9073.kmn | 24 + .../text_selection_tests_keyboard_9073.kps | 67 +++ .../text_selection_tests_keyboard_9073.kvks | 110 ++++ .../source/welcome.htm | 26 + ...election_tests_keyboard_9073.keyboard_info | 7 + .../text_selection_tests_keyboard_9073.kpj | 110 ++++ web/src/test/manual/web/index.html | 1 + .../web/text_selection_tests_9073/index.html | 78 +++ .../text_selection_tests_keyboard_9073.js | 1 + 15 files changed, 1033 insertions(+) create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/HISTORY.md create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/LICENSE.md create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/README.md create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/source/readme.htm create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.ico create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.keyman-touch-layout create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kmn create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kps create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kvks create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/source/welcome.htm create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.keyboard_info create mode 100644 common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.kpj create mode 100644 web/src/test/manual/web/text_selection_tests_9073/index.html create mode 100644 web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/HISTORY.md b/common/test/keyboards/text_selection_tests_keyboard_9073/HISTORY.md new file mode 100644 index 0000000000..e7e7675aa4 --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/HISTORY.md @@ -0,0 +1,6 @@ +Text Selection Tests Keyboard Change History +==================== + +1.0 (2023-11-14) +---------------- +* Created by Keyman Team diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/LICENSE.md b/common/test/keyboards/text_selection_tests_keyboard_9073/LICENSE.md new file mode 100644 index 0000000000..f199066a02 --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +© 2023 Keyman Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/README.md b/common/test/keyboards/text_selection_tests_keyboard_9073/README.md new file mode 100644 index 0000000000..1ab216d60f --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/README.md @@ -0,0 +1,31 @@ +Text Selection Tests Keyboard keyboard +============== + +Version 1.0 + +Description +----------- +Text Selection Tests Keyboard generated from template + +Links +----- +https://github.com/keymanapp/keyman/issues/9073 + +Copyright +--------- +See [LICENSE.md](LICENSE.md) + +Supported Platforms +------------------- + * Windows + * macOS + * Linux + * Web + * iPhone + * iPad + * Android phone + * Android tablet + * Mobile devices + * Desktop devices + * Tablet devices + diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/source/readme.htm b/common/test/keyboards/text_selection_tests_keyboard_9073/source/readme.htm new file mode 100644 index 0000000000..1d87395da8 --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/source/readme.htm @@ -0,0 +1,24 @@ + + + + + + Text Selection Tests Keyboard + + + + +

Text Selection Tests Keyboard

+ +

+ Text Selection Tests Keyboard 1.0 generated from template. +

+ +

© Keyman Team

+ + + diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.ico b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.ico new file mode 100644 index 0000000000000000000000000000000000000000..6a5271df0cfc45e0a53596020c181fa4decd151e GIT binary patch literal 1150 zcmZQzU<5(|0R;vS$Y5b$5ChU0Kr8^n3P8*VCV>o~96C5~=orID$1{Lo;OJPy;Na+t zg4eW0Gl1kGfN}@cb-=?ZZx%?*87_uR4J=I2<<@}gitHd;KgjO9d}kClq1yqo8$=_^ zf$WX|+C2m47i2$y)L`@ffmuZ;`ayQj0NRagCb}KScB9Kh" + }, + { + "id": "K_SLASH", + "text": "?" + }, + { + "width": 10, + "sp": 10 + } + ] + }, + { + "id": 5, + "key": [ + { + "width": 140, + "id": "K_LOPT", + "sp": 1, + "text": "*Menu*" + }, + { + "width": 930, + "id": "K_SPACE" + }, + { + "width": 145, + "id": "K_ENTER", + "sp": 1, + "text": "*Enter*" + } + ] + } + ] + } + ] + } +} \ No newline at end of file diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kmn b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kmn new file mode 100644 index 0000000000..4d72f81ded --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kmn @@ -0,0 +1,24 @@ +c text_selection_tests_keyboard_9073 generated from template at 2023-11-14 15:23:49 +c with name "Text Selection Tests Keyboard" +store(&VERSION) '10.0' +store(&NAME) 'Text Selection Tests Keyboard' +store(©RIGHT) '© Keyman Team' +store(&KEYBOARDVERSION) '1.0' +store(&TARGETS) 'any' +store(&BITMAP) 'text_selection_tests_keyboard_9073.ico' +store(&VISUALKEYBOARD) 'text_selection_tests_keyboard_9073.kvks' +store(&LAYOUTFILE) 'text_selection_tests_keyboard_9073.keyman-touch-layout' + +begin Unicode > use(main) + +group(main) using keys +'^' + [K_A] > 'â' +'^' + [SHIFT K_A] > 'Â' +'^' + [K_BKSP] > 'foo' + ++ '`' > dk(1) + +'a' dk(1) 'b' + [K_BKSP] > 'ok1' +'a' 'b' + [K_BKSP] > 'fail1' +'a' dk(1) + [K_BKSP] > 'fail2' +dk(1) + 'o' > 'ok3' diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kps b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kps new file mode 100644 index 0000000000..999160d84d --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kps @@ -0,0 +1,67 @@ + + + + 16.0.142.0 + 7.0 + + + + readme.htm + + + + + + + + + + Text Selection Tests Keyboard + © Keyman Team + Keyman Team + + + + + ..\build\text_selection_tests_keyboard_9073.kmx + + 0 + .kmx + + + ..\build\text_selection_tests_keyboard_9073.js + + 0 + .js + + + ..\build\text_selection_tests_keyboard_9073.kvk + + 0 + .kvk + + + welcome.htm + + 0 + .htm + + + readme.htm + + 0 + .htm + + + + + Text Selection Tests Keyboard + text_selection_tests_keyboard_9073 + 1.0 + + English + + + + + diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kvks b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kvks new file mode 100644 index 0000000000..9b69397b35 --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kvks @@ -0,0 +1,110 @@ + + +
+ 10.0 + text_selection_tests_keyboard_9073 + +
+ + + dk(1) + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + - + = + q + w + e + r + t + y + u + i + o + p + [ + ] + \ + a + s + d + f + g + h + j + k + l + ; + ' + \ + z + x + c + v + b + n + m + , + . + / + + + ~ + ! + @ + # + $ + % + ^ + & + * + ( + ) + _ + + + Q + W + E + R + T + Y + U + I + O + P + { + } + | + A + S + D + F + G + H + J + K + L + : + " + | + Z + X + C + V + B + N + M + < + > + ? + + +
diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/source/welcome.htm b/common/test/keyboards/text_selection_tests_keyboard_9073/source/welcome.htm new file mode 100644 index 0000000000..18b821f8c9 --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/source/welcome.htm @@ -0,0 +1,26 @@ + + + + + + Start Using Text Selection Tests Keyboard + + + + +

Start Using Text Selection Tests Keyboard

+ +

+ Text Selection Tests Keyboard 1.0 generated from template. +

+ +

Keyboard Layout

+ + + + + \ No newline at end of file diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.keyboard_info b/common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.keyboard_info new file mode 100644 index 0000000000..db0a8bf7bd --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.keyboard_info @@ -0,0 +1,7 @@ +{ + "license": "mit", + "languages": [ + "en" + ], + "description": "Text Selection Tests Keyboard generated from template" +} diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.kpj b/common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.kpj new file mode 100644 index 0000000000..3a80bf4be5 --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.kpj @@ -0,0 +1,110 @@ + + + + $PROJECTPATH\build + True + True + True + keyboard + + + + id_af1590e09d357f1c16c9a1fe9991a9d4 + text_selection_tests_keyboard_9073.kmn + source\text_selection_tests_keyboard_9073.kmn + 1.0 + .kmn +
+ Text Selection Tests Keyboard + © Keyman Team +
+
+ + id_ba932837e6a67a86abc409a393242255 + text_selection_tests_keyboard_9073.kps + source\text_selection_tests_keyboard_9073.kps + + .kps +
+ Text Selection Tests Keyboard + © Keyman Team +
+
+ + id_ede98e4633e239f933cbfd1f4e1b766c + HISTORY.md + HISTORY.md + + .md + + + id_53e892b8b41cc4caece1cfd5ef21d6e7 + LICENSE.md + LICENSE.md + + .md + + + id_0730bb7c2e8f9ea2438b52e419dd86c9 + README.md + README.md + + .md + + + id_4b87bd35cc2e16f1ff8680a6f2caed52 + text_selection_tests_keyboard_9073.keyboard_info + text_selection_tests_keyboard_9073.keyboard_info + + .keyboard_info + + + id_0993fe0cb7835cdfb2a101ceccc03e85 + text_selection_tests_keyboard_9073.ico + source\text_selection_tests_keyboard_9073.ico + + .ico + id_af1590e09d357f1c16c9a1fe9991a9d4 + + + id_aff9466042ad8bb0edf57fea7134c373 + text_selection_tests_keyboard_9073.kmx + source\..\build\text_selection_tests_keyboard_9073.kmx + + .kmx + id_ba932837e6a67a86abc409a393242255 + + + id_c463c12f68ab14a1f91927146a1942b8 + text_selection_tests_keyboard_9073.js + source\..\build\text_selection_tests_keyboard_9073.js + + .js + id_ba932837e6a67a86abc409a393242255 + + + id_4a6d9dbdd46a11790e170f92ffe90a6b + text_selection_tests_keyboard_9073.kvk + source\..\build\text_selection_tests_keyboard_9073.kvk + + .kvk + id_ba932837e6a67a86abc409a393242255 + + + id_356e5d149c1e539356d72698c1e401a6 + welcome.htm + source\welcome.htm + + .htm + id_ba932837e6a67a86abc409a393242255 + + + id_8da344c4cea6f467013357fe099006f5 + readme.htm + source\readme.htm + + .htm + id_ba932837e6a67a86abc409a393242255 + +
+
diff --git a/web/src/test/manual/web/index.html b/web/src/test/manual/web/index.html index 61ee99d2de..e98979f094 100644 --- a/web/src/test/manual/web/index.html +++ b/web/src/test/manual/web/index.html @@ -66,6 +66,7 @@

Tests predictive text & other handling of rule matching when the final rule group does not match (#6005)

Tests handling of new default-subkey feature (#9430)

Test special characters rendering with keymanweb-osk.ttf (#9469)

+

Test text selection (#9073)

Other

Keystroke processing regression test engine.


diff --git a/web/src/test/manual/web/text_selection_tests_9073/index.html b/web/src/test/manual/web/text_selection_tests_9073/index.html new file mode 100644 index 0000000000..20bd3cda68 --- /dev/null +++ b/web/src/test/manual/web/text_selection_tests_9073/index.html @@ -0,0 +1,78 @@ + + + + + + + + + KeymanWeb #9073 + + + + + + + + + + + + + + +

Text Selection Test Cases (#9073)

+ +
+ +
+ + +
+ +
+

Return to testing home page

+ + + + diff --git a/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js b/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js new file mode 100644 index 0000000000..7235b9c022 --- /dev/null +++ b/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js @@ -0,0 +1 @@ +if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_text_selection_tests_keyboard_9073());}function Keyboard_text_selection_tests_keyboard_9073(){this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;this.KI="Keyboard_text_selection_tests_keyboard_9073";this.KN="Text Selection Tests Keyboard";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KV.KLS={"default": ["dk(1)","1","2","3","4","5","6","7","8","9","0","-","=","","","","q","w","e","r","t","y","u","i","o","p","[","]","\\","","","","a","s","d","f","g","h","j","k","l",";","'","","","","","","\\","z","x","c","v","b","n","m",",",".","/","","","","","",""],"shift": ["~","!","@","#","$","%","^","&","*","(",")","_","+","","","","Q","W","E","R","T","Y","U","I","O","P","{","}","|","","","","A","S","D","F","G","H","J","K","L",":","\"","","","","","","|","Z","X","C","V","B","N","M","<",">","?","","","","","",""]};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KDU=0;this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x10;this.KVKL={"tablet":{"displayUnderlying":false,"layer":[{"id":"default","row":[{"id":"1","key":[{"id":"K_1","text":"1"},{"id":"K_2","text":"2"},{"id":"K_3","text":"3"},{"id":"K_4","text":"4"},{"id":"K_5","text":"5"},{"id":"K_6","text":"6"},{"id":"K_7","text":"7"},{"id":"K_8","text":"8"},{"id":"K_9","text":"9"},{"id":"K_0","text":"0"},{"id":"K_HYPHEN","text":"-"},{"id":"K_EQUAL","text":"="},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":"2","key":[{"id":"K_Q","text":"q","pad":"75"},{"id":"K_W","text":"w"},{"id":"K_E","text":"e"},{"id":"K_R","text":"r"},{"id":"K_T","text":"t"},{"id":"K_Y","text":"y"},{"id":"K_U","text":"u"},{"id":"K_I","text":"i"},{"id":"K_O","text":"o"},{"id":"K_P","text":"p"},{"id":"K_LBRKT","text":"["},{"id":"K_RBRKT","text":"]"},{"id":"T_new_136","width":"10","sp":"10"}]},{"id":"3","key":[{"id":"K_BKQUOTE","text":"dk(1)"},{"id":"K_A","text":"a"},{"id":"K_S","text":"s"},{"id":"K_D","text":"d"},{"id":"K_F","text":"f"},{"id":"K_G","text":"g"},{"id":"K_H","text":"h"},{"id":"K_J","text":"j"},{"id":"K_K","text":"k"},{"id":"K_L","text":"l"},{"id":"K_COLON","text":";"},{"id":"K_QUOTE","text":"'"},{"id":"K_BKSLASH","text":"\\"}]},{"id":"4","key":[{"id":"K_SHIFT","text":"*Shift*","width":"160","sp":"1"},{"id":"K_oE2","text":"\\"},{"id":"K_Z","text":"z"},{"id":"K_X","text":"x"},{"id":"K_C","text":"c"},{"id":"K_V","text":"v"},{"id":"K_B","text":"b"},{"id":"K_N","text":"n"},{"id":"K_M","text":"m"},{"id":"K_COMMA","text":","},{"id":"K_PERIOD","text":"."},{"id":"K_SLASH","text":"/"},{"id":"T_new_162","width":"10","sp":"10"}]},{"id":"5","key":[{"id":"K_LOPT","text":"*Menu*","width":"140","sp":"1"},{"id":"K_SPACE","width":"930"},{"id":"K_ENTER","text":"*Enter*","width":"145","sp":"1"}]}]},{"id":"shift","row":[{"id":"1","key":[{"id":"K_1","text":"!"},{"id":"K_2","text":"@"},{"id":"K_3","text":"#"},{"id":"K_4","text":"$"},{"id":"K_5","text":"%"},{"id":"K_6","text":"^"},{"id":"K_7","text":"&"},{"id":"K_8","text":"*"},{"id":"K_9","text":"("},{"id":"K_0","text":")"},{"id":"K_HYPHEN","text":"_"},{"id":"K_EQUAL","text":"+"},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"id":"K_Q","pad":"75","text":"Q"},{"id":"K_W","text":"W"},{"id":"K_E","text":"E"},{"id":"K_R","text":"R"},{"id":"K_T","text":"T"},{"id":"K_Y","text":"Y"},{"id":"K_U","text":"U"},{"id":"K_I","text":"I"},{"id":"K_O","text":"O"},{"id":"K_P","text":"P"},{"id":"K_LBRKT","text":"{"},{"id":"K_RBRKT","text":"}"},{"width":"10","sp":"10"}]},{"id":"3","key":[{"id":"K_BKQUOTE","text":"~"},{"id":"K_A","text":"A"},{"id":"K_S","text":"S"},{"id":"K_D","text":"D"},{"id":"K_F","text":"F"},{"id":"K_G","text":"G"},{"id":"K_H","text":"H"},{"id":"K_J","text":"J"},{"id":"K_K","text":"K"},{"id":"K_L","text":"L"},{"id":"K_COLON","text":":"},{"id":"K_QUOTE","text":"\""},{"id":"K_BKSLASH","text":"|"}]},{"id":"4","key":[{"width":"160","id":"K_SHIFT","sp":"1","text":"*Shift*"},{"id":"K_oE2","text":"|"},{"id":"K_Z","text":"Z"},{"id":"K_X","text":"X"},{"id":"K_C","text":"C"},{"id":"K_V","text":"V"},{"id":"K_B","text":"B"},{"id":"K_N","text":"N"},{"id":"K_M","text":"M"},{"id":"K_COMMA","text":"<"},{"id":"K_PERIOD","text":">"},{"id":"K_SLASH","text":"?"},{"width":"10","sp":"10"}]},{"id":"5","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"width":"930","id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]}]}};this.KVER="17.0.211.0";this.KVS=[];this.gs=function(t,e) {return this.g0(t,e);};this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,8)) {if(k.KFCM(3,t,['a',{t:'d',d:0},'b'])){r=m=1;k.KDC(3,t);k.KO(-1,t,"ok1");}else if(k.KFCM(2,t,['a','b'])){r=m=1;k.KDC(2,t);k.KO(-1,t,"fail1");}else if(k.KFCM(2,t,['a',{t:'d',d:0}])){r=m=1;k.KDC(2,t);k.KO(-1,t,"fail2");}else if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"foo");}}else if(k.KKM(e,16400,65)) {if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"Â");}}else if(k.KKM(e,16384,192)) {if(1){r=m=1;k.KDC(0,t);k.KDO(-1,t,0);}}else if(k.KKM(e,16384,65)) {if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"â");}}else if(k.KKM(e,16384,79)) {if(k.KFCM(1,t,[{t:'d',d:0}])){r=m=1;k.KDC(1,t);k.KO(-1,t,"ok3");}}return r;};} \ No newline at end of file From ef8b9888c864039881e89c5088caa6179bfbe135 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 23 Nov 2023 17:19:04 +0100 Subject: [PATCH 10/14] chore(web): Update touch layout --- ...on_tests_keyboard_9073.keyman-touch-layout | 39 +++++++++++-------- .../text_selection_tests_keyboard_9073.kpj | 12 +++--- .../text_selection_tests_keyboard_9073.js | 2 +- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.keyman-touch-layout b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.keyman-touch-layout index d6506b8fb2..6d02edfad8 100644 --- a/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.keyman-touch-layout +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.keyman-touch-layout @@ -10,7 +10,8 @@ "key": [ { "id": "K_1", - "text": "1" + "text": "1", + "nextlayer": "shift" }, { "id": "K_2", @@ -187,7 +188,8 @@ "id": "K_SHIFT", "text": "*Shift*", "width": 160, - "sp": 1 + "sp": 1, + "nextlayer": "shift" }, { "id": "K_oE2", @@ -318,10 +320,10 @@ "text": "+" }, { - "width": 100, "id": "K_BKSP", - "sp": 1, - "text": "*BkSp*" + "text": "*BkSp*", + "width": 100, + "sp": 1 } ] }, @@ -330,8 +332,8 @@ "key": [ { "id": "K_Q", - "pad": 75, - "text": "Q" + "text": "Q", + "pad": 75 }, { "id": "K_W", @@ -378,6 +380,7 @@ "text": "}" }, { + "id": "T_new_246", "width": 10, "sp": 10 } @@ -444,10 +447,11 @@ "id": 4, "key": [ { - "width": 160, "id": "K_SHIFT", + "text": "*Shift*", + "width": 160, "sp": 1, - "text": "*Shift*" + "nextlayer": "default" }, { "id": "K_oE2", @@ -494,6 +498,7 @@ "text": "?" }, { + "id": "T_new_272", "width": 10, "sp": 10 } @@ -503,20 +508,20 @@ "id": 5, "key": [ { - "width": 140, "id": "K_LOPT", - "sp": 1, - "text": "*Menu*" + "text": "*Menu*", + "width": 140, + "sp": 1 }, { - "width": 930, - "id": "K_SPACE" + "id": "K_SPACE", + "width": 930 }, { - "width": 145, "id": "K_ENTER", - "sp": 1, - "text": "*Enter*" + "text": "*Enter*", + "width": 145, + "sp": 1 } ] } diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.kpj b/common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.kpj index 3a80bf4be5..98b9ad7e0e 100644 --- a/common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.kpj +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/text_selection_tests_keyboard_9073.kpj @@ -9,7 +9,7 @@ - id_af1590e09d357f1c16c9a1fe9991a9d4 + id_dda967022de452e1fe199096e795f0ab text_selection_tests_keyboard_9073.kmn source\text_selection_tests_keyboard_9073.kmn 1.0 @@ -59,15 +59,15 @@ .keyboard_info - id_0993fe0cb7835cdfb2a101ceccc03e85 + id_bbf31cea8a9cfe0cb838f67055690bf8 text_selection_tests_keyboard_9073.ico source\text_selection_tests_keyboard_9073.ico .ico - id_af1590e09d357f1c16c9a1fe9991a9d4 + id_dda967022de452e1fe199096e795f0ab - id_aff9466042ad8bb0edf57fea7134c373 + id_b8f7a473cac52dd0436273de657cdf46 text_selection_tests_keyboard_9073.kmx source\..\build\text_selection_tests_keyboard_9073.kmx @@ -75,7 +75,7 @@ id_ba932837e6a67a86abc409a393242255 - id_c463c12f68ab14a1f91927146a1942b8 + id_73d0cd87e78d9b8d7f514809dbb36a47 text_selection_tests_keyboard_9073.js source\..\build\text_selection_tests_keyboard_9073.js @@ -83,7 +83,7 @@ id_ba932837e6a67a86abc409a393242255 - id_4a6d9dbdd46a11790e170f92ffe90a6b + id_71aafc060dc3251e4bb611ea539dc8e0 text_selection_tests_keyboard_9073.kvk source\..\build\text_selection_tests_keyboard_9073.kvk diff --git a/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js b/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js index 7235b9c022..a50848e7ea 100644 --- a/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js +++ b/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js @@ -1 +1 @@ -if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_text_selection_tests_keyboard_9073());}function Keyboard_text_selection_tests_keyboard_9073(){this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;this.KI="Keyboard_text_selection_tests_keyboard_9073";this.KN="Text Selection Tests Keyboard";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KV.KLS={"default": ["dk(1)","1","2","3","4","5","6","7","8","9","0","-","=","","","","q","w","e","r","t","y","u","i","o","p","[","]","\\","","","","a","s","d","f","g","h","j","k","l",";","'","","","","","","\\","z","x","c","v","b","n","m",",",".","/","","","","","",""],"shift": ["~","!","@","#","$","%","^","&","*","(",")","_","+","","","","Q","W","E","R","T","Y","U","I","O","P","{","}","|","","","","A","S","D","F","G","H","J","K","L",":","\"","","","","","","|","Z","X","C","V","B","N","M","<",">","?","","","","","",""]};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KDU=0;this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x10;this.KVKL={"tablet":{"displayUnderlying":false,"layer":[{"id":"default","row":[{"id":"1","key":[{"id":"K_1","text":"1"},{"id":"K_2","text":"2"},{"id":"K_3","text":"3"},{"id":"K_4","text":"4"},{"id":"K_5","text":"5"},{"id":"K_6","text":"6"},{"id":"K_7","text":"7"},{"id":"K_8","text":"8"},{"id":"K_9","text":"9"},{"id":"K_0","text":"0"},{"id":"K_HYPHEN","text":"-"},{"id":"K_EQUAL","text":"="},{"id":"K_BKSP","text":"*BkSp*","width":"100","sp":"1"}]},{"id":"2","key":[{"id":"K_Q","text":"q","pad":"75"},{"id":"K_W","text":"w"},{"id":"K_E","text":"e"},{"id":"K_R","text":"r"},{"id":"K_T","text":"t"},{"id":"K_Y","text":"y"},{"id":"K_U","text":"u"},{"id":"K_I","text":"i"},{"id":"K_O","text":"o"},{"id":"K_P","text":"p"},{"id":"K_LBRKT","text":"["},{"id":"K_RBRKT","text":"]"},{"id":"T_new_136","width":"10","sp":"10"}]},{"id":"3","key":[{"id":"K_BKQUOTE","text":"dk(1)"},{"id":"K_A","text":"a"},{"id":"K_S","text":"s"},{"id":"K_D","text":"d"},{"id":"K_F","text":"f"},{"id":"K_G","text":"g"},{"id":"K_H","text":"h"},{"id":"K_J","text":"j"},{"id":"K_K","text":"k"},{"id":"K_L","text":"l"},{"id":"K_COLON","text":";"},{"id":"K_QUOTE","text":"'"},{"id":"K_BKSLASH","text":"\\"}]},{"id":"4","key":[{"id":"K_SHIFT","text":"*Shift*","width":"160","sp":"1"},{"id":"K_oE2","text":"\\"},{"id":"K_Z","text":"z"},{"id":"K_X","text":"x"},{"id":"K_C","text":"c"},{"id":"K_V","text":"v"},{"id":"K_B","text":"b"},{"id":"K_N","text":"n"},{"id":"K_M","text":"m"},{"id":"K_COMMA","text":","},{"id":"K_PERIOD","text":"."},{"id":"K_SLASH","text":"/"},{"id":"T_new_162","width":"10","sp":"10"}]},{"id":"5","key":[{"id":"K_LOPT","text":"*Menu*","width":"140","sp":"1"},{"id":"K_SPACE","width":"930"},{"id":"K_ENTER","text":"*Enter*","width":"145","sp":"1"}]}]},{"id":"shift","row":[{"id":"1","key":[{"id":"K_1","text":"!"},{"id":"K_2","text":"@"},{"id":"K_3","text":"#"},{"id":"K_4","text":"$"},{"id":"K_5","text":"%"},{"id":"K_6","text":"^"},{"id":"K_7","text":"&"},{"id":"K_8","text":"*"},{"id":"K_9","text":"("},{"id":"K_0","text":")"},{"id":"K_HYPHEN","text":"_"},{"id":"K_EQUAL","text":"+"},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"id":"K_Q","pad":"75","text":"Q"},{"id":"K_W","text":"W"},{"id":"K_E","text":"E"},{"id":"K_R","text":"R"},{"id":"K_T","text":"T"},{"id":"K_Y","text":"Y"},{"id":"K_U","text":"U"},{"id":"K_I","text":"I"},{"id":"K_O","text":"O"},{"id":"K_P","text":"P"},{"id":"K_LBRKT","text":"{"},{"id":"K_RBRKT","text":"}"},{"width":"10","sp":"10"}]},{"id":"3","key":[{"id":"K_BKQUOTE","text":"~"},{"id":"K_A","text":"A"},{"id":"K_S","text":"S"},{"id":"K_D","text":"D"},{"id":"K_F","text":"F"},{"id":"K_G","text":"G"},{"id":"K_H","text":"H"},{"id":"K_J","text":"J"},{"id":"K_K","text":"K"},{"id":"K_L","text":"L"},{"id":"K_COLON","text":":"},{"id":"K_QUOTE","text":"\""},{"id":"K_BKSLASH","text":"|"}]},{"id":"4","key":[{"width":"160","id":"K_SHIFT","sp":"1","text":"*Shift*"},{"id":"K_oE2","text":"|"},{"id":"K_Z","text":"Z"},{"id":"K_X","text":"X"},{"id":"K_C","text":"C"},{"id":"K_V","text":"V"},{"id":"K_B","text":"B"},{"id":"K_N","text":"N"},{"id":"K_M","text":"M"},{"id":"K_COMMA","text":"<"},{"id":"K_PERIOD","text":">"},{"id":"K_SLASH","text":"?"},{"width":"10","sp":"10"}]},{"id":"5","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"width":"930","id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]}]}};this.KVER="17.0.211.0";this.KVS=[];this.gs=function(t,e) {return this.g0(t,e);};this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,8)) {if(k.KFCM(3,t,['a',{t:'d',d:0},'b'])){r=m=1;k.KDC(3,t);k.KO(-1,t,"ok1");}else if(k.KFCM(2,t,['a','b'])){r=m=1;k.KDC(2,t);k.KO(-1,t,"fail1");}else if(k.KFCM(2,t,['a',{t:'d',d:0}])){r=m=1;k.KDC(2,t);k.KO(-1,t,"fail2");}else if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"foo");}}else if(k.KKM(e,16400,65)) {if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"Â");}}else if(k.KKM(e,16384,192)) {if(1){r=m=1;k.KDC(0,t);k.KDO(-1,t,0);}}else if(k.KKM(e,16384,65)) {if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"â");}}else if(k.KKM(e,16384,79)) {if(k.KFCM(1,t,[{t:'d',d:0}])){r=m=1;k.KDC(1,t);k.KO(-1,t,"ok3");}}return r;};} \ No newline at end of file +if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_text_selection_tests_keyboard_9073());}function Keyboard_text_selection_tests_keyboard_9073(){this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;this.KI="Keyboard_text_selection_tests_keyboard_9073";this.KN="Text Selection Tests Keyboard";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KV.KLS={"default": ["dk(1)","1","2","3","4","5","6","7","8","9","0","-","=","","","","q","w","e","r","t","y","u","i","o","p","[","]","\\","","","","a","s","d","f","g","h","j","k","l",";","'","","","","","","\\","z","x","c","v","b","n","m",",",".","/","","","","","",""],"shift": ["~","!","@","#","$","%","^","&","*","(",")","_","+","","","","Q","W","E","R","T","Y","U","I","O","P","{","}","|","","","","A","S","D","F","G","H","J","K","L",":","\"","","","","","","|","Z","X","C","V","B","N","M","<",">","?","","","","","",""]};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KDU=0;this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x0010;this.KVKL={"tablet":{"displayUnderlying":false,"layer":[{"id":"default","row":[{"id":"1","key":[{"nextlayer":"shift","id":"K_1","text":"1"},{"id":"K_2","text":"2"},{"id":"K_3","text":"3"},{"id":"K_4","text":"4"},{"id":"K_5","text":"5"},{"id":"K_6","text":"6"},{"id":"K_7","text":"7"},{"id":"K_8","text":"8"},{"id":"K_9","text":"9"},{"id":"K_0","text":"0"},{"id":"K_HYPHEN","text":"-"},{"id":"K_EQUAL","text":"="},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"id":"K_Q","pad":"75","text":"q"},{"id":"K_W","text":"w"},{"id":"K_E","text":"e"},{"id":"K_R","text":"r"},{"id":"K_T","text":"t"},{"id":"K_Y","text":"y"},{"id":"K_U","text":"u"},{"id":"K_I","text":"i"},{"id":"K_O","text":"o"},{"id":"K_P","text":"p"},{"id":"K_LBRKT","text":"["},{"id":"K_RBRKT","text":"]"},{"width":"10","id":"T_new_136","sp":"10"}]},{"id":"3","key":[{"id":"K_BKQUOTE","text":"dk(1)"},{"id":"K_A","text":"a"},{"id":"K_S","text":"s"},{"id":"K_D","text":"d"},{"id":"K_F","text":"f"},{"id":"K_G","text":"g"},{"id":"K_H","text":"h"},{"id":"K_J","text":"j"},{"id":"K_K","text":"k"},{"id":"K_L","text":"l"},{"id":"K_COLON","text":";"},{"id":"K_QUOTE","text":"'"},{"id":"K_BKSLASH","text":"\\"}]},{"id":"4","key":[{"nextlayer":"shift","width":"160","id":"K_SHIFT","sp":"1","text":"*Shift*"},{"id":"K_oE2","text":"\\"},{"id":"K_Z","text":"z"},{"id":"K_X","text":"x"},{"id":"K_C","text":"c"},{"id":"K_V","text":"v"},{"id":"K_B","text":"b"},{"id":"K_N","text":"n"},{"id":"K_M","text":"m"},{"id":"K_COMMA","text":","},{"id":"K_PERIOD","text":"."},{"id":"K_SLASH","text":"\/"},{"width":"10","id":"T_new_162","sp":"10"}]},{"id":"5","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"width":"930","id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]},{"id":"shift","row":[{"id":"1","key":[{"id":"K_1","text":"!"},{"id":"K_2","text":"@"},{"id":"K_3","text":"#"},{"id":"K_4","text":"$"},{"id":"K_5","text":"%"},{"id":"K_6","text":"^"},{"id":"K_7","text":"&"},{"id":"K_8","text":"*"},{"id":"K_9","text":"("},{"id":"K_0","text":")"},{"id":"K_HYPHEN","text":"_"},{"id":"K_EQUAL","text":"+"},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"id":"K_Q","pad":"75","text":"Q"},{"id":"K_W","text":"W"},{"id":"K_E","text":"E"},{"id":"K_R","text":"R"},{"id":"K_T","text":"T"},{"id":"K_Y","text":"Y"},{"id":"K_U","text":"U"},{"id":"K_I","text":"I"},{"id":"K_O","text":"O"},{"id":"K_P","text":"P"},{"id":"K_LBRKT","text":"{"},{"id":"K_RBRKT","text":"}"},{"width":"10","id":"T_new_246","sp":"10"}]},{"id":"3","key":[{"id":"K_BKQUOTE","text":"~"},{"id":"K_A","text":"A"},{"id":"K_S","text":"S"},{"id":"K_D","text":"D"},{"id":"K_F","text":"F"},{"id":"K_G","text":"G"},{"id":"K_H","text":"H"},{"id":"K_J","text":"J"},{"id":"K_K","text":"K"},{"id":"K_L","text":"L"},{"id":"K_COLON","text":":"},{"id":"K_QUOTE","text":"\""},{"id":"K_BKSLASH","text":"|"}]},{"id":"4","key":[{"nextlayer":"default","width":"160","id":"K_SHIFT","sp":"1","text":"*Shift*"},{"id":"K_oE2","text":"|"},{"id":"K_Z","text":"Z"},{"id":"K_X","text":"X"},{"id":"K_C","text":"C"},{"id":"K_V","text":"V"},{"id":"K_B","text":"B"},{"id":"K_N","text":"N"},{"id":"K_M","text":"M"},{"id":"K_COMMA","text":"<"},{"id":"K_PERIOD","text":">"},{"id":"K_SLASH","text":"?"},{"width":"10","id":"T_new_272","sp":"10"}]},{"id":"5","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"width":"930","id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]}]}};this.KVER="16.0.142.0";this.KVS=[];this.gs=function(t,e) {return this.g0(t,e);};this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,8)) {if(k.KFCM(3,t,['a',{t:'d',d:0},'b'])){r=m=1;k.KDC(3,t);k.KO(-1,t,"ok1");}else if(k.KFCM(2,t,['a','b'])){r=m=1;k.KDC(2,t);k.KO(-1,t,"fail1");}else if(k.KFCM(2,t,['a',{t:'d',d:0}])){r=m=1;k.KDC(2,t);k.KO(-1,t,"fail2");}else if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"foo");}}else if(k.KKM(e,16400,65)) {if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"Â");}}else if(k.KKM(e,16384,192)) {if(1){r=m=1;k.KDC(0,t);k.KDO(-1,t,0);}}else if(k.KKM(e,16384,65)) {if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"â");}}else if(k.KKM(e,16384,79)) {if(k.KFCM(1,t,[{t:'d',d:0}])){r=m=1;k.KDC(1,t);k.KO(-1,t,"ok3");}}return r;};} \ No newline at end of file From f56033f5379ac128957546e7943c5fb023768039 Mon Sep 17 00:00:00 2001 From: Eberhard Beilharz Date: Thu, 23 Nov 2023 18:02:36 +0100 Subject: [PATCH 11/14] chore(web): Add TAB output to test keyboard --- .../text_selection_tests_keyboard_9073.kmn | 2 + .../text_selection_tests_keyboard_9073.js | 642 +++++++++++++++++- 2 files changed, 643 insertions(+), 1 deletion(-) diff --git a/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kmn b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kmn index 4d72f81ded..b40278a930 100644 --- a/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kmn +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kmn @@ -18,6 +18,8 @@ group(main) using keys + '`' > dk(1) ++ [K_T] > U+0009 c TAB + 'a' dk(1) 'b' + [K_BKSP] > 'ok1' 'a' 'b' + [K_BKSP] > 'fail1' 'a' dk(1) + [K_BKSP] > 'fail2' diff --git a/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js b/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js index a50848e7ea..f1e93eb48e 100644 --- a/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js +++ b/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js @@ -1 +1,641 @@ -if(typeof keyman === 'undefined') {console.log('Keyboard requires KeymanWeb 10.0 or later');if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later");} else {KeymanWeb.KR(new Keyboard_text_selection_tests_keyboard_9073());}function Keyboard_text_selection_tests_keyboard_9073(){this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9;this.KI="Keyboard_text_selection_tests_keyboard_9073";this.KN="Text Selection Tests Keyboard";this.KMINVER="10.0";this.KV={F:' 1em "Arial"',K102:0};this.KV.KLS={"default": ["dk(1)","1","2","3","4","5","6","7","8","9","0","-","=","","","","q","w","e","r","t","y","u","i","o","p","[","]","\\","","","","a","s","d","f","g","h","j","k","l",";","'","","","","","","\\","z","x","c","v","b","n","m",",",".","/","","","","","",""],"shift": ["~","!","@","#","$","%","^","&","*","(",")","_","+","","","","Q","W","E","R","T","Y","U","I","O","P","{","}","|","","","","A","S","D","F","G","H","J","K","L",":","\"","","","","","","|","Z","X","C","V","B","N","M","<",">","?","","","","","",""]};this.KV.BK=(function(x){var e=Array.apply(null,Array(65)).map(String.prototype.valueOf,""),r=[],v,i,m=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt'];for(i=m.length-1;i>=0;i--)if((v=x[m[i]])||r.length)r=(v?v:e).slice().concat(r);return r})(this.KV.KLS);this.KDU=0;this.KH='';this.KM=0;this.KBVER="1.0";this.KMBM=0x0010;this.KVKL={"tablet":{"displayUnderlying":false,"layer":[{"id":"default","row":[{"id":"1","key":[{"nextlayer":"shift","id":"K_1","text":"1"},{"id":"K_2","text":"2"},{"id":"K_3","text":"3"},{"id":"K_4","text":"4"},{"id":"K_5","text":"5"},{"id":"K_6","text":"6"},{"id":"K_7","text":"7"},{"id":"K_8","text":"8"},{"id":"K_9","text":"9"},{"id":"K_0","text":"0"},{"id":"K_HYPHEN","text":"-"},{"id":"K_EQUAL","text":"="},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"id":"K_Q","pad":"75","text":"q"},{"id":"K_W","text":"w"},{"id":"K_E","text":"e"},{"id":"K_R","text":"r"},{"id":"K_T","text":"t"},{"id":"K_Y","text":"y"},{"id":"K_U","text":"u"},{"id":"K_I","text":"i"},{"id":"K_O","text":"o"},{"id":"K_P","text":"p"},{"id":"K_LBRKT","text":"["},{"id":"K_RBRKT","text":"]"},{"width":"10","id":"T_new_136","sp":"10"}]},{"id":"3","key":[{"id":"K_BKQUOTE","text":"dk(1)"},{"id":"K_A","text":"a"},{"id":"K_S","text":"s"},{"id":"K_D","text":"d"},{"id":"K_F","text":"f"},{"id":"K_G","text":"g"},{"id":"K_H","text":"h"},{"id":"K_J","text":"j"},{"id":"K_K","text":"k"},{"id":"K_L","text":"l"},{"id":"K_COLON","text":";"},{"id":"K_QUOTE","text":"'"},{"id":"K_BKSLASH","text":"\\"}]},{"id":"4","key":[{"nextlayer":"shift","width":"160","id":"K_SHIFT","sp":"1","text":"*Shift*"},{"id":"K_oE2","text":"\\"},{"id":"K_Z","text":"z"},{"id":"K_X","text":"x"},{"id":"K_C","text":"c"},{"id":"K_V","text":"v"},{"id":"K_B","text":"b"},{"id":"K_N","text":"n"},{"id":"K_M","text":"m"},{"id":"K_COMMA","text":","},{"id":"K_PERIOD","text":"."},{"id":"K_SLASH","text":"\/"},{"width":"10","id":"T_new_162","sp":"10"}]},{"id":"5","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"width":"930","id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]},{"id":"shift","row":[{"id":"1","key":[{"id":"K_1","text":"!"},{"id":"K_2","text":"@"},{"id":"K_3","text":"#"},{"id":"K_4","text":"$"},{"id":"K_5","text":"%"},{"id":"K_6","text":"^"},{"id":"K_7","text":"&"},{"id":"K_8","text":"*"},{"id":"K_9","text":"("},{"id":"K_0","text":")"},{"id":"K_HYPHEN","text":"_"},{"id":"K_EQUAL","text":"+"},{"width":"100","id":"K_BKSP","sp":"1","text":"*BkSp*"}]},{"id":"2","key":[{"id":"K_Q","pad":"75","text":"Q"},{"id":"K_W","text":"W"},{"id":"K_E","text":"E"},{"id":"K_R","text":"R"},{"id":"K_T","text":"T"},{"id":"K_Y","text":"Y"},{"id":"K_U","text":"U"},{"id":"K_I","text":"I"},{"id":"K_O","text":"O"},{"id":"K_P","text":"P"},{"id":"K_LBRKT","text":"{"},{"id":"K_RBRKT","text":"}"},{"width":"10","id":"T_new_246","sp":"10"}]},{"id":"3","key":[{"id":"K_BKQUOTE","text":"~"},{"id":"K_A","text":"A"},{"id":"K_S","text":"S"},{"id":"K_D","text":"D"},{"id":"K_F","text":"F"},{"id":"K_G","text":"G"},{"id":"K_H","text":"H"},{"id":"K_J","text":"J"},{"id":"K_K","text":"K"},{"id":"K_L","text":"L"},{"id":"K_COLON","text":":"},{"id":"K_QUOTE","text":"\""},{"id":"K_BKSLASH","text":"|"}]},{"id":"4","key":[{"nextlayer":"default","width":"160","id":"K_SHIFT","sp":"1","text":"*Shift*"},{"id":"K_oE2","text":"|"},{"id":"K_Z","text":"Z"},{"id":"K_X","text":"X"},{"id":"K_C","text":"C"},{"id":"K_V","text":"V"},{"id":"K_B","text":"B"},{"id":"K_N","text":"N"},{"id":"K_M","text":"M"},{"id":"K_COMMA","text":"<"},{"id":"K_PERIOD","text":">"},{"id":"K_SLASH","text":"?"},{"width":"10","id":"T_new_272","sp":"10"}]},{"id":"5","key":[{"width":"140","id":"K_LOPT","sp":"1","text":"*Menu*"},{"width":"930","id":"K_SPACE"},{"width":"145","id":"K_ENTER","sp":"1","text":"*Enter*"}]}]}]}};this.KVER="16.0.142.0";this.KVS=[];this.gs=function(t,e) {return this.g0(t,e);};this.gs=function(t,e) {return this.g0(t,e);};this.g0=function(t,e) {var k=KeymanWeb,r=0,m=0;if(k.KKM(e,16384,8)) {if(k.KFCM(3,t,['a',{t:'d',d:0},'b'])){r=m=1;k.KDC(3,t);k.KO(-1,t,"ok1");}else if(k.KFCM(2,t,['a','b'])){r=m=1;k.KDC(2,t);k.KO(-1,t,"fail1");}else if(k.KFCM(2,t,['a',{t:'d',d:0}])){r=m=1;k.KDC(2,t);k.KO(-1,t,"fail2");}else if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"foo");}}else if(k.KKM(e,16400,65)) {if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"Â");}}else if(k.KKM(e,16384,192)) {if(1){r=m=1;k.KDC(0,t);k.KDO(-1,t,0);}}else if(k.KKM(e,16384,65)) {if(k.KFCM(1,t,['^'])){r=m=1;k.KDC(1,t);k.KO(-1,t,"â");}}else if(k.KKM(e,16384,79)) {if(k.KFCM(1,t,[{t:'d',d:0}])){r=m=1;k.KDC(1,t);k.KO(-1,t,"ok3");}}return r;};} \ No newline at end of file +if(typeof keyman === 'undefined') { + console.log('Keyboard requires KeymanWeb 10.0 or later'); + if(typeof tavultesoft !== 'undefined') tavultesoft.keymanweb.util.alert("This keyboard requires KeymanWeb 10.0 or later"); +} else { +KeymanWeb.KR(new Keyboard_text_selection_tests_keyboard_9073()); +} +function Keyboard_text_selection_tests_keyboard_9073() +{ + var modCodes = keyman.osk.modifierCodes; + var keyCodes = keyman.osk.keyCodes; + + this._v=(typeof keyman!="undefined"&&typeof keyman.version=="string")?parseInt(keyman.version,10):9; + this.KI="Keyboard_text_selection_tests_keyboard_9073"; + this.KN="Text Selection Tests Keyboard"; + this.KMINVER="10.0"; + this.KV={F:' 1em "Arial"',K102:0}; + this.KV.KLS={ + "default": ["dk(1)","1","2","3","4","5","6","7","8","9","0","-","=","","","","q","w","e","r","t","y","u","i","o","p","[","]","\\","","","","a","s","d","f","g","h","j","k","l",";","'","","","","","","\\","z","x","c","v","b","n","m",",",".","/","","","","","",""], + "shift": ["~","!","@","#","$","%","^","&","*","(",")","_","+","","","","Q","W","E","R","T","Y","U","I","O","P","{","}","|","","","","A","S","D","F","G","H","J","K","L",":","\"","","","","","","|","Z","X","C","V","B","N","M","<",">","?","","","","","",""] + }; + this.KV.BK=(function(x){ + var + empty=Array.apply(null, Array(65)).map(String.prototype.valueOf,""), + result=[], v, i, + modifiers=['default','shift','ctrl','shift-ctrl','alt','shift-alt','ctrl-alt','shift-ctrl-alt']; + for(i=modifiers.length-1;i>=0;i--) { + v = x[modifiers[i]]; + if(v || result.length > 0) { + result=(v ? v : empty).slice().concat(result); + } + } + return result; + })(this.KV.KLS); + this.KDU=0; + this.KH=''; + this.KM=0; + this.KBVER="1.0"; + this.KMBM=modCodes.SHIFT /* 0x0010 */; + this.KVKL={ + "tablet": { + "displayUnderlying": false, + "layer": [ + { + "id": "default", + "row": [ + { + "id": "1", + "key": [ + { + "nextlayer": "shift", + "id": "K_1", + "text": "1" + }, + { + "id": "K_2", + "text": "2" + }, + { + "id": "K_3", + "text": "3" + }, + { + "id": "K_4", + "text": "4" + }, + { + "id": "K_5", + "text": "5" + }, + { + "id": "K_6", + "text": "6" + }, + { + "id": "K_7", + "text": "7" + }, + { + "id": "K_8", + "text": "8" + }, + { + "id": "K_9", + "text": "9" + }, + { + "id": "K_0", + "text": "0" + }, + { + "id": "K_HYPHEN", + "text": "-" + }, + { + "id": "K_EQUAL", + "text": "=" + }, + { + "width": "100", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + } + ] + }, + { + "id": "2", + "key": [ + { + "id": "K_Q", + "pad": "75", + "text": "q" + }, + { + "id": "K_W", + "text": "w" + }, + { + "id": "K_E", + "text": "e" + }, + { + "id": "K_R", + "text": "r" + }, + { + "id": "K_T", + "text": "t" + }, + { + "id": "K_Y", + "text": "y" + }, + { + "id": "K_U", + "text": "u" + }, + { + "id": "K_I", + "text": "i" + }, + { + "id": "K_O", + "text": "o" + }, + { + "id": "K_P", + "text": "p" + }, + { + "id": "K_LBRKT", + "text": "[" + }, + { + "id": "K_RBRKT", + "text": "]" + }, + { + "width": "10", + "id": "T_new_136", + "sp": "10" + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "K_BKQUOTE", + "text": "dk(1)" + }, + { + "id": "K_A", + "text": "a" + }, + { + "id": "K_S", + "text": "s" + }, + { + "id": "K_D", + "text": "d" + }, + { + "id": "K_F", + "text": "f" + }, + { + "id": "K_G", + "text": "g" + }, + { + "id": "K_H", + "text": "h" + }, + { + "id": "K_J", + "text": "j" + }, + { + "id": "K_K", + "text": "k" + }, + { + "id": "K_L", + "text": "l" + }, + { + "id": "K_COLON", + "text": ";" + }, + { + "id": "K_QUOTE", + "text": "'" + }, + { + "id": "K_BKSLASH", + "text": "\\" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "shift", + "width": "160", + "id": "K_SHIFT", + "sp": "1", + "text": "*Shift*" + }, + { + "id": "K_oE2", + "text": "\\" + }, + { + "id": "K_Z", + "text": "z" + }, + { + "id": "K_X", + "text": "x" + }, + { + "id": "K_C", + "text": "c" + }, + { + "id": "K_V", + "text": "v" + }, + { + "id": "K_B", + "text": "b" + }, + { + "id": "K_N", + "text": "n" + }, + { + "id": "K_M", + "text": "m" + }, + { + "id": "K_COMMA", + "text": "," + }, + { + "id": "K_PERIOD", + "text": "." + }, + { + "id": "K_SLASH", + "text": "/" + }, + { + "width": "10", + "id": "T_new_162", + "sp": "10" + } + ] + }, + { + "id": "5", + "key": [ + { + "width": "140", + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "width": "930", + "id": "K_SPACE" + }, + { + "width": "145", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + }, + { + "id": "shift", + "row": [ + { + "id": "1", + "key": [ + { + "id": "K_1", + "text": "!" + }, + { + "id": "K_2", + "text": "@" + }, + { + "id": "K_3", + "text": "#" + }, + { + "id": "K_4", + "text": "$" + }, + { + "id": "K_5", + "text": "%" + }, + { + "id": "K_6", + "text": "^" + }, + { + "id": "K_7", + "text": "&" + }, + { + "id": "K_8", + "text": "*" + }, + { + "id": "K_9", + "text": "(" + }, + { + "id": "K_0", + "text": ")" + }, + { + "id": "K_HYPHEN", + "text": "_" + }, + { + "id": "K_EQUAL", + "text": "+" + }, + { + "width": "100", + "id": "K_BKSP", + "sp": "1", + "text": "*BkSp*" + } + ] + }, + { + "id": "2", + "key": [ + { + "id": "K_Q", + "pad": "75", + "text": "Q" + }, + { + "id": "K_W", + "text": "W" + }, + { + "id": "K_E", + "text": "E" + }, + { + "id": "K_R", + "text": "R" + }, + { + "id": "K_T", + "text": "T" + }, + { + "id": "K_Y", + "text": "Y" + }, + { + "id": "K_U", + "text": "U" + }, + { + "id": "K_I", + "text": "I" + }, + { + "id": "K_O", + "text": "O" + }, + { + "id": "K_P", + "text": "P" + }, + { + "id": "K_LBRKT", + "text": "{" + }, + { + "id": "K_RBRKT", + "text": "}" + }, + { + "width": "10", + "id": "T_new_246", + "sp": "10" + } + ] + }, + { + "id": "3", + "key": [ + { + "id": "K_BKQUOTE", + "text": "~" + }, + { + "id": "K_A", + "text": "A" + }, + { + "id": "K_S", + "text": "S" + }, + { + "id": "K_D", + "text": "D" + }, + { + "id": "K_F", + "text": "F" + }, + { + "id": "K_G", + "text": "G" + }, + { + "id": "K_H", + "text": "H" + }, + { + "id": "K_J", + "text": "J" + }, + { + "id": "K_K", + "text": "K" + }, + { + "id": "K_L", + "text": "L" + }, + { + "id": "K_COLON", + "text": ":" + }, + { + "id": "K_QUOTE", + "text": "\"" + }, + { + "id": "K_BKSLASH", + "text": "|" + } + ] + }, + { + "id": "4", + "key": [ + { + "nextlayer": "default", + "width": "160", + "id": "K_SHIFT", + "sp": "1", + "text": "*Shift*" + }, + { + "id": "K_oE2", + "text": "|" + }, + { + "id": "K_Z", + "text": "Z" + }, + { + "id": "K_X", + "text": "X" + }, + { + "id": "K_C", + "text": "C" + }, + { + "id": "K_V", + "text": "V" + }, + { + "id": "K_B", + "text": "B" + }, + { + "id": "K_N", + "text": "N" + }, + { + "id": "K_M", + "text": "M" + }, + { + "id": "K_COMMA", + "text": "<" + }, + { + "id": "K_PERIOD", + "text": ">" + }, + { + "id": "K_SLASH", + "text": "?" + }, + { + "width": "10", + "id": "T_new_272", + "sp": "10" + } + ] + }, + { + "id": "5", + "key": [ + { + "width": "140", + "id": "K_LOPT", + "sp": "1", + "text": "*Menu*" + }, + { + "width": "930", + "id": "K_SPACE" + }, + { + "width": "145", + "id": "K_ENTER", + "sp": "1", + "text": "*Enter*" + } + ] + } + ] + } + ] + } +} +; + this.KVER="16.0.142.0"; + this.KVS=[]; + this.gs=function(t,e) { + return this.g_main_0(t,e); + }; + this.gs=function(t,e) { + return this.g_main_0(t,e); + }; + this.g_main_0=function(t,e) { + var k=KeymanWeb,r=0,m=0; + if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKSP /* 0x08 */)) { + if(k.KFCM(3,t,['a',{t:'d',d:0},'b'])){ + r=m=1; // Line 23 + k.KDC(3,t); + k.KO(-1,t,"ok1"); + } + else if(k.KFCM(2,t,['a','b'])){ + r=m=1; // Line 24 + k.KDC(2,t); + k.KO(-1,t,"fail1"); + } + else if(k.KFCM(2,t,['a',{t:'d',d:0}])){ + r=m=1; // Line 25 + k.KDC(2,t); + k.KO(-1,t,"fail2"); + } + else if(k.KFCM(1,t,['^'])){ + r=m=1; // Line 17 + k.KDC(1,t); + k.KO(-1,t,"foo"); + } + } + else if(k.KKM(e, modCodes.SHIFT | modCodes.VIRTUAL_KEY /* 0x4010 */, keyCodes.K_A /* 0x41 */)) { + if(k.KFCM(1,t,['^'])){ + r=m=1; // Line 16 + k.KDC(1,t); + k.KO(-1,t,"Â"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_BKQUOTE /* 0xC0 */)) { + if(1){ + r=m=1; // Line 19 + k.KDC(0,t); + k.KDO(-1,t,0); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_A /* 0x41 */)) { + if(k.KFCM(1,t,['^'])){ + r=m=1; // Line 15 + k.KDC(1,t); + k.KO(-1,t,"â"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_O /* 0x4F */)) { + if(k.KFCM(1,t,[{t:'d',d:0}])){ + r=m=1; // Line 26 + k.KDC(1,t); + k.KO(-1,t,"ok3"); + } + } + else if(k.KKM(e, modCodes.VIRTUAL_KEY /* 0x4000 */, keyCodes.K_T /* 0x54 */)) { + if(1){ + r=m=1; // Line 21 + k.KDC(0,t); + k.KO(-1,t,"\t"); + } + } + return r; + }; +} From 511f2645acd7897d7583f878bb65ccc7928ec101 Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Thu, 23 Nov 2023 13:03:23 -0500 Subject: [PATCH 12/14] auto: increment master version to 17.0.217 --- HISTORY.md | 11 +++++++++++ VERSION.md | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index b0587ac8fa..2342633ded 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,16 @@ # Keyman Version History +## 17.0.216 alpha 2023-11-23 + +* fix(common): kmx struct alignment (#9977) +* fix(developer): vis kbd callbacks instead of throw (#9979) +* fix(core): dx: ldml: startContext should be optional in ldml test data (#10021) +* chore(windows): remove `wm_keymandebug` messages and functions (#10055) +* chore(windows): remove legacy LoadKeyboard (#10057) +* chore(windows): remove unused globals relating to old keyboard debugging (#10058) +* chore(core): remove vkey output from kmx processor (#10060) +* fix(web): app/webview did not clear deadkeys on context-reset (#10039) + ## 17.0.215 alpha 2023-11-22 * feat(core): ldml marker normalization (#9761) diff --git a/VERSION.md b/VERSION.md index 1a17e0d6c0..980da1ad1a 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.216 \ No newline at end of file +17.0.217 \ No newline at end of file From 7ec4832edc617530152286d2e8d7782bb39a2533 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 24 Nov 2023 07:52:31 +1000 Subject: [PATCH 13/14] fix(core): memory management of options in action struct Fixes #10067. Management of memory for persisted options was wrong in the action struct, as the members key and value would be freed immediately after being added to the temporary vector (because the vector was of the struct rather than of the class). Given the struct is a C struct, we need the memory management to be explicit, so we now release() each option into the vector as we create it, which means that its member values will not be freed when the option is then immediately deleted. (This allows us to use the initial copy of the members of option that option() constructor does.) Added the release() function as that was a relatively clear way of indicating that the contents of the structure are now owned by the caller, following the pattern from std::unique_ptr. Finally, the unit test for persisted options was in the action_api.cpp test module, but it was never called, so this was not being tested. Now it is. --- core/src/action.cpp | 8 +++++--- core/src/option.cpp | 8 ++++++++ core/src/option.hpp | 7 ++++++- core/tests/unit/kmnkbd/action_api.cpp | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/core/src/action.cpp b/core/src/action.cpp index 3387d8f85d..4c018cabbd 100644 --- a/core/src/action.cpp +++ b/core/src/action.cpp @@ -95,13 +95,15 @@ km_core_actions * km::core::action_item_list_to_actions_object( output.push_back({KM_CORE_CT_MARKER,{0},{action_items->marker}}); break; case KM_CORE_IT_PERSIST_OPT: + { // TODO: lowpri: replace existing item if already present in options vector? - options.push_back(km::core::option( - static_cast(action_items->option->scope), + km::core::option opt(static_cast(action_items->option->scope), action_items->option->key, action_items->option->value - )); + ); + options.push_back(opt.release()); // hand over memory management of the option item to the action struct break; + } default: assert(false); } diff --git a/core/src/option.cpp b/core/src/option.cpp index dd9242ef0a..71cb395ddf 100644 --- a/core/src/option.cpp +++ b/core/src/option.cpp @@ -43,6 +43,14 @@ option::option(km_core_option_scope s, char16_t const *k, char16_t const *v) } } +km_core_option_item +option::release() { + km_core_option_item opt = *this; + key = nullptr; + value = nullptr; + return opt; +} + // TODO: Relocate this and fix it json & km::core::operator << (json &j, abstract_processor const &) { diff --git a/core/src/option.hpp b/core/src/option.hpp index cbfbf76436..43f3397049 100644 --- a/core/src/option.hpp +++ b/core/src/option.hpp @@ -34,10 +34,15 @@ namespace core option & operator=(option const & rhs); option & operator=(option && rhs); + /** + * Returns contents of this object as a C struct, releasing memory + * management of key and value, and invalidates this object. + */ + km_core_option_item release(); + bool empty() const; }; - inline option::option(km_core_option_scope s, std::u16string const & k, std::u16string const & v) diff --git a/core/tests/unit/kmnkbd/action_api.cpp b/core/tests/unit/kmnkbd/action_api.cpp index 79512352a3..fc04a3ee11 100644 --- a/core/tests/unit/kmnkbd/action_api.cpp +++ b/core/tests/unit/kmnkbd/action_api.cpp @@ -374,6 +374,7 @@ int main(int argc, char *argv []) { test_alert(); test_emit_keystroke(); test_invalidate_context(); + test_persist_opt(); // context -- todo move to another file test_context_set_if_needed(); From d0b23c96b4ca848fca805524f22d71412fd4292b Mon Sep 17 00:00:00 2001 From: Keyman Build Agent Date: Fri, 24 Nov 2023 13:03:05 -0500 Subject: [PATCH 14/14] auto: increment master version to 17.0.218 --- HISTORY.md | 7 +++++++ VERSION.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 2342633ded..ec21fd7509 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,12 @@ # Keyman Version History +## 17.0.217 alpha 2023-11-24 + +* feat(developer): warn on usage of virtual keys in rule output (#10062) +* fix(core): memory management of options in action struct (#10073) +* chore(linux): Update debian changelog (#10047) +* chore(core): Add test keyboard for text selection tests (#10026) + ## 17.0.216 alpha 2023-11-23 * fix(common): kmx struct alignment (#9977) diff --git a/VERSION.md b/VERSION.md index 980da1ad1a..84c38c9084 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.217 \ No newline at end of file +17.0.218 \ No newline at end of file