Address physicalKeyboardHighlight issue on older browsers. Fixes #1035

This commit is contained in:
Francisco Hodge 2021-05-16 22:40:31 -07:00
parent c2d9cc0f3f
commit b993885bd5
10 changed files with 851 additions and 753 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,14 @@
import "./css/CandidateBox.css";
import Utilities from "../services/Utilities";
import { CandidateBoxParams, CandidateBoxRenderParams, CandidateBoxShowParams } from "./../interfaces";
declare class CandidateBox {
utilities: Utilities;
candidateBoxElement: HTMLDivElement;
pageIndex: number;
pageSize: number;
constructor({ utilities }: CandidateBoxParams);
destroy(): void;
show({ candidateValue, targetElement, onSelect, }: CandidateBoxShowParams): void;
renderPage({ candidateListPages, targetElement, pageIndex, nbPages, onItemSelected, }: CandidateBoxRenderParams): void;
}
export default CandidateBox;
import "./css/CandidateBox.css";
import Utilities from "../services/Utilities";
import { CandidateBoxParams, CandidateBoxRenderParams, CandidateBoxShowParams } from "./../interfaces";
declare class CandidateBox {
utilities: Utilities;
candidateBoxElement: HTMLDivElement;
pageIndex: number;
pageSize: number;
constructor({ utilities }: CandidateBoxParams);
destroy(): void;
show({ candidateValue, targetElement, onSelect, }: CandidateBoxShowParams): void;
renderPage({ candidateListPages, targetElement, pageIndex, nbPages, onItemSelected, }: CandidateBoxRenderParams): void;
}
export default CandidateBox;

View File

@ -1,278 +1,278 @@
import "./css/Keyboard.css";
import PhysicalKeyboard from "../services/PhysicalKeyboard";
import { KeyboardOptions, KeyboardInput, KeyboardButtonElements, KeyboardHandlerEvent, KeyboardElement, KeyboardParams } from "../interfaces";
import CandidateBox from "./CandidateBox";
/**
* Root class for simple-keyboard.
* This class:
* - Parses the options
* - Renders the rows and buttons
* - Handles button functionality
*/
declare class SimpleKeyboard {
input: KeyboardInput;
options: KeyboardOptions;
utilities: any;
caretPosition: number | null;
caretPositionEnd: number | null;
keyboardDOM: KeyboardElement;
keyboardPluginClasses: string;
keyboardDOMClass: string;
buttonElements: KeyboardButtonElements;
currentInstanceName: string;
allKeyboardInstances: {
[key: string]: SimpleKeyboard;
};
keyboardInstanceNames: string[];
isFirstKeyboardInstance: boolean;
physicalKeyboard: PhysicalKeyboard;
modules: {
[key: string]: any;
};
activeButtonClass: string;
holdInteractionTimeout: number;
holdTimeout: number;
isMouseHold: boolean;
initialized: boolean;
candidateBox: CandidateBox | null;
keyboardRowsDOM: KeyboardElement;
defaultName: string;
/**
* Creates an instance of SimpleKeyboard
* @param {Array} params If first parameter is a string, it is considered the container class. The second parameter is then considered the options object. If first parameter is an object, it is considered the options object.
*/
constructor(...params: KeyboardParams);
/**
* parseParams
*/
handleParams: (params: KeyboardParams) => {
keyboardDOMClass: string;
keyboardDOM: KeyboardElement;
options: Partial<KeyboardOptions | undefined>;
};
/**
* Getters
*/
getOptions: () => KeyboardOptions;
getCaretPosition: () => number | null;
getCaretPositionEnd: () => number | null;
/**
* Changes the internal caret position
* @param {number} position The caret's start position
* @param {number} positionEnd The caret's end position
*/
setCaretPosition(position: number | null, endPosition?: number | null): void;
/**
* Retrieve the candidates for a given input
* @param input The input string to check
*/
getInputCandidates(input: string): {
candidateKey: string;
candidateValue: string;
} | Record<string, never>;
/**
* Shows a suggestion box with a list of candidate words
* @param candidates The chosen candidates string as defined in the layoutCandidates option
* @param targetElement The element next to which the candidates box will be shown
*/
showCandidatesBox(candidateKey: string, candidateValue: string, targetElement: KeyboardElement): void;
/**
* Handles clicks made to keyboard buttons
* @param {string} button The button's layout name.
*/
handleButtonClicked(button: string, e?: KeyboardHandlerEvent): void;
/**
* Handles button mousedown
*/
handleButtonMouseDown(button: string, e: KeyboardHandlerEvent): void;
/**
* Handles button mouseup
*/
handleButtonMouseUp(button?: string, e?: KeyboardHandlerEvent): void;
/**
* Handles container mousedown
*/
handleKeyboardContainerMouseDown(e: KeyboardHandlerEvent): void;
/**
* Handles button hold
*/
handleButtonHold(button: string): void;
/**
* Send a command to all simple-keyboard instances (if you have several instances).
*/
syncInstanceInputs(): void;
/**
* Clear the keyboards input.
* @param {string} [inputName] optional - the internal input to select
*/
clearInput(inputName?: string): void;
/**
* Get the keyboards input (You can also get it from the onChange prop).
* @param {string} [inputName] optional - the internal input to select
*/
getInput(inputName?: string, skipSync?: boolean): string;
/**
* Get all simple-keyboard inputs
*/
getAllInputs(): KeyboardInput;
/**
* Set the keyboards input.
* @param {string} input the input value
* @param {string} inputName optional - the internal input to select
*/
setInput(input: string, inputName?: string, skipSync?: boolean): void;
/**
* Replace the input object (`keyboard.input`)
* @param {object} inputObj The input object
*/
replaceInput(inputObj: KeyboardInput): void;
/**
* Set new option or modify existing ones after initialization.
* @param {object} options The options to set
*/
setOptions(options?: {}): void;
/**
* Detecting changes to non-function options
* This allows us to ascertain whether a button re-render is needed
*/
changedOptions(newOptions: Partial<KeyboardOptions>): string[];
/**
* Executing actions depending on changed options
* @param {object} options The options to set
*/
onSetOptions(changedOptions?: string[]): void;
/**
* Remove all keyboard rows and reset keyboard values.
* Used internally between re-renders.
*/
resetRows(): void;
/**
* Send a command to all simple-keyboard instances at once (if you have multiple instances).
* @param {function(instance: object, key: string)} callback Function to run on every instance
*/
dispatch(callback: (instance: SimpleKeyboard, key?: string) => void): void;
/**
* Adds/Modifies an entry to the `buttonTheme`. Basically a way to add a class to a button.
* @param {string} buttons List of buttons to select (separated by a space).
* @param {string} className Classes to give to the selected buttons (separated by space).
*/
addButtonTheme(buttons: string, className: string): void;
/**
* Removes/Amends an entry to the `buttonTheme`. Basically a way to remove a class previously added to a button through buttonTheme or addButtonTheme.
* @param {string} buttons List of buttons to select (separated by a space).
* @param {string} className Classes to give to the selected buttons (separated by space).
*/
removeButtonTheme(buttons: string, className: string): void;
/**
* Get the DOM Element of a button. If there are several buttons with the same name, an array of the DOM Elements is returned.
* @param {string} button The button layout name to select
*/
getButtonElement(button: string): KeyboardElement | KeyboardElement[] | undefined;
/**
* This handles the "inputPattern" option
* by checking if the provided inputPattern passes
*/
inputPatternIsValid(inputVal: string): boolean;
/**
* Handles simple-keyboard event listeners
*/
setEventListeners(): void;
/**
* Event Handler: KeyUp
*/
handleKeyUp(event: KeyboardHandlerEvent): void;
/**
* Event Handler: KeyDown
*/
handleKeyDown(event: KeyboardHandlerEvent): void;
/**
* Event Handler: MouseUp
*/
handleMouseUp(event: KeyboardHandlerEvent): void;
/**
* Event Handler: TouchEnd
*/
handleTouchEnd(event: KeyboardHandlerEvent): void;
/**
* Event Handler: Select
*/
handleSelect(event: KeyboardHandlerEvent): void;
/**
* Called by {@link setEventListeners} when an event that warrants a cursor position update is triggered
*/
caretEventHandler(event: KeyboardHandlerEvent): void;
/**
* Execute an operation on each button
*/
recurseButtons(fn: any): void;
/**
* Destroy keyboard listeners and DOM elements
*/
destroy(): void;
/**
* Process buttonTheme option
*/
getButtonThemeClasses(button: string): string[];
/**
* Process buttonAttributes option
*/
setDOMButtonAttributes(button: string, callback: any): void;
onTouchDeviceDetected(): void;
/**
* Disabling contextual window for hg-button
*/
disableContextualWindow(): void;
/**
* Process autoTouchEvents option
*/
processAutoTouchEvents(): void;
/**
* Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
*/
onInit(): void;
/**
* Executes the callback function before a simple-keyboard render.
*/
beforeFirstRender(): void;
/**
* Executes the callback function before a simple-keyboard render.
*/
beforeRender(): void;
/**
* Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
*/
onRender(): void;
/**
* Executes the callback function once all modules have been loaded
*/
onModulesLoaded(): void;
/**
* Register module
*/
registerModule: (name: string, initCallback: any) => void;
/**
* Load modules
*/
loadModules(): void;
/**
* Get module prop
*/
getModuleProp(name: string, prop: string): any;
/**
* getModulesList
*/
getModulesList(): string[];
/**
* Parse Row DOM containers
*/
parseRowDOMContainers(rowDOM: HTMLDivElement, rowIndex: number, containerStartIndexes: number[], containerEndIndexes: number[]): HTMLDivElement;
/**
* getKeyboardClassString
*/
getKeyboardClassString: (...baseDOMClasses: any[]) => string;
/**
* Renders rows and buttons as per options
*/
render(): void;
}
export default SimpleKeyboard;
import "./css/Keyboard.css";
import PhysicalKeyboard from "../services/PhysicalKeyboard";
import { KeyboardOptions, KeyboardInput, KeyboardButtonElements, KeyboardHandlerEvent, KeyboardElement, KeyboardParams } from "../interfaces";
import CandidateBox from "./CandidateBox";
/**
* Root class for simple-keyboard.
* This class:
* - Parses the options
* - Renders the rows and buttons
* - Handles button functionality
*/
declare class SimpleKeyboard {
input: KeyboardInput;
options: KeyboardOptions;
utilities: any;
caretPosition: number | null;
caretPositionEnd: number | null;
keyboardDOM: KeyboardElement;
keyboardPluginClasses: string;
keyboardDOMClass: string;
buttonElements: KeyboardButtonElements;
currentInstanceName: string;
allKeyboardInstances: {
[key: string]: SimpleKeyboard;
};
keyboardInstanceNames: string[];
isFirstKeyboardInstance: boolean;
physicalKeyboard: PhysicalKeyboard;
modules: {
[key: string]: any;
};
activeButtonClass: string;
holdInteractionTimeout: number;
holdTimeout: number;
isMouseHold: boolean;
initialized: boolean;
candidateBox: CandidateBox | null;
keyboardRowsDOM: KeyboardElement;
defaultName: string;
/**
* Creates an instance of SimpleKeyboard
* @param {Array} params If first parameter is a string, it is considered the container class. The second parameter is then considered the options object. If first parameter is an object, it is considered the options object.
*/
constructor(...params: KeyboardParams);
/**
* parseParams
*/
handleParams: (params: KeyboardParams) => {
keyboardDOMClass: string;
keyboardDOM: KeyboardElement;
options: Partial<KeyboardOptions | undefined>;
};
/**
* Getters
*/
getOptions: () => KeyboardOptions;
getCaretPosition: () => number | null;
getCaretPositionEnd: () => number | null;
/**
* Changes the internal caret position
* @param {number} position The caret's start position
* @param {number} positionEnd The caret's end position
*/
setCaretPosition(position: number | null, endPosition?: number | null): void;
/**
* Retrieve the candidates for a given input
* @param input The input string to check
*/
getInputCandidates(input: string): {
candidateKey: string;
candidateValue: string;
} | Record<string, never>;
/**
* Shows a suggestion box with a list of candidate words
* @param candidates The chosen candidates string as defined in the layoutCandidates option
* @param targetElement The element next to which the candidates box will be shown
*/
showCandidatesBox(candidateKey: string, candidateValue: string, targetElement: KeyboardElement): void;
/**
* Handles clicks made to keyboard buttons
* @param {string} button The button's layout name.
*/
handleButtonClicked(button: string, e?: KeyboardHandlerEvent): void;
/**
* Handles button mousedown
*/
handleButtonMouseDown(button: string, e: KeyboardHandlerEvent): void;
/**
* Handles button mouseup
*/
handleButtonMouseUp(button?: string, e?: KeyboardHandlerEvent): void;
/**
* Handles container mousedown
*/
handleKeyboardContainerMouseDown(e: KeyboardHandlerEvent): void;
/**
* Handles button hold
*/
handleButtonHold(button: string): void;
/**
* Send a command to all simple-keyboard instances (if you have several instances).
*/
syncInstanceInputs(): void;
/**
* Clear the keyboards input.
* @param {string} [inputName] optional - the internal input to select
*/
clearInput(inputName?: string): void;
/**
* Get the keyboards input (You can also get it from the onChange prop).
* @param {string} [inputName] optional - the internal input to select
*/
getInput(inputName?: string, skipSync?: boolean): string;
/**
* Get all simple-keyboard inputs
*/
getAllInputs(): KeyboardInput;
/**
* Set the keyboards input.
* @param {string} input the input value
* @param {string} inputName optional - the internal input to select
*/
setInput(input: string, inputName?: string, skipSync?: boolean): void;
/**
* Replace the input object (`keyboard.input`)
* @param {object} inputObj The input object
*/
replaceInput(inputObj: KeyboardInput): void;
/**
* Set new option or modify existing ones after initialization.
* @param {object} options The options to set
*/
setOptions(options?: {}): void;
/**
* Detecting changes to non-function options
* This allows us to ascertain whether a button re-render is needed
*/
changedOptions(newOptions: Partial<KeyboardOptions>): string[];
/**
* Executing actions depending on changed options
* @param {object} options The options to set
*/
onSetOptions(changedOptions?: string[]): void;
/**
* Remove all keyboard rows and reset keyboard values.
* Used internally between re-renders.
*/
resetRows(): void;
/**
* Send a command to all simple-keyboard instances at once (if you have multiple instances).
* @param {function(instance: object, key: string)} callback Function to run on every instance
*/
dispatch(callback: (instance: SimpleKeyboard, key?: string) => void): void;
/**
* Adds/Modifies an entry to the `buttonTheme`. Basically a way to add a class to a button.
* @param {string} buttons List of buttons to select (separated by a space).
* @param {string} className Classes to give to the selected buttons (separated by space).
*/
addButtonTheme(buttons: string, className: string): void;
/**
* Removes/Amends an entry to the `buttonTheme`. Basically a way to remove a class previously added to a button through buttonTheme or addButtonTheme.
* @param {string} buttons List of buttons to select (separated by a space).
* @param {string} className Classes to give to the selected buttons (separated by space).
*/
removeButtonTheme(buttons: string, className: string): void;
/**
* Get the DOM Element of a button. If there are several buttons with the same name, an array of the DOM Elements is returned.
* @param {string} button The button layout name to select
*/
getButtonElement(button: string): KeyboardElement | KeyboardElement[] | undefined;
/**
* This handles the "inputPattern" option
* by checking if the provided inputPattern passes
*/
inputPatternIsValid(inputVal: string): boolean;
/**
* Handles simple-keyboard event listeners
*/
setEventListeners(): void;
/**
* Event Handler: KeyUp
*/
handleKeyUp(event: KeyboardHandlerEvent): void;
/**
* Event Handler: KeyDown
*/
handleKeyDown(event: KeyboardHandlerEvent): void;
/**
* Event Handler: MouseUp
*/
handleMouseUp(event: KeyboardHandlerEvent): void;
/**
* Event Handler: TouchEnd
*/
handleTouchEnd(event: KeyboardHandlerEvent): void;
/**
* Event Handler: Select
*/
handleSelect(event: KeyboardHandlerEvent): void;
/**
* Called by {@link setEventListeners} when an event that warrants a cursor position update is triggered
*/
caretEventHandler(event: KeyboardHandlerEvent): void;
/**
* Execute an operation on each button
*/
recurseButtons(fn: any): void;
/**
* Destroy keyboard listeners and DOM elements
*/
destroy(): void;
/**
* Process buttonTheme option
*/
getButtonThemeClasses(button: string): string[];
/**
* Process buttonAttributes option
*/
setDOMButtonAttributes(button: string, callback: any): void;
onTouchDeviceDetected(): void;
/**
* Disabling contextual window for hg-button
*/
disableContextualWindow(): void;
/**
* Process autoTouchEvents option
*/
processAutoTouchEvents(): void;
/**
* Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
*/
onInit(): void;
/**
* Executes the callback function before a simple-keyboard render.
*/
beforeFirstRender(): void;
/**
* Executes the callback function before a simple-keyboard render.
*/
beforeRender(): void;
/**
* Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
*/
onRender(): void;
/**
* Executes the callback function once all modules have been loaded
*/
onModulesLoaded(): void;
/**
* Register module
*/
registerModule: (name: string, initCallback: any) => void;
/**
* Load modules
*/
loadModules(): void;
/**
* Get module prop
*/
getModuleProp(name: string, prop: string): any;
/**
* getModulesList
*/
getModulesList(): string[];
/**
* Parse Row DOM containers
*/
parseRowDOMContainers(rowDOM: HTMLDivElement, rowIndex: number, containerStartIndexes: number[], containerEndIndexes: number[]): HTMLDivElement;
/**
* getKeyboardClassString
*/
getKeyboardClassString: (...baseDOMClasses: any[]) => string;
/**
* Renders rows and buttons as per options
*/
render(): void;
}
export default SimpleKeyboard;

View File

@ -1,3 +1,3 @@
import "./polyfills";
import SimpleKeyboard from "./components/Keyboard";
export default SimpleKeyboard;
import "./polyfills";
import SimpleKeyboard from "./components/Keyboard";
export default SimpleKeyboard;

View File

@ -1,202 +1,202 @@
import SimpleKeyboard from "./components/Keyboard";
import Utilities from "./services/Utilities";
export interface KeyboardLayoutObject {
[key: string]: string[];
}
export declare type KeyboardButtonTheme = {
class: string;
buttons: string;
} | null;
export interface KeyboardButtonAttributes {
attribute: string;
value: string;
buttons: string;
}
export interface KeyboardInput {
[key: string]: string;
}
export declare type KeyboardParams = [KeyboardOptions] | [string | HTMLDivElement, KeyboardOptions];
export declare type CandidateBoxParams = {
utilities: Utilities;
};
export declare type CandidateBoxShowParams = {
candidateValue: string;
targetElement: KeyboardElement;
onSelect: (selectedCandidate: string) => void;
};
export declare type CandidateBoxRenderParams = {
candidateListPages: string[][];
targetElement: KeyboardElement;
pageIndex: number;
nbPages: number;
onItemSelected: (selectedCandidate: string) => void;
};
export declare type KeyboardElement = HTMLDivElement | HTMLButtonElement;
export declare type KeyboardHandlerEvent = any;
export interface KeyboardButtonElements {
[key: string]: KeyboardElement[];
}
export interface UtilitiesParams {
getOptions: () => KeyboardOptions;
getCaretPosition: () => number | null;
getCaretPositionEnd: () => number | null;
dispatch: any;
}
export interface PhysicalKeyboardParams {
getOptions: () => KeyboardOptions;
dispatch: any;
}
export interface KeyboardOptions {
/**
* Modify the keyboard layout.
*/
layout?: KeyboardLayoutObject;
/**
* Specifies which layout should be used.
*/
layoutName?: string;
/**
* Replaces variable buttons (such as `{bksp}`) with a human-friendly name (e.g.: `backspace`).
*/
display?: {
[button: string]: string;
};
/**
* By default, when you set the display property, you replace the default one. This setting merges them instead.
*/
mergeDisplay?: boolean;
/**
* A prop to add your own css classes to the keyboard wrapper. You can add multiple classes separated by a space.
*/
theme?: string;
/**
* A prop to add your own css classes to one or several buttons.
*/
buttonTheme?: KeyboardButtonTheme[];
/**
* A prop to add your own attributes to one or several buttons.
*/
buttonAttributes?: KeyboardButtonAttributes[];
/**
* Runs a `console.log` every time a key is pressed. Displays the buttons pressed and the current input.
*/
debug?: boolean;
/**
* Specifies whether clicking the "ENTER" button will input a newline (`\n`) or not.
*/
newLineOnEnter?: boolean;
/**
* Specifies whether clicking the "TAB" button will input a tab character (`\t`) or not.
*/
tabCharOnTab?: boolean;
/**
* Allows you to use a single simple-keyboard instance for several inputs.
*/
inputName?: string;
/**
* `number`: Restrains all of simple-keyboard inputs to a certain length. This should be used in addition to the input elements maxlengthattribute.
*
* `{ [inputName: string]: number }`: Restrains simple-keyboards individual inputs to a certain length. This should be used in addition to the input elements maxlengthattribute.
*/
maxLength?: any;
/**
* When set to true, this option synchronizes the internal input of every simple-keyboard instance.
*/
syncInstanceInputs?: boolean;
/**
* Enable highlighting of keys pressed on physical keyboard.
*/
physicalKeyboardHighlight?: boolean;
/**
* Presses keys highlighted by physicalKeyboardHighlight
*/
physicalKeyboardHighlightPress?: boolean;
/**
* Define the text color that the physical keyboard highlighted key should have.
*/
physicalKeyboardHighlightTextColor?: string;
/**
* Define the background color that the physical keyboard highlighted key should have.
*/
physicalKeyboardHighlightBgColor?: string;
/**
* Calling preventDefault for the mousedown events keeps the focus on the input.
*/
preventMouseDownDefault?: boolean;
/**
* Calling preventDefault for the mouseup events.
*/
preventMouseUpDefault?: boolean;
/**
* Stops pointer down events on simple-keyboard buttons from bubbling to parent elements.
*/
stopMouseDownPropagation?: boolean;
/**
* Stops pointer up events on simple-keyboard buttons from bubbling to parent elements.
*/
stopMouseUpPropagation?: boolean;
/**
* Render buttons as a button element instead of a div element.
*/
useButtonTag?: boolean;
/**
* A prop to ensure characters are always be added/removed at the end of the string.
*/
disableCaretPositioning?: boolean;
/**
* Restrains input(s) change to the defined regular expression pattern.
*/
inputPattern?: any;
/**
* Instructs simple-keyboard to use touch events instead of click events.
*/
useTouchEvents?: boolean;
/**
* Enable useTouchEvents automatically when touch device is detected.
*/
autoUseTouchEvents?: boolean;
/**
* Opt out of PointerEvents handling, falling back to the prior mouse event logic.
*/
useMouseEvents?: boolean;
/**
* Disable button hold action.
*/
disableButtonHold?: boolean;
/**
* Adds unicode right-to-left control characters to input return values.
*/
rtl?: boolean;
/**
* Enable input method editor candidate list support.
*/
enableLayoutCandidates?: boolean;
/**
* Character suggestions to be shown on certain key presses
*/
layoutCandidates?: {
[key: string]: string;
};
/**
* Exclude buttons from layout
*/
excludeFromLayout?: {
[key: string]: string[];
};
/**
* Determine size of layout candidate list
*/
layoutCandidatesPageSize?: number;
/**
* Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
*/
onRender?: (instance?: SimpleKeyboard) => void;
/**
* Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
*/
onInit?: (instance?: SimpleKeyboard) => void;
/**
* Module options can have any format
*/
[name: string]: any;
}
import SimpleKeyboard from "./components/Keyboard";
import Utilities from "./services/Utilities";
export interface KeyboardLayoutObject {
[key: string]: string[];
}
export declare type KeyboardButtonTheme = {
class: string;
buttons: string;
} | null;
export interface KeyboardButtonAttributes {
attribute: string;
value: string;
buttons: string;
}
export interface KeyboardInput {
[key: string]: string;
}
export declare type KeyboardParams = [KeyboardOptions] | [string | HTMLDivElement, KeyboardOptions];
export declare type CandidateBoxParams = {
utilities: Utilities;
};
export declare type CandidateBoxShowParams = {
candidateValue: string;
targetElement: KeyboardElement;
onSelect: (selectedCandidate: string) => void;
};
export declare type CandidateBoxRenderParams = {
candidateListPages: string[][];
targetElement: KeyboardElement;
pageIndex: number;
nbPages: number;
onItemSelected: (selectedCandidate: string) => void;
};
export declare type KeyboardElement = HTMLDivElement | HTMLButtonElement;
export declare type KeyboardHandlerEvent = any;
export interface KeyboardButtonElements {
[key: string]: KeyboardElement[];
}
export interface UtilitiesParams {
getOptions: () => KeyboardOptions;
getCaretPosition: () => number | null;
getCaretPositionEnd: () => number | null;
dispatch: any;
}
export interface PhysicalKeyboardParams {
getOptions: () => KeyboardOptions;
dispatch: any;
}
export interface KeyboardOptions {
/**
* Modify the keyboard layout.
*/
layout?: KeyboardLayoutObject;
/**
* Specifies which layout should be used.
*/
layoutName?: string;
/**
* Replaces variable buttons (such as `{bksp}`) with a human-friendly name (e.g.: `backspace`).
*/
display?: {
[button: string]: string;
};
/**
* By default, when you set the display property, you replace the default one. This setting merges them instead.
*/
mergeDisplay?: boolean;
/**
* A prop to add your own css classes to the keyboard wrapper. You can add multiple classes separated by a space.
*/
theme?: string;
/**
* A prop to add your own css classes to one or several buttons.
*/
buttonTheme?: KeyboardButtonTheme[];
/**
* A prop to add your own attributes to one or several buttons.
*/
buttonAttributes?: KeyboardButtonAttributes[];
/**
* Runs a `console.log` every time a key is pressed. Displays the buttons pressed and the current input.
*/
debug?: boolean;
/**
* Specifies whether clicking the "ENTER" button will input a newline (`\n`) or not.
*/
newLineOnEnter?: boolean;
/**
* Specifies whether clicking the "TAB" button will input a tab character (`\t`) or not.
*/
tabCharOnTab?: boolean;
/**
* Allows you to use a single simple-keyboard instance for several inputs.
*/
inputName?: string;
/**
* `number`: Restrains all of simple-keyboard inputs to a certain length. This should be used in addition to the input elements maxlengthattribute.
*
* `{ [inputName: string]: number }`: Restrains simple-keyboards individual inputs to a certain length. This should be used in addition to the input elements maxlengthattribute.
*/
maxLength?: any;
/**
* When set to true, this option synchronizes the internal input of every simple-keyboard instance.
*/
syncInstanceInputs?: boolean;
/**
* Enable highlighting of keys pressed on physical keyboard.
*/
physicalKeyboardHighlight?: boolean;
/**
* Presses keys highlighted by physicalKeyboardHighlight
*/
physicalKeyboardHighlightPress?: boolean;
/**
* Define the text color that the physical keyboard highlighted key should have.
*/
physicalKeyboardHighlightTextColor?: string;
/**
* Define the background color that the physical keyboard highlighted key should have.
*/
physicalKeyboardHighlightBgColor?: string;
/**
* Calling preventDefault for the mousedown events keeps the focus on the input.
*/
preventMouseDownDefault?: boolean;
/**
* Calling preventDefault for the mouseup events.
*/
preventMouseUpDefault?: boolean;
/**
* Stops pointer down events on simple-keyboard buttons from bubbling to parent elements.
*/
stopMouseDownPropagation?: boolean;
/**
* Stops pointer up events on simple-keyboard buttons from bubbling to parent elements.
*/
stopMouseUpPropagation?: boolean;
/**
* Render buttons as a button element instead of a div element.
*/
useButtonTag?: boolean;
/**
* A prop to ensure characters are always be added/removed at the end of the string.
*/
disableCaretPositioning?: boolean;
/**
* Restrains input(s) change to the defined regular expression pattern.
*/
inputPattern?: any;
/**
* Instructs simple-keyboard to use touch events instead of click events.
*/
useTouchEvents?: boolean;
/**
* Enable useTouchEvents automatically when touch device is detected.
*/
autoUseTouchEvents?: boolean;
/**
* Opt out of PointerEvents handling, falling back to the prior mouse event logic.
*/
useMouseEvents?: boolean;
/**
* Disable button hold action.
*/
disableButtonHold?: boolean;
/**
* Adds unicode right-to-left control characters to input return values.
*/
rtl?: boolean;
/**
* Enable input method editor candidate list support.
*/
enableLayoutCandidates?: boolean;
/**
* Character suggestions to be shown on certain key presses
*/
layoutCandidates?: {
[key: string]: string;
};
/**
* Exclude buttons from layout
*/
excludeFromLayout?: {
[key: string]: string[];
};
/**
* Determine size of layout candidate list
*/
layoutCandidatesPageSize?: number;
/**
* Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
*/
onRender?: (instance?: SimpleKeyboard) => void;
/**
* Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
*/
onInit?: (instance?: SimpleKeyboard) => void;
/**
* Module options can have any format
*/
[name: string]: any;
}

View File

@ -1,4 +1,4 @@
export declare const getDefaultLayout: () => {
default: string[];
shift: string[];
};
export declare const getDefaultLayout: () => {
default: string[];
shift: string[];
};

View File

@ -1,20 +1,24 @@
import { KeyboardOptions, PhysicalKeyboardParams } from "../interfaces";
/**
* Physical Keyboard Service
*/
declare class PhysicalKeyboard {
getOptions: () => KeyboardOptions;
dispatch: any;
/**
* Creates an instance of the PhysicalKeyboard service
*/
constructor({ dispatch, getOptions }: PhysicalKeyboardParams);
handleHighlightKeyDown(event: KeyboardEvent): void;
handleHighlightKeyUp(event: KeyboardEvent): void;
/**
* Transforms a KeyboardEvent's "key.code" string into a simple-keyboard layout format
* @param {object} event The KeyboardEvent
*/
getSimpleKeyboardLayoutKey(event: KeyboardEvent): string;
}
export default PhysicalKeyboard;
import { KeyboardOptions, PhysicalKeyboardParams } from "../interfaces";
/**
* Physical Keyboard Service
*/
declare class PhysicalKeyboard {
getOptions: () => KeyboardOptions;
dispatch: any;
/**
* Creates an instance of the PhysicalKeyboard service
*/
constructor({ dispatch, getOptions }: PhysicalKeyboardParams);
handleHighlightKeyDown(event: KeyboardEvent): void;
handleHighlightKeyUp(event: KeyboardEvent): void;
/**
* Transforms a KeyboardEvent's "key.code" string into a simple-keyboard layout format
* @param {object} event The KeyboardEvent
*/
getSimpleKeyboardLayoutKey(event: KeyboardEvent): string | undefined;
/**
* Retrieve key from keyCode
*/
keyCodeToKey(keyCode: number): string | undefined;
}
export default PhysicalKeyboard;

View File

@ -1,189 +1,189 @@
import { KeyboardInput } from "./../interfaces";
import { KeyboardOptions, UtilitiesParams } from "../interfaces";
/**
* Utility Service
*/
declare class Utilities {
getOptions: () => KeyboardOptions;
getCaretPosition: () => number | null;
getCaretPositionEnd: () => number | null;
dispatch: any;
maxLengthReached: boolean;
/**
* Creates an instance of the Utility service
*/
constructor({ getOptions, getCaretPosition, getCaretPositionEnd, dispatch, }: UtilitiesParams);
/**
* Retrieve button type
*
* @param {string} button The button's layout name
* @return {string} The button type
*/
getButtonType(button: string): string;
/**
* Adds default classes to a given button
*
* @param {string} button The button's layout name
* @return {string} The classes to be added to the button
*/
getButtonClass(button: string): string;
/**
* Default button display labels
*/
getDefaultDiplay(): {
"{bksp}": string;
"{backspace}": string;
"{enter}": string;
"{shift}": string;
"{shiftleft}": string;
"{shiftright}": string;
"{alt}": string;
"{s}": string;
"{tab}": string;
"{lock}": string;
"{capslock}": string;
"{accept}": string;
"{space}": string;
"{//}": string;
"{esc}": string;
"{escape}": string;
"{f1}": string;
"{f2}": string;
"{f3}": string;
"{f4}": string;
"{f5}": string;
"{f6}": string;
"{f7}": string;
"{f8}": string;
"{f9}": string;
"{f10}": string;
"{f11}": string;
"{f12}": string;
"{numpaddivide}": string;
"{numlock}": string;
"{arrowup}": string;
"{arrowleft}": string;
"{arrowdown}": string;
"{arrowright}": string;
"{prtscr}": string;
"{scrolllock}": string;
"{pause}": string;
"{insert}": string;
"{home}": string;
"{pageup}": string;
"{delete}": string;
"{forwarddelete}": string;
"{end}": string;
"{pagedown}": string;
"{numpadmultiply}": string;
"{numpadsubtract}": string;
"{numpadadd}": string;
"{numpadenter}": string;
"{period}": string;
"{numpaddecimal}": string;
"{numpad0}": string;
"{numpad1}": string;
"{numpad2}": string;
"{numpad3}": string;
"{numpad4}": string;
"{numpad5}": string;
"{numpad6}": string;
"{numpad7}": string;
"{numpad8}": string;
"{numpad9}": string;
};
/**
* Returns the display (label) name for a given button
*
* @param {string} button The button's layout name
* @param {object} display The provided display option
* @param {boolean} mergeDisplay Whether the provided param value should be merged with the default one.
*/
getButtonDisplayName(button: string, display: KeyboardOptions["display"], mergeDisplay: boolean): string;
/**
* Returns the updated input resulting from clicking a given button
*
* @param {string} button The button's layout name
* @param {string} input The input string
* @param {number} caretPos The cursor's current position
* @param {number} caretPosEnd The cursor's current end position
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor
*/
getUpdatedInput(button: string, input: string, caretPos: number, caretPosEnd?: number, moveCaret?: boolean): string;
/**
* Moves the cursor position by a given amount
*
* @param {number} length Represents by how many characters the input should be moved
* @param {boolean} minus Whether the cursor should be moved to the left or not.
*/
updateCaretPos(length: number, minus?: boolean): void;
/**
* Action method of updateCaretPos
*
* @param {number} length Represents by how many characters the input should be moved
* @param {boolean} minus Whether the cursor should be moved to the left or not.
*/
updateCaretPosAction(length: number, minus?: boolean): number | null;
/**
* Adds a string to the input at a given position
*
* @param {string} source The source input
* @param {string} str The string to add
* @param {number} position The (cursor) position where the string should be added
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor
*/
addStringAt(source: string, str: string, position?: number, positionEnd?: number, moveCaret?: boolean): string;
/**
* Removes an amount of characters before a given position
*
* @param {string} source The source input
* @param {number} position The (cursor) position from where the characters should be removed
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor
*/
removeAt(source: string, position?: number, positionEnd?: number, moveCaret?: boolean): string;
/**
* Removes an amount of characters after a given position
*
* @param {string} source The source input
* @param {number} position The (cursor) position from where the characters should be removed
*/
removeForwardsAt(source: string, position?: number, positionEnd?: number, moveCaret?: boolean): string;
/**
* Determines whether the maxLength has been reached. This function is called when the maxLength option it set.
*
* @param {object} inputObj
* @param {string} updatedInput
*/
handleMaxLength(inputObj: KeyboardInput, updatedInput: string): boolean | undefined;
/**
* Gets the current value of maxLengthReached
*/
isMaxLengthReached(): boolean;
/**
* Determines whether a touch device is being used
*/
isTouchDevice(): number | true;
/**
* Determines whether pointer events are supported
*/
pointerEventsSupported(): boolean;
/**
* Bind all methods in a given class
*/
static bindMethods(myClass: any, instance: any): void;
/**
* Transforms an arbitrary string to camelCase
*
* @param {string} str The string to transform.
*/
camelCase(str: string): string;
/**
* Split array into chunks
*/
chunkArray<T>(arr: T[], size: number): T[][];
/**
* Reusable empty function
*/
static noop: () => void;
}
export default Utilities;
import { KeyboardInput } from "./../interfaces";
import { KeyboardOptions, UtilitiesParams } from "../interfaces";
/**
* Utility Service
*/
declare class Utilities {
getOptions: () => KeyboardOptions;
getCaretPosition: () => number | null;
getCaretPositionEnd: () => number | null;
dispatch: any;
maxLengthReached: boolean;
/**
* Creates an instance of the Utility service
*/
constructor({ getOptions, getCaretPosition, getCaretPositionEnd, dispatch, }: UtilitiesParams);
/**
* Retrieve button type
*
* @param {string} button The button's layout name
* @return {string} The button type
*/
getButtonType(button: string): string;
/**
* Adds default classes to a given button
*
* @param {string} button The button's layout name
* @return {string} The classes to be added to the button
*/
getButtonClass(button: string): string;
/**
* Default button display labels
*/
getDefaultDiplay(): {
"{bksp}": string;
"{backspace}": string;
"{enter}": string;
"{shift}": string;
"{shiftleft}": string;
"{shiftright}": string;
"{alt}": string;
"{s}": string;
"{tab}": string;
"{lock}": string;
"{capslock}": string;
"{accept}": string;
"{space}": string;
"{//}": string;
"{esc}": string;
"{escape}": string;
"{f1}": string;
"{f2}": string;
"{f3}": string;
"{f4}": string;
"{f5}": string;
"{f6}": string;
"{f7}": string;
"{f8}": string;
"{f9}": string;
"{f10}": string;
"{f11}": string;
"{f12}": string;
"{numpaddivide}": string;
"{numlock}": string;
"{arrowup}": string;
"{arrowleft}": string;
"{arrowdown}": string;
"{arrowright}": string;
"{prtscr}": string;
"{scrolllock}": string;
"{pause}": string;
"{insert}": string;
"{home}": string;
"{pageup}": string;
"{delete}": string;
"{forwarddelete}": string;
"{end}": string;
"{pagedown}": string;
"{numpadmultiply}": string;
"{numpadsubtract}": string;
"{numpadadd}": string;
"{numpadenter}": string;
"{period}": string;
"{numpaddecimal}": string;
"{numpad0}": string;
"{numpad1}": string;
"{numpad2}": string;
"{numpad3}": string;
"{numpad4}": string;
"{numpad5}": string;
"{numpad6}": string;
"{numpad7}": string;
"{numpad8}": string;
"{numpad9}": string;
};
/**
* Returns the display (label) name for a given button
*
* @param {string} button The button's layout name
* @param {object} display The provided display option
* @param {boolean} mergeDisplay Whether the provided param value should be merged with the default one.
*/
getButtonDisplayName(button: string, display: KeyboardOptions["display"], mergeDisplay: boolean): string;
/**
* Returns the updated input resulting from clicking a given button
*
* @param {string} button The button's layout name
* @param {string} input The input string
* @param {number} caretPos The cursor's current position
* @param {number} caretPosEnd The cursor's current end position
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor
*/
getUpdatedInput(button: string, input: string, caretPos: number, caretPosEnd?: number, moveCaret?: boolean): string;
/**
* Moves the cursor position by a given amount
*
* @param {number} length Represents by how many characters the input should be moved
* @param {boolean} minus Whether the cursor should be moved to the left or not.
*/
updateCaretPos(length: number, minus?: boolean): void;
/**
* Action method of updateCaretPos
*
* @param {number} length Represents by how many characters the input should be moved
* @param {boolean} minus Whether the cursor should be moved to the left or not.
*/
updateCaretPosAction(length: number, minus?: boolean): number | null;
/**
* Adds a string to the input at a given position
*
* @param {string} source The source input
* @param {string} str The string to add
* @param {number} position The (cursor) position where the string should be added
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor
*/
addStringAt(source: string, str: string, position?: number, positionEnd?: number, moveCaret?: boolean): string;
/**
* Removes an amount of characters before a given position
*
* @param {string} source The source input
* @param {number} position The (cursor) position from where the characters should be removed
* @param {boolean} moveCaret Whether to update simple-keyboard's cursor
*/
removeAt(source: string, position?: number, positionEnd?: number, moveCaret?: boolean): string;
/**
* Removes an amount of characters after a given position
*
* @param {string} source The source input
* @param {number} position The (cursor) position from where the characters should be removed
*/
removeForwardsAt(source: string, position?: number, positionEnd?: number, moveCaret?: boolean): string;
/**
* Determines whether the maxLength has been reached. This function is called when the maxLength option it set.
*
* @param {object} inputObj
* @param {string} updatedInput
*/
handleMaxLength(inputObj: KeyboardInput, updatedInput: string): boolean | undefined;
/**
* Gets the current value of maxLengthReached
*/
isMaxLengthReached(): boolean;
/**
* Determines whether a touch device is being used
*/
isTouchDevice(): number | true;
/**
* Determines whether pointer events are supported
*/
pointerEventsSupported(): boolean;
/**
* Bind all methods in a given class
*/
static bindMethods(myClass: any, instance: any): void;
/**
* Transforms an arbitrary string to camelCase
*
* @param {string} str The string to transform.
*/
camelCase(str: string): string;
/**
* Split array into chunks
*/
chunkArray<T>(arr: T[], size: number): T[][];
/**
* Reusable empty function
*/
static noop: () => void;
}
export default Utilities;

View File

@ -40,22 +40,13 @@ class PhysicalKeyboard {
options.physicalKeyboardHighlightTextColor || "black";
if (options.physicalKeyboardHighlightPress) {
/**
* Trigger pointerdown
*/
(
buttonDOM.onpointerdown ||
buttonDOM.onmousedown ||
buttonDOM.ontouchstart ||
Utilities.noop
)();
buttonDOM.click();
}
}
});
}
handleHighlightKeyUp(event: KeyboardEvent) {
const options = this.getOptions();
const buttonPressed = this.getSimpleKeyboardLayoutKey(event);
this.dispatch((instance: any) => {
@ -65,18 +56,6 @@ class PhysicalKeyboard {
if (buttonDOM && buttonDOM.removeAttribute) {
buttonDOM.removeAttribute("style");
if (options.physicalKeyboardHighlightPress) {
/**
* Trigger pointerup
*/
(
buttonDOM.onpointerup ||
buttonDOM.onmouseup ||
buttonDOM.ontouchend ||
Utilities.noop
)();
}
}
});
}
@ -87,34 +66,128 @@ class PhysicalKeyboard {
*/
getSimpleKeyboardLayoutKey(event: KeyboardEvent) {
let output;
const keyId = event.code || event.key || this.keyCodeToKey(event?.keyCode);
if (
event.code.includes("Numpad") ||
event.code.includes("Shift") ||
event.code.includes("Space") ||
event.code.includes("Backspace") ||
event.code.includes("Control") ||
event.code.includes("Alt") ||
event.code.includes("Meta")
keyId?.includes("Numpad") ||
keyId?.includes("Shift") ||
keyId?.includes("Space") ||
keyId?.includes("Backspace") ||
keyId?.includes("Control") ||
keyId?.includes("Alt") ||
keyId?.includes("Meta")
) {
output = event.code;
} else {
output = event.key;
output = event.key || this.keyCodeToKey(event?.keyCode);
}
/**
* Casting key to lowercase
*/
if (
(output && output !== output.toUpperCase()) ||
(event.code[0] === "F" &&
Number.isInteger(Number(event.code[1])) &&
event.code.length <= 3)
) {
output = output ? output.toLowerCase() : output;
}
return output?.toLowerCase();
}
return output;
/**
* Retrieve key from keyCode
*/
keyCodeToKey(keyCode: number) {
return {
8: "Backspace",
9: "Tab",
13: "Enter",
16: "Shift",
17: "Ctrl",
18: "Alt",
19: "Pause",
20: "CapsLock",
27: "Esc",
32: "Space",
33: "PageUp",
34: "PageDown",
35: "End",
36: "Home",
37: "ArrowLeft",
38: "ArrowUp",
39: "ArrowRight",
40: "ArrowDown",
45: "Insert",
46: "Delete",
48: "0",
49: "1",
50: "2",
51: "3",
52: "4",
53: "5",
54: "6",
55: "7",
56: "8",
57: "9",
65: "A",
66: "B",
67: "C",
68: "D",
69: "E",
70: "F",
71: "G",
72: "H",
73: "I",
74: "J",
75: "K",
76: "L",
77: "M",
78: "N",
79: "O",
80: "P",
81: "Q",
82: "R",
83: "S",
84: "T",
85: "U",
86: "V",
87: "W",
88: "X",
89: "Y",
90: "Z",
91: "Meta",
96: "Numpad0",
97: "Numpad1",
98: "Numpad2",
99: "Numpad3",
100: "Numpad4",
101: "Numpad5",
102: "Numpad6",
103: "Numpad7",
104: "Numpad8",
105: "Numpad9",
106: "NumpadMultiply",
107: "NumpadAdd",
109: "NumpadSubtract",
110: "NumpadDecimal",
111: "NumpadDivide",
112: "F1",
113: "F2",
114: "F3",
115: "F4",
116: "F5",
117: "F6",
118: "F7",
119: "F8",
120: "F9",
121: "F10",
122: "F11",
123: "F12",
144: "NumLock",
145: "ScrollLock",
186: ";",
187: "=",
188: ",",
189: "-",
190: ".",
191: "/",
192: "`",
219: "[",
220: "\\",
221: "]",
222: "'",
}[keyCode];
}
}

View File

@ -201,4 +201,25 @@ it('PhysicalKeyboard with physicalKeyboardHighlightPress can trigger noop', () =
tagName: "input"
}
}));
});
it('PhysicalKeyboard keyCodeToKey will work', () => {
setDOM();
const keyboard = new Keyboard({
physicalKeyboardHighlight: true
});
expect(keyboard.physicalKeyboard.keyCodeToKey(186)).toBe(";");
const methodTest = spyOn(keyboard.physicalKeyboard, "keyCodeToKey");
document.dispatchEvent(new KeyboardEvent('keyup', {
keyCode: 186,
target: {
tagName: "input"
}
}));
expect(methodTest).toBeCalledWith(186);
});