AltGr key emulation support

Lost key-modifier events recovery support
This commit is contained in:
Hirokazu Takahashi 2012-12-11 17:30:22 +09:00
parent 0820c08dfc
commit 77c250c442
2 changed files with 130 additions and 11 deletions

View File

@ -29,6 +29,10 @@ Util.conf_defaults(conf, that, defaults, [
['onKeyPress', 'rw', 'func', null, 'Handler for key press/release']
]);
// CTRL/ALT/SHIFT/ALTGR key status.
var keyModifiers = {'altKey': false, 'ctrlKey': false, 'shiftKey': false,
'altgrKey': false, 'altgrKey_fake': false, 'altgrKey_native': false};
//
// Private functions
@ -92,6 +96,10 @@ function getKeysymSpecial(evt) {
}
if ((!keysym) && (evt.ctrlKey || evt.altKey)) {
if (evt.ctrlKey && evt.altKey) {
// This is a key event with ALTGR.
return keysym;
}
if ((typeof(evt.which) !== "undefined") && (evt.which > 0)) {
keysym = evt.which;
} else {
@ -248,6 +256,81 @@ function ignoreKeyEvent(evt) {
return false;
}
// 1. Save the current status of modifier keys to enable the keypress event
// handler to refer the status. Some browers may not fire keyup events
// pairing with some keydown events for modifier keys like CTRL, ALT and
// SHIFT keys. noVNC is expected to detect this situation to issue fake
// keyup events to fix it up.
// 2. Emulate ALTGR key events. Most browsers generate two key events
// when hitting an ALTGR key, events which are CTRL and ALT ones.
// But unfortunately there exist some vnc servers that can't handle
// them as an emulated ALTGR key event. noVNC has to convert them into
// one ALTGR key event on behalf of vnc servers.
function saveKeyModifiers(evt, keysym) {
var km = keyModifiers;
km.shiftKey = evt.shiftKey;
if (evt.type === 'keydown') {
switch (keysym) {
// If this event is ALT or CTRL down and both evt.ctrlKey and
// evt.altKey get true, pass the decision to the next key event
// that whether it should be turned into an ALTGR key event.
case 0xFFE3 :
if (evt.ctrlKey && evt.altKey) break;
km.ctrlKey = true;
break;
case 0xFFE9 :
if (evt.ctrlKey && evt.altKey) break;
km.altKey = true;
break;
default :
switch (keysym) {
case 0xFFE1 : km.shiftKey = true; break;
case 0xFE03 : km.altgrKey_native = true; break;
}
km.altKey = evt.altKey;
km.ctrlKey = evt.ctrlKey;
break;
}
if (!(keysym) && km.ctrlKey && km.altKey) {
// Turn the ALT and CTRL events into an ALTGR. The keycode will
// be translated by the ALTGR even if it is an emulated one.
km.altgrKey_fake = true;
km.ctrlKey = km.altKey = false;
} else {
km.altgrKey_fake = false;
}
} else { // keyup event
switch (keysym) {
// Notice: FireFox 15 for linux doesn't set evt.altKey and
// evt.ctrlKey false even when this is an ALT or CTRL keyup
// event. Don't use evt.altKey and evt.ctrlKey here.
case 0xFFE3 : km.ctrlKey = false; break;
case 0xFFE9 : km.altKey = false; break;
default :
switch (keysym) {
case 0xFFE1 : km.shiftKey = false; break;
case 0xFE03 : km.altgrKey_native = false; break;
}
km.altKey = evt.altKey;
km.ctrlKey = evt.ctrlKey;
break;
}
if (km.altgrKey_fake) {
if (keysym == 0xFFE3 || keysym == 0xFFE9) {
// This is a part of an emulated ALTGR keyup event.
// Don't let ALT or CTRL down yet.
km.altgrKey_fake = false;
km.ctrlKey = km.altKey = false;
} else if (km.altKey && km.ctrlKey) {
km.ctrlKey = km.altKey = false;
} else {
km.altgrKey_fake = false;
}
}
}
km.altgrKey = km.altgrKey_fake || km.altgrKey_native;
};
//
// Key Event Handling:
@ -307,6 +390,7 @@ function onKeyDown(e) {
keysym = getKeysymSpecial(evt);
// Save keysym decoding for use in keyUp
fevt.keysym = keysym;
saveKeyModifiers(evt, keysym);
if (keysym) {
// If it is a key or key combination that might trigger
// browser behaviors or it has no corresponding keyPress
@ -315,7 +399,7 @@ function onKeyDown(e) {
Util.Debug("onKeyPress down, keysym: " + keysym +
" (onKeyDown key: " + evt.keyCode +
", which: " + evt.which + ")");
conf.onKeyPress(keysym, 1, evt);
conf.onKeyPress(keysym, 1, keyModifiers);
pushKeyEvent(fevt);
}
suppress = true;
@ -356,6 +440,11 @@ function onKeyPress(e) {
//show_keyDownMap('press');
if (Util.Engine.presto && (evt.ctrlKey || evt.altKey)) {
// Opera may fire two keypress events againt one keydown when
// hitting a key with some modifiers. Just ignore the first one.
return false;
}
// Send the translated keysym
if (conf.onKeyPress && (keysym > 0)) {
Util.Debug("onKeyPress down, keysym: " + keysym +
@ -364,7 +453,7 @@ function onKeyPress(e) {
Util.Debug("onKeyPress up, keysym: " + keysym +
" (onKeyPress key: " + evt.keyCode +
", which: " + evt.which + ")");
conf.onKeyPress(keysym, 2, evt);
conf.onKeyPress(keysym, 2, keyModifiers);
}
// Stop keypress events just in case
@ -388,6 +477,7 @@ function onKeyUp(e) {
// ") not found on keyDownMap");
keysym = 0;
}
saveKeyModifiers(evt, keysym);
//show_keyDownMap('up');
@ -397,7 +487,7 @@ function onKeyUp(e) {
Util.Debug("onKeyPress up, keysym: " + keysym +
" (onKeyPress key: " + evt.keyCode +
", which: " + evt.which + ")");
conf.onKeyPress(keysym, 0, evt);
conf.onKeyPress(keysym, 0, keyModifiers);
}
Util.stopEvent(e);
return false;
@ -406,6 +496,8 @@ function onKeyUp(e) {
function allKeysUp() {
Util.Debug(">> Keyboard.allKeysUp");
var keyCode, keysym, fevt;
keyModifiers = {'altKey': false, 'ctrlKey': false, 'shiftKey': false,
'altgrKey': false, 'altgrKey_fake': false, 'altgrKey_native': false};
for (keyCode in keyDownMap) {
fevt = getKeyEvent(keyCode, true);
keysym = fevt.keysym;
@ -413,7 +505,7 @@ function allKeysUp() {
Util.Debug("allKeysUp, keysym: " + keysym +
" (keyCode: " + fevt.keyCode +
", which: " + fevt.which + ")");
conf.onKeyPress(keysym, 0, fevt);
conf.onKeyPress(keysym, 0, keyModifiers);
}
}
Util.Debug("<< Keyboard.allKeysUp");

View File

@ -596,21 +596,48 @@ checkEvents = function() {
setTimeout(checkEvents, conf.check_rate);
};
keyPress = function(keysym, down) {
var arr;
// The status of the VNC server side key modifers.
var remote_status = {shift: false, ctrl: false, alt: false, altgr: false};
keyPress = function(keysym, down, km) {
var arr = [];
if (conf.view_only) { return; } // View only, skip keyboard events
if (down === 2) {
// keypress event
// Generate all modifier keys' events on demand.
// Send key events for modifiers to the vnc server when:
// 1. the status of modifers have been changed
// 2. this is a repeated keydown event for a modifer
if (remote_status.ctrl !== km.ctrlKey || keysym === 0xFFE3) {
arr = arr.concat(keyEvent(0xFFE3, km.ctrlKey)); // CTRL
remote_status.ctrl = km.ctrlKey;
}
if (remote_status.alt !== km.altKey || keysym === 0xFFE9) {
arr = arr.concat(keyEvent(0xFFE9, km.altKey)); // ALT
remote_status.alt = km.altKey;
}
if (remote_status.altgr !== km.altgrKey || keysym === 0xFE03) {
arr = arr.concat(keyEvent(0xFE03, km.altgrKey)); // ALTGR
remote_status.altgr = km.altgrKey;
}
if (remote_status.shift !== km.shiftKey || keysym === 0xFFE1) {
arr = arr.concat(keyEvent(0xFFE1, km.shiftKey)); // SHIFT
remote_status.shift = km.shiftKey;
}
if (keysym === 0xFFE1 || keysym === 0xFFE3
|| keysym === 0xFFE9 || keysym === 0xFE03) {
// SHIFT, CTRL, ALT and ALTGR events are already set in arr[].
} else if (down === 2) {
// This is a keypress event.
// Send a keyup event here to avoid letting the server side generate
// repeated-key events. Otherwise, both sides will independently
// generate key down and press events against the same key.
arr = keyEvent(keysym, 1);
arr = arr.concat(keyEvent(keysym, 1));
arr = arr.concat(keyEvent(keysym, 0));
} else {
// keydown or keyup event
arr = keyEvent(keysym, down);
// This is a keydown or keyup event.
arr = arr.concat(keyEvent(keysym, down));
}
arr = arr.concat(fbUpdateRequests());
ws.send(arr);