v6502/vm/computer/keyboard.js

151 lines
4.7 KiB
JavaScript

/*
* 6502 Based Virtual Computer
* Copyright (C) 2011 Scott C. Duensing <scott@jaegertech.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
// Our keyboard object.
function keyboard() {
// OMFGWTFBBQ - http://unixpapa.com/js/key.html
// --- Private variables.
// Memory location for keyboard status.
var MEMORY = null;
var MEMORY_START = 0;
var CHARACTER_ADDRESS = 0;
var META_ADDRESS = 0;
// Keymaps. Swiped from http://jonathan.tang.name/code/js_keycode
var KEY_MAP = {};
var SHIFTED_SYMBOLS = {
58: 59, // : -> ;
43: 61, // = -> +
60: 44, // < -> ,
95: 45, // _ -> -
62: 46, // > -> .
63: 47, // ? -> /
96: 192, // ` -> ~
124: 92, // | -> \
39: 222, // ' -> 222
34: 222, // " -> 222
33: 49, // ! -> 1
64: 50, // @ -> 2
35: 51, // # -> 3
36: 52, // $ -> 4
37: 53, // % -> 5
94: 54, // ^ -> 6
38: 55, // & -> 7
42: 56, // * -> 8
40: 57, // ( -> 9
41: 58, // ) -> 0
123: 91, // { -> [
125: 93 // } -> ]
};
var GECKO_IE_KEYMAP = {
186: 59, // ;: in IE
187: 61, // =+ in IE
188: 44, // ,<
109: 95, // -_ in Mozilla
107: 61, // =+ in Mozilla
189: 95, // -_ in IE
190: 62, // .>
191: 47, // /?
192: 126, // `~
219: 91, // {[
220: 92, // \|
221: 93 // }]
};
var OPERA_KEYMAP = {};
// Browser detection taken from quirksmode.org
var IS_WINDOWS = navigator.platform.indexOf('Win') != -1;
var IS_OPERA = window.opera && window.opera.version() < '9.5';
var IS_KONQUEROR = navigator.vendor && navigator.vendor.indexOf('KDE') != -1;
var IS_ICAB = navigator.vendor && navigator.vendor.indexOf('iCab') != -1;
// --- Public methods.
// Attach keyboard to DOM.
this.attach = function(newMemory, newStartPosition) {
MEMORY = newMemory;
MEMORY_START = newStartPosition;
CHARACTER_ADDRESS = MEMORY_START;
META_ADDRESS = MEMORY_START + 1;
// Determine key map.
if (IS_OPERA && IS_WINDOWS) {
KEY_MAP = OPERA_KEYMAP;
} else if (IS_OPERA || IS_KONQUEROR || IS_ICAB) {
var unshift = [33, 64, 35, 36, 37, 94, 38, 42, 40, 41,
58, 43, 60, 95, 62, 63, 124, 34];
KEY_MAP = OPERA_KEYMAP;
for (var i = 0; i < unshift.length; ++i) {
KEY_MAP[unshift[i]] = SHIFTED_SYMBOLS[unshift[i]];
}
} else {
// IE and Gecko are close enough that we can use the same map for both,
// and the rest of the world (eg. Opera 9.50) seems to be standardizing
// on them
KEY_MAP = GECKO_IE_KEYMAP;
}
if (IS_KONQUEROR) {
KEY_MAP[0] = 45;
KEY_MAP[127] = 46;
KEY_MAP[45] = 95;
}
// Hook browser for keydown events.
document.onkeydown = function(e){
e = e || window.event;
// Process the key press.
var code = e.which || e.keyCode;
var k = {
code: KEY_MAP[code] || code,
shift: e.shiftKey,
alt: e.altKey,
ctrl: e.ctrlKey
};
// Un-funk the input.
if (k.shift) {
// Fix shifted characters.
var oldC = "1234567890,/=[]\\';";
var newC = "!@#$%^&*()<?+{}|\":";
var x = oldC.indexOf(String.fromCharCode(k.code));
if (x >= 0) k.code = newC.charCodeAt(x);
if (k.code == 222) k.code = 34; // "
} else {
// Fix unshifted characters.
var oldC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ~_>";
var newC = "abcdefghijklmnopqrstuvwxyz`-.";
var x = oldC.indexOf(String.fromCharCode(k.code));
if (x >= 0) k.code = newC.charCodeAt(x);
if (k.code == 222) k.code = 39; // '
}
// Write meta first. Then we can process on the character being written.
MEMORY.writeByte(META_ADDRESS, (k.alt * 4) + (k.ctrl * 2) + k.shift);
// Ignore "naked" meta keys in the character address.
if ((k.code != 16) && (k.code != 17) && (k.code != 18) && (k.code != 145) && (k.code != 146)) {
MEMORY.writeByte(CHARACTER_ADDRESS, k.code);
}
};
};
// Fetch how much RAM the current settings will require.
this.getMemoryNeeded = function() {
return 2; // Complicated, huh?
};
}