mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 16:35:33 +00:00
886 lines
No EOL
36 KiB
TypeScript
886 lines
No EOL
36 KiB
TypeScript
/***
|
||
KeymanWeb 10.0
|
||
Copyright 2017 SIL International
|
||
***/
|
||
|
||
///<reference path="../utils/version.ts"/>
|
||
|
||
namespace com.keyman.osk {
|
||
let Codes = com.keyman.text.Codes;
|
||
|
||
export type KLS = {[layerName: string]: string[]};
|
||
|
||
// The following types provide type definitions for the full JSON format we use for visual keyboard definitions.
|
||
export type ButtonClass = number|"0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"|"10"
|
||
|
||
export type LayoutKey = {
|
||
"id"?: string,
|
||
"text"?: string,
|
||
"sp"?: ButtonClass,
|
||
"width"?: string,
|
||
"layer"?: string, // Key derives any modifiers from the value set here if specified, not the actual display layer.
|
||
"nextlayer"?: string,
|
||
"pad"?: string,
|
||
"sk"?: LayoutKey[]
|
||
}
|
||
|
||
export type LayoutRow = {
|
||
"id": string, // represents a number, though...
|
||
"key": LayoutKey[]
|
||
};
|
||
|
||
export type LayoutLayer = {
|
||
"id": string,
|
||
"row": LayoutRow[],
|
||
|
||
// Post-processing elements.
|
||
shiftKey?: LayoutKey,
|
||
capsKey?: LayoutKey,
|
||
numKey?: LayoutKey,
|
||
scrollKey?: LayoutKey
|
||
aligned?: boolean
|
||
}
|
||
|
||
export type LayoutFormFactor = {
|
||
"font": string,
|
||
"layer": LayoutLayer[],
|
||
keyLabels?: boolean
|
||
}
|
||
|
||
export type LayoutSpec = {
|
||
"desktop"?: LayoutFormFactor,
|
||
"phone"?: LayoutFormFactor,
|
||
"tablet"?: LayoutFormFactor
|
||
}
|
||
|
||
// This class manages default layout construction for consumption by OSKs without a specified layout.
|
||
export class Layouts {
|
||
static dfltCodes=[
|
||
"K_BKQUOTE","K_1","K_2","K_3","K_4","K_5","K_6","K_7","K_8","K_9","K_0",
|
||
"K_HYPHEN","K_EQUAL","K_*","K_*","K_*","K_Q","K_W","K_E","K_R","K_T",
|
||
"K_Y","K_U","K_I","K_O","K_P","K_LBRKT","K_RBRKT","K_BKSLASH","K_*",
|
||
"K_*","K_*","K_A","K_S","K_D","K_F","K_G","K_H","K_J","K_K","K_L",
|
||
"K_COLON","K_QUOTE","K_*","K_*","K_*","K_*","K_*","K_oE2",
|
||
"K_Z","K_X","K_C","K_V","K_B","K_N","K_M","K_COMMA","K_PERIOD",
|
||
"K_SLASH","K_*","K_*","K_*","K_*","K_*","K_SPACE"
|
||
];
|
||
|
||
static dfltText='`1234567890-=\xA7~~qwertyuiop[]\\~~~asdfghjkl;\'~~~~~?zxcvbnm,./~~~~~ '
|
||
+'~!@#$%^&*()_+\xA7~~QWERTYUIOP{}\\~~~ASDFGHJKL:"~~~~~?ZXCVBNM<>?~~~~~ ';
|
||
|
||
// Cross-reference with the ids in osk.setButtonClass.
|
||
static buttonClasses: {[name: string]: ButtonClass} = {
|
||
'DEFAULT':'0',
|
||
'SHIFT':'1',
|
||
'SHIFT-ON':'2',
|
||
'SPECIAL':'3',
|
||
'SPECIAL-ON':'4',
|
||
'DEADKEY':'8',
|
||
'BLANK':'9',
|
||
'HIDDEN':'10'
|
||
};
|
||
|
||
static modifierSpecials = {
|
||
'leftalt': '*LAlt*',
|
||
'rightalt': '*RAlt*',
|
||
'alt': '*Alt*',
|
||
'leftctrl': '*LCtrl*',
|
||
'rightctrl': '*RCtrl*',
|
||
'ctrl': '*Ctrl*',
|
||
'ctrl-alt': '*AltGr*',
|
||
'leftctrl-leftalt': '*LAltCtrl*',
|
||
'rightctrl-rightalt': '*RAltCtrl*',
|
||
'leftctrl-leftalt-shift': '*LAltCtrlShift*',
|
||
'rightctrl-rightalt-shift': '*RAltCtrlShift*',
|
||
'shift': '*Shift*',
|
||
'shift-alt': '*AltShift*',
|
||
'shift-ctrl': '*CtrlShift*',
|
||
'shift-ctrl-alt': '*AltCtrlShift*',
|
||
'leftalt-shift': '*LAltShift*',
|
||
'rightalt-shift': '*RAltShift*',
|
||
'leftctrl-shift': '*LCtrlShift*',
|
||
'rightctrl-shift': '*RCtrlShift*'
|
||
};
|
||
|
||
static _BaseLayout: string = 'us'; // default BaseLayout
|
||
static _BaseLayoutEuro: {[code: string]: string} = {
|
||
'se': '\u00a71234567890+´~~~QWERTYUIOP\u00c5\u00a8\'~~~ASDFGHJKL\u00d6\u00c4~~~~~<ZXCVBNM,.-~~~~~ ', // Swedish
|
||
'uk': '`1234567890-=~~~QWERTYUIOP[]#~~~ASDFGHJKL;\'~~~~~\\ZXCVBNM,./~~~~~ ' // UK
|
||
}; // I1299 (not currently exposed, but may need to be e.g. for external users)
|
||
|
||
/**
|
||
* Build a default layout for keyboards with no explicit layout
|
||
*
|
||
* @param {Object} PVK keyboard object (as loaded)
|
||
* @param {Object} kbdDevVersion object representing the version of Developer that compiled the keyboard
|
||
* @param {number} kbdBitmask keyboard modifier bitmask
|
||
* @param {string} formFactor
|
||
* @return {Object}
|
||
*/
|
||
static buildDefaultLayout(PVK, kbdDevVersion: utils.Version, kbdBitmask: number, formFactor: string): LayoutFormFactor {
|
||
let keyman = com.keyman.singleton;
|
||
let util = keyman.util;
|
||
|
||
// Build a layout using the default for the device
|
||
var layoutType=formFactor;
|
||
|
||
if(typeof Layouts.dfltLayout[layoutType] != 'object') {
|
||
layoutType = 'desktop';
|
||
}
|
||
|
||
// Clone the default layout object for this device
|
||
var layout: LayoutFormFactor = util.deepCopy(Layouts.dfltLayout[layoutType]);
|
||
|
||
var n,layers=layout['layer'], keyLabels: KLS=PVK['KLS'], key102=PVK['K102'];
|
||
var i, j, k, m, row, rows: LayoutRow[], key: LayoutKey, keys: LayoutKey[];
|
||
var chiral: boolean = (kbdBitmask & Codes.modifierBitmasks.IS_CHIRAL) != 0;
|
||
|
||
var kmw10Plus = !(typeof keyLabels == 'undefined' || !keyLabels);
|
||
if(!kmw10Plus) {
|
||
// Save the processed key label information to the keyboard's general data.
|
||
// Makes things more efficient elsewhere and for reloading after keyboard swaps.
|
||
keyLabels = PVK['KLS'] = Layouts.processLegacyDefinitions(PVK['BK']);
|
||
}
|
||
|
||
// Identify key labels (e.g. *Shift*) that require the special OSK font
|
||
var specialLabel=/\*\w+\*/;
|
||
|
||
// *** Step 1: instantiate the layer objects. ***
|
||
|
||
// Get the list of valid layers, enforcing that the 'default' layer must be the first one processed.
|
||
var validIdList = Object.getOwnPropertyNames(keyLabels), invalidIdList = [];
|
||
validIdList.splice(validIdList.indexOf('default'), 1);
|
||
validIdList = [ 'default' ].concat(validIdList);
|
||
|
||
// Automatic AltGr emulation if the 'leftctrl-leftalt' layer is otherwise undefined.
|
||
if(Layouts.emulatesAltGr(keyLabels)) {
|
||
// We insert only the layers that need to be emulated.
|
||
if((validIdList.indexOf('leftctrl-leftalt') == -1) && validIdList.indexOf('rightalt') != -1) {
|
||
validIdList.push('leftctrl-leftalt');
|
||
keyLabels['leftctrl-leftalt'] = keyLabels['rightalt'];
|
||
}
|
||
|
||
if((validIdList.indexOf('leftctrl-leftalt-shift') == -1) && validIdList.indexOf('rightalt-shift') != -1) {
|
||
validIdList.push('leftctrl-leftalt-shift');
|
||
keyLabels['leftctrl-leftalt-shift'] = keyLabels['rightalt-shift'];
|
||
}
|
||
}
|
||
|
||
// For desktop devices, we must create all layers, even if invalid.
|
||
if(formFactor == 'desktop') {
|
||
invalidIdList = Layouts.generateLayerIds(chiral);
|
||
|
||
// Filter out all ids considered valid. (We also don't want duplicates in the following list...)
|
||
for(n=0; n<invalidIdList.length; n++) {
|
||
if(validIdList.indexOf(invalidIdList[n]) != -1) {
|
||
invalidIdList.splice(n--, 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
// This ensures all 'valid' layers are at the front of the layer array and managed by the main loop below.
|
||
// 'invalid' layers aren't handled by the loop and thus remain blank after it.
|
||
var idList = validIdList.concat(invalidIdList);
|
||
|
||
if(kmw10Plus && formFactor != 'desktop') { // KLS exists, so we know the exact layer set.
|
||
// Find the SHIFT key...
|
||
var shiftKey: LayoutKey = null;
|
||
|
||
rows = layers[0]['row'];
|
||
for(var r=0; r < rows.length; r++) {
|
||
keys = rows[r]['key'];
|
||
for(var c=0; c < keys.length; c++) {
|
||
key = keys[c];
|
||
if(key['id'] == 'K_SHIFT') {
|
||
shiftKey = key;
|
||
}
|
||
}
|
||
}
|
||
|
||
if(shiftKey) {
|
||
// Erase the legacy shifted subkey array.
|
||
shiftKey['sk'] = [];
|
||
|
||
for(var layerID in keyLabels) {
|
||
if(layerID == 'default' || layerID == 'shift') {
|
||
// These two are accessible from the layer without subkeys.
|
||
continue;
|
||
}
|
||
|
||
// Create a new subkey for the specified layer so that it will be accessible via OSK.
|
||
var specialChar = Layouts.modifierSpecials[layerID];
|
||
shiftKey['sk'].push(new OSKKeySpec("K_" + specialChar, specialChar, null, "1", layerID));
|
||
}
|
||
} else {
|
||
// Seriously, this should never happen. It's here for the debugging log only.
|
||
console.warn("Error in default layout - cannot find default Shift key!");
|
||
}
|
||
}
|
||
|
||
for(n=0; n<idList.length; n++) {
|
||
// Populate non-default (shifted) keygroups
|
||
if(n > 0) {
|
||
layers[n]=util.deepCopy(layers[0]);
|
||
}
|
||
layers[n]['id']=idList[n];
|
||
layers[n]['nextlayer']=idList[n]; // This would only be different for a dynamic keyboard
|
||
|
||
// Extraced into a helper method to improve readability.
|
||
Layouts.formatDefaultLayer(layers[n], chiral, formFactor, !!key102);
|
||
}
|
||
|
||
// *** Step 2: Layer objects now exist; time to fill them with the appropriate key labels and key styles ***
|
||
for(n=0; n<layers.length; n++) {
|
||
var layer=layers[n], kx, shiftKey: LayoutKey = null, nextKey=null, allText='';
|
||
var capsKey: LayoutKey = null, numKey: LayoutKey = null, scrollKey: LayoutKey = null; // null if not in the OSK layout.
|
||
var layerSpec = keyLabels[layer['id']];
|
||
var isShift = layer['id'] == 'shift' ? 1 : 0;
|
||
var isDefault = layer['id'] == 'default' || isShift ? 1 : 0;
|
||
|
||
rows=layer['row'];
|
||
for(i=0; i<rows.length; i++) {
|
||
keys=rows[i]['key'];
|
||
for(j=0; j<keys.length; j++) {
|
||
key=keys[j];
|
||
kx=Layouts.dfltCodes.indexOf(key['id']);
|
||
|
||
// Only create keys for defined layers. ('default' and 'shift' are always defined.)
|
||
if(layerSpec || isDefault) {
|
||
// Get keycap text from visual keyboard array, if defined in keyboard
|
||
if(layerSpec) {
|
||
if(kx >= 0 && kx < layerSpec.length) key['text']=layerSpec[kx];
|
||
}
|
||
|
||
// Legacy (pre 12.0) behavior: fall back to US English keycap text as default for the base two layers
|
||
// if a key cap is not otherwise defined. (Any intentional 'ghost' keys must be explicitly defined.)
|
||
if(isDefault && kbdDevVersion.precedes(utils.Version.NO_DEFAULT_KEYCAPS)) {
|
||
if(key['id'] != 'K_SPACE' && kx+65 * isShift < Layouts.dfltText.length && key['text'] !== null) {
|
||
key['text'] = key['text'] || Layouts.dfltText[kx+65*isShift];
|
||
}
|
||
}
|
||
}
|
||
|
||
// Leave any unmarked key caps as null strings
|
||
if(key['text'] !== null) {
|
||
key['text'] = key['text'] || '';
|
||
}
|
||
|
||
// Detect important tracking keys.
|
||
switch(key['id']) {
|
||
case "K_SHIFT":
|
||
shiftKey=key;
|
||
break;
|
||
case "K_TAB":
|
||
nextKey=key;
|
||
break;
|
||
case "K_CAPS":
|
||
capsKey=key;
|
||
break;
|
||
case "K_NUMLOCK":
|
||
numKey=key;
|
||
break;
|
||
case "K_SCROLL":
|
||
scrollKey=key;
|
||
break;
|
||
}
|
||
|
||
// Remove pop-up shift keys referencing invalid layers (Build 349)
|
||
if(key['sk'] != null) {
|
||
for(k=0; k<key['sk'].length; k++) {
|
||
if(validIdList.indexOf(key['sk'][k]['nextlayer']) == -1) {
|
||
key['sk'].splice(k--, 1);
|
||
}
|
||
}
|
||
|
||
if(key['sk'].length == 0) {
|
||
key['sk']=null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// We're done with the layer keys initialization pass. Time to do post-analysis layer-level init where necessary.
|
||
layer.shiftKey=shiftKey;
|
||
layer.capsKey=capsKey;
|
||
layer.numKey=numKey;
|
||
layer.scrollKey=scrollKey;
|
||
|
||
// Set modifier key appearance and behaviour for non-desktop devices using the default layout
|
||
if(formFactor != 'desktop') {
|
||
if(n > 0 && shiftKey != null) {
|
||
shiftKey['sp']=Layouts.buttonClasses['SHIFT-ON'];
|
||
shiftKey['sk']=null;
|
||
shiftKey['text'] = Layouts.modifierSpecials[layers[n].id] ? Layouts.modifierSpecials[layers[n].id] : "*Shift*";
|
||
}
|
||
}
|
||
}
|
||
|
||
return layout;
|
||
}
|
||
|
||
/**
|
||
* Function getLayerId
|
||
* Scope Private
|
||
* @param {number} m shift modifier code
|
||
* @return {string} layer string from shift modifier code (desktop keyboards)
|
||
* Description Get name of layer from code, where the modifer order is determined by ascending bit-flag value.
|
||
*/
|
||
static getLayerId(m: number): string {
|
||
let modifierCodes = Codes.modifierCodes;
|
||
|
||
var s='';
|
||
if(m == 0) {
|
||
return 'default';
|
||
} else {
|
||
if(m & modifierCodes['LCTRL']) {
|
||
s = (s.length > 0 ? s + '-' : '') + 'leftctrl';
|
||
}
|
||
if(m & modifierCodes['RCTRL']) {
|
||
s = (s.length > 0 ? s + '-' : '') + 'rightctrl';
|
||
}
|
||
if(m & modifierCodes['LALT']) {
|
||
s = (s.length > 0 ? s + '-' : '') + 'leftalt';
|
||
}
|
||
if(m & modifierCodes['RALT']) {
|
||
s = (s.length > 0 ? s + '-' : '') + 'rightalt';
|
||
}
|
||
if(m & modifierCodes['SHIFT']) {
|
||
s = (s.length > 0 ? s + '-' : '') + 'shift';
|
||
}
|
||
if(m & modifierCodes['CTRL']) {
|
||
s = (s.length > 0 ? s + '-' : '') + 'ctrl';
|
||
}
|
||
if(m & modifierCodes['ALT']) {
|
||
s = (s.length > 0 ? s + '-' : '') + 'alt';
|
||
}
|
||
return s;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Signifies whether or not the OSK facilitates AltGr / Right-alt emulation for this keyboard.
|
||
* @param {Object=} keyLabels
|
||
* @return {boolean}
|
||
*/
|
||
static emulatesAltGr(keyLabels?: KLS): boolean { // TODO: typing for keyLabels (corresponds to KLS)
|
||
var layers;
|
||
let keyman = <KeymanBase> window['keyman'];
|
||
let modifierCodes = Codes.modifierCodes;
|
||
|
||
// If we're not chiral, we're not emulating.
|
||
if(!keyman.keyboardManager.isChiral()) {
|
||
return false;
|
||
}
|
||
|
||
if(!keyLabels) {
|
||
var activeKeyboard = keyman.keyboardManager.activeKeyboard;
|
||
if(activeKeyboard == null || activeKeyboard['KV'] == null) {
|
||
return false;
|
||
}
|
||
|
||
layers = activeKeyboard['KV']['KLS'];
|
||
} else {
|
||
layers = keyLabels;
|
||
}
|
||
|
||
var emulationMask = modifierCodes['LCTRL'] | modifierCodes['LALT'];
|
||
|
||
var unshiftedEmulationLayer = layers[Layouts.getLayerId(emulationMask)];
|
||
var shiftedEmulationLayer = layers[Layouts.getLayerId(modifierCodes['SHIFT'] | emulationMask)];
|
||
|
||
// buildDefaultLayout ensures that these are aliased to the original modifier set being emulated.
|
||
// As a result, we can directly test for reference equality.
|
||
if(unshiftedEmulationLayer != null &&
|
||
unshiftedEmulationLayer != layers[Layouts.getLayerId(modifierCodes['RALT'])]) {
|
||
return false;
|
||
}
|
||
|
||
if(shiftedEmulationLayer != null &&
|
||
shiftedEmulationLayer != layers[Layouts.getLayerId(modifierCodes['RALT'] | modifierCodes['SHIFT'])]) {
|
||
return false;
|
||
}
|
||
|
||
// It's technically possible for the OSK to not specify anything while allowing chiral input. A last-ditch catch:
|
||
|
||
var bitmask = keyman.keyboardManager.getKeyboardModifierBitmask();
|
||
if((bitmask & emulationMask) != emulationMask) {
|
||
// At least one of the emulation modifiers is never used by the keyboard! We can confirm everything's safe.
|
||
return true;
|
||
}
|
||
|
||
if(unshiftedEmulationLayer == null && shiftedEmulationLayer == null) {
|
||
// We've run out of things to go on; we can't detect if chiral AltGr emulation is intended or not.
|
||
// TODO: handle this again!
|
||
// if(!osk.altGrWarning) {
|
||
// console.warn("Could not detect if AltGr emulation is safe, but defaulting to active emulation!")
|
||
// // Avoid spamming the console with warnings on every call of the method.
|
||
// osk.altGrWarning = true;
|
||
// }
|
||
return true;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Generates a list of potential layer ids for the specified chirality mode.
|
||
*
|
||
* @param {boolean} chiral // Does the keyboard use chiral modifiers or not?
|
||
*/
|
||
static generateLayerIds(chiral: boolean): string[] {
|
||
var layerCnt, offset;
|
||
|
||
if(chiral) {
|
||
layerCnt=32;
|
||
offset=0x01;
|
||
} else {
|
||
layerCnt=8;
|
||
offset=0x10;
|
||
}
|
||
|
||
var layerIds = [];
|
||
|
||
for(var i=0; i < layerCnt; i++) {
|
||
layerIds.push(Layouts.getLayerId(i * offset));
|
||
}
|
||
|
||
return layerIds;
|
||
}
|
||
|
||
/**
|
||
* Sets a formatting property for the modifier keys when constructing a default layout for a keyboard.
|
||
*
|
||
* @param {Object} layer // One layer specification
|
||
* @param {boolean} chiral // Whether or not the keyboard uses chiral modifier information.
|
||
* @param {string} formFactor // The form factor of the device the layout is being constructed for.
|
||
* @param {boolean} key102 // Whether or not the extended key 102 should be hidden.
|
||
*/
|
||
static formatDefaultLayer(layer: LayoutLayer, chiral: boolean, formFactor: string, key102: boolean) {
|
||
var layerId = layer['id'];
|
||
let buttonClasses = Layouts.buttonClasses;
|
||
|
||
// Correct appearance of state-dependent modifier keys according to group
|
||
for(var i=0; i<layer['row'].length; i++) {
|
||
var row=layer['row'][i];
|
||
var keys=row['key'];
|
||
for(var j=0; j<keys.length; j++) {
|
||
var key=keys[j];
|
||
switch(key['id']) {
|
||
case 'K_SHIFT':
|
||
case 'K_LSHIFT':
|
||
case 'K_RSHIFT':
|
||
if(layerId.indexOf('shift') != -1) {
|
||
key['sp'] = buttonClasses['SHIFT-ON'];
|
||
}
|
||
if((formFactor != 'desktop') && (layerId != 'default')) {
|
||
key['nextlayer']='default';
|
||
}
|
||
break;
|
||
case 'K_LCTRL':
|
||
case 'K_LCONTROL':
|
||
if(chiral) {
|
||
if(layerId.indexOf('leftctrl') != -1) {
|
||
key['sp'] = buttonClasses['SHIFT-ON'];
|
||
}
|
||
break;
|
||
}
|
||
case 'K_RCTRL':
|
||
case 'K_RCONTROL':
|
||
if(chiral) {
|
||
if(layerId.indexOf('rightctrl') != -1) {
|
||
key['sp'] = buttonClasses['SHIFT-ON'];
|
||
}
|
||
break;
|
||
}
|
||
case 'K_CONTROL':
|
||
if(layerId.indexOf('ctrl') != -1) {
|
||
if(!chiral || (layerId.indexOf('leftctrl') != -1 && layerId.indexOf('rightctrl') != -1)) {
|
||
key['sp'] = buttonClasses['SHIFT-ON'];
|
||
}
|
||
}
|
||
break;
|
||
case 'K_LALT':
|
||
if(chiral) {
|
||
if(layerId.indexOf('leftalt') != -1) {
|
||
key['sp'] = buttonClasses['SHIFT-ON'];
|
||
}
|
||
break;
|
||
}
|
||
case 'K_RALT':
|
||
if(chiral) {
|
||
if(layerId.indexOf('rightalt') != -1) {
|
||
key['sp'] = buttonClasses['SHIFT-ON'];
|
||
}
|
||
break;
|
||
}
|
||
case 'K_ALT':
|
||
if(layerId.indexOf('alt') != -1) {
|
||
if(!chiral || (layerId.indexOf('leftalt') != -1 && layerId.indexOf('rightalt') != -1)) {
|
||
key['sp'] = buttonClasses['SHIFT-ON'];
|
||
}
|
||
}
|
||
break;
|
||
case 'K_oE2':
|
||
if(typeof key102 == 'undefined' || !key102) {
|
||
if(formFactor == 'desktop') {
|
||
keys.splice(j--, 1);
|
||
keys[0]['width']='200';
|
||
} else {
|
||
keys[j]['sp']=buttonClasses['HIDDEN'];
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Converts the legacy BK property from pre 10.0 into the KLS keyboard layer spec format,
|
||
* sparsifying it as possible to pre-emptively check invalid layers.
|
||
*
|
||
* @param {Array} BK keyboard object (as loaded)
|
||
* @return {Object}
|
||
*/
|
||
static processLegacyDefinitions(BK: string[]): KLS {
|
||
//['default','shift','ctrl','shiftctrl','alt','shiftalt','ctrlalt','shiftctrlalt'];
|
||
var idList=Layouts.generateLayerIds(false); // Non-chiral.
|
||
|
||
var KLS: KLS = {};
|
||
|
||
// The old default: eight auto-managed layers...
|
||
for(var n=0; n<idList.length; n++) {
|
||
var id = idList[n], arr = [], valid = false;
|
||
|
||
// ... with keycode mappings in blocks of 65.
|
||
for(var k=0; k < 65; k++) {
|
||
var index = k + 65 * n;
|
||
arr.push(BK[index]);
|
||
|
||
// The entry for K_SPACE's keycode tends to hold ' ' instead of '', which causes
|
||
// the whole layer to be treated as 'valid' if not included in the conditional.
|
||
if(index < BK.length && BK[index] != '' && k != Layouts.dfltCodes.indexOf('K_SPACE')) {
|
||
valid = true;
|
||
}
|
||
}
|
||
|
||
if(valid) {
|
||
KLS[id] = arr;
|
||
}
|
||
}
|
||
|
||
// There must always be at least a plain 'default' layer. Array(65).fill('') would be preferable but isn't supported on IE,
|
||
// but buildDefaultLayer will set the defaults for these layers if no entry exists for them in the array due to length.
|
||
if(typeof KLS['default'] == 'undefined' || ! KLS['default']) {
|
||
KLS['default'] = [''];
|
||
}
|
||
|
||
// There must always be at least a plain 'shift' layer.
|
||
if(typeof KLS['shift'] == 'undefined' || ! KLS['shift']) {
|
||
KLS['shift'] = [''];
|
||
}
|
||
|
||
return KLS;
|
||
}
|
||
|
||
// Defines the default visual layout for a keyboard.
|
||
static dfltLayout: LayoutSpec = {
|
||
"desktop":
|
||
{
|
||
"font": "Tahoma,Helvetica",
|
||
"layer": [
|
||
{
|
||
"id": "default",
|
||
"row": [
|
||
{
|
||
"id": "1",
|
||
"key": [
|
||
{ "id": "K_BKQUOTE" },
|
||
{ "id": "K_1" },
|
||
{ "id": "K_2" },
|
||
{ "id": "K_3" },
|
||
{ "id": "K_4" },
|
||
{ "id": "K_5" },
|
||
{ "id": "K_6" },
|
||
{ "id": "K_7" },
|
||
{ "id": "K_8" },
|
||
{ "id": "K_9" },
|
||
{ "id": "K_0" },
|
||
{ "id": "K_HYPHEN" },
|
||
{ "id": "K_EQUAL" },
|
||
{ "id": "K_BKSP", "text": "*BkSp*", "sp": "1", "width": "130" }
|
||
]
|
||
},
|
||
{
|
||
"id": "2",
|
||
"key": [
|
||
{ "id": "K_TAB", "text": "*Tab*", "sp": "1", "width": "130" },
|
||
{ "id": "K_Q" },
|
||
{ "id": "K_W" },
|
||
{ "id": "K_E" },
|
||
{ "id": "K_R" },
|
||
{ "id": "K_T" },
|
||
{ "id": "K_Y" },
|
||
{ "id": "K_U" },
|
||
{ "id": "K_I" },
|
||
{ "id": "K_O" },
|
||
{ "id": "K_P" },
|
||
{ "id": "K_LBRKT" },
|
||
{ "id": "K_RBRKT" },
|
||
{ "id": "K_BKSLASH" }
|
||
]
|
||
},
|
||
{
|
||
"id": "3",
|
||
"key": [
|
||
{ "id": "K_CAPS", "text": "*Caps*", "sp": "1", "width": "165" },
|
||
{ "id": "K_A" },
|
||
{ "id": "K_S" },
|
||
{ "id": "K_D" },
|
||
{ "id": "K_F" },
|
||
{ "id": "K_G" },
|
||
{ "id": "K_H" },
|
||
{ "id": "K_J" },
|
||
{ "id": "K_K" },
|
||
{ "id": "K_L" },
|
||
{ "id": "K_COLON" },
|
||
{ "id": "K_QUOTE" },
|
||
{ "id": "K_ENTER", "text": "*Enter*", "sp": "1", "width": "165" }
|
||
]
|
||
},
|
||
{
|
||
"id": "4",
|
||
"key": [
|
||
{ "id": "K_SHIFT", "text": "*Shift*", "sp": "1", "width": "130" },
|
||
{ "id": "K_oE2" },
|
||
{ "id": "K_Z" },
|
||
{ "id": "K_X" },
|
||
{ "id": "K_C" },
|
||
{ "id": "K_V" },
|
||
{ "id": "K_B" },
|
||
{ "id": "K_N" },
|
||
{ "id": "K_M" },
|
||
{ "id": "K_COMMA" },
|
||
{ "id": "K_PERIOD" },
|
||
{ "id": "K_SLASH" },
|
||
{ "id": "K_RSHIFT", "text": "*Shift*", "sp": "1", "width": "130" }
|
||
]
|
||
},
|
||
{
|
||
"id": "5",
|
||
"key": [
|
||
{ "id": "K_LCONTROL", "text": "*Ctrl*", "sp": "1", "width": "170" },
|
||
{ "id": "K_LALT", "text": "*Alt*", "sp": "1", "width": "160" },
|
||
{ "id": "K_SPACE", "text": "", "width": "770" },
|
||
{ "id": "K_RALT", "text": "*Alt*", "sp": "1", "width": "160" },
|
||
{ "id": "K_RCONTROL", "text": "*Ctrl*", "sp": "1", "width": "170" }
|
||
]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
"tablet":
|
||
{
|
||
"font": "Tahoma,Helvetica",
|
||
"layer": [
|
||
{
|
||
"id": "default",
|
||
"row": [
|
||
{
|
||
"id": "0",
|
||
"key": [
|
||
{ "id": "K_1" },
|
||
{ "id": "K_2" },
|
||
{ "id": "K_3" },
|
||
{ "id": "K_4" },
|
||
{ "id": "K_5" },
|
||
{ "id": "K_6" },
|
||
{ "id": "K_7" },
|
||
{ "id": "K_8" },
|
||
{ "id": "K_9" },
|
||
{ "id": "K_0" },
|
||
{ "id": "K_HYPHEN" },
|
||
{ "id": "K_EQUAL" },
|
||
{ "sp": "10", "width": "1" }
|
||
]
|
||
},
|
||
{
|
||
"id": "1",
|
||
"key": [
|
||
{ "id": "K_Q", "pad": "25" },
|
||
{ "id": "K_W" },
|
||
{ "id": "K_E" },
|
||
{ "id": "K_R" },
|
||
{ "id": "K_T" },
|
||
{ "id": "K_Y" },
|
||
{ "id": "K_U" },
|
||
{ "id": "K_I" },
|
||
{ "id": "K_O" },
|
||
{ "id": "K_P" },
|
||
{ "id": "K_LBRKT" },
|
||
{ "id": "K_RBRKT" },
|
||
{ "sp": "10", "width": "1" }
|
||
]
|
||
},
|
||
{
|
||
"id": "2",
|
||
"key": [
|
||
{ "id": "K_A", "pad": "50" },
|
||
{ "id": "K_S" },
|
||
{ "id": "K_D" },
|
||
{ "id": "K_F" },
|
||
{ "id": "K_G" },
|
||
{ "id": "K_H" },
|
||
{ "id": "K_J" },
|
||
{ "id": "K_K" },
|
||
{ "id": "K_L" },
|
||
{ "id": "K_COLON" },
|
||
{ "id": "K_QUOTE" },
|
||
{ "id": "K_BKSLASH", "width": "90" }
|
||
]
|
||
},
|
||
{
|
||
"id": "3",
|
||
"key": [
|
||
{ "id": "K_oE2", "width": "90" },
|
||
{ "id": "K_Z" },
|
||
{ "id": "K_X" },
|
||
{ "id": "K_C" },
|
||
{ "id": "K_V" },
|
||
{ "id": "K_B" },
|
||
{ "id": "K_N" },
|
||
{ "id": "K_M" },
|
||
{ "id": "K_COMMA" },
|
||
{ "id": "K_PERIOD" },
|
||
{ "id": "K_SLASH" },
|
||
{ "id": "K_BKQUOTE" },
|
||
{ "sp": "10", "width": "1" }
|
||
]
|
||
},
|
||
{
|
||
"id": "4",
|
||
"key": [
|
||
{
|
||
"id": "K_SHIFT", "text": "*Shift*", "sp": "1", "width": "200", "sk": [
|
||
{ "id": "K_LCONTROL", "text": "*Ctrl*", "sp": "1", "width": "50", "nextlayer": "ctrl" },
|
||
{ "id": "K_LCONTROL", "text": "*LCtrl*", "sp": "1", "width": "50", "nextlayer": "leftctrl" },
|
||
{ "id": "K_RCONTROL", "text": "*RCtrl*", "sp": "1", "width": "50", "nextlayer": "rightctrl" },
|
||
{ "id": "K_LALT", "text": "*Alt*", "sp": "1", "width": "50", "nextlayer": "alt" },
|
||
{ "id": "K_LALT", "text": "*LAlt*", "sp": "1", "width": "50", "nextlayer": "leftalt" },
|
||
{ "id": "K_RALT", "text": "*RAlt*", "sp": "1", "width": "50", "nextlayer": "rightalt" },
|
||
{ "id": "K_ALTGR", "text": "*AltGr*", "sp": "1", "width": "50", "nextlayer": "ctrl-alt" }]
|
||
},
|
||
{ "id": "K_LOPT", "text": "*Menu*", "sp": "1", "width": "150" },
|
||
{ "id": "K_SPACE", "text": "", "width": "570" },
|
||
{ "id": "K_BKSP", "text": "*BkSp*", "sp": "1", "width": "150" },
|
||
{ "id": "K_ENTER", "text": "*Enter*", "sp": "1", "width": "200" }
|
||
]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
"phone":
|
||
{
|
||
"font": "Tahoma,Helvetica",
|
||
"layer": [
|
||
{
|
||
"id": "default",
|
||
"row": [
|
||
{
|
||
"id": "0",
|
||
"key": [
|
||
{ "id": "K_1" },
|
||
{ "id": "K_2" },
|
||
{ "id": "K_3" },
|
||
{ "id": "K_4" },
|
||
{ "id": "K_5" },
|
||
{ "id": "K_6" },
|
||
{ "id": "K_7" },
|
||
{ "id": "K_8" },
|
||
{ "id": "K_9" },
|
||
{ "id": "K_0" },
|
||
{ "id": "K_HYPHEN" },
|
||
{ "id": "K_EQUAL" },
|
||
{ "sp": "10", "width": "1" }
|
||
]
|
||
},
|
||
{
|
||
"id": "1",
|
||
"key": [
|
||
{ "id": "K_Q", "pad": "25" },
|
||
{ "id": "K_W" },
|
||
{ "id": "K_E" },
|
||
{ "id": "K_R" },
|
||
{ "id": "K_T" },
|
||
{ "id": "K_Y" },
|
||
{ "id": "K_U" },
|
||
{ "id": "K_I" },
|
||
{ "id": "K_O" },
|
||
{ "id": "K_P" },
|
||
{ "id": "K_LBRKT" },
|
||
{ "id": "K_RBRKT" },
|
||
{ "sp": "10", "width": "1" }
|
||
]
|
||
},
|
||
{
|
||
"id": "2",
|
||
"key": [
|
||
{ "id": "K_A", "pad": "50" },
|
||
{ "id": "K_S" },
|
||
{ "id": "K_D" },
|
||
{ "id": "K_F" },
|
||
{ "id": "K_G" },
|
||
{ "id": "K_H" },
|
||
{ "id": "K_J" },
|
||
{ "id": "K_K" },
|
||
{ "id": "K_L" },
|
||
{ "id": "K_COLON" },
|
||
{ "id": "K_QUOTE" },
|
||
{ "id": "K_BKSLASH", "width": "90" }
|
||
]
|
||
},
|
||
{
|
||
"id": "3",
|
||
"key": [
|
||
{ "id": "K_oE2", "width": "90" },
|
||
{ "id": "K_Z" },
|
||
{ "id": "K_X" },
|
||
{ "id": "K_C" },
|
||
{ "id": "K_V" },
|
||
{ "id": "K_B" },
|
||
{ "id": "K_N" },
|
||
{ "id": "K_M" },
|
||
{ "id": "K_COMMA" },
|
||
{ "id": "K_PERIOD" },
|
||
{ "id": "K_SLASH" },
|
||
{ "id": "K_BKQUOTE" },
|
||
{ "sp": "10", "width": "1" }
|
||
]
|
||
},
|
||
{
|
||
"id": "4",
|
||
"key": [
|
||
{
|
||
"id": "K_SHIFT", "text": "*Shift*", "sp": "1", "width": "200", "sk": [
|
||
{ "id": "K_LCONTROL", "text": "*Ctrl*", "sp": "1", "width": "50", "nextlayer": "ctrl" },
|
||
{ "id": "K_LCONTROL", "text": "*LCtrl*", "sp": "1", "width": "50", "nextlayer": "leftctrl" },
|
||
{ "id": "K_RCONTROL", "text": "*RCtrl*", "sp": "1", "width": "50", "nextlayer": "rightctrl" },
|
||
{ "id": "K_LALT", "text": "*Alt*", "sp": "1", "width": "50", "nextlayer": "alt" },
|
||
{ "id": "K_LALT", "text": "*LAlt*", "sp": "1", "width": "50", "nextlayer": "leftalt" },
|
||
{ "id": "K_RALT", "text": "*RAlt*", "sp": "1", "width": "50", "nextlayer": "rightalt" },
|
||
{ "id": "K_ALTGR", "text": "*AltGr*", "sp": "1", "width": "50", "nextlayer": "ctrl-alt" }]
|
||
},
|
||
{ "id": "K_LOPT", "text": "*Menu*", "width": "150", "sp": "1" },
|
||
{ "id": "K_SPACE", "width": "570", "text": "" },
|
||
{ "id": "K_BKSP", "text": "*BkSp*", "width": "150", "sp": "1" },
|
||
{ "id": "K_ENTER", "text": "*Enter*", "width": "200", "sp": "1" }
|
||
]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
};
|
||
}
|
||
} |