function parsekb(s) {
// a string looks like "N c a s"
// N is the keycode; c, a, s are
// cntrlKey, altKey, shiftKey, respectively
// 1 = true (this key was pressed)
// 0 = false (key was not pressed)
s = s.split(' ');
for (var i=1; i<4; i++)
s[i] = s[i] == '1';
return s;
}

kbindings = {};
// i don't like to use var for global keywords
// it presents an insoluble conflict between
// illegal redeclaration and an indesirable
// ambiguity; good programmers don't use
// ambiguous names, anyway. you could claim
// that it would be possible to use window.x
// and var x, and that you could not distinguish.
// i argue that it there must never be a js
// variable with the same name as an object
// property in the current scope. thus i do
// not use "var kbindings = blah"

document.onkeypress = function(e) {
var f;
if (!e) e = event; else event = e;
// for IE; I strongly believe that
// netscape's implementation is wrong, and that
// all event models should use window.event instead of
// the handler(event) nonsense.
if (f = kbindings[e.keyCode || e.charCode]) {
if (f[1] == e.ctrlKey
&& f[2] == e.altKey
&& f[3] == e.shiftKey)
return f[0]();
}
}

sbindings = ''; // semicolon-joined
// e.g. "blowup=102 c a s;shoot=5 c a s"

function loadbindings() {
var m = sbindings.split(';'), i, kb;
for (i=0; i<m.length; i++) {
kb = m[i].split('=');
kb[1] = parsekb(kb[1]);
kbindings[kb[1][0]] = kb[1];
kb[1][0] = eval(kb[0]); // this is the source of
// errors if sbindings has undefined functions
}
}

// for instructions and to create new key functions, see
// http://www.myersdaily.org/joseph/javascript/keybindings.html
