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;
  ...