blob: 5b767c0d664ce1e539c1c2e84faf50e57cc98f61 [file] [log] [blame] [raw]
"use strict";
/**
* @constructor
*/
function KeyboardAdapter()
{
var
/**
* @type {!Object.<boolean>}
*/
keys_pressed = {},
keyboard = this,
// callback to call on a keypress
send_code;
this.enabled = true;
/**
* Format:
* Javascript event.keyCode -> make code
* @const
*/
var charmap = new Uint16Array([
0, 0, 0, 0, 0, 0, 0, 0,
// 0x08: backspace, tab, enter
0x0E, 0x0F, 0, 0, 0, 0x1C, 0, 0,
// 0x10: shift, ctrl, alt, pause, caps lock
0x2A, 0x1D, 0x38, 0, 0x3A, 0, 0, 0,
// 0x18: escape
0, 0, 0, 0x01, 0, 0, 0, 0,
// 0x20: spacebar, page down/up, end, home, arrow keys, ins, del
0x39, 0xE049, 0xE051, 0xE04F, 0xE047, 0xE04B, 0xE048, 0xE04D,
0x50, 0, 0, 0, 0, 0x52, 0x53, 0,
// 0x30: numbers
0x0B, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A,
// 0x3B: ;= (firefox only)
0, 0x27, 0, 0x0D, 0, 0, 0,
// 0x65: letters
0x1E, 0x30, 0x2E, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32,
0x31, 0x18, 0x19, 0x10, 0x13, 0x1F, 0x14, 0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C,
0, 0, 0, 0, 0,
// 0x60: keypad
0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47,
0x48, 0x49, 0, 0, 0, 0, 0, 0,
// 0x70: F1 to F12
0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x57, 0x58,
0, 0, 0, 0,
// 0x80
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
// 0x90: Numlock
0x45, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
// 0xA0: - (firefox only)
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0x0C, 0, 0,
// 0xB0
// ,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0x27, 0x0D, 0x33, 0x0C, 0x34, 0x35,
// 0xC0
// `
0x29, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
// 0xD0
// [']\
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0x1A, 0x2B, 0x1B, 0x28, 0
]);
this.init = function(code_fn)
{
this.destroy();
send_code = code_fn;
window.addEventListener("keyup", keyup_handler, false);
window.addEventListener("keydown", keydown_handler, false);
window.addEventListener("blur", blur_handler, false);
};
this.destroy = function()
{
window.removeEventListener("keyup", keyup_handler, false);
window.removeEventListener("keydown", keydown_handler, false);
window.removeEventListener("blur", blur_handler, false);
};
function may_handle(e)
{
if(
(e.shiftKey && e.ctrlKey && e.keyCode === 74) ||
e.keyCode === 116
) {
// don't prevent opening chromium dev tools or F5
// maybe add other important combinations here, too
return false;
}
if(!keyboard.enabled)
{
return false;
}
if(e.target)
{
// className shouldn't be hardcoded here
return e.target.className === "phone_keyboard" ||
(e.target.nodeName !== "INPUT" && e.target.nodeName !== "TEXTAREA");
}
else
{
return true;
}
}
function keyup_handler(e)
{
if(!may_handle(e))
{
return;
}
var code = e.keyCode;
if(!keys_pressed[code])
{
// stray keyup
return false;
}
keys_pressed[code] = false;
if(!handler(code, false))
{
e.preventDefault();
}
}
function keydown_handler(e)
{
if(!may_handle(e))
{
return;
}
var code = e.keyCode;
if(keys_pressed[code])
{
handler(code, false);
}
keys_pressed[code] = true;
if(!handler(code, true))
{
e.preventDefault();
}
}
function blur_handler(e)
{
// trigger keyup for all pressed keys
var keys = Object.keys(keys_pressed),
key;
for(var i = 0; i < keys.length; i++)
{
key = +keys[i];
if(keys_pressed[key])
{
handler(key, false);
}
}
keys_pressed = {};
}
/**
* @param {number} chr
* @param {boolean} keydown
*/
function handler(chr, keydown)
{
if(chr >= charmap.length || charmap[chr] === 0)
{
console.log("Missing char in map: " + chr.toString(16));
return true;
}
var code = charmap[chr];
if(!keydown)
{
code |= 0x80;
}
//console.log("Key: " + code.toString(16) + " from " + chr.toString(16) + " down=" + keydown);
if(code > 0xFF)
{
// prefix
send_code(code >> 8);
send_code(code & 0xFF);
}
else
{
send_code(code);
}
return false;
}
}