Merge branch 'master' into feat/developer-9446-bad-unicode-epic-ldml

This commit is contained in:
Steven R. Loomis 2023-11-25 14:08:41 -06:00 committed by GitHub
commit 02c8db9fdd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 1786 additions and 1106 deletions

View file

@ -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)

View file

@ -1 +1 @@
17.0.216
17.0.218

View file

@ -0,0 +1,6 @@
Text Selection Tests Keyboard Change History
====================
1.0 (2023-11-14)
----------------
* Created by Keyman Team

View file

@ -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.

View file

@ -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

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Text Selection Tests Keyboard</title>
<style type="text/css">
p { font: 10pt Tahoma; }
h1 { font: bold 16pt Tahoma; color: #4444cc; margin-bottom: 2px }
h2 { font: bold 12pt Tahoma; color: #4444cc; }
</style>
</head>
<body>
<h1>Text Selection Tests Keyboard</h1>
<p>
Text Selection Tests Keyboard 1.0 generated from template.
</p>
<p>© Keyman Team</p>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -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
}
]
}
]
}
]
}
}

View file

@ -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(&COPYRIGHT) '© 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'

View file

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<Package>
<System>
<KeymanDeveloperVersion>16.0.142.0</KeymanDeveloperVersion>
<FileVersion>7.0</FileVersion>
</System>
<Options>
<ExecuteProgram></ExecuteProgram>
<ReadMeFile>readme.htm</ReadMeFile>
<MSIFileName></MSIFileName>
<MSIOptions></MSIOptions>
<FollowKeyboardVersion/>
</Options>
<StartMenu>
<Folder></Folder>
<Items/>
</StartMenu>
<Info>
<Name URL="">Text Selection Tests Keyboard</Name>
<Copyright URL="">© Keyman Team</Copyright>
<Author URL="">Keyman Team</Author>
<Version URL=""></Version>
</Info>
<Files>
<File>
<Name>..\build\text_selection_tests_keyboard_9073.kmx</Name>
<Description></Description>
<CopyLocation>0</CopyLocation>
<FileType>.kmx</FileType>
</File>
<File>
<Name>..\build\text_selection_tests_keyboard_9073.js</Name>
<Description></Description>
<CopyLocation>0</CopyLocation>
<FileType>.js</FileType>
</File>
<File>
<Name>..\build\text_selection_tests_keyboard_9073.kvk</Name>
<Description></Description>
<CopyLocation>0</CopyLocation>
<FileType>.kvk</FileType>
</File>
<File>
<Name>welcome.htm</Name>
<Description></Description>
<CopyLocation>0</CopyLocation>
<FileType>.htm</FileType>
</File>
<File>
<Name>readme.htm</Name>
<Description></Description>
<CopyLocation>0</CopyLocation>
<FileType>.htm</FileType>
</File>
</Files>
<Keyboards>
<Keyboard>
<Name>Text Selection Tests Keyboard</Name>
<ID>text_selection_tests_keyboard_9073</ID>
<Version>1.0</Version>
<Languages>
<Language ID="en">English</Language>
</Languages>
</Keyboard>
</Keyboards>
<Strings/>
</Package>

View file

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<visualkeyboard>
<header>
<version>10.0</version>
<kbdname>text_selection_tests_keyboard_9073</kbdname>
<flags/>
</header>
<encoding name="unicode" fontname="Arial" fontsize="-12">
<layer shift="">
<key vkey="K_BKQUOTE">dk(1)</key>
<key vkey="K_1">1</key>
<key vkey="K_2">2</key>
<key vkey="K_3">3</key>
<key vkey="K_4">4</key>
<key vkey="K_5">5</key>
<key vkey="K_6">6</key>
<key vkey="K_7">7</key>
<key vkey="K_8">8</key>
<key vkey="K_9">9</key>
<key vkey="K_0">0</key>
<key vkey="K_HYPHEN">-</key>
<key vkey="K_EQUAL">=</key>
<key vkey="K_Q">q</key>
<key vkey="K_W">w</key>
<key vkey="K_E">e</key>
<key vkey="K_R">r</key>
<key vkey="K_T">t</key>
<key vkey="K_Y">y</key>
<key vkey="K_U">u</key>
<key vkey="K_I">i</key>
<key vkey="K_O">o</key>
<key vkey="K_P">p</key>
<key vkey="K_LBRKT">[</key>
<key vkey="K_RBRKT">]</key>
<key vkey="K_BKSLASH">\</key>
<key vkey="K_A">a</key>
<key vkey="K_S">s</key>
<key vkey="K_D">d</key>
<key vkey="K_F">f</key>
<key vkey="K_G">g</key>
<key vkey="K_H">h</key>
<key vkey="K_J">j</key>
<key vkey="K_K">k</key>
<key vkey="K_L">l</key>
<key vkey="K_COLON">;</key>
<key vkey="K_QUOTE">'</key>
<key vkey="K_oE2">\</key>
<key vkey="K_Z">z</key>
<key vkey="K_X">x</key>
<key vkey="K_C">c</key>
<key vkey="K_V">v</key>
<key vkey="K_B">b</key>
<key vkey="K_N">n</key>
<key vkey="K_M">m</key>
<key vkey="K_COMMA">,</key>
<key vkey="K_PERIOD">.</key>
<key vkey="K_SLASH">/</key>
</layer>
<layer shift="S">
<key vkey="K_BKQUOTE">~</key>
<key vkey="K_1">!</key>
<key vkey="K_2">@</key>
<key vkey="K_3">#</key>
<key vkey="K_4">$</key>
<key vkey="K_5">%</key>
<key vkey="K_6">^</key>
<key vkey="K_7">&amp;</key>
<key vkey="K_8">*</key>
<key vkey="K_9">(</key>
<key vkey="K_0">)</key>
<key vkey="K_HYPHEN">_</key>
<key vkey="K_EQUAL">+</key>
<key vkey="K_Q">Q</key>
<key vkey="K_W">W</key>
<key vkey="K_E">E</key>
<key vkey="K_R">R</key>
<key vkey="K_T">T</key>
<key vkey="K_Y">Y</key>
<key vkey="K_U">U</key>
<key vkey="K_I">I</key>
<key vkey="K_O">O</key>
<key vkey="K_P">P</key>
<key vkey="K_LBRKT">{</key>
<key vkey="K_RBRKT">}</key>
<key vkey="K_BKSLASH">|</key>
<key vkey="K_A">A</key>
<key vkey="K_S">S</key>
<key vkey="K_D">D</key>
<key vkey="K_F">F</key>
<key vkey="K_G">G</key>
<key vkey="K_H">H</key>
<key vkey="K_J">J</key>
<key vkey="K_K">K</key>
<key vkey="K_L">L</key>
<key vkey="K_COLON">:</key>
<key vkey="K_QUOTE">"</key>
<key vkey="K_oE2">|</key>
<key vkey="K_Z">Z</key>
<key vkey="K_X">X</key>
<key vkey="K_C">C</key>
<key vkey="K_V">V</key>
<key vkey="K_B">B</key>
<key vkey="K_N">N</key>
<key vkey="K_M">M</key>
<key vkey="K_COMMA">&lt;</key>
<key vkey="K_PERIOD">&gt;</key>
<key vkey="K_SLASH">?</key>
</layer>
</encoding>
</visualkeyboard>

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Start Using Text Selection Tests Keyboard</title>
<style type="text/css">
p { font: 10pt Tahoma; }
h1 { font: bold 16pt Tahoma; color: #4444cc; margin-bottom: 2px }
h2 { font: bold 12pt Tahoma; color: #4444cc; }
</style>
</head>
<body>
<h1>Start Using Text Selection Tests Keyboard</h1>
<p>
Text Selection Tests Keyboard 1.0 generated from template.
</p>
<h1>Keyboard Layout</h1>
<!-- Insert Keyboard Layout Images or HTML here -->
</body>
</html>

View file

@ -0,0 +1,7 @@
{
"license": "mit",
"languages": [
"en"
],
"description": "Text Selection Tests Keyboard generated from template"
}

View file

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<KeymanDeveloperProject>
<Options>
<BuildPath>$PROJECTPATH\build</BuildPath>
<CompilerWarningsAsErrors>True</CompilerWarningsAsErrors>
<WarnDeprecatedCode>True</WarnDeprecatedCode>
<CheckFilenameConventions>True</CheckFilenameConventions>
<ProjectType>keyboard</ProjectType>
</Options>
<Files>
<File>
<ID>id_dda967022de452e1fe199096e795f0ab</ID>
<Filename>text_selection_tests_keyboard_9073.kmn</Filename>
<Filepath>source\text_selection_tests_keyboard_9073.kmn</Filepath>
<FileVersion>1.0</FileVersion>
<FileType>.kmn</FileType>
<Details>
<Name>Text Selection Tests Keyboard</Name>
<Copyright>© Keyman Team</Copyright>
</Details>
</File>
<File>
<ID>id_ba932837e6a67a86abc409a393242255</ID>
<Filename>text_selection_tests_keyboard_9073.kps</Filename>
<Filepath>source\text_selection_tests_keyboard_9073.kps</Filepath>
<FileVersion></FileVersion>
<FileType>.kps</FileType>
<Details>
<Name>Text Selection Tests Keyboard</Name>
<Copyright>© Keyman Team</Copyright>
</Details>
</File>
<File>
<ID>id_ede98e4633e239f933cbfd1f4e1b766c</ID>
<Filename>HISTORY.md</Filename>
<Filepath>HISTORY.md</Filepath>
<FileVersion></FileVersion>
<FileType>.md</FileType>
</File>
<File>
<ID>id_53e892b8b41cc4caece1cfd5ef21d6e7</ID>
<Filename>LICENSE.md</Filename>
<Filepath>LICENSE.md</Filepath>
<FileVersion></FileVersion>
<FileType>.md</FileType>
</File>
<File>
<ID>id_0730bb7c2e8f9ea2438b52e419dd86c9</ID>
<Filename>README.md</Filename>
<Filepath>README.md</Filepath>
<FileVersion></FileVersion>
<FileType>.md</FileType>
</File>
<File>
<ID>id_4b87bd35cc2e16f1ff8680a6f2caed52</ID>
<Filename>text_selection_tests_keyboard_9073.keyboard_info</Filename>
<Filepath>text_selection_tests_keyboard_9073.keyboard_info</Filepath>
<FileVersion></FileVersion>
<FileType>.keyboard_info</FileType>
</File>
<File>
<ID>id_bbf31cea8a9cfe0cb838f67055690bf8</ID>
<Filename>text_selection_tests_keyboard_9073.ico</Filename>
<Filepath>source\text_selection_tests_keyboard_9073.ico</Filepath>
<FileVersion></FileVersion>
<FileType>.ico</FileType>
<ParentFileID>id_dda967022de452e1fe199096e795f0ab</ParentFileID>
</File>
<File>
<ID>id_b8f7a473cac52dd0436273de657cdf46</ID>
<Filename>text_selection_tests_keyboard_9073.kmx</Filename>
<Filepath>source\..\build\text_selection_tests_keyboard_9073.kmx</Filepath>
<FileVersion></FileVersion>
<FileType>.kmx</FileType>
<ParentFileID>id_ba932837e6a67a86abc409a393242255</ParentFileID>
</File>
<File>
<ID>id_73d0cd87e78d9b8d7f514809dbb36a47</ID>
<Filename>text_selection_tests_keyboard_9073.js</Filename>
<Filepath>source\..\build\text_selection_tests_keyboard_9073.js</Filepath>
<FileVersion></FileVersion>
<FileType>.js</FileType>
<ParentFileID>id_ba932837e6a67a86abc409a393242255</ParentFileID>
</File>
<File>
<ID>id_71aafc060dc3251e4bb611ea539dc8e0</ID>
<Filename>text_selection_tests_keyboard_9073.kvk</Filename>
<Filepath>source\..\build\text_selection_tests_keyboard_9073.kvk</Filepath>
<FileVersion></FileVersion>
<FileType>.kvk</FileType>
<ParentFileID>id_ba932837e6a67a86abc409a393242255</ParentFileID>
</File>
<File>
<ID>id_356e5d149c1e539356d72698c1e401a6</ID>
<Filename>welcome.htm</Filename>
<Filepath>source\welcome.htm</Filepath>
<FileVersion></FileVersion>
<FileType>.htm</FileType>
<ParentFileID>id_ba932837e6a67a86abc409a393242255</ParentFileID>
</File>
<File>
<ID>id_8da344c4cea6f467013357fe099006f5</ID>
<Filename>readme.htm</Filename>
<Filepath>source\readme.htm</Filepath>
<FileVersion></FileVersion>
<FileType>.htm</FileType>
<ParentFileID>id_ba932837e6a67a86abc409a393242255</ParentFileID>
</File>
</Files>
</KeymanDeveloperProject>

View file

@ -570,6 +570,9 @@ export default class KeyboardProcessor extends EventEmitter<EventMap> {
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.

View file

@ -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<km_core_option_scope>(action_items->option->scope),
km::core::option opt(static_cast<km_core_option_scope>(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);
}

View file

@ -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);

View file

@ -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:

View file

@ -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

View file

@ -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);

View file

@ -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 &)
{

View file

@ -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)

View file

@ -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();

View file

@ -240,6 +240,8 @@
#define CHINT_UnreachableRule 0x000010AE
#define CWARN_VirtualKeyInOutput 0x000020AF
#define CERR_BufferOverflow 0x000080C0
#define CERR_Break 0x000080C1

View file

@ -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;
};

View file

@ -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]

View file

@ -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");
});
});

View file

@ -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 }
};

View file

@ -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

View file

@ -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 <eb1@sil.org> Wed, 22 Nov 2023 15:24:59 +0100
keyman (16.0.141-1) unstable; urgency=medium
* Work around mips64el build failure (#1041499)

View file

@ -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),

View file

@ -66,6 +66,7 @@
<h2><a href="./issue6005/index.html">Tests predictive text & other handling of rule matching when the final rule group does not match (#6005)</a></h2>
<h2><a href="./default-subkey/index.html">Tests handling of new default-subkey feature (#9430)</a></h2>
<h2><a href="./issue9469/index.html">Test special characters rendering with keymanweb-osk.ttf (#9469)</a></h2>
<h2><a href="./text_selection_tests_9073/index.html">Test text selection (#9073)</a></h2>
<h1>Other</h1>
<h2><a href="./regression-tests/index.html">Keystroke processing regression test engine.</a></h2>
<hr>

View file

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<!-- Set the viewport width to match phone and tablet device widths -->
<meta name="viewport" content="width=device-width,user-scalable=no" />
<title>KeymanWeb #9073</title>
<!-- Your page CSS -->
<style type='text/css'>
body {font-family: Tahoma,helvetica;}
h3 {font-size: 1em;font-weight:normal;color: darkred; margin-bottom: 4px}
.test {font-size: 1.5em; width:80%; min-height:30px; border: 1px solid gray;}
#KeymanWebControl {width:50%;min-width:600px;}
</style>
<script src="../../../../../build/publish/debug/keymanweb.js" type="application/javascript"></script>
<script src="../../../../../build/publish/debug/kmwuitoggle.js"></script>
<!-- Initialization: set paths to keyboards, resources and fonts as required -->
<script>
(function(kmw) {
kmw.init({
attachType:'auto'
}).then(function() {
kmw.addKeyboards({
id:'text_selection_tests_keyboard_9073',
name:'Text selection test cases (#9073)',
languages:{
id:'en',
name:'English'
},
filename:'./text_selection_tests_keyboard_9073.js',
displayName: 'Text selection test cases (#9073)'
});
});
})(keyman);
</script>
</head>
<!-- Sample page HTML -->
<body>
<h2>Text Selection Test Cases (#9073)</h2>
<div>
<!--
The following DIV is used to position the Button or Toolbar User Interfaces on the page.
If omitted, those User Interfaces will appear at the top of the document body.
(It is ignored by other User Interfaces.)
-->
<div id='KeymanWebControl'></div>
<textarea id='ta1' class='test' placeholder='Type here'></textarea>
</div>
<hr />
<h3><a href="../index.html">Return to testing home page</a></h3>
</body>
<!--
*** DEVELOPER NOTE -- FIREFOX CONFIGURATION FOR TESTING ***
*
* If the URL bar starts with <b>file://</b>, Firefox may not load the font used
* to display the special characters used in the On-Screen Keyboard.
*
* To work around this Firefox bug, navigate to <b>about:config</b>
* and set <b>security.fileuri.strict_origin_policy</b> to <b>false</b>
* while testing.
*
* Firefox resolves website-based CSS URI references correctly without needing
* any configuration change, so this change should only be made for file-based testing.
*
***
-->
</html>

View file

@ -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;
};
}

View file

@ -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 <g>
*
\****************************************************************************/
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 <g>
*
\****************************************************************************/
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 <g>
*
\****************************************************************************/
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;
}

View file

@ -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;
}

View file

@ -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 */

View file

@ -54,10 +54,6 @@
#include <evntprov.h>
#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,

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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);
}

View file

@ -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());