Merge 3a2027e4be into 3b2acc2258
This commit is contained in:
commit
c939c0cd55
|
|
@ -17,6 +17,7 @@ is not limited to):
|
||||||
include/vnc.js
|
include/vnc.js
|
||||||
include/websock.js
|
include/websock.js
|
||||||
include/webutil.js
|
include/webutil.js
|
||||||
|
include/keymap.js
|
||||||
|
|
||||||
The HTML, CSS, font and images files that included with the noVNC
|
The HTML, CSS, font and images files that included with the noVNC
|
||||||
source distibution (or repository) are not considered part of the
|
source distibution (or repository) are not considered part of the
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@ html {
|
||||||
background-color:#313131;
|
background-color:#313131;
|
||||||
border-bottom-right-radius: 800px 600px;
|
border-bottom-right-radius: 800px 600px;
|
||||||
/*border-top-left-radius: 800px 600px;*/
|
/*border-top-left-radius: 800px 600px;*/
|
||||||
|
ime-mode: disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
#noVNC_container, #noVNC_canvas {
|
#noVNC_container, #noVNC_canvas {
|
||||||
|
|
|
||||||
172
include/input.js
172
include/input.js
|
|
@ -18,7 +18,7 @@ function Keyboard(defaults) {
|
||||||
var that = {}, // Public API methods
|
var that = {}, // Public API methods
|
||||||
conf = {}, // Configuration attributes
|
conf = {}, // Configuration attributes
|
||||||
|
|
||||||
keyDownList = []; // List of depressed keys
|
keyDownMap = {}; // List of depressed keys
|
||||||
// (even if they are happy)
|
// (even if they are happy)
|
||||||
|
|
||||||
// Configuration attributes
|
// Configuration attributes
|
||||||
|
|
@ -29,6 +29,10 @@ Util.conf_defaults(conf, that, defaults, [
|
||||||
['onKeyPress', 'rw', 'func', null, 'Handler for key press/release']
|
['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
|
// Private functions
|
||||||
|
|
@ -92,6 +96,10 @@ function getKeysymSpecial(evt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!keysym) && (evt.ctrlKey || evt.altKey)) {
|
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)) {
|
if ((typeof(evt.which) !== "undefined") && (evt.which > 0)) {
|
||||||
keysym = evt.which;
|
keysym = evt.which;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -202,12 +210,15 @@ function getKeysym(evt) {
|
||||||
return keysym;
|
return keysym;
|
||||||
}
|
}
|
||||||
|
|
||||||
function show_keyDownList(kind) {
|
function show_keyDownMap(kind) {
|
||||||
var c;
|
var c = 0;
|
||||||
var msg = "keyDownList (" + kind + "):\n";
|
var keyCode, fevt;
|
||||||
for (c = 0; c < keyDownList.length; c++) {
|
var msg = "keyDownMap (" + kind + "):\n";
|
||||||
msg = msg + " " + c + " - keyCode: " + keyDownList[c].keyCode +
|
for (keyCode in keyDownMap) {
|
||||||
" - which: " + keyDownList[c].which + "\n";
|
fevt = getKeyEvent(keyCode, false);
|
||||||
|
msg = msg + " " + c + " - keyCode: " + fevt.keyCode +
|
||||||
|
" - which: " + fevt.which + "\n";
|
||||||
|
c++;
|
||||||
}
|
}
|
||||||
Util.Debug(msg);
|
Util.Debug(msg);
|
||||||
}
|
}
|
||||||
|
|
@ -225,20 +236,15 @@ function copyKeyEvent(evt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushKeyEvent(fevt) {
|
function pushKeyEvent(fevt) {
|
||||||
keyDownList.push(fevt);
|
keyDownMap[fevt.keyCode] = fevt;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getKeyEvent(keyCode, pop) {
|
function getKeyEvent(keyCode, pop) {
|
||||||
var i, fevt = null;
|
var fevt = keyDownMap[keyCode];
|
||||||
for (i = keyDownList.length-1; i >= 0; i--) {
|
if (typeof(fevt) === 'undefined') {
|
||||||
if (keyDownList[i].keyCode === keyCode) {
|
fevt = null;
|
||||||
if ((typeof(pop) !== "undefined") && (pop)) {
|
} else if ((typeof(pop) !== "undefined") && (pop)) {
|
||||||
fevt = keyDownList.splice(i, 1)[0];
|
delete keyDownMap[keyCode];
|
||||||
} else {
|
|
||||||
fevt = keyDownList[i];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return fevt;
|
return fevt;
|
||||||
}
|
}
|
||||||
|
|
@ -254,6 +260,81 @@ function ignoreKeyEvent(evt) {
|
||||||
return false;
|
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:
|
// Key Event Handling:
|
||||||
|
|
@ -313,6 +394,7 @@ function onKeyDown(e) {
|
||||||
keysym = getKeysymSpecial(evt);
|
keysym = getKeysymSpecial(evt);
|
||||||
// Save keysym decoding for use in keyUp
|
// Save keysym decoding for use in keyUp
|
||||||
fevt.keysym = keysym;
|
fevt.keysym = keysym;
|
||||||
|
saveKeyModifiers(evt, keysym);
|
||||||
if (keysym) {
|
if (keysym) {
|
||||||
// If it is a key or key combination that might trigger
|
// If it is a key or key combination that might trigger
|
||||||
// browser behaviors or it has no corresponding keyPress
|
// browser behaviors or it has no corresponding keyPress
|
||||||
|
|
@ -321,17 +403,12 @@ function onKeyDown(e) {
|
||||||
Util.Debug("onKeyPress down, keysym: " + keysym +
|
Util.Debug("onKeyPress down, keysym: " + keysym +
|
||||||
" (onKeyDown key: " + evt.keyCode +
|
" (onKeyDown key: " + evt.keyCode +
|
||||||
", which: " + evt.which + ")");
|
", which: " + evt.which + ")");
|
||||||
conf.onKeyPress(keysym, 1, evt);
|
conf.onKeyPress(keysym, 1, keyModifiers);
|
||||||
|
pushKeyEvent(fevt);
|
||||||
}
|
}
|
||||||
suppress = true;
|
suppress = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! ignoreKeyEvent(evt)) {
|
|
||||||
// Add it to the list of depressed keys
|
|
||||||
pushKeyEvent(fevt);
|
|
||||||
//show_keyDownList('down');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (suppress) {
|
if (suppress) {
|
||||||
// Suppress bubbling/default actions
|
// Suppress bubbling/default actions
|
||||||
Util.stopEvent(e);
|
Util.stopEvent(e);
|
||||||
|
|
@ -348,7 +425,7 @@ function onKeyPress(e) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var evt = (e ? e : window.event),
|
var evt = (e ? e : window.event),
|
||||||
kdlen = keyDownList.length, keysym = null;
|
kdlen = keyDownMap.length, keysym = null;
|
||||||
//Util.Debug("onKeyPress kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
|
//Util.Debug("onKeyPress kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
|
||||||
|
|
||||||
if (((evt.which !== "undefined") && (evt.which === 0)) ||
|
if (((evt.which !== "undefined") && (evt.which === 0)) ||
|
||||||
|
|
@ -365,23 +442,22 @@ function onKeyPress(e) {
|
||||||
|
|
||||||
keysym = getKeysym(evt);
|
keysym = getKeysym(evt);
|
||||||
|
|
||||||
// Modify the the which attribute in the depressed keys list so
|
//show_keyDownMap('press');
|
||||||
// that the keyUp event will be able to have the character code
|
|
||||||
// translation available.
|
if (Util.Engine.presto && (evt.ctrlKey || evt.altKey)) {
|
||||||
if (kdlen > 0) {
|
// Opera may fire two keypress events againt one keydown when
|
||||||
keyDownList[kdlen-1].keysym = keysym;
|
// hitting a key with some modifiers. Just ignore the first one.
|
||||||
} else {
|
return false;
|
||||||
Util.Warn("keyDownList empty when keyPress triggered");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//show_keyDownList('press');
|
|
||||||
|
|
||||||
// Send the translated keysym
|
// Send the translated keysym
|
||||||
if (conf.onKeyPress && (keysym > 0)) {
|
if (conf.onKeyPress && (keysym > 0)) {
|
||||||
Util.Debug("onKeyPress down, keysym: " + keysym +
|
Util.Debug("onKeyPress down, keysym: " + keysym +
|
||||||
" (onKeyPress key: " + evt.keyCode +
|
" (onKeyPress key: " + evt.keyCode +
|
||||||
", which: " + evt.which + ")");
|
", which: " + evt.which + ")");
|
||||||
conf.onKeyPress(keysym, 1, evt);
|
Util.Debug("onKeyPress up, keysym: " + keysym +
|
||||||
|
" (onKeyPress key: " + evt.keyCode +
|
||||||
|
", which: " + evt.which + ")");
|
||||||
|
conf.onKeyPress(keysym, 2, keyModifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop keypress events just in case
|
// Stop keypress events just in case
|
||||||
|
|
@ -401,12 +477,13 @@ function onKeyUp(e) {
|
||||||
if (fevt) {
|
if (fevt) {
|
||||||
keysym = fevt.keysym;
|
keysym = fevt.keysym;
|
||||||
} else {
|
} else {
|
||||||
Util.Warn("Key event (keyCode = " + evt.keyCode +
|
//Util.Debug("Key event (keyCode = " + evt.keyCode +
|
||||||
") not found on keyDownList");
|
// ") not found on keyDownMap");
|
||||||
keysym = 0;
|
keysym = 0;
|
||||||
}
|
}
|
||||||
|
saveKeyModifiers(evt, keysym);
|
||||||
|
|
||||||
//show_keyDownList('up');
|
//show_keyDownMap('up');
|
||||||
|
|
||||||
if (conf.onKeyPress && (keysym > 0)) {
|
if (conf.onKeyPress && (keysym > 0)) {
|
||||||
//Util.Debug("keyPress up, keysym: " + keysym +
|
//Util.Debug("keyPress up, keysym: " + keysym +
|
||||||
|
|
@ -414,7 +491,7 @@ function onKeyUp(e) {
|
||||||
Util.Debug("onKeyPress up, keysym: " + keysym +
|
Util.Debug("onKeyPress up, keysym: " + keysym +
|
||||||
" (onKeyPress key: " + evt.keyCode +
|
" (onKeyPress key: " + evt.keyCode +
|
||||||
", which: " + evt.which + ")");
|
", which: " + evt.which + ")");
|
||||||
conf.onKeyPress(keysym, 0, evt);
|
conf.onKeyPress(keysym, 0, keyModifiers);
|
||||||
}
|
}
|
||||||
Util.stopEvent(e);
|
Util.stopEvent(e);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -422,18 +499,17 @@ function onKeyUp(e) {
|
||||||
|
|
||||||
function allKeysUp() {
|
function allKeysUp() {
|
||||||
Util.Debug(">> Keyboard.allKeysUp");
|
Util.Debug(">> Keyboard.allKeysUp");
|
||||||
if (keyDownList.length > 0) {
|
var keyCode, keysym, fevt;
|
||||||
Util.Info("Releasing pressed/down keys");
|
keyModifiers = {'altKey': false, 'ctrlKey': false, 'shiftKey': false,
|
||||||
}
|
'altgrKey': false, 'altgrKey_fake': false, 'altgrKey_native': false};
|
||||||
var i, keysym, fevt = null;
|
for (keyCode in keyDownMap) {
|
||||||
for (i = keyDownList.length-1; i >= 0; i--) {
|
fevt = getKeyEvent(keyCode, true);
|
||||||
fevt = keyDownList.splice(i, 1)[0];
|
|
||||||
keysym = fevt.keysym;
|
keysym = fevt.keysym;
|
||||||
if (conf.onKeyPress && (keysym > 0)) {
|
if (conf.onKeyPress && (keysym > 0)) {
|
||||||
Util.Debug("allKeysUp, keysym: " + keysym +
|
Util.Debug("allKeysUp, keysym: " + keysym +
|
||||||
" (keyCode: " + fevt.keyCode +
|
" (keyCode: " + fevt.keyCode +
|
||||||
", which: " + fevt.which + ")");
|
", which: " + fevt.which + ")");
|
||||||
conf.onKeyPress(keysym, 0, fevt);
|
conf.onKeyPress(keysym, 0, keyModifiers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Util.Debug("<< Keyboard.allKeysUp");
|
Util.Debug("<< Keyboard.allKeysUp");
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
101
include/rfb.js
101
include/rfb.js
|
|
@ -126,7 +126,9 @@ var that = {}, // Public API methods
|
||||||
mouse_buttonMask = 0,
|
mouse_buttonMask = 0,
|
||||||
mouse_arr = [],
|
mouse_arr = [],
|
||||||
viewportDragging = false,
|
viewportDragging = false,
|
||||||
viewportDragPos = {};
|
viewportDragPos = {},
|
||||||
|
|
||||||
|
keymap = null;
|
||||||
|
|
||||||
// Configuration attributes
|
// Configuration attributes
|
||||||
Util.conf_defaults(conf, that, defaults, [
|
Util.conf_defaults(conf, that, defaults, [
|
||||||
|
|
@ -596,16 +598,95 @@ checkEvents = function() {
|
||||||
setTimeout(checkEvents, conf.check_rate);
|
setTimeout(checkEvents, conf.check_rate);
|
||||||
};
|
};
|
||||||
|
|
||||||
keyPress = function(keysym, down) {
|
// The status of the VNC server side key modifers.
|
||||||
var arr;
|
var remote_status = {shift: false, ctrl: false, alt: false, altgr: false};
|
||||||
|
var softKeyState = {ctrlKey: false, altKey: false};
|
||||||
|
|
||||||
|
keyPress = function(keysym, down, km) {
|
||||||
|
var arr = [];
|
||||||
|
|
||||||
if (conf.view_only) { return; } // View only, skip keyboard events
|
if (conf.view_only) { return; } // View only, skip keyboard events
|
||||||
|
|
||||||
arr = keyEvent(keysym, down);
|
// Remap the modifiers with apppropriate ones depending on the
|
||||||
|
// keyboard type of the vnc server if this is a presskey event.
|
||||||
|
if (!!keymap && down === 2)
|
||||||
|
km = remapModifiers(km, keysym);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
var ctrlKey = km.ctrlKey || softKeyState.ctrlKey;
|
||||||
|
var altKey = km.altKey || softKeyState.altKey;
|
||||||
|
if (remote_status.ctrl !== ctrlKey || keysym === 0xFFE3) {
|
||||||
|
arr = arr.concat(keyEvent(0xFFE3, ctrlKey)); // CTRL
|
||||||
|
remote_status.ctrl = ctrlKey;
|
||||||
|
}
|
||||||
|
if (remote_status.alt !== altKey || keysym === 0xFFE9) {
|
||||||
|
arr = arr.concat(keyEvent(0xFFE9, altKey)); // ALT
|
||||||
|
remote_status.alt = 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 = arr.concat(keyEvent(keysym, 1));
|
||||||
|
arr = arr.concat(keyEvent(keysym, 0));
|
||||||
|
} else {
|
||||||
|
// This is a keydown or keyup event.
|
||||||
|
arr = arr.concat(keyEvent(keysym, down));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!keymap && down === 2) {
|
||||||
|
// Turn off SHIFT and ALTGR every time when emulating modifiers.
|
||||||
|
if (remote_status.shift) {
|
||||||
|
arr = arr.concat(keyEvent(0xFFE1, 0)); // SHIFT up
|
||||||
|
remote_status.shift = false;
|
||||||
|
}
|
||||||
|
if (remote_status.altgr) {
|
||||||
|
arr = arr.concat(keyEvent(0xFE03, 0)); // ALTGR up
|
||||||
|
remote_status.altgr = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
arr = arr.concat(fbUpdateRequests());
|
arr = arr.concat(fbUpdateRequests());
|
||||||
ws.send(arr);
|
ws.send(arr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Remap the modifiers depending on keyboard types. It depends on keyboards
|
||||||
|
// whether a certain keycode should be issued with modifiers. For example,
|
||||||
|
// the US keyboard issues '@' with SHIFT, the Japanese keyboard issues '@'
|
||||||
|
// without any modifers, and the German keyboard issues '@' with ALTGR.
|
||||||
|
// When the keyboard types are different between the viewer and the vnc
|
||||||
|
// server, the server is expected to generate fake modifer key events
|
||||||
|
// if needed. But unfortunately there are a lot of VNC servers that can't
|
||||||
|
// handle this. Then there is no choice but to make noVNC take care of it
|
||||||
|
// on behalf of them.
|
||||||
|
function remapModifiers(km, keysym)
|
||||||
|
{
|
||||||
|
var remap = {'altKey': km.altKey, 'ctrlKey': km.ctrlKey,
|
||||||
|
'shiftKey': km.shiftKey, 'altgrKey': km.altgrKey};
|
||||||
|
var key = keymap[keysym];
|
||||||
|
if (typeof key !== "undefined") {
|
||||||
|
remap.altgrKey = key.altgr;
|
||||||
|
remap.shiftKey = key.shift;
|
||||||
|
}
|
||||||
|
return remap;
|
||||||
|
}
|
||||||
|
|
||||||
mouseButton = function(x, y, down, bmask) {
|
mouseButton = function(x, y, down, bmask) {
|
||||||
if (down) {
|
if (down) {
|
||||||
mouse_buttonMask |= bmask;
|
mouse_buttonMask |= bmask;
|
||||||
|
|
@ -1838,6 +1919,10 @@ that.sendKey = function(code, down) {
|
||||||
ws.send(arr);
|
ws.send(arr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
that.updateSoftKeyState = function(name, value) {
|
||||||
|
softKeyState[name] = value;
|
||||||
|
};
|
||||||
|
|
||||||
that.clipboardPasteFrom = function(text) {
|
that.clipboardPasteFrom = function(text) {
|
||||||
if (rfb_state !== "normal") { return; }
|
if (rfb_state !== "normal") { return; }
|
||||||
//Util.Debug(">> clipboardPasteFrom: " + text.substr(0,40) + "...");
|
//Util.Debug(">> clipboardPasteFrom: " + text.substr(0,40) + "...");
|
||||||
|
|
@ -1860,6 +1945,14 @@ that.testMode = function(override_send, data_mode) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
that.setKeymap = function(kb) {
|
||||||
|
if (!kb || kb === 'default') {
|
||||||
|
keymap = null;
|
||||||
|
} else {
|
||||||
|
keymap = Kmap.getKeymap(kb);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return constructor(); // Return the public API interface
|
return constructor(); // Return the public API interface
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@
|
||||||
// Load supporting scripts
|
// Load supporting scripts
|
||||||
window.onscriptsload = function () { UI.load(); };
|
window.onscriptsload = function () { UI.load(); };
|
||||||
Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
|
Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
|
||||||
"input.js", "display.js", "jsunzip.js", "rfb.js"]);
|
"input.js", "display.js", "jsunzip.js", "rfb.js",
|
||||||
|
"keymap.js"]);
|
||||||
|
|
||||||
var UI = {
|
var UI = {
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ load: function (callback) {
|
||||||
|
|
||||||
// Render default UI and initialize settings menu
|
// Render default UI and initialize settings menu
|
||||||
start: function(callback) {
|
start: function(callback) {
|
||||||
var html = '', i, sheet, sheets, llevels;
|
var html = '', i, sheet, sheets, llevels, kbtypes;
|
||||||
|
|
||||||
// Stylesheet selection dropdown
|
// Stylesheet selection dropdown
|
||||||
sheet = WebUtil.selectStylesheet();
|
sheet = WebUtil.selectStylesheet();
|
||||||
|
|
@ -46,6 +47,19 @@ start: function(callback) {
|
||||||
UI.addOption($D('noVNC_logging'),llevels[i], llevels[i]);
|
UI.addOption($D('noVNC_logging'),llevels[i], llevels[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keyboard type selection dropdown
|
||||||
|
kbtypes = ['default', 'ar', 'bepo', 'da', 'de', 'de-ch', 'en-gb',
|
||||||
|
'en-us', 'es', 'et', 'fi', 'fo', 'fr', 'fr-be', 'fr-ca',
|
||||||
|
'fr-ch', 'hr', 'hu', 'is', 'it', 'ja', 'lt', 'lv', 'mk',
|
||||||
|
'nl', 'nl-be', 'no', 'pl', 'pt', 'pt-br', 'ru', 'sl',
|
||||||
|
'sv', 'th', 'tr'];
|
||||||
|
|
||||||
|
for (i = 0; i < kbtypes.length; i += 1) {
|
||||||
|
UI.addOption($D('noVNC_keymap'), kbtypes[i], kbtypes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
UI.initSetting('keymap', 'default');
|
||||||
|
|
||||||
// Settings with immediate effects
|
// Settings with immediate effects
|
||||||
UI.initSetting('logging', 'warn');
|
UI.initSetting('logging', 'warn');
|
||||||
WebUtil.init_logging(UI.getSetting('logging'));
|
WebUtil.init_logging(UI.getSetting('logging'));
|
||||||
|
|
@ -71,6 +85,7 @@ start: function(callback) {
|
||||||
UI.rfb = RFB({'target': $D('noVNC_canvas'),
|
UI.rfb = RFB({'target': $D('noVNC_canvas'),
|
||||||
'onUpdateState': UI.updateState,
|
'onUpdateState': UI.updateState,
|
||||||
'onClipboard': UI.clipReceive});
|
'onClipboard': UI.clipReceive});
|
||||||
|
UI.rfb.setKeymap(UI.getSetting('keymap'));
|
||||||
UI.updateVisualState();
|
UI.updateVisualState();
|
||||||
|
|
||||||
// Unfocus clipboard when over the VNC area
|
// Unfocus clipboard when over the VNC area
|
||||||
|
|
@ -149,6 +164,8 @@ addMouseHandlers: function() {
|
||||||
$D("connectButton").onclick = UI.toggleConnectPanel;
|
$D("connectButton").onclick = UI.toggleConnectPanel;
|
||||||
$D("disconnectButton").onclick = UI.disconnect;
|
$D("disconnectButton").onclick = UI.disconnect;
|
||||||
$D("descriptionButton").onclick = UI.toggleConnectPanel;
|
$D("descriptionButton").onclick = UI.toggleConnectPanel;
|
||||||
|
$D("ctrlLockCheckBox").onclick = UI.updateSoftKeyState;
|
||||||
|
$D("altLockCheckBox").onclick = UI.updateSoftKeyState;
|
||||||
|
|
||||||
$D("noVNC_clipboard_text").onfocus = UI.displayBlur;
|
$D("noVNC_clipboard_text").onfocus = UI.displayBlur;
|
||||||
$D("noVNC_clipboard_text").onblur = UI.displayFocus;
|
$D("noVNC_clipboard_text").onblur = UI.displayFocus;
|
||||||
|
|
@ -326,6 +343,7 @@ toggleSettingsPanel: function() {
|
||||||
UI.updateSetting('repeaterID');
|
UI.updateSetting('repeaterID');
|
||||||
UI.updateSetting('stylesheet');
|
UI.updateSetting('stylesheet');
|
||||||
UI.updateSetting('logging');
|
UI.updateSetting('logging');
|
||||||
|
UI.updateSetting('keymap');
|
||||||
|
|
||||||
UI.openSettingsMenu();
|
UI.openSettingsMenu();
|
||||||
}
|
}
|
||||||
|
|
@ -370,8 +388,10 @@ settingsApply: function() {
|
||||||
UI.saveSetting('repeaterID');
|
UI.saveSetting('repeaterID');
|
||||||
UI.saveSetting('stylesheet');
|
UI.saveSetting('stylesheet');
|
||||||
UI.saveSetting('logging');
|
UI.saveSetting('logging');
|
||||||
|
UI.saveSetting('keymap');
|
||||||
|
|
||||||
// Settings with immediate (non-connected related) effect
|
// Settings with immediate (non-connected related) effect
|
||||||
|
UI.rfb.setKeymap(UI.getSetting('keymap'));
|
||||||
WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
|
WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
|
||||||
WebUtil.init_logging(UI.getSetting('logging'));
|
WebUtil.init_logging(UI.getSetting('logging'));
|
||||||
UI.setViewClip();
|
UI.setViewClip();
|
||||||
|
|
@ -395,6 +415,10 @@ sendCtrlAltDel: function() {
|
||||||
UI.rfb.sendCtrlAltDel();
|
UI.rfb.sendCtrlAltDel();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateSoftKeyState: function() {
|
||||||
|
UI.rfb.updateSoftKeyState(this.value, this.checked);
|
||||||
|
},
|
||||||
|
|
||||||
setMouseButton: function(num) {
|
setMouseButton: function(num) {
|
||||||
var b, blist = [0, 1,2,4], button;
|
var b, blist = [0, 1,2,4], button;
|
||||||
|
|
||||||
|
|
@ -490,11 +514,19 @@ updateVisualState: function() {
|
||||||
$D('clipboardButton').style.display = "inline";
|
$D('clipboardButton').style.display = "inline";
|
||||||
$D('showKeyboard').style.display = "inline";
|
$D('showKeyboard').style.display = "inline";
|
||||||
$D('sendCtrlAltDelButton').style.display = "inline";
|
$D('sendCtrlAltDelButton').style.display = "inline";
|
||||||
|
$D('ctrlLockCheckBox').style.display = "inline";
|
||||||
|
$D('altLockCheckBox').style.display = "inline";
|
||||||
|
$D('ctrlLockLabel').style.display = "inline";
|
||||||
|
$D('altLockLabel').style.display = "inline";
|
||||||
} else {
|
} else {
|
||||||
UI.setMouseButton();
|
UI.setMouseButton();
|
||||||
$D('clipboardButton').style.display = "none";
|
$D('clipboardButton').style.display = "none";
|
||||||
$D('showKeyboard').style.display = "none";
|
$D('showKeyboard').style.display = "none";
|
||||||
$D('sendCtrlAltDelButton').style.display = "none";
|
$D('sendCtrlAltDelButton').style.display = "none";
|
||||||
|
$D('ctrlLockCheckBox').style.display = "none";
|
||||||
|
$D('altLockCheckBox').style.display = "none";
|
||||||
|
$D('ctrlLockLabel').style.display = "none";
|
||||||
|
$D('altLockLabel').style.display = "none";
|
||||||
}
|
}
|
||||||
// State change disables viewport dragging.
|
// State change disables viewport dragging.
|
||||||
// It is enabled (toggled) by direct click on the button
|
// It is enabled (toggled) by direct click on the button
|
||||||
|
|
|
||||||
12
vnc.html
12
vnc.html
|
|
@ -70,6 +70,12 @@
|
||||||
|
|
||||||
<!--noVNC Buttons-->
|
<!--noVNC Buttons-->
|
||||||
<div class="noVNC-buttons-right">
|
<div class="noVNC-buttons-right">
|
||||||
|
<input type=checkbox value="ctrlKey"
|
||||||
|
id="ctrlLockCheckBox">
|
||||||
|
<label for="ctrlLockCheckBox" id="ctrlLockLabel">CtrlLock</label>
|
||||||
|
<input type=checkbox value="altKey"
|
||||||
|
id="altLockCheckBox">
|
||||||
|
<label for="altLockCheckBox" id="altLockLabel" >AltLock</label>
|
||||||
<input type="image" src="images/ctrlaltdel.png"
|
<input type="image" src="images/ctrlaltdel.png"
|
||||||
id="sendCtrlAltDelButton" class="noVNC_status_button"
|
id="sendCtrlAltDelButton" class="noVNC_status_button"
|
||||||
title="Send Ctrl-Alt-Del" />
|
title="Send Ctrl-Alt-Del" />
|
||||||
|
|
@ -138,6 +144,12 @@
|
||||||
<select id="noVNC_logging" name="vncLogging">
|
<select id="noVNC_logging" name="vncLogging">
|
||||||
</select></label>
|
</select></label>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<!-- keyboard selection dropdown -->
|
||||||
|
<li><label><strong>Keyboard: </strong>
|
||||||
|
<select id="noVNC_keymap" name="vncKeymap">
|
||||||
|
</select></label>
|
||||||
|
</li>
|
||||||
<hr>
|
<hr>
|
||||||
<li><input type="button" id="noVNC_apply" value="Apply"></li>
|
<li><input type="button" id="noVNC_apply" value="Apply"></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,20 @@
|
||||||
<div id="noVNC_status_bar" class="noVNC_status_bar" style="margin-top: 0px;">
|
<div id="noVNC_status_bar" class="noVNC_status_bar" style="margin-top: 0px;">
|
||||||
<table border=0 width="100%"><tr>
|
<table border=0 width="100%"><tr>
|
||||||
<td><div id="noVNC_status">Loading</div></td>
|
<td><div id="noVNC_status">Loading</div></td>
|
||||||
<td width="1%"><div id="noVNC_buttons">
|
<td width="300pt"><div id="noVNC_buttons">
|
||||||
|
<span style="float: right">
|
||||||
<input type=button value="Send CtrlAltDel"
|
<input type=button value="Send CtrlAltDel"
|
||||||
id="sendCtrlAltDelButton">
|
id="sendCtrlAltDelButton">
|
||||||
</div></td>
|
</span>
|
||||||
|
<span style="float: right">
|
||||||
|
<input type=checkbox value="ctrlKey"
|
||||||
|
id="ctrlLockCheckBox">
|
||||||
|
<label for="ctrlLockCheckBox">CtrlLock</label>
|
||||||
|
<input type=checkbox value="altKey"
|
||||||
|
id="altLockCheckBox">
|
||||||
|
<label for="altLockCheckBox">AltLock</label>
|
||||||
|
</span>
|
||||||
|
</div></td>
|
||||||
</tr></table>
|
</tr></table>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="noVNC_canvas" width="640px" height="20px">
|
<canvas id="noVNC_canvas" width="640px" height="20px">
|
||||||
|
|
@ -43,9 +53,15 @@
|
||||||
|
|
||||||
// Load supporting scripts
|
// Load supporting scripts
|
||||||
Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
|
Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
|
||||||
"input.js", "display.js", "jsunzip.js", "rfb.js"]);
|
"input.js", "display.js", "jsunzip.js", "rfb.js",
|
||||||
|
"keymap.js"]);
|
||||||
|
|
||||||
var rfb;
|
var rfb;
|
||||||
|
var buttons = [
|
||||||
|
{name: 'ctrlLockCheckBox', onclick: updateSoftKeyState},
|
||||||
|
{name: 'altLockCheckBox', onclick: updateSoftKeyState},
|
||||||
|
{name: 'sendCtrlAltDelButton', onclick: sendCtrlAltDel}
|
||||||
|
];
|
||||||
|
|
||||||
function passwordRequired(rfb) {
|
function passwordRequired(rfb) {
|
||||||
var msg;
|
var msg;
|
||||||
|
|
@ -65,11 +81,14 @@
|
||||||
rfb.sendCtrlAltDel();
|
rfb.sendCtrlAltDel();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
function updateSoftKeyState() {
|
||||||
|
rfb.updateSoftKeyState(this.value, this.checked);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
function updateState(rfb, state, oldstate, msg) {
|
function updateState(rfb, state, oldstate, msg) {
|
||||||
var s, sb, cad, level;
|
var s, sb, level;
|
||||||
s = $D('noVNC_status');
|
s = $D('noVNC_status');
|
||||||
sb = $D('noVNC_status_bar');
|
sb = $D('noVNC_status_bar');
|
||||||
cad = $D('sendCtrlAltDelButton');
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 'failed': level = "error"; break;
|
case 'failed': level = "error"; break;
|
||||||
case 'fatal': level = "error"; break;
|
case 'fatal': level = "error"; break;
|
||||||
|
|
@ -79,8 +98,15 @@
|
||||||
default: level = "warn"; break;
|
default: level = "warn"; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state === "normal") { cad.disabled = false; }
|
var i;
|
||||||
else { cad.disabled = true; }
|
for (i = 0; i < buttons.length; i++) {
|
||||||
|
var elem = $D(buttons[i].name);
|
||||||
|
if (state === "normal") {
|
||||||
|
elem.disabled = false;
|
||||||
|
} else {
|
||||||
|
elem.disabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof(msg) !== 'undefined') {
|
if (typeof(msg) !== 'undefined') {
|
||||||
sb.setAttribute("class", "noVNC_status_" + level);
|
sb.setAttribute("class", "noVNC_status_" + level);
|
||||||
|
|
@ -89,10 +115,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onscriptsload = function () {
|
window.onscriptsload = function () {
|
||||||
var host, port, password, path, token;
|
var host, port, password, path, token, i;
|
||||||
|
|
||||||
$D('sendCtrlAltDelButton').style.display = "inline";
|
for (i = 0; i < buttons.length; i++) {
|
||||||
$D('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
|
var button = buttons[i];
|
||||||
|
$D(button.name).style.display = "inline";
|
||||||
|
if (button.onclick) {
|
||||||
|
$D(button.name).onclick = button.onclick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WebUtil.init_logging(WebUtil.getQueryVar('logging', 'warn'));
|
WebUtil.init_logging(WebUtil.getQueryVar('logging', 'warn'));
|
||||||
document.title = unescape(WebUtil.getQueryVar('title', 'noVNC'));
|
document.title = unescape(WebUtil.getQueryVar('title', 'noVNC'));
|
||||||
|
|
@ -126,6 +157,7 @@
|
||||||
'view_only': WebUtil.getQueryVar('view_only', false),
|
'view_only': WebUtil.getQueryVar('view_only', false),
|
||||||
'updateState': updateState,
|
'updateState': updateState,
|
||||||
'onPasswordRequired': passwordRequired});
|
'onPasswordRequired': passwordRequired});
|
||||||
|
rfb.setKeymap(WebUtil.getQueryVar('keymap', 'default'));
|
||||||
rfb.connect(host, port, password, path);
|
rfb.connect(host, port, password, path);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue