diff --git a/HISTORY.md b/HISTORY.md index b0587ac8fa..ec21fd7509 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,23 @@ # 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) +* 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..84c38c9084 100644 --- a/VERSION.md +++ b/VERSION.md @@ -1 +1 @@ -17.0.216 \ No newline at end of file +17.0.218 \ No newline at end of file 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 0000000000..6a5271df0c Binary files /dev/null and b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.ico differ 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 new file mode 100644 index 0000000000..6d02edfad8 --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.keyman-touch-layout @@ -0,0 +1,532 @@ +{ + "tablet": { + "displayUnderlying": false, + "layer": [ + { + "id": "default", + "row": [ + { + "id": 1, + "key": [ + { + "id": "K_1", + "text": "1", + "nextlayer": "shift" + }, + { + "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, + "nextlayer": "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": "/" + }, + { + "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": "+" + }, + { + "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_246", + "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": [ + { + "id": "K_SHIFT", + "text": "*Shift*", + "width": 160, + "sp": 1, + "nextlayer": "default" + }, + { + "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_272", + "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 + } + ] + } + ] + } + ] + } +} \ 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..b40278a930 --- /dev/null +++ b/common/test/keyboards/text_selection_tests_keyboard_9073/source/text_selection_tests_keyboard_9073.kmn @@ -0,0 +1,26 @@ +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) + ++ [K_T] > U+0009 c TAB + +'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..98b9ad7e0e --- /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_dda967022de452e1fe199096e795f0ab + 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_bbf31cea8a9cfe0cb838f67055690bf8 + text_selection_tests_keyboard_9073.ico + source\text_selection_tests_keyboard_9073.ico + + .ico + id_dda967022de452e1fe199096e795f0ab + + + id_b8f7a473cac52dd0436273de657cdf46 + text_selection_tests_keyboard_9073.kmx + source\..\build\text_selection_tests_keyboard_9073.kmx + + .kmx + id_ba932837e6a67a86abc409a393242255 + + + id_73d0cd87e78d9b8d7f514809dbb36a47 + text_selection_tests_keyboard_9073.js + source\..\build\text_selection_tests_keyboard_9073.js + + .js + id_ba932837e6a67a86abc409a393242255 + + + id_71aafc060dc3251e4bb611ea539dc8e0 + 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/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/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/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..4b98312c36 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,10 @@ 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); - + // virtual keys in output are not supported + 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); 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(); 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 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) 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), 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..f1e93eb48e --- /dev/null +++ b/web/src/test/manual/web/text_selection_tests_9073/text_selection_tests_keyboard_9073.js @@ -0,0 +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() +{ + 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; + }; +} 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/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..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; @@ -263,12 +250,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..fb82735377 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, @@ -218,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 @@ -296,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; } @@ -428,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 c563210a76..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; @@ -124,14 +117,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 +135,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); 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());