This commit is contained in:
Hirokazu Takahashi 2013-01-31 07:10:59 -08:00
commit c939c0cd55
8 changed files with 6718 additions and 64 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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");

6407
include/keymap.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>