Declarative-style key handler demonstration
Rather than managing a stupid-complicated event handler where every handled input is hard-coded in, and/or the pressed keys are mashed into a data structure, this puts all the handled inputs into a data structure and looks them up every time a key is pressed. Making it possible to modify at runtime, and greatly simplifying the process as a whole. It also makes it possible to automatically generate a list of the available key bindings, which would have to be hard-coded if the controls were themselves hard-coded.
by Braden Best
HTML
<div class="input">Click me to focus (border will turn red). Then hit '?'</div>
<pre class="output">output</pre>
CSS
.input, .output{
width: 300px;
font: 12px monospace;
min-height: 3em;
padding: 10px;
border: 2px solid #eee;
}
.input:focus{
border: 2px solid red;
}
.output{
background: black;
color: white;
}
JavaScript
const Keyboard = Object.freeze({
final: Object.freeze({
bind_proto: Object.freeze({
key: null,
ctrlKey: false,
altKey: false,
desc: null,
callback: null,
})
}),
private: Object.seal({
el: null,
bindings: null,
ev_keydown_ptr: null
}),
public: Object.seal({
/* (nothing here yet) */
}),
_mkbind: function(bind){
let self = this;
return Object.seal({...self.final.bind_proto, ...bind});
},
_binding_filter: function(search){
return bind => (
bind.altKey === search.altKey &&
bind.ctrlKey === search.ctrlKey &&
bind.key === search.key
);
},
_binding_lookup: function(bind){
let self = this;
let result = self.private.bindings.find(self._binding_filter(bind));
if(typeof result === "undefined")
return null;
return result;
},
_ev_keydown: function(){
let self = this;
return function(ev){
let result = self._binding_lookup(ev);
if(result === null)
return;
ev.preventDefault();
result.callback(ev);
}
},
_get_label: function(binding){
let ret = binding.key;
if("ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(binding.key) !== -1)
ret = "shift-" + ret;
if(binding.ctrlKey)
ret = "ctrl-" + ret;
if(binding.altKey)
ret = "alt-" + ret;
return ret;
},
_pad_left: function(text, width){
while(text.length < width)
text = " " + text;
return text;
},
attach: function(el){
let self = this;
self.private.ev_keydown_ptr = self._ev_keydown();
self.private.el = el;
self.private.el.tabIndex = 0;
...