Skip to content

An AutoHotKey library for creating simple XMB™-like visual keyboards.

License

Notifications You must be signed in to change notification settings

A-AhkUser/vKeyboard

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 

Repository files navigation

vKeyboard interface

An AutoHotKey library for creating simple XMB™-like visual keyboards.
AutoHotkey v1.1.32.00+ (recommended)


Acknowledgements

special thanks to brutus_skywalker, coco, GeekDude, fenchai, helgef, ixiko, jeeswg, ManiacDC, Rohwedder and Uberi

Table of Contents


Presentation

The library allows to create basic but nevertheless rather customizable visual keyboards, via an AutoHotkey programmable interface. Practically, the script enables you to invoke a visual keyboard whenever text entry is required - and as an alternative to type, enter text.


Main features

  • The visual keyboard is endowed with an eAutocomplete control, which allows autocompletion. This latter enables you, as you are composing text, to rather quickly find, get info tips and select from a dynamic pre-populated list of suggestions and, by this means, to expand/replace partially entered strings into/by complete strings. The eAutocomplete component allows fuzzy search.
  • The visual keyboard is designed to be easily handled using a 12keys-1POV-4axes PC game controller.
  • Basic event handling.
  • Customizable keyboard/joystick hotkeys, autocomplete lists, keyboard layouts and UI graphics.

Deployment

An instance of vKeyboard (the visual keyboard object) will be from now on referred to as vk.

Sample example (sample_example.ahk)

#NoEnv
#SingleInstance force
SetWorkingDir % A_ScriptDir
SendMode, Input
#Warn
; tested on Windows 10 (19041) 64 bit with Autohotkey v1.1.32.00 32-bit Unicode

#Include %A_ScriptDir%\..\..\lib\vKeyboard.ahk

eAutocomplete.setSourceFromFile("fr", A_ScriptDir . "\autocompletion\fr")

vk := new vKeyboard()
vk.autocomplete.source := "fr"
vKeyboard.defineLayout("français", A_ScriptDir . "\keymaps\français.json")
vk.setLayout("français")
vKeyboard.defineStyle("default", A_ScriptDir . "\styles\default.css")
vk.setStyle("default")
vk.autocomplete.bkColor := vk.backgroundColor
vk.autocomplete.fontColor := "FFFFFF"
vk.autocomplete.fontName := "Segoe UI"
vk.autocomplete.fontSize := 14
vk.autocomplete.listbox.bkColor := vk.backgroundColor
vk.autocomplete.listbox.fontColor := "666666"
vk.autocomplete.listbox.fontName := "Segoe UI"
vk.autocomplete.listbox.fontSize := 11
vk.setHotkeys({}, 1, "Joy5")
vk.showHide()
vk.fitContent(16, 5, true)
vk.onSubmit(Func("vk_onSubmit"))
OnExit, handleExit
return

vk_onSubmit(this, _hLastFoundControl, _input) {
	ToolTip % _hLastFoundControl "," _input
	if (_hLastFoundControl)
		ControlSend,, % "{Text}" . _input, % "ahk_id " . _hLastFoundControl
	else SendInput % "{Text}" . _input
}

handleExit:
	vk.dispose()
ExitApp

!x::ExitApp

you can find this sample script, commented, in the examples folder. see also: Keyboard and joystick shortcuts to start using the script!


Namespace reservations

The library sets the following class variables:

  • JSON (by coco)
  • eAutocomplete
  • Hotkey [_HotkeyIt, _Hotkey, __Hotkey__, _Hk, _Context, _JoyButtonKeypressHandler, ObjBindTimedMethod]
  • Joystick
  • Keypad [_Keypad, _KeypadEvents, _KeypadGraphicsMapping, _KeypadAXObjectWrapper]
  • KeypadInterface
  • vKeyboard

you can find the tree structure of the library in the lib folder.

The #Warn directive can be used to show a warning for each assignment targeting a class variable.


vKeyboard (the visual keyboard object)

Syntax description for creating a new object derived from vKeyboard, using the new keyword:

vk := new vKeyboard() ; create a new instance of the visual keyboard object and stores it in 'vk'

The constructor throws an exception on failure.


Object members

note: the following list may not be exhaustive.

Object member description
vk.AXObject The wrapper of the ActiveX object embedded into the visual keyboard window (for example, the root node of the HTML document can be retrieved using vk.AXObject.document).
vk.autocomplete The visual keyboard's own specific eAutocomplete (v1.2.30) interface. It differs from a standard eAutocomplete interface in that both its autoSuggest and onResize properties have been made read-only and in that it offers four additional properties (i.e. bkColor, fontName, fontSize and fontColor) - through which one can style the visual keyboard's text entry field. Otherwise, see the eAutocomplete's readme for an overview of all available properties and methods for this member.
vk.hostWindow An interface to the window which hosts the visual keyboard. It has the following relevant read-only property: HWND, which contains the visual keyboard GUI window's HWND - and besides having three transparent methods: show(), hide() and isVisible().


Available properties

note: the following list may not be exhaustive.

property description default value
vk.X
[READ-ONLY]
Returns the position, along the x-axis (columns), of the key currently focused. 1
vk.Y
[READ-ONLY]
Returns the position, along the y-axis (rows), of the key currently focused. 1
vk.columns
[READ-ONLY]
Returns the number of columns in the mapping of the visual keyboard current layout. runtime/user-defined
vk.rows
[READ-ONLY]
Returns the number of rows in the mapping of the visual keyboard current layout. runtime/user-defined
vk.hideOnSubmit Set or get the boolean value which determine if the visual keyboard should be hidden each time the text entered is submitted. true
vk.resetOnSubmit Set or get the boolean value which determine if the entire text entry field of the visual keyboard should be cleared upon submission. true
vk.transparency Set or get the visual keyboard GUI window's degree of transparency. Could be any integer value between 10 and 255. 255
vk.alwaysOnTop Set or get the boolean value which determine if the visual keyboard host window should stay on top of all other windows. true
vk.style
[READ-ONLY]
Returns the name of the css stylesheet used to graphically render the keyboard layout. Use the setStyle method to set the visual keyboard style. ""
vk.layout
[READ-ONLY]
Returns the name of the current keyboard layout. Use the setLayout method to set the visual keyboard layout. runtime/user-defined
vk.layer
[READ-ONLY]
Returns the index of the current keyboard layout's layer. Use the setLayer method to set the visual keyboard layer. 1
vk.layers
[READ-ONLY]
Returns the total number of layers available for the current keyboard layout. runtime/user-defined
vk.altIndex
[READ-ONLY]
Returns the current altIndex. 1
vk.altMode
[READ-ONLY]
Returns true if the visual keyboard is currently in 'alt mode' (that is, displays key variants to select from) and false otherwise. false
vk.fontSize Set or get a positive integer between 8 and 112 defining the size (in px) of the keyboard's font. 16
vk.backgroundColor
[READ-ONLY]
Returns the current background colour of the keypad. FFFFFF


Available methods

note: the following list may not be exhaustive.

  • defineLayout
  • defineStyle
  • setHotkeys
  • setStyle
  • setLayout
  • setLayer
  • showHide
  • fitContent
  • expand
  • shrink
  • redraw
  • dispose

defineLayout

vKeyboard.defineLayout(_name, _pathOrContent, _defaultObjectWrapper:="", _defaultCallback:="")
This base method allows to define a 'keymap' (keyboard layout mapping) for future calls of the setLayout instance method.
parameter description
_name [STRING] The name identifying the keymap, which may consist of alphanumeric characters, underscore and non-ASCII characters.
_pathOrContent [STRING - PATH/JSON-FORMATTED STRING] Can be either a keyboard layout JSON representation or the full path of a file containing such JSON-formatted string. In the first case, you can use FileRead or a continuation section to save a series of lines to a variable. Alternatively, you can run the keymapMaker: by means of its GUI, you can the WYSIWYG-way create keyboard layouts, export and save them as Layout JSON representations, compatible with this interface method.
_defaultObjectWrapper [OBJECT] OPTIONAL If specified, a class that wraps press handlers, used as target object for all keyboard keys whose f-function is not a 'floating' function defined in the script. If omitted, the script's own internal wrapper is used instead, allowing you to use the built-in f-functions.
_defaultCallback [STRING] OPTIONAL The name of a function that will be executed in place of the built-in default callback each time a key on the visual keyboard is pressed/clicked, assuming that a f-function has not been set for this key. If the function does not exist, the script searches for a matching method in [_defaultObjectWrapper]. To omit this parameter while specifying a _defaultObjectWrapper amounts to specify call.

The method throws an exception upon failure (for instance, if the keyboard layout JSON representation is badly formatted).

; usage examples:
; 1
vKeyboard.defineLayout("english", A_ScriptDir . "\myLayouts\english.json")
; 2
vKeyboard.defineLayout("français", A_ScriptDir . "\myLayouts\français.json",, "myFunc")
; somewhere in your script:
myFunc(this, _keyDescriptor, _count) {
	; some stuff
}
; 3
vKeyboard.defineLayout("русский", A_ScriptDir . "\myLayouts\русский.json", myEventHandler, "defaultCb")
; somewhere in your script:
Class myEventHandler {
	defaultCb(_vKeyboardInst, _keyDescriptor, _count) {
		; some stuff
	}
	onStarPress(_vKeyboardInst, _keyDescriptor, _count) {
		; some stuff
	}
}
/* somewhere in your keyboard layout mapping:
	...
	{ ; key descriptor
		"caption": "★",
		"f": "onStarPress"
	}
	...
*/

see also: Layout JSON representations.


defineStyle

vKeyboard.defineStyle(_name, _pathOrContent)
This base method allows to define a style for future calls of the setStyle instance method.
parameter description
_name [STRING] The name identifying the style, which may consist of alphanumeric characters, underscore and non-ASCII characters.
_pathOrContent [STRING - PATH/CSS-FORMATTED STRING] A CSS style sheet describing how the visual keyboard's layout should be rendered. Can be either a css style sheet string or the full path of a file containing such stylesheet. In the first case, you can use FileRead or a continuation section to save a series of lines to a variable.
; usage examples:
vKeyboard.defineStyle("myCustomStyle", A_ScriptDir . "\myStyles\myCustomStyle.css")
cascadingStyleSheet =
(Join`r`n
body {
	background-color: #000000;
}
button.key {
	background-color: #111111;
	font-family: Segoe UI;
	color: #EA72C0;
}
button.key:focus {
	background-color: #333333;
	outline: none;
}
button.key:hover {
	background-color: #222222;
}
)
vKeyboard.defineStyle("myCustomStyle", cascadingStyleSheet)

see also: Styling the keyboard.


setHotkeys

vk.setHotkeys(_obj, _joystickPort:=1, _joyModifier:="Joy5")
Set up all keyboard/joystick shortcuts for a given vKeyboard instance. Joystick hotkeys are set taking into account the value of _joystickPort, which defaults to 1.
parameter description
_obj [OBJECT] An object that observes the tree structure shown below. It will indicate to the script the value of each keyboard/joystick shortcuts which are to be used by the visual keyboard. If a given value is not passed to the caller, its default value is used instead (see Keyboard and joystick shortcuts to get an overview of all default values used by the script). Actually, branches, sub-branches and keys are all optional. Also, the keys for a branch or sub-branch may be in any order within that branch or sub-branch, as they are referenced by name. Note that you can find an example of such JSON description in the script directory: /examples/test/settings.json - you can copy it and merely set the relevant values at your convenience whilst keeping it within the limitations imposed below on acceptable values.
_joystickPort [INTEGER] OPTIONAL If the computer has more than one joystick and you want to use one beyond the first to control the visual keyboard, specify a positive integer between 2 and 8. Specify 0 for _joystickPort to avoid setting up joystick hotkeys and polling, seeking for events, joystick axes.
_joyModifier [INTEGER] OPTIONAL Any joystick button name without the joystick number prefix (e.g. Joy1, Joy2, ... and up to Joy32 - at least if your joystick controller actually has 32 buttons). It will be used as 'modifier' - so that you would hold down it then press a second joystick button to trigger the joystick hotkey. It must be represented by a ! (that is, an exclamation mark) right before the key name (e.g. !Joy3) in _obj's values.

The method throws an exception upon failure.

The _obj parameter must observe the following tree structure:

├── "autocomplete"
│   ├── "keyboard"
│   ├── ├──[AUTOCOMPLETE_HOTKEYS]
│   ├── "joystick"
│   ├── ├──[AUTOCOMPLETE_HOTKEYS]
├── "keypad"
│   ├── "keyboard"
│   ├── ├──[KEYPAD_HOTKEYS]
│   ├── "joystick"
│   ├── ├──[KEYPAD_HOTKEYS]
├── "window"
│   ├── "keyboard"
│   ├── ├──[WINDOW_HOTKEYS]
│   ├── "joystick"
│   ├── ├──[WINDOW_HOTKEYS]
  • where [AUTOCOMPLETE_HOTKEYS], [KEYPAD_HOTKEYS] and [WINDOW_HOTKEYS] stand respectively for the following objects:
{"listboxDismiss": [HOTKEY_NAME]
, "listboxSelectUp": [HOTKEY_NAME]
, "listboxSelectDown": [HOTKEY_NAME]
, "dataLookUp1": [HOTKEY_NAME]
, "dataLookUp2": [HOTKEY_NAME]
, "complete1": [HOTKEY_NAME]
, "complete2": [HOTKEY_NAME]} ; [AUTOCOMPLETE_HOTKEYS]
{"pressKey": [SINGLE_KEY_NAME]
, "altReset": [SINGLE_KEY_NAME]
, "sendBackSpace": [HOTKEY_NAME]
, "sendSpace": [HOTKEY_NAME]
, "startNewLine": [HOTKEY_NAME]
, "submit": [HOTKEY_NAME]
, "switchLayer": [HOTKEY_NAME]
, "decreaseFontSize": [HOTKEY_NAME]
, "increaseFontSize": [HOTKEY_NAME]
, "clearContent": [HOTKEY_NAME]} ; [KEYPAD_HOTKEYS]
{"showHide": [AHK_KEY_NAME]} ; [WINDOW_HOTKEYS]
  • where [HOTKEY_NAME] can be any hotkey's activation key name supported by the hotkey command while also allowing, for joystick buttons, a 'modifier' to be specified. In this case, it must be represented by a ! (that is, an exclamation mark) right before the key name (e.g. !Joy3) - so that you would hold down _joyModifier then press the second joystick button (here Joy3) to trigger the joystick hotkey.
  • where [AHK_KEY_NAME] can be any hotkey's activation key name supported by the hotkey command.
  • where [SINGLE_KEY_NAME] must consist in a single key - either it is a joystick button name or a non-modifier keyboard key (e.g. a, F1, NumpadEnter, Insert, Tab etc.).
  • In any case, do not specify the joystick number prefix in front of the control name (e.g. 1Joy3): use the second parameter instead to set the joystick number.
; usage examples:
vk.setHotkeys({}, 0) ; use default values
vk.setHotkeys({autocomplete:{keyboard:{"listboxSelectUp": "!Up", "listboxSelectUp": "!Down"}}}, 1)
vk.setHotkeys({window:{keyboard:{"showHide": "F11"}}}, 1)
obj :=
(LTrim Join C
{
	window: {
		keyboard: {
			"showHide": "F11" ; [AHK_KEY_NAME]
		}
	},
	keypad: {
		joystick: {
			pressKey: "Joy1", ; [SINGLE_KEY_NAME]
			sendBackSpace: "!Joy4" ; [HOTKEY_NAME]
		},
		keyboard: {
			pressKey: "NumpadEnter",
			sendBackSpace: "!Backspace"
		}
	}
}
)
vk.setHotkeys(obj, 2, "Joy2")

see also: Keyboard and joystick shortcuts.


setStyle

vk.setStyle(_style)
Set the visual appearance of the keyboard layout.
parameter description
_style [STRING] Can be an empty string or the name of a css stylesheet that was previously defined as style using the defineStyle base method. If the value is an empty string all keypad's user-defined styles are removed.

The method throws an exception on failure.


setLayout

vk.setLayout(_layout, _layer:=1, _center:=false)
Set the visual keyboard's layout.
parameter description
_layout [STRING] The value must be the name of a layout JSON representation that was previously defined using the defineLayout base method.
layer [INTEGER] An integer indicating the index of the new keyboard layout's starting layer.
_center [BOOLEAN] A boolean value which determines if the script has to center the visual keyboard window immediately after having set the new layout.

The method throws an exception on failure.


setLayer

vk.setLayer(_layer)
Set the visual keyboard layout's layer.
parameter description
_layer [INTEGER] The index of the layer to navigate to.

return value: the method returns 0 upon failure and the index of the new visual keyboard layout's layer upon success.


showHide

vk.showHide()
Shows the visual keyboard if it is hidden - and vice versa.

fitContent

vk.fitContent(_size:="", _padding:=2, _center:=true)
Resize the visual keyboard so that it fits its content.
parameter description
_size [INTEGER] The keypad's font size to be taken into account for the resizing operation. If omitted, defaults to the current keypad's font size.
_padding [INTEGER] The keypad's keys 'padding' value to be taken into account for the resizing operation.
_center [BOOLEAN] A boolean value which determines if the script has to center the visual keyboard window after resizing, if it is visible.

expand

vk.expand()
This method is a shorthand for vk.fitcontent(vk.fontSize + 2)

shrink

vk.shrink()
This method is a shorthand for vk.fitcontent(vk.fontSize - 2)

redraw

vk.redraw()
Attempts to update the appearance of the keyboard layout graphics. This method solves painting artefacts that may occur when, for instance, you set the background color of the visual keyboard's text entry field using vk.autocomplete.bkColor.

dispose

vk.dispose()
Destroys the visual keyboard window. Releases all circular references by unregistering instance’s own hotkeys, event handlers and event hook functions (the autocomplete component hooks a few events instead of querying windows objects when needed). A script should call the dispose method, at the latest at the time the script exits, if it implements one or more __Delete meta-functions. On a side note, calling dispose ensures that words collected by the autocomplete component, if any, are stored into the appropriate database. Once the method has been called, the script is assumed not to query, interact with the instance thereafter.


Event handling

The script is able to call a user-defined callback for the following events:

  • onKeyPress (not yet implemented)
  • onSubmit
  • onShowHide

Note that the autocomplete vKeyboard's object member has also its own event handling you can take advantage of.

onKeyPress


vk.onKeyPress(Func("myKeyPressEventMonitor"))

description:

[NOT YET IMPLEMENTED] Executes a custom function each time a keyboard's key is pressed or clicked. It is executed before the key's own f-function is actually called. The function can prevent the key's default behaviour by returning a non-zero integer.
The function can optionally accept the following parameters:
preventDefault := myKeyPressEventMonitor(this, _x, _y, _count, _key)

parameters description
_x Represents the position, along the x-axis (columns), of the key being clicked or pressed.
_y Represents the position, along the y-axis (rows), of the key being pressed or clicked.
_count A non-zero integer which represents the number of clicks or presses that generated the event. Up to 3 consecutive presses/clicks are detected as such - while -1 stands for a long click/press.
_key A reference to the key descriptor of the key currently focused/hovered whose press/click triggered the event handler.

onShowHide


vk.onShowHide(Func("myShowHideEventMonitor"))

description:

Executes a user-defined function each time the keyboard is shown/hidden (by means of the showHide method).
The function can optionally accept the following parameters:
myShowHideEventMonitor(this, _isVisible)

parameters description
_isVisible Contains 1 (true) if the keyboard is now visible or 0 (false) otherwise.
; usage example:
; ...
vk.onShowHide(Func("vk_onShowHide"))
return
; ...
vk_onShowHide(this, _isVisible) {
	ToolTip % _isVisible
}

onSubmit


vk.onSubmit(Func("mySubmitEventMonitor"))

description:

Executes a user-defined function each time the text entered so far is submitted.
The function can optionally accept the following parameters:
mySubmitEventMonitor(this, _hLastFoundControl, _input)

parameters description
_hLastFoundControl If any, the HWND of the control that had focus and whose focus has been stolen by the visual keyboard at the moment this latter was last shown.
_input The content of the visual keyboard's text entry field upon submission.
; usage example:
; ...
vk.onSubmit(Func("vk_onSubmit"))
return
; ...
vk_onSubmit(this, _hLastFoundControl, _input) {
	if (_hLastFoundControl)
		ControlSend,, % "{Text}" . _input, % "ahk_id " . _hLastFoundControl
	else SendInput % "{Text}" . _input
}

Customization

Keyboard and joystick shortcuts

Hotkeys default to the following values:

hotkey description
Left-Up-Right-Down \ JoyPOV Navigate through keyboard's keys.
JoyX \ JoyY Move the visual keyboard window.
Enter \ Joy3 Press the keyboard key currently focused. Keys can alternatively be clicked. Long press (respectively long click) to display the key's own variants, if any. Multiple clicks and presses can also be handled as such.
Escape \ Joy1 Reset both the visual keyboard's alt mode and index.
F2 \ Joy5 & Joy3 Switch the keyboard layer (from the greater stack order to the lowest one in the z-index axis).
Shift + Enter \ Joy10 Submit the text entered so far in the visual keyboard's text entry field (should call the onSubmit callback, if any).
F1 \ Joy12 Show/hide the visual keyboard (should call the onShowHide callback, if any).
NumpadSub \ Joy9 Decrease the visual keyboard keys' font size.
NumpadAdd \ Joy5 & Joy9 Increase the visual keyboard keys' font size.
NumpadDown-NumpadUp-NumpadLeft-NumpadRight \ JoyZR [text entry field] Shift the caret/insert position.
Backspace \ Joy4 [text entry field] Remove the last character starting from the left-hand side of the caret/insert current position.
Space \ Joy4 [text entry field] Insert a space character.
NumpadEnter \ Joy5 & Joy4 [text entry field] Insert a line break.
Shift + Delete \ Joy5 & Joy1 [text entry field] Clear the entire visual keyboard's text entry field.
Escape \ Joy1 [autocomplete mode] Dismiss the list of autocomplete suggestions.
PageUp \ Joy7 [autocomplete mode] Select the previous item from the list of available suggestions.
PageDown \ Joy8 [autocomplete mode] Select the next item from the list of available suggestions.
Alt + Left \ Joy5 & Joy7 [autocomplete mode] Hold the first key and press the second one to look up the selected suggestion’s first associated data, if any.
Alt + Right \ Joy5 & Joy8 [autocomplete mode] Hold the first key and press the second one to look up the selected suggestion’s second associated data, if any.
Tab \ Joy6 [autocomplete mode] Complete a pending word with the currently selected suggestion. Long press to replace instead the current partial string by the selected suggestion’s first associated data.
Shift + Tab \ Joy5 & Joy6 [autocomplete mode] Long press to replace the current partial string by the selected suggestion’s second associated data.

The vast majority of these hotkeys are customizable. See also: setHotkeys.


Autocomplete lists

Use eAutocomplete.setSourceFromFile or eAutocomplete.setSourceFromVar to create a new autocomplete dictionary, respectively from a file’s content or from an input string. Thus, you can thereafter use at any time the setter/getter vk.autocomplete.source to set the autocomplete list to use for the visual keyboard.

see also: eAutocomplete - Custom autocomplete lists.


Styling the keyboard

So far, you can use the following setters/getters to style - using 6-digit RGB color values - the autocomplete control:

; usage examples:
vk := new vKeyboard()
; ...
vk.autocomplete.bkColor := "000000" ; black
vk.autocomplete.fontColor := "FFFFFF" ; white
vk.autocomplete.listbox.bkColor := "000000"
vk.autocomplete.listbox.fontColor := "FFFFFF"

Besides, the script offers a basic css interface that allows you to indicate how the visual keyboard's keys should be rendered. You can use both the button.key and button.variant css selectors in your custom css stylesheet - as an example:

body {
	background-color: #000000;
}
/* the 'key' class identifies all keys but
the 'variants' ones (see comment below) */
button.key {
	background-color: #111111;
	font-family: Segoe UI;
	color: #EA72C0;
}
button.key:focus {
	background-color: #333333;
	outline: none;
}
button.key:hover {
	background-color: #222222;
}
/* the 'variant' class identifies all keys displayed when
the visual keyboard enters alt mode and suggests key
variants (e.g. letters with diacritics) to select from */
button.variant {
	color: #EA72C0;
}
button.variant:focus {
	background-color: #555555;
	outline: none;
}
button.variant:hover {
	background-color: #444444;
}

You must call the defineStyle base method to define a style. Thus, you can thereafter use the setStyle method to set at any time the style used to render the visual keyboard graphics.


Layout JSON representations

note: The following provides extensive details on the implementation. You can also run the keymapMaker if you don't need to know the ins and outs of this layout stuff: by means of this script, you can the WYSIWYG-way create keyboard layouts, export and save them as Layout JSON representations.

The vKeyboard interface uses JSON-formatted object descriptions in order to represent keyboard layouts. These descriptions help the script determine the structure (layers, rows, columns etc.) but also the semantic content (key captions, key's associated callback function etc.) of the keyboard layout.

The structure of keymaps

We can model, map a keyboard layout as a tri-dimensional array. Actually, it can be seen as one or more layers (z-axis), only one of them being visible at a given time - in that way:

  • A layer can be described as a two-dimensional array: an array of rows (y-axis).
  • A row can be itself described as an array of keys (x-axis).
  • A key can be a descriptor; it can be either a string (for simple keys) or an object (for semantically richer keys).

The following example describes a bare keyboard layout (one layer, one row, one key):

[
    [
        [
            null
        ]
    ]
]

The following layout object representation describes a keyboard layout with just one layer and one row (consisting itself in three keys: two complex ones and a simple one):

[ ; keymap
	[ ; first layer (3rd dimension -z)
		[ ; first row (2nd dimension -y)
			{ ; first key (1st dimension -x)
				"caption": "",
				"f": "myCustomFunc",
				"myCustomKey": "myCustomValue"
			},
			{ ; second key
				"caption": "a",
				"f": "keyWithVariantsProc",
				"params": [
					"å","â","ä","ā","à","ã","æ","à"
				]
			},
			"z" ; third key
		]
	]
]

You can find some basic examples of such keyboard layouts representations in the keymaps directory (/examples/test/keymaps).

The semantics of keymaps - key descriptors

Key descriptors are the constitutive elements of a keyboard layout mapping (see above). By default, if the descriptor is not an object, press or click the key will simply send its caption right on the keyboard's text entry field each time it is pressed or clicked. Otherwise, if a given descriptor is an object, the following properties have a special meaning for the script and are processed accordingly by it:

property description
caption [STRING] specifies the symbol displayed on the visual keyboard's key.
f OPTIONAL [STRING] specifies a function - the 'f-function' - to execute each time the key is pressed. A reference to the key descriptor itself will be passed to the caller of the key's associated f-function each time it is executed. If a given key descriptor lacks its f property, the built-it default callback will be used as associated f-function for this key.
style OPTIONAL [STRING] (not yet implemented) specifies the CSS class name whose rules describe how the visual keyboard's key should be rendered. Both variant and key CSS class names are used internally and, for this very reason, must not be used as custom class names.
params OPTIONAL Reserved by the script. Relevant when used with one of the built-in f-functions.
altCaption OPTIONAL Reserved by the script. Might be implemented and, thus, have special meaning later.
accessKey OPTIONAL Reserved by the script. Might be implemented and, thus, have special meaning later.
[CUSTOM_NAME] OPTIONAL [STRING/OBJECT/ARRAY/STRING/NUMBER/true/false/null] You can add custom keys in the key descriptor to take advantage of their respective values from within the key's own f-function callback each time the key is pressed or clicked. The [CUSTOM_NAME] key's value can be any of the value supported by the JSON data-interchange format.

note: in cases where your key descriptor lacks all its optional keys, you can merely specify the letter which is intended to be displayed on the visual keyboard as a shorthand for the key descriptor object:{"caption": "a"} - which does works, but amounts to specify "a".

The built-in default callback

If a key descriptor is not an object, press or click the key will simply send its caption right on the keyboard's text entry field each time it is pressed or clicked: the built-it default callback and its default procedure will be used as associated f-function for the keyboard's key. You can modify this behaviour by specifying a custom default callback for a specific keymap when calling defineLayout.

F-functions

example:
/*
assuming at least one of the key in your keyboard layout consists in the following descriptor...
{ ; key descriptor
	"caption": "★",
	"f": "myCustomFunc",
	"myCustomKey": "MsgBox!"
}
*/
; somewhere in your script:
myCustomFunc(this, _keyDescriptor, _count) {
	_msgBoxOption := this.alwaysOnTop ? 4096 : 0
	GUI % this.hostWindow.HWND . ":+OwnDialogs"
	MsgBox, % _msgBoxOption
			, % _keyDescriptor.myCustomKey
			, % "You pressed on the " . _keyDescriptor.caption . " key "
				. ((_count = -1) ? "a long time" : _count . "time(s)") . "!"
; return 0
}

description:

The f key in the key descriptor allows you to specify a function to execute each time the keyboard's key is pressed or clicked. In case it is a non-zero integer, the return value of the callback will be used to set the altIndex accordingly.
The function can optionally accept the following parameters (where this refers to the vKeyboard instance, not the key descriptor object):
altIndex := myCustomFunc(this, _keyDescriptor, _count)

parameters description
_keyDescriptor Contains a reference to the descriptor of the key whose click/press triggered the f-function.
_count A non-zero integer which represents the number of clicks or presses that triggered the callback. Up to 3 consecutive presses/clicks are detected as such - while -1 stands for a long click/press.

Built-in 'f-functions'

Unless you specified a custom default object wrapper when calling defineLayout, you don't necessary have to define in your script functions in order to handle key presses and clicks on the visual keyboard. Instead, you can specify one of the built-in f-functions and the params key in your key descriptor.

note: the following list may not be exhaustive.

keyWithVariantsProc
{
	"caption": "i",
	"f": "keyWithVariantsProc",
	"params": [
		"ī","î","ï","ì","į","í"
	]
} ; each time the keyboard's key is long pressed/clicked, the visual keyboard
; enters alt mode and all params will be suggested as variants to select from


setAltIndexProc
{
	"caption": "^",
	"f": "setAltIndexProc",
	"params": [
		2
	]
} ; 2 will set alt index to 2 so that if you click this key on the
; keyboard and then click on a key with variants (see above) the second
; variant will be sent
altEntryModeProc
{
	"caption": "abc",
	"f": "altEntryModeProc",
	"params": [
		"a",
		"b",
		"c"
	]
} ; the index of the letter that will be sent depends on the amount
; of clicks/presses
setCaretPosProc
{
	"caption": "",
	"f": "setCaretPosProc",
	"params": [
		-1
	]
} ; -1 shifts from right to left the caret/insert position; conversely, 1
; would shift from left to right the caret/insert position
toLayerProc
{
	"caption": "",
	"f": "toLayerProc",
	"params": [
		2
	]
} ; 2 is the index of layer to navigate to
submitProc
switchLayerProc
sendBackSpaceProc
sendSpaceProc
startNewLineProc
clearContentProc

Licence

Unlicence