Skip to content

Commit

Permalink
Merge pull request #9496 from keymanapp/feat/web/default-subkeys-9430
Browse files Browse the repository at this point in the history
feat(web): browser-KMW support for default subkeys
  • Loading branch information
jahorton authored Sep 29, 2023
2 parents 4d2dd47 + a5cbf6a commit 4a4c759
Show file tree
Hide file tree
Showing 19 changed files with 1,183 additions and 8 deletions.
6 changes: 6 additions & 0 deletions common/web/keyboard-processor/src/keyboards/activeLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ export class ActiveKey implements LayoutKey {
_baseKeyEvent: KeyEvent;
isMnemonic: boolean = false;

/**
* Only available on subkeys, but we don't distinguish between base keys and subkeys
* at this level yet in KMW.
*/
default?: boolean;

proportionalPad: number;
proportionalX: number;
proportionalWidth: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type LayoutKey = {
"nextlayer"?: string,
"pad"?: string | number,
"sk"?: LayoutKey[]
"default"?: boolean
}

export type LayoutRow = {
Expand Down
46 changes: 38 additions & 8 deletions web/src/engine/osk/src/input/gestures/browser/subkeyPopup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export default class SubkeyPopup implements RealizedGesture {
public readonly baseKey: KeyElement;
public readonly promise: Promise<KeyEvent>;

private initialX: number;
private initialY: number;

// Resolves the promise that generated this SubkeyPopup.
private resolver: (keyEvent: KeyEvent) => void;

Expand Down Expand Up @@ -219,25 +222,26 @@ export default class SubkeyPopup implements RealizedGesture {
let skElement = <KeyElement> popupBase.childNodes[i].firstChild;

// Preference order:
// #1: if a default subkey has been specified, select it. (pending, for 15.0+)
// #1: if a default subkey has been specified, select it.
// #2: if no default subkey is specified, default to a subkey with the same
// key ID and layer / modifier spec.
//if(skSpec.isDefault) { TODO for 15.0
// bk = skElement;
// break;
//} else
if(!baseKey.key || !baseKey.key.spec) {
if(skSpec.default) {
bk = skElement;
break;
} else if(!baseKey.key || !baseKey.key.spec) {
continue;
}

if(skSpec.elementID == baseKey.key.spec.elementID) {
bk = skElement;
break; // Best possible match has been found. (Disable 'break' once above block is implemented.)
}
}

if(bk) {
// Prevent sticky-highlighting should the default key be selected.
vkbd.keyPending?.key.highlight(false);
vkbd.keyPending = bk;
this.currentSelection = bk;
// Subkeys never get key previews, so we can directly highlight the subkey.
bk.key.highlight(true);
}
Expand Down Expand Up @@ -268,7 +272,33 @@ export default class SubkeyPopup implements RealizedGesture {
}

updateTouch(input: InputEventCoordinate) {
this.currentSelection = null;
// For 'default' subkey handling, we want a small fudge factor.
if(this.initialX === undefined || this.initialY === undefined) {
this.initialX = input.x;
this.initialY = input.y;
}

const deltaX = this.initialX - input.x;
const deltaY = this.initialY - input.y;
const dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY);

if(dist > 5) {
this.initialX = Number.MAX_SAFE_INTEGER; // it'll always exceed the threshold hereafter.
this.currentSelection = null;
} else {
// The function that calls this to perform subkey updates auto-unhighlights the active selection;
// make sure that highlighting is maintained if no new key was selected, but we haven't cancelled
// default-selection mode yet.
this.currentSelection.key.highlight(true);

// Even if we technically have a different subkey underneath the touchpoint, we're still in
// default-selection mode. Require more movement before cancelling default-selection mode.
//
// Can occur for large subkey menus or when subkey menus are "constrained" within OSK bounds,
// as with the iOS app.
return;
}

this.baseKey.key.highlight(false);

for(let i=0; i < this.baseKey['subKeys'].length; i++) {
Expand Down
1 change: 1 addition & 0 deletions web/src/engine/osk/src/keyboard-layout/oskKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class OSKKeySpec implements LayoutKey {
nextlayer?: string;
pad?: number;
sk?: OSKKeySpec[];
default?: boolean;

constructor(id: string, text?: string, width?: number, sp?: ButtonClass, nextlayer?: string, pad?: number) {
this.id = id;
Expand Down
1 change: 1 addition & 0 deletions web/src/test/manual/web/default-subkey/default_subkey.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

99 changes: 99 additions & 0 deletions web/src/test/manual/web/default-subkey/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />

<!-- Set the viewport width to match phone and tablet device widths -->
<meta name="viewport" content="width=device-width,user-scalable=no" />

<!-- Allow KeymanWeb to be saved to the iPhone home screen -->
<meta name="apple-mobile-web-app-capable" content="yes" />

<!-- Enable IE9 Standards mode -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />

<title>KeymanWeb Testing Page - Predictive Text: robust testing</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>

<!-- Insert uncompiled KeymanWeb source scripts -->
<script src="../../../../../build/publish/debug/keymanweb.js" type="application/javascript"></script>

<!--
For desktop browsers, a script for the user interface must be inserted here.
Standard UIs are toggle, button, float and toolbar.
The toolbar UI is best for any page designed to support keyboards for
a large number of languages.
-->
<script src="../../../../../build/publish/debug/kmwuitoggle.js"></script>

<!-- Initialization: set paths to keyboards, resources and fonts as required -->
<script>
var kmw=window.keyman;
kmw.init({
attachType:'auto'
}).then(function() {
kmw.addKeyboards({id:'default_subkey',name:'English',languages:{id:'en',name:'English'}, filename:'./default_subkey.js'});

var pageRef = (window.location.protocol == 'file:')
? window.location.href.substr(0, window.location.href.lastIndexOf('/')+1)
: window.location.href;
});
</script>
</head>

<!-- Sample page HTML -->
<body>
<h2>KeymanWeb Sample Page - default subkey bootstrap-testing</h2>
<p>Note: the intended tests require use of a touch-form-factor device or emulation thereof.
</p>
<p>
The primary test is held on the default layer's 'd' key - the key labeled 'default' should
be autoselected.
</p>
<p>
A secondary test is held on the default layer's 'a' key - the key labeled 'a', matching the
base key, should be autoselected.
</p>
<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>

<h3>Type in your language in this text area:</h3>
<textarea id='ta1' class='test' placeholder='Type here'></textarea>

<h3>or in this input field:</h3>
<input class='test' value='' placeholder='or here'/>

<h3><a href="./">Return to testing home page</a></h3>
</div>

</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>
6 changes: 6 additions & 0 deletions web/src/test/manual/web/default-subkey/kbd_source/HISTORY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
default-subkey Change History
====================

1.0 (2023-08-21)
----------------
* Created by SIL International
21 changes: 21 additions & 0 deletions web/src/test/manual/web/default-subkey/kbd_source/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

© 2023 SIL International

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.
30 changes: 30 additions & 0 deletions web/src/test/manual/web/default-subkey/kbd_source/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
default-subkey keyboard
==============

Version 1.0

Description
-----------
default-subkey generated from template

Links
-----

Copyright
---------
See [LICENSE.md](LICENSE.md)

Supported Platforms
-------------------
* Windows
* macOS
* Linux
* Web
* iPhone
* iPad
* Android phone
* Android tablet
* Mobile devices
* Desktop devices
* Tablet devices

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"license": "mit",
"languages": [

],
"description": "default-subkey generated from template"
}
110 changes: 110 additions & 0 deletions web/src/test/manual/web/default-subkey/kbd_source/default_subkey.kpj
Original file line number Diff line number Diff line change
@@ -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_8305ac63cf6c1388736030b6b94f996d</ID>
<Filename>default_subkey.kmn</Filename>
<Filepath>source\default_subkey.kmn</Filepath>
<FileVersion>1.0</FileVersion>
<FileType>.kmn</FileType>
<Details>
<Name>default-subkey</Name>
<Copyright>© SIL International</Copyright>
</Details>
</File>
<File>
<ID>id_f586f51f683bde64c75f566e643e59bd</ID>
<Filename>default_subkey.kps</Filename>
<Filepath>source\default_subkey.kps</Filepath>
<FileVersion></FileVersion>
<FileType>.kps</FileType>
<Details>
<Name>default-subkey</Name>
<Copyright>© SIL International</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_9cc75be74cee7f9a4937893e80b91b5f</ID>
<Filename>default_subkey.keyboard_info</Filename>
<Filepath>default_subkey.keyboard_info</Filepath>
<FileVersion></FileVersion>
<FileType>.keyboard_info</FileType>
</File>
<File>
<ID>id_d8483af80632f8b611983c11137efccd</ID>
<Filename>default_subkey.ico</Filename>
<Filepath>source\default_subkey.ico</Filepath>
<FileVersion></FileVersion>
<FileType>.ico</FileType>
<ParentFileID>id_8305ac63cf6c1388736030b6b94f996d</ParentFileID>
</File>
<File>
<ID>id_5086f2e8ef1d731c015a78f418aba1e8</ID>
<Filename>default_subkey.kmx</Filename>
<Filepath>source\..\build\default_subkey.kmx</Filepath>
<FileVersion></FileVersion>
<FileType>.kmx</FileType>
<ParentFileID>id_f586f51f683bde64c75f566e643e59bd</ParentFileID>
</File>
<File>
<ID>id_c8c9acd9c28010e45856034bff6c9d90</ID>
<Filename>default_subkey.js</Filename>
<Filepath>source\..\build\default_subkey.js</Filepath>
<FileVersion></FileVersion>
<FileType>.js</FileType>
<ParentFileID>id_f586f51f683bde64c75f566e643e59bd</ParentFileID>
</File>
<File>
<ID>id_7b38ddd4f3836ebf9365696475ade08a</ID>
<Filename>default_subkey.kvk</Filename>
<Filepath>source\..\build\default_subkey.kvk</Filepath>
<FileVersion></FileVersion>
<FileType>.kvk</FileType>
<ParentFileID>id_f586f51f683bde64c75f566e643e59bd</ParentFileID>
</File>
<File>
<ID>id_356e5d149c1e539356d72698c1e401a6</ID>
<Filename>welcome.htm</Filename>
<Filepath>source\welcome.htm</Filepath>
<FileVersion></FileVersion>
<FileType>.htm</FileType>
<ParentFileID>id_f586f51f683bde64c75f566e643e59bd</ParentFileID>
</File>
<File>
<ID>id_8da344c4cea6f467013357fe099006f5</ID>
<Filename>readme.htm</Filename>
<Filepath>source\readme.htm</Filepath>
<FileVersion></FileVersion>
<FileType>.htm</FileType>
<ParentFileID>id_f586f51f683bde64c75f566e643e59bd</ParentFileID>
</File>
</Files>
</KeymanDeveloperProject>
Binary file not shown.
Loading

0 comments on commit 4a4c759

Please sign in to comment.