Please let me know what exactly youâre looking for if this doesnât answer your question:
Final use case:
I want users to fire a gun across all platforms. The keyboard fire key is f, they can press the right mouse button, they can tap once with 2 fingers, or they can use a on the controller. When they release any of those gestures, the gun will stop firing.
Here is the code adding those events to a keymap:
const my_keymap = new KeyMap([
{input:"key_f", event:"fire", state:1},
{input:"key_f", event:"stop_fire", state:0},
{input:"rightmousebutton", event:"fire", state:1},
{input:"rightmousebutton", event:"stop_fire", state:0}
])
//taken from the Zingtouch idea for touch events
const two_finger_touch = new TouchEvent({
type: "tap",
maxDelay: -1, //this is to say that the tap could go on forever
numInputs: 2,
tolerance: 10,
})
my_keymap.add([
{input:two_finger_touch, event:"fire", state:1},
{input:two_finger_touch, event:"stop_fire", state:0}
])
Here is a module that only works for keyboard in JavaScript, but the other functions are there, they just need to be tweeked a little:
/*
Manages the usage of keymaps
usage{
keymap = new KeyMap()
keymap.add({key:["f"], mods:["shift"], event:"fligh"})
*/
//functions for checking if two arrays have the same items but in a different order
const containsAll = (arr1, arr2) =>
arr2.every(arr2Item => arr1.includes(arr2Item))
//use this to do your array same check
const sameMembers = (arr1, arr2) =>
containsAll(arr1, arr2) && containsAll(arr2, arr1) && arr1.length === arr2.length
// sameMembers(arr1, arr2) // will return true or false
export default class KeyMap {
constructor(keymap=[]){
this._keymap = []
this.add(keymap)
}
_addSingle(mapping={}){
// adds a key mapping to this._keymap. either one or both of function or event need to be passed.
let local_mapping = Object.assign({key:[], mods:[], event:null, function:null, state:1}, mapping)
if(local_mapping["key"] && (local_mapping["function"] || local_mapping["event"])){
local_mapping["key"] = Array.isArray(local_mapping['key']) ? local_mapping['key'] : [local_mapping['key']]
local_mapping["mods"] = Array.isArray(local_mapping["mods"]) ? local_mapping["mods"] : [local_mapping["mods"]]
this._keymap.push(local_mapping)
} else{
let missing_items = Object.keys(local_mapping).map(m=> m !== 'mods' && !local_mapping[m] ? m:null).filter(t=>t)
missing_items = missing_items.join(', ')
throw new Error("KeymapError: KeyMap.add was passed a mapping without a value for: " + missing_items)
}
}
add(mapping={}){
if(Array.isArray(mapping)){
mapping.map((m)=>this._addSingle(m))
} else{
this._addSingle(mapping)
}
}
/*
getModsSets(mods){
`converts mods into a couple different sets and returns a list. That way users can use shift,and alt, rather than leftctrl and rightctrl.`
nutral = []
with_alt = []
nutral_with_alt = []
for mod in mods{
if "meta" in mod{
alt = mod.replace("meta", "alt")
with_alt.add(alt)
nutral.add("meta")
nutral_with_alt.add("alt")
elif not mod in ['left', 'right'] and ('left' in mod or 'right' in mod){
with_alt.add(mod)
mod = mod.replace('left', '').replace('right', '').strip()
nutral.add(mod)
nutral_with_alt.add(mod)
else{
with_alt.add(mod)
nutral.add(mod)
nutral_with_alt.add(mod)
return [with_alt, nutral, nutral_with_alt]
*/
getEvent({key=[], mods=[], state=1}={}){
// Gets the event that is triggered by the list of key and mods.
key = Array.isArray(key) ? key : [key]
mods = Array.isArray(mods) ? mods : [mods]
for(let i = 0; i < this._keymap.length; i++){
const mapping = this._keymap[i]
if(sameMembers(mapping['key'], key) && sameMembers(mapping['mods'], mods) && mapping['state'] === state){
if(mapping['function']){
return mapping['function']()
}
return mapping['event']
}
}
}
/*
else if(mods){
mod_sets = this.getModsSets(mods)
for mod_set in mod_sets{
if mapping['key'] == key and mapping['mods'] == mod_set and mapping['state'] == state{
if mapping['function']{
return mapping['function']()
return mapping['event']
*/
}