mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
1416 lines
46 KiB
JavaScript
1416 lines
46 KiB
JavaScript
/*
|
|
Licensed to the Apache Software Foundation (ASF) under one
|
|
or more contributor license agreements. See the NOTICE file
|
|
distributed with this work for additional information
|
|
regarding copyright ownership. The ASF licenses this file
|
|
to you under the Apache License, Version 2.0 (the
|
|
"License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing,
|
|
software distributed under the License is distributed on an
|
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
KIND, either express or implied. See the License for the
|
|
specific language governing permissions and limitations
|
|
under the License.
|
|
*/
|
|
|
|
var g_logger;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// class StringBuilder
|
|
//
|
|
function StringBuilder(initStr) {
|
|
this.strings = new Array("");
|
|
this.append(initStr);
|
|
}
|
|
|
|
StringBuilder.prototype = {
|
|
append : function (str) {
|
|
if (str) {
|
|
this.strings.push(str);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
clear : function() {
|
|
this.strings.length = 1;
|
|
return this;
|
|
},
|
|
|
|
toString: function() {
|
|
return this.strings.join("");
|
|
}
|
|
};
|
|
|
|
|
|
function getCurrentLanguage() {
|
|
if(acceptLanguages) {
|
|
var tokens = acceptLanguages.split(',');
|
|
if(tokens.length > 0)
|
|
return tokens[0];
|
|
|
|
return "en-us";
|
|
} else {
|
|
return "en-us";
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// class KeyboardMapper
|
|
//
|
|
function KeyboardMapper() {
|
|
this.mappedInput = [];
|
|
this.jsX11KeysymMap = [];
|
|
this.jsKeyPressX11KeysymMap = [];
|
|
}
|
|
|
|
//
|
|
// RAW keyboard
|
|
// Primarily translates KeyDown/KeyUp event, either as is (if there is no mapping entry)
|
|
// or through mapped result.
|
|
//
|
|
// For KeyPress event, it translates it only if there exist a mapping entry
|
|
// in jsX11KeysymMap map and the entry meets the condition
|
|
//
|
|
// COOKED keyboard
|
|
// Primarily translates KeyPress event, either as is or through mapped result
|
|
// It translates KeyDown/KeyUp only there exists a mapping entry, or if there
|
|
// is no mapping entry, translate when certain modifier key is pressed (i.e.,
|
|
// CTRL or ALT key
|
|
//
|
|
// Mapping entry types
|
|
// direct : will be directly mapped into the entry value with the same event type
|
|
// boolean : only valid for jsX11KeysymMap, existence of this type, no matter true or false
|
|
// in value, corresponding KeyDown/KeyUp event will be masked
|
|
// array : contains a set of conditional mapping entry
|
|
//
|
|
// Conditional mapping entry
|
|
//
|
|
// {
|
|
// type: <event type>, code: <mapped key code>, modifiers: <modifiers>,
|
|
// shift : <shift state match condition>, -- match on shift state
|
|
// guestos : <guest os match condition>, -- match on guestos type
|
|
// browser: <browser type match condition>, -- match on browser
|
|
// browserVersion: <brower version match condition> -- match on browser version
|
|
// }
|
|
//
|
|
KeyboardMapper.KEYBOARD_TYPE_RAW = 0;
|
|
KeyboardMapper.KEYBOARD_TYPE_COOKED = 1;
|
|
KeyboardMapper.KEYBOARD_TYPE_UK = 2;
|
|
KeyboardMapper.KEYBOARD_TYPE_FR = 3;
|
|
|
|
KeyboardMapper.prototype = {
|
|
|
|
setKeyboardType : function(keyboardType) {
|
|
this.keyboardType = keyboardType;
|
|
if(keyboardType == KeyboardMapper.KEYBOARD_TYPE_COOKED || keyboardType == KeyboardMapper.KEYBOARD_TYPE_UK || keyboardType == KeyboardMapper.KEYBOARD_TYPE_FR) {
|
|
// initialize mapping for COOKED keyboard
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_CAPSLOCK] = AjaxViewer.X11_KEY_CAPSLOCK;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_BACKSPACE] = AjaxViewer.X11_KEY_BACKSPACE;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_TAB] = AjaxViewer.X11_KEY_TAB;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_ENTER] = AjaxViewer.X11_KEY_ENTER;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_ESCAPE] = AjaxViewer.X11_KEY_ESCAPE;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_INSERT] = AjaxViewer.X11_KEY_INSERT;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_DELETE] = AjaxViewer.X11_KEY_DELETE;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_HOME] = AjaxViewer.X11_KEY_HOME;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_END] = AjaxViewer.X11_KEY_END;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_PAGEUP] = AjaxViewer.X11_KEY_PAGEUP;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_PAGEDOWN] = AjaxViewer.X11_KEY_PAGEDOWN;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_LEFT] = AjaxViewer.X11_KEY_LEFT;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_UP] = AjaxViewer.X11_KEY_UP;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_RIGHT] = AjaxViewer.X11_KEY_RIGHT;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_DOWN] = AjaxViewer.X11_KEY_DOWN;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F1] = AjaxViewer.X11_KEY_F1;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F2] = AjaxViewer.X11_KEY_F2;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F3] = AjaxViewer.X11_KEY_F3;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F4] = AjaxViewer.X11_KEY_F4;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F5] = AjaxViewer.X11_KEY_F5;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F6] = AjaxViewer.X11_KEY_F6;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F7] = AjaxViewer.X11_KEY_F7;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F8] = AjaxViewer.X11_KEY_F8;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F9] = AjaxViewer.X11_KEY_F9;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F10] = AjaxViewer.X11_KEY_F10;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F11] = AjaxViewer.X11_KEY_F11;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_F12] = AjaxViewer.X11_KEY_F12;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_SHIFT] = AjaxViewer.X11_KEY_SHIFT;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_CTRL] = AjaxViewer.X11_KEY_CTRL;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_ALT] = AjaxViewer.X11_KEY_ALT;
|
|
this.jsX11KeysymMap[AjaxViewer.JS_KEY_SELECT_KEY] = AjaxViewer.X11_KEY_SELECT_KEY;
|
|
//this.jsX11KeysymMap[AjaxViewer.JS_KEY_DECIMAL_POINT] = AjaxViewer.X11_KEY_DECIMAL_POINT;
|
|
this.jsKeyPressX11KeysymMap[45] = [{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SUBSTRACT, modifiers: 0, shift: true },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SUBSTRACT, modifiers: 0, shift: true },
|
|
{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SUBSTRACT, modifiers: 0, shift: false },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SUBSTRACT, modifiers: 0, shift: false }];
|
|
this.jsKeyPressX11KeysymMap[47] = [{type: AjaxViewer.KEY_DOWN, code: 0x2f, modifiers: 0, shift: true },
|
|
{type: AjaxViewer.KEY_UP, code: 0x2f, modifiers: 0, shift: true },
|
|
{type: AjaxViewer.KEY_DOWN, code: 0x2f, modifiers: 0, shift: false },
|
|
{type: AjaxViewer.KEY_UP, code: 0x2f, modifiers: 0, shift: false }];
|
|
}
|
|
},
|
|
RawkeyboardInputHandler : function(eventType, code, modifiers, guestos, browser, browserVersion) {
|
|
if(eventType == AjaxViewer.KEY_DOWN || eventType == AjaxViewer.KEY_UP) {
|
|
|
|
// special handling for Alt + Ctrl + Ins, convert it into Alt-Ctrl-Del
|
|
if(code == AjaxViewer.JS_KEY_INSERT) {
|
|
if((modifiers & AjaxViewer.ALT_KEY_MASK) != 0 && (modifiers & AjaxViewer.CTRL_KEY_MASK) != 0) {
|
|
this.mappedInput.push({type : eventType, code: 0xffff, modifiers: modifiers});
|
|
return;
|
|
}
|
|
}
|
|
|
|
var X11Keysym = code;
|
|
if(this.jsX11KeysymMap[code] != undefined && (guestos == 'windows' || modifiers != AjaxViewer.SHIFT_KEY_MASK || code == AjaxViewer.JS_KEY_CAPSLOCK)) {
|
|
X11Keysym = this.jsX11KeysymMap[code];
|
|
if(typeof this.jsX11KeysymMap[code] == "boolean") {
|
|
return;
|
|
} else if($.isArray(X11Keysym)) {
|
|
for(var i = 0; i < X11Keysym.length; i++) {
|
|
// How to set the guestos, browser, version value??? add later
|
|
if(this.isConditionalEntryMatched(eventType, code, modifiers, X11Keysym[i], guestos, browser, browserVersion)) {
|
|
this.mappedInput.push(X11Keysym[i]);
|
|
}
|
|
}
|
|
} else {
|
|
this.mappedInput.push({type : eventType, code: X11Keysym, modifiers: modifiers});
|
|
}
|
|
} else if(guestos == 'windows' || ((modifiers & (AjaxViewer.CTRL_KEY_MASK | AjaxViewer.ALT_KEY_MASK)) != 0)){
|
|
this.mappedInput.push({type : eventType, code: X11Keysym, modifiers: modifiers});
|
|
}
|
|
|
|
// special handling for ALT/CTRL key
|
|
if(eventType == AjaxViewer.KEY_UP && (code == AjaxViewer.JS_KEY_ALT || code == AjaxViewer.JS_KEY_CTRL))
|
|
this.mappedInput.push({type : eventType, code: this.jsX11KeysymMap[code], modifiers: modifiers});
|
|
|
|
} else if(eventType == AjaxViewer.KEY_PRESS && guestos == 'null') {
|
|
// ENTER/BACKSPACE key should already have been sent through KEY DOWN/KEY UP event
|
|
if(code == AjaxViewer.JS_KEY_ENTER || code == AjaxViewer.JS_KEY_BACKSPACE)
|
|
return;
|
|
|
|
var X11Keysym = code;
|
|
X11Keysym = this.jsKeyPressX11KeysymMap[code];
|
|
if(X11Keysym) {
|
|
if($.isArray(X11Keysym)) {
|
|
for(var i = 0; i < X11Keysym.length; i++) {
|
|
if(this.isConditionalEntryMatched(eventType, code, modifiers, X11Keysym[i], guestos, browser))
|
|
this.mappedInput.push(X11Keysym[i]);
|
|
}
|
|
} else {
|
|
this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: X11Keysym, modifiers: modifiers});
|
|
this.mappedInput.push({type : AjaxViewer.KEY_UP, code: X11Keysym, modifiers: modifiers});
|
|
}
|
|
} else if(!(code == 48 && modifiers == AjaxViewer.SHIFT_KEY_MASK) && !(code == 95 && modifiers == 0)){
|
|
this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: code, modifiers: modifiers});
|
|
this.mappedInput.push({type : AjaxViewer.KEY_UP, code: code, modifiers: modifiers});
|
|
}
|
|
}
|
|
},
|
|
|
|
CookedKeyboardInputHandler : function(eventType, code, modifiers, guestos, browser, browserVersion) {
|
|
if(eventType == AjaxViewer.KEY_DOWN || eventType == AjaxViewer.KEY_UP) {
|
|
|
|
// special handling for Alt + Ctrl + Ins, convert it into Alt-Ctrl-Del
|
|
if(code == AjaxViewer.JS_KEY_INSERT) {
|
|
if((modifiers & AjaxViewer.ALT_KEY_MASK) != 0 && (modifiers & AjaxViewer.CTRL_KEY_MASK) != 0) {
|
|
this.mappedInput.push({type : eventType, code: 0xffff, modifiers: modifiers});
|
|
return;
|
|
}
|
|
}
|
|
|
|
var X11Keysym = code;
|
|
if(this.jsX11KeysymMap[code] != undefined) {
|
|
X11Keysym = this.jsX11KeysymMap[code];
|
|
if(typeof this.jsX11KeysymMap[code] == "boolean") {
|
|
return;
|
|
} else if($.isArray(X11Keysym)) {
|
|
for(var i = 0; i < X11Keysym.length; i++) {
|
|
if(this.isConditionalEntryMatched(eventType, code, modifiers, X11Keysym[i], guestos, browser, browserVersion)) {
|
|
this.mappedInput.push(X11Keysym[i]);
|
|
}
|
|
}
|
|
} else {
|
|
this.mappedInput.push({type : eventType, code: X11Keysym, modifiers: modifiers});
|
|
}
|
|
} else {
|
|
if((modifiers & (AjaxViewer.CTRL_KEY_MASK | AjaxViewer.ALT_KEY_MASK)) != 0) {
|
|
this.mappedInput.push({type : eventType, code: X11Keysym, modifiers: modifiers});
|
|
}
|
|
}
|
|
|
|
// special handling for ALT/CTRL key
|
|
if(eventType == AjaxViewer.KEY_UP && (code == AjaxViewer.JS_KEY_ALT || code == code == AjaxViewer.JS_KEY_CTRL)) {
|
|
this.mappedInput.push({type : eventType, code: this.jsX11KeysymMap[code], modifiers: modifiers});
|
|
}
|
|
} else if(eventType == AjaxViewer.KEY_PRESS) {
|
|
// special handling for * and + key on number pad
|
|
if(code == AjaxViewer.JS_NUMPAD_MULTIPLY) {
|
|
this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: modifiers});
|
|
this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: 42, modifiers: modifiers});
|
|
this.mappedInput.push({type : AjaxViewer.KEY_UP, code: 42, modifiers: modifiers});
|
|
this.mappedInput.push({type : AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: modifiers});
|
|
return;
|
|
}
|
|
|
|
if(code == AjaxViewer.JS_NUMPAD_PLUS) {
|
|
this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: modifiers});
|
|
this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: 43, modifiers: modifiers});
|
|
this.mappedInput.push({type : AjaxViewer.KEY_UP, code: 43, modifiers: modifiers});
|
|
this.mappedInput.push({type : AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: modifiers});
|
|
return;
|
|
}
|
|
|
|
// ENTER/BACKSPACE key should already have been sent through KEY DOWN/KEY UP event
|
|
if(code == AjaxViewer.JS_KEY_ENTER || code == AjaxViewer.JS_KEY_BACKSPACE)
|
|
return;
|
|
if(code > 0) {
|
|
var X11Keysym = code;
|
|
X11Keysym = this.jsKeyPressX11KeysymMap[code];
|
|
if(X11Keysym) {
|
|
if($.isArray(X11Keysym)) {
|
|
for(var i = 0; i < X11Keysym.length; i++) {
|
|
if(this.isConditionalEntryMatched(eventType, code, modifiers, X11Keysym[i], guestos, browser))
|
|
this.mappedInput.push(X11Keysym[i]);
|
|
}
|
|
} else {
|
|
this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: X11Keysym, modifiers: modifiers});
|
|
this.mappedInput.push({type : AjaxViewer.KEY_UP, code: X11Keysym, modifiers: modifiers});
|
|
}
|
|
} else {
|
|
// if there is no mappting entry, use the JS keypress code directly
|
|
this.mappedInput.push({type : AjaxViewer.KEY_DOWN, code: code, modifiers: modifiers});
|
|
this.mappedInput.push({type : AjaxViewer.KEY_UP, code: code, modifiers: modifiers});
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
inputFeed : function(eventType, code, modifiers, guestos, browser, browserVersion) {
|
|
if(this.keyboardType == KeyboardMapper.KEYBOARD_TYPE_RAW)
|
|
this.RawkeyboardInputHandler(eventType, code, modifiers, guestos, browser, browserVersion);
|
|
else
|
|
this.CookedKeyboardInputHandler(eventType, code, modifiers, guestos, browser, browserVersion);
|
|
},
|
|
|
|
getMappedInput : function() {
|
|
var mappedInput = this.mappedInput;
|
|
this.mappedInput = [];
|
|
return mappedInput;
|
|
},
|
|
|
|
isConditionalEntryMatched : function(eventType, code, modifiers, entry, guestos, browser, browserVersion) {
|
|
if(eventType == AjaxViewer.KEY_DOWN || eventType == AjaxViewer.KEY_UP) {
|
|
// for KeyDown/KeyUp events, we require that the type in entry should match with
|
|
// the real input
|
|
if(entry.type != eventType)
|
|
return false;
|
|
}
|
|
|
|
// check conditional match
|
|
if(entry.shift != undefined) {
|
|
var shift = ((modifiers & AjaxViewer.SHIFT_KEY_MASK) != 0 ? true : false);
|
|
if(entry.shift ^ shift)
|
|
return false;
|
|
}
|
|
|
|
// Consider Alt+Ctrl as AltGr
|
|
if(entry.altgr != undefined){
|
|
var altgr = ((modifiers & AjaxViewer.ALT_KEY_MASK) && (modifiers & AjaxViewer.CTRL_KEY_MASK)) != 0 ? true : false;
|
|
if(entry.altgr ^ altgr)
|
|
return false;
|
|
}
|
|
|
|
if(entry.guestos != undefined) {
|
|
if(entry.guestos != guestos)
|
|
return false;
|
|
}
|
|
|
|
if(entry.browser != undefined) {
|
|
if(entry.browser != browser)
|
|
return false;
|
|
}
|
|
|
|
if(entry.browserVersion != undefined) {
|
|
if(entry.browserVersion != browserVersion)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
|
|
isModifierInput : function(code) {
|
|
return $.inArray(code, [AjaxViewer.ALT_KEY_MASK, AjaxViewer.SHIFT_KEY_MASK, AjaxViewer.CTRL_KEY_MASK, AjaxViewer.META_KEY_MASK]) >= 0;
|
|
}
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// class AjaxViewer
|
|
//
|
|
function AjaxViewer(panelId, imageUrl, updateUrl, locale, guestos, tileMap, width, height, tileWidth, tileHeight) {
|
|
// logging is disabled by default so that it won't have negative impact on performance
|
|
// however, a back door key-sequence can trigger to open the logger window, it is designed to help
|
|
// trouble-shooting
|
|
g_logger = new Logger();
|
|
|
|
// g_logger.enable(true);
|
|
// g_logger.open();
|
|
|
|
var ajaxViewer = this;
|
|
this.imageLoaded = false;
|
|
this.fullImage = true;
|
|
this.imgUrl = imageUrl;
|
|
this.img = new Image();
|
|
$(this.img).attr('src', imageUrl).load(function() {
|
|
ajaxViewer.imageLoaded = true;
|
|
});
|
|
|
|
this.updateUrl = updateUrl;
|
|
this.tileMap = tileMap;
|
|
this.guestos = guestos;
|
|
this.dirty = true;
|
|
this.width = width;
|
|
this.height = height;
|
|
this.tileWidth = tileWidth;
|
|
this.tileHeight = tileHeight;
|
|
this.maxTileZIndex = 1;
|
|
|
|
if (locale == AjaxViewer.KEYBOARD_TYPE_UK_ENGLISH || locale == AjaxViewer.KEYBOARD_TYPE_JAPANESE || locale == AjaxViewer.KEYBOARD_TYPE_FRENCH)
|
|
this.currentKeyboard = locale;
|
|
else
|
|
this.currentKeyboard = AjaxViewer.KEYBOARD_TYPE_ENGLISH;
|
|
|
|
this.keyboardMappers = [];
|
|
|
|
this.timer = 0;
|
|
this.eventQueue = [];
|
|
this.sendingEventInProgress = false;
|
|
|
|
this.lastClickEvent = { x: 0, y: 0, button: 0, modifiers: 0, time: new Date().getTime() };
|
|
|
|
if(window.onStatusNotify == undefined)
|
|
window.onStatusNotify = function(status) {};
|
|
|
|
this.panel = this.generateCanvas(panelId, width, height, tileWidth, tileHeight);
|
|
// this.setupKeyboardTranslationle();
|
|
this.setupKeyboardTranslationTable(this.keyboardMappers);
|
|
this.setupUIController();
|
|
}
|
|
|
|
// client event types
|
|
AjaxViewer.MOUSE_MOVE = 1;
|
|
AjaxViewer.MOUSE_DOWN = 2;
|
|
AjaxViewer.MOUSE_UP = 3;
|
|
AjaxViewer.KEY_PRESS = 4;
|
|
AjaxViewer.KEY_DOWN = 5;
|
|
AjaxViewer.KEY_UP = 6;
|
|
AjaxViewer.EVENT_BAG = 7;
|
|
AjaxViewer.MOUSE_DBLCLK = 8;
|
|
|
|
// use java AWT key modifier masks
|
|
AjaxViewer.SHIFT_KEY_MASK = 64;
|
|
AjaxViewer.CTRL_KEY_MASK = 128;
|
|
AjaxViewer.META_KEY_MASK = 256;
|
|
AjaxViewer.ALT_KEY_MASK = 512;
|
|
AjaxViewer.LEFT_SHIFT_MASK = 1024;
|
|
AjaxViewer.LEFT_CTRL_MASK = 2048;
|
|
AjaxViewer.LEFT_ALT_MASK = 4096;
|
|
|
|
AjaxViewer.EVENT_QUEUE_MOUSE_EVENT = 1;
|
|
AjaxViewer.EVENT_QUEUE_KEYBOARD_EVENT = 2;
|
|
|
|
AjaxViewer.STATUS_RECEIVING = 1;
|
|
AjaxViewer.STATUS_RECEIVED = 2;
|
|
AjaxViewer.STATUS_SENDING = 3;
|
|
AjaxViewer.STATUS_SENT = 4;
|
|
|
|
AjaxViewer.KEYBOARD_TYPE_ENGLISH = "us";
|
|
AjaxViewer.KEYBOARD_TYPE_UK_ENGLISH = "uk";
|
|
AjaxViewer.KEYBOARD_TYPE_JAPANESE = "jp";
|
|
AjaxViewer.KEYBOARD_TYPE_FRENCH = "fr";
|
|
|
|
AjaxViewer.JS_KEY_BACKSPACE = 8;
|
|
AjaxViewer.JS_KEY_TAB = 9;
|
|
AjaxViewer.JS_KEY_ENTER = 13;
|
|
AjaxViewer.JS_KEY_SHIFT = 16;
|
|
AjaxViewer.JS_KEY_CTRL = 17;
|
|
AjaxViewer.JS_KEY_ALT = 18;
|
|
AjaxViewer.JS_KEY_PAUSE = 19;
|
|
AjaxViewer.JS_KEY_CAPSLOCK = 20;
|
|
AjaxViewer.JS_KEY_ESCAPE = 27;
|
|
AjaxViewer.JS_KEY_PAGEUP = 33;
|
|
AjaxViewer.JS_KEY_PAGEDOWN = 34;
|
|
AjaxViewer.JS_KEY_END = 35;
|
|
AjaxViewer.JS_KEY_HOME = 36;
|
|
AjaxViewer.JS_KEY_LEFT = 37;
|
|
AjaxViewer.JS_KEY_UP = 38;
|
|
AjaxViewer.JS_KEY_RIGHT = 39;
|
|
AjaxViewer.JS_KEY_DOWN = 40;
|
|
AjaxViewer.JS_KEY_INSERT = 45;
|
|
AjaxViewer.JS_KEY_DELETE = 46;
|
|
AjaxViewer.JS_KEY_LEFT_WINDOW_KEY = 91;
|
|
AjaxViewer.JS_KEY_RIGHT_WINDOW_KEY = 92;
|
|
AjaxViewer.JS_KEY_SELECT_KEY = 93;
|
|
AjaxViewer.JS_KEY_NUMPAD0 = 96;
|
|
AjaxViewer.JS_KEY_NUMPAD1 = 97;
|
|
AjaxViewer.JS_KEY_NUMPAD2 = 98;
|
|
AjaxViewer.JS_KEY_NUMPAD3 = 99;
|
|
AjaxViewer.JS_KEY_NUMPAD4 = 100;
|
|
AjaxViewer.JS_KEY_NUMPAD5 = 101;
|
|
AjaxViewer.JS_KEY_NUMPAD6 = 102;
|
|
AjaxViewer.JS_KEY_NUMPAD7 = 103;
|
|
AjaxViewer.JS_KEY_NUMPAD8 = 104;
|
|
AjaxViewer.JS_KEY_NUMPAD9 = 105;
|
|
AjaxViewer.JS_KEY_MULTIPLY = 106;
|
|
AjaxViewer.JS_KEY_ADD = 107;
|
|
AjaxViewer.JS_KEY_SUBSTRACT = 109;
|
|
AjaxViewer.JS_KEY_DECIMAL_POINT = 110;
|
|
AjaxViewer.JS_KEY_DIVIDE = 111;
|
|
AjaxViewer.JS_KEY_F1 = 112;
|
|
AjaxViewer.JS_KEY_F2 = 113;
|
|
AjaxViewer.JS_KEY_F3 = 114;
|
|
AjaxViewer.JS_KEY_F4 = 115;
|
|
AjaxViewer.JS_KEY_F5 = 116;
|
|
AjaxViewer.JS_KEY_F6 = 117;
|
|
AjaxViewer.JS_KEY_F7 = 118;
|
|
AjaxViewer.JS_KEY_F8 = 119;
|
|
AjaxViewer.JS_KEY_F9 = 120;
|
|
AjaxViewer.JS_KEY_F10 = 121;
|
|
AjaxViewer.JS_KEY_F11 = 122;
|
|
AjaxViewer.JS_KEY_F12 = 123;
|
|
AjaxViewer.JS_KEY_NUMLOCK = 144;
|
|
AjaxViewer.JS_KEY_SCROLLLOCK = 145;
|
|
AjaxViewer.JS_KEY_SEMI_COLON = 186; // ;
|
|
AjaxViewer.JS_KEY_EQUAL_SIGN = 187; // =
|
|
AjaxViewer.JS_KEY_COMMA = 188; // ,
|
|
AjaxViewer.JS_KEY_DASH = 189; // -
|
|
AjaxViewer.JS_KEY_PERIOD = 190; // .
|
|
AjaxViewer.JS_KEY_FORWARD_SLASH = 191; // /
|
|
AjaxViewer.JS_KEY_GRAVE_ACCENT = 192; // `
|
|
AjaxViewer.JS_KEY_OPEN_BRACKET = 219; // [
|
|
AjaxViewer.JS_KEY_BACK_SLASH = 220; // \
|
|
AjaxViewer.JS_KEY_CLOSE_BRACKET = 221; // ]
|
|
AjaxViewer.JS_KEY_SINGLE_QUOTE = 222; // '
|
|
AjaxViewer.JS_NUMPAD_PLUS = 43;
|
|
AjaxViewer.JS_NUMPAD_MULTIPLY = 42;
|
|
AjaxViewer.JS_KEY_NUM8 = 56;
|
|
|
|
// keycode from Japanese keyboard
|
|
AjaxViewer.JS_KEY_JP_COLON = 222; // :* on JP keyboard
|
|
AjaxViewer.JS_KEY_JP_CLOSE_BRACKET = 220; // [{ on JP keyboard
|
|
AjaxViewer.JS_KEY_JP_AT_SIGN = 219; // @` on JP keyboard
|
|
AjaxViewer.JS_KEY_JP_OPEN_BRACKET = 221; // [{ on JP keyboard
|
|
AjaxViewer.JS_KEY_JP_BACK_SLASH = 193; // \| on JP keyboard
|
|
AjaxViewer.JS_KEY_JP_YEN_MARK = 255;
|
|
|
|
AjaxViewer.JS_KEY_JP_EQUAL = 109; // -= ON JP keyboard
|
|
AjaxViewer.JS_KEY_JP_ACUTE = 107; // ^~ on JP keyboard
|
|
|
|
// X11 keysym definitions
|
|
AjaxViewer.X11_KEY_CAPSLOCK = 0xffe5;
|
|
AjaxViewer.X11_KEY_BACKSPACE = 0xff08;
|
|
AjaxViewer.X11_KEY_TAB = 0xff09;
|
|
AjaxViewer.X11_KEY_ENTER = 0xff0d;
|
|
AjaxViewer.X11_KEY_ESCAPE = 0xff1b;
|
|
AjaxViewer.X11_KEY_INSERT = 0xff63;
|
|
AjaxViewer.X11_KEY_DELETE = 0xffff;
|
|
AjaxViewer.X11_KEY_HOME = 0xff50;
|
|
AjaxViewer.X11_KEY_END = 0xff57;
|
|
AjaxViewer.X11_KEY_PAGEUP = 0xff55;
|
|
AjaxViewer.X11_KEY_PAGEDOWN = 0xff56;
|
|
AjaxViewer.X11_KEY_LEFT = 0xff51;
|
|
AjaxViewer.X11_KEY_UP = 0xff52;
|
|
AjaxViewer.X11_KEY_RIGHT = 0xff53;
|
|
AjaxViewer.X11_KEY_DOWN = 0xff54;
|
|
AjaxViewer.X11_KEY_F1 = 0xffbe;
|
|
AjaxViewer.X11_KEY_F2 = 0xffbf;
|
|
AjaxViewer.X11_KEY_F3 = 0xffc0;
|
|
AjaxViewer.X11_KEY_F4 = 0xffc1;
|
|
AjaxViewer.X11_KEY_F5 = 0xffc2;
|
|
AjaxViewer.X11_KEY_F6 = 0xffc3;
|
|
AjaxViewer.X11_KEY_F7 = 0xffc4;
|
|
AjaxViewer.X11_KEY_F8 = 0xffc5;
|
|
AjaxViewer.X11_KEY_F9 = 0xffc6;
|
|
AjaxViewer.X11_KEY_F10 = 0xffc7;
|
|
AjaxViewer.X11_KEY_F11 = 0xffc8;
|
|
AjaxViewer.X11_KEY_F12 = 0xffc9;
|
|
AjaxViewer.X11_KEY_SHIFT = 0xffe1;
|
|
AjaxViewer.X11_KEY_CTRL = 0xffe3;
|
|
AjaxViewer.X11_KEY_ALT = 0xffe9;
|
|
AjaxViewer.X11_KEY_SELECT_KEY = 0xff67;
|
|
AjaxViewer.X11_KEY_GRAVE_ACCENT = 0x60;
|
|
AjaxViewer.X11_KEY_SUBSTRACT = 0x2d;
|
|
AjaxViewer.X11_KEY_ADD = 0x2b;
|
|
AjaxViewer.X11_KEY_OPEN_BRACKET = 0x5b;
|
|
AjaxViewer.X11_KEY_CLOSE_BRACKET = 0x5d;
|
|
AjaxViewer.X11_KEY_BACK_SLASH = 0x7c;
|
|
AjaxViewer.X11_KEY_REVERSE_SOLIUS = 0x5c; // another back slash (back slash on JP keyboard)
|
|
AjaxViewer.X11_KEY_SINGLE_QUOTE = 0x22;
|
|
AjaxViewer.X11_KEY_COMMA = 0x3c;
|
|
AjaxViewer.X11_KEY_PERIOD = 0x3e;
|
|
AjaxViewer.X11_KEY_FORWARD_SLASH = 0x3f;
|
|
AjaxViewer.X11_KEY_DASH = 0x2d;
|
|
AjaxViewer.X11_KEY_COLON = 0x3a;
|
|
AjaxViewer.X11_KEY_SEMI_COLON = 0x3b;
|
|
AjaxViewer.X11_KEY_NUMPAD0 = 0x30;
|
|
AjaxViewer.X11_KEY_NUMPAD1 = 0x31;
|
|
AjaxViewer.X11_KEY_NUMPAD2 = 0x32;
|
|
AjaxViewer.X11_KEY_NUMPAD3 = 0x33;
|
|
AjaxViewer.X11_KEY_NUMPAD4 = 0x34;
|
|
AjaxViewer.X11_KEY_NUMPAD5 = 0x35;
|
|
AjaxViewer.X11_KEY_NUMPAD6 = 0x36;
|
|
AjaxViewer.X11_KEY_NUMPAD7 = 0x37;
|
|
AjaxViewer.X11_KEY_NUMPAD8 = 0x38;
|
|
AjaxViewer.X11_KEY_NUMPAD9 = 0x39;
|
|
AjaxViewer.X11_KEY_DECIMAL_POINT = 0x2e;
|
|
AjaxViewer.X11_KEY_DIVIDE = 0x3f;
|
|
AjaxViewer.X11_KEY_TILDE = 0x7e; // ~
|
|
AjaxViewer.X11_KEY_CIRCUMFLEX_ACCENT = 0x5e; // ^
|
|
AjaxViewer.X11_KEY_YEN_MARK = 0xa5; // Japanese YEN mark
|
|
AjaxViewer.X11_KEY_ASTERISK = 0x2a;
|
|
|
|
AjaxViewer.getEventName = function(type) {
|
|
switch(type) {
|
|
case AjaxViewer.MOUSE_MOVE :
|
|
return "MOUSE_MOVE";
|
|
|
|
case AjaxViewer.MOUSE_DOWN :
|
|
return "MOUSE_DOWN";
|
|
|
|
case AjaxViewer.MOUSE_UP :
|
|
return "MOUSE_UP";
|
|
|
|
case AjaxViewer.KEY_PRESS :
|
|
return "KEY_PRESS";
|
|
|
|
case AjaxViewer.KEY_DOWN :
|
|
return "KEY_DOWN";
|
|
|
|
case AjaxViewer.KEY_UP :
|
|
return "KEY_UP";
|
|
|
|
case AjaxViewer.EVENT_BAG :
|
|
return "EVENT_BAG";
|
|
|
|
case AjaxViewer.MOUSE_DBLCLK :
|
|
return "MOUSE_DBLCLK";
|
|
}
|
|
|
|
return "N/A";
|
|
};
|
|
|
|
AjaxViewer.prototype = {
|
|
setDirty: function(value) {
|
|
this.dirty = value;
|
|
},
|
|
|
|
isDirty: function() {
|
|
return this.dirty;
|
|
},
|
|
|
|
isImageLoaded: function() {
|
|
return this.imageLoaded;
|
|
},
|
|
|
|
refresh: function(imageUrl, tileMap, fullImage) {
|
|
var ajaxViewer = this;
|
|
var img = $(this.img);
|
|
this.fullImage = fullImage;
|
|
this.imgUrl=imageUrl;
|
|
|
|
img.attr('src', imageUrl).load(function() {
|
|
ajaxViewer.imageLoaded = true;
|
|
});
|
|
this.tileMap = tileMap;
|
|
},
|
|
|
|
resize: function(panelId, width, height, tileWidth, tileHeight) {
|
|
$(".canvas_tile", document.body).each(function() {
|
|
$(this).remove();
|
|
});
|
|
$("table", $("#" + panelId)).remove();
|
|
|
|
this.width = width;
|
|
this.height = height;
|
|
this.tileWidth = tileWidth;
|
|
this.tileHeight = tileHeight;
|
|
this.panel = this.generateCanvas(panelId, width, height, tileWidth, tileHeight);
|
|
},
|
|
|
|
start: function() {
|
|
var ajaxViewer = this;
|
|
this.timer = setInterval(function() { ajaxViewer.heartbeat(); }, 50);
|
|
|
|
$(document).bind("ajaxError", function(event, XMLHttpRequest, ajaxOptions, thrownError) {
|
|
ajaxViewer.onAjaxError(event, XMLHttpRequest, ajaxOptions, thrownError);
|
|
});
|
|
|
|
this.eventQueue = []; // reset event queue
|
|
this.sendingEventInProgress = false;
|
|
ajaxViewer.installMouseHook();
|
|
ajaxViewer.installKeyboardHook();
|
|
|
|
$(window).bind("resize", function() {
|
|
ajaxViewer.onWindowResize();
|
|
});
|
|
},
|
|
|
|
stop: function() {
|
|
clearInterval(this.timer);
|
|
this.deleteCanvas();
|
|
|
|
this.uninstallMouseHook();
|
|
this.uninstallKeyboardHook();
|
|
this.eventQueue = [];
|
|
this.sendingEventInProgress = false;
|
|
|
|
$(document).unbind("ajaxError");
|
|
$(window).unbind("resize");
|
|
},
|
|
|
|
sendMouseEvent: function(event, x, y, whichButton, modifiers) {
|
|
this.eventQueue.push({
|
|
type: AjaxViewer.EVENT_QUEUE_MOUSE_EVENT,
|
|
event: event,
|
|
x: x,
|
|
y: y,
|
|
code: whichButton,
|
|
modifiers: modifiers
|
|
});
|
|
this.checkEventQueue();
|
|
},
|
|
//NEW insert the keyboard tables file here
|
|
// ajaxKeys.js
|
|
|
|
setupKeyboardTranslationTable : function() {
|
|
this.keyboardMappers = [];
|
|
|
|
var mapper = new KeyboardMapper();
|
|
this.keyboardMappers[AjaxViewer.KEYBOARD_TYPE_ENGLISH] = mapper;
|
|
mapper.setKeyboardType(KeyboardMapper.KEYBOARD_TYPE_COOKED);
|
|
|
|
var mapper = new KeyboardMapper();
|
|
this.keyboardMappers[AjaxViewer.KEYBOARD_TYPE_UK_ENGLISH] = mapper;
|
|
mapper.setKeyboardType(KeyboardMapper.KEYBOARD_TYPE_UK);
|
|
|
|
mapper = new KeyboardMapper();
|
|
this.keyboardMappers[AjaxViewer.KEYBOARD_TYPE_JAPANESE] = mapper;
|
|
mapper.setKeyboardType(KeyboardMapper.KEYBOARD_TYPE_RAW);
|
|
|
|
var mapper = new KeyboardMapper();
|
|
this.keyboardMappers[AjaxViewer.KEYBOARD_TYPE_FRENCH] = mapper;
|
|
mapper.setKeyboardType(KeyboardMapper.KEYBOARD_TYPE_FR);
|
|
|
|
// JP keyboard plugged in a English host OS
|
|
/*
|
|
mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_COLON] = AjaxViewer.X11_KEY_COLON;
|
|
mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_CLOSE_BRACKET] = AjaxViewer.X11_KEY_CLOSE_BRACKET;
|
|
mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_AT_SIGN] = AjaxViewer.X11_KEY_GRAVE_ACCENT;
|
|
mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_OPEN_BRACKET] = AjaxViewer.X11_KEY_OPEN_BRACKET;
|
|
mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_BACK_SLASH] = AjaxViewer.X11_KEY_REVERSE_SOLIUS; // X11 REVERSE SOLIDUS
|
|
mapper.jsX11KeysymMap[AjaxViewer.JS_KEY_JP_YEN_MARK] = AjaxViewer.X11_KEY_YEN_MARK; // X11 YEN SIGN
|
|
mapper.jsKeyPressX11KeysymMap[61] = [
|
|
{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_CIRCUMFLEX_ACCENT, modifiers: 0 },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_CIRCUMFLEX_ACCENT, modifiers: 0 },
|
|
];
|
|
|
|
mapper.jsKeyPressX11KeysymMap[43] = [
|
|
{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false },
|
|
{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false },
|
|
{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_TILDE, modifiers: 0, shift: true },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_TILDE, modifiers: 0, shift: true }
|
|
];
|
|
*/
|
|
|
|
/* Old
|
|
// JP keyboard plugged in a Japanese host OS
|
|
mapper.jsX11KeysymMap[222] = AjaxViewer.X11_KEY_CIRCUMFLEX_ACCENT;
|
|
mapper.jsX11KeysymMap[220] = AjaxViewer.X11_KEY_YEN_MARK;
|
|
mapper.jsX11KeysymMap[219] = AjaxViewer.X11_KEY_OPEN_BRACKET;
|
|
mapper.jsX11KeysymMap[221] = AjaxViewer.X11_KEY_CLOSE_BRACKET;
|
|
mapper.jsX11KeysymMap[59] = AjaxViewer.X11_KEY_COLON; // Firefox
|
|
mapper.jsX11KeysymMap[186] = AjaxViewer.X11_KEY_COLON; // Chrome
|
|
mapper.jsX11KeysymMap[226] = AjaxViewer.X11_KEY_REVERSE_SOLIUS; // \| key left to right SHIFT on JP keyboard
|
|
mapper.jsX11KeysymMap[240] = [
|
|
{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_CAPSLOCK, modifiers: 0 },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_CAPSLOCK, modifiers: 0 },
|
|
];
|
|
|
|
// for keycode 107, keypress 59
|
|
mapper.jsKeyPressX11KeysymMap[59] = [
|
|
{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SEMI_COLON, modifiers: 0 },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SEMI_COLON, modifiers: 0 },
|
|
];
|
|
|
|
// for keycode 107, keypress 43
|
|
mapper.jsKeyPressX11KeysymMap[43] = [
|
|
{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false },
|
|
{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: false },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0, shift: false },
|
|
{type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: true },
|
|
{type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ADD, modifiers: 0, shift: true },
|
|
];
|
|
|
|
*/
|
|
// create the mapping table based on the tables input
|
|
if (keyboardTables != undefined ) {
|
|
|
|
for(var i = 0; i < keyboardTables.length; i++) {
|
|
var mappingTbl = keyboardTables[i];
|
|
var keyboardType = mappingTbl.keyboardType;
|
|
var mappings = mappingTbl.mappingTable;
|
|
var x11Maps = mappings.X11;
|
|
for (var j = 0; j < x11Maps.length; j++) {
|
|
var code = x11Maps[j].keycode;
|
|
var mappedEntry = x11Maps[j].entry;
|
|
if(x11Maps[j].guestos == undefined || x11Maps[j].guestos == this.guestos) {
|
|
this.keyboardMappers[keyboardType].jsX11KeysymMap[code] = mappedEntry;
|
|
}
|
|
}
|
|
var keyPressMaps = mappings.keyPress;
|
|
for (var j = 0; j < keyPressMaps.length; j++) {
|
|
var code = keyPressMaps[j].keycode;
|
|
var mappedEntry = keyPressMaps[j].entry;
|
|
if(keyPressMaps[j].guestos == undefined || keyPressMaps[j].guestos == this.guestos) {
|
|
this.keyboardMappers[keyboardType].jsKeyPressX11KeysymMap[code] = mappedEntry;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}, // end of the setupKeyboardTranslationTable function
|
|
|
|
getCurrentKeyboardMapper : function() {
|
|
return this.keyboardMappers[this.currentKeyboard];
|
|
},
|
|
|
|
setupUIController : function() {
|
|
var ajaxViewer = this;
|
|
var pullDownElement = $("#toolbar").find(".pulldown");
|
|
pullDownElement.hover(
|
|
function(e) {
|
|
var subMenu = pullDownElement.find("ul");
|
|
var offset = subMenu.parent().offset();
|
|
subMenu.css("left", offset.left);
|
|
|
|
$("li.current").removeClass("current");
|
|
$("li:has(a[cmd$=" + ajaxViewer.currentKeyboard + "])", subMenu).addClass("current");
|
|
subMenu.css("z-index", "" + ajaxViewer.maxTileZIndex + 1).show();
|
|
return false;
|
|
},
|
|
|
|
function(e) {
|
|
pullDownElement.find("ul").hide();
|
|
return false;
|
|
}
|
|
);
|
|
|
|
$("[cmd]", "#toolbar").each(function(i, val) {
|
|
$(val).click(function(e) {
|
|
var cmd = $(e.target).attr("cmd");
|
|
if(cmd)
|
|
ajaxViewer.onCommand(cmd);
|
|
else {
|
|
var cmdLink = $(e.target).closest("a");
|
|
|
|
if(cmdLink.attr("cmd")) {
|
|
var cmd = cmdLink.attr("cmd");
|
|
ajaxViewer.onCommand(cmd);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
onCommand : function(cmd) {
|
|
if(cmd == "keyboard_jp") {
|
|
$("#toolbar").find(".pulldown").find("ul").hide();
|
|
this.currentKeyboard = AjaxViewer.KEYBOARD_TYPE_JAPANESE;
|
|
} else if(cmd == "keyboard_us") {
|
|
$("#toolbar").find(".pulldown").find("ul").hide();
|
|
this.currentKeyboard = AjaxViewer.KEYBOARD_TYPE_ENGLISH;
|
|
} else if(cmd == "keyboard_uk") {
|
|
$("#toolbar").find(".pulldown").find("ul").hide();
|
|
this.currentKeyboard = AjaxViewer.KEYBOARD_TYPE_UK_ENGLISH;
|
|
} else if(cmd == "keyboard_fr") {
|
|
$("#toolbar").find(".pulldown").find("ul").hide();
|
|
this.currentKeyboard = AjaxViewer.KEYBOARD_TYPE_FRENCH;
|
|
} else if(cmd == "sendCtrlAltDel") {
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xffe9, 0); // X11 Alt
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xffe3, 0); // X11 Ctrl
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xffff, 0); // X11 Del
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_UP, 0xffff, 0);
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_UP, 0xffe3, 0);
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_UP, 0xffe9, 0);
|
|
} else if(cmd == "sendCtrlEsc") {
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xffe3, 0); // X11 Ctrl
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, 0xff1b, 0); // X11 ESC
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_UP, 0xff1b, 0);
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_UP, 0xffe3, 0);
|
|
} else if(cmd == "toggle_logwin") {
|
|
if(!g_logger.isOpen()) {
|
|
g_logger.enable(true);
|
|
g_logger.open();
|
|
g_logger.log(Logger.LEVEL_SYS, "Accept languages: " + acceptLanguages + ", current language: " + getCurrentLanguage());
|
|
} else {
|
|
g_logger.close();
|
|
}
|
|
}
|
|
},
|
|
|
|
sendKeyboardEvent: function(event, code, modifiers) {
|
|
// back door to open logger window - CTRL-ATL-SHIFT+SPACE
|
|
if(code == 32 &&
|
|
(modifiers & AjaxViewer.SHIFT_KEY_MASK | AjaxViewer.CTRL_KEY_MASK | AjaxViewer.ALT_KEY_MASK) == (AjaxViewer.SHIFT_KEY_MASK | AjaxViewer.CTRL_KEY_MASK | AjaxViewer.ALT_KEY_MASK)) {
|
|
|
|
if(!g_logger.isOpen()) {
|
|
g_logger.enable(true);
|
|
g_logger.open();
|
|
g_logger.log(Logger.LEVEL_SYS, "Accept languages: " + acceptLanguages + ", current language: " + getCurrentLanguage());
|
|
} else {
|
|
g_logger.close();
|
|
}
|
|
}
|
|
|
|
var len;
|
|
g_logger.log(Logger.LEVEL_INFO, "Keyboard event: " + AjaxViewer.getEventName(event) + ", code: " + code + ", modifiers: " + modifiers + ', char: ' + String.fromCharCode(code));
|
|
this.eventQueue.push({
|
|
type: AjaxViewer.EVENT_QUEUE_KEYBOARD_EVENT,
|
|
event: event,
|
|
code: code,
|
|
modifiers: modifiers
|
|
});
|
|
|
|
if(event != AjaxViewer.KEY_DOWN)
|
|
this.checkEventQueue();
|
|
},
|
|
|
|
aggregateEvents: function() {
|
|
var ajaxViewer = this;
|
|
var aggratedQueue = [];
|
|
|
|
var aggregating = false;
|
|
var mouseX;
|
|
var mouseY;
|
|
$.each(ajaxViewer.eventQueue, function(index, item) {
|
|
if(item.type != AjaxViewer.EVENT_QUEUE_MOUSE_EVENT) {
|
|
aggratedQueue.push(item);
|
|
} else {
|
|
if(!aggregating) {
|
|
if(item.event == AjaxViewer.MOUSE_MOVE) {
|
|
aggregating = true;
|
|
mouseX = item.x;
|
|
mouseY = item.y;
|
|
} else {
|
|
aggratedQueue.push(item);
|
|
}
|
|
} else {
|
|
if(item.event == AjaxViewer.MOUSE_MOVE) {
|
|
// continue to aggregate mouse move event
|
|
mouseX = item.x;
|
|
mouseY = item.y;
|
|
} else {
|
|
aggratedQueue.push({
|
|
type: AjaxViewer.EVENT_QUEUE_MOUSE_EVENT,
|
|
event: AjaxViewer.MOUSE_MOVE,
|
|
x: mouseX,
|
|
y: mouseY,
|
|
code: 0,
|
|
modifiers: 0
|
|
});
|
|
aggregating = false;
|
|
|
|
aggratedQueue.push(item);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
if(aggregating) {
|
|
aggratedQueue.push({
|
|
type: AjaxViewer.EVENT_QUEUE_MOUSE_EVENT,
|
|
event: AjaxViewer.MOUSE_MOVE,
|
|
x: mouseX,
|
|
y: mouseY,
|
|
code: 0,
|
|
modifiers: 0
|
|
});
|
|
}
|
|
|
|
this.eventQueue = aggratedQueue;
|
|
},
|
|
|
|
checkEventQueue: function() {
|
|
var ajaxViewer = this;
|
|
|
|
if(!this.sendingEventInProgress && this.eventQueue.length > 0) {
|
|
var sb = new StringBuilder();
|
|
sb.append(""+this.eventQueue.length).append("|");
|
|
$.each(this.eventQueue, function() {
|
|
var item = this;
|
|
if(item.type == AjaxViewer.EVENT_QUEUE_MOUSE_EVENT) {
|
|
sb.append(""+item.type).append("|");
|
|
sb.append(""+item.event).append("|");
|
|
sb.append(""+item.x).append("|");
|
|
sb.append(""+item.y).append("|");
|
|
sb.append(""+item.code).append("|");
|
|
sb.append(""+item.modifiers).append("|");
|
|
} else {
|
|
sb.append(""+item.type).append("|");
|
|
sb.append(""+item.event).append("|");
|
|
sb.append(""+item.code).append("|");
|
|
sb.append(""+item.modifiers).append("|");
|
|
}
|
|
});
|
|
this.eventQueue.length = 0;
|
|
|
|
var url = ajaxViewer.updateUrl + "&event=" + AjaxViewer.EVENT_BAG;
|
|
|
|
g_logger.log(Logger.LEVEL_TRACE, "Posting client event " + sb.toString() + "...");
|
|
|
|
ajaxViewer.sendingEventInProgress = true;
|
|
window.onStatusNotify(AjaxViewer.STATUS_SENDING);
|
|
$.post(url, {data: sb.toString()}, function(data, textStatus) {
|
|
g_logger.log(Logger.LEVEL_TRACE, "Client event " + sb.toString() + " is posted");
|
|
|
|
ajaxViewer.sendingEventInProgress = false;
|
|
window.onStatusNotify(AjaxViewer.STATUS_SENT);
|
|
|
|
ajaxViewer.checkUpdate();
|
|
}, 'html');
|
|
}
|
|
},
|
|
|
|
onAjaxError: function(event, XMLHttpRequest, ajaxOptions, thrownError) {
|
|
if(window.onClientError != undefined && jQuery.isFunction(window.onClientError)) {
|
|
window.onClientError();
|
|
}
|
|
},
|
|
|
|
onWindowResize: function() {
|
|
var offset = this.panel.offset();
|
|
|
|
var row = $('tr:first', this.panel);
|
|
var cell = $('td:first', row);
|
|
var tile = this.getTile(cell, 'tile');
|
|
|
|
var tileOffset = tile.offset();
|
|
var deltaX = offset.left - tileOffset.left;
|
|
var deltaY = offset.top - tileOffset.top;
|
|
|
|
if(deltaX != 0 || deltaY != 0) {
|
|
$(".canvas_tile").each(function() {
|
|
var offsetFrom = $(this).offset();
|
|
$(this).css('left', offsetFrom.left + deltaX).css('top', offsetFrom.top + deltaY);
|
|
});
|
|
}
|
|
},
|
|
|
|
deleteCanvas: function() {
|
|
$('.canvas_tile', $(document.body)).each(function() {
|
|
$(this).remove();
|
|
});
|
|
},
|
|
|
|
generateCanvas: function(wrapperDivId, width, height, tileWidth, tileHeight) {
|
|
var canvasParent = $('#' + wrapperDivId);
|
|
canvasParent.width(width);
|
|
canvasParent.height(height);
|
|
|
|
if(window.onCanvasSizeChange != undefined && jQuery.isFunction(window.onCanvasSizeChange))
|
|
window.onCanvasSizeChange(width, height);
|
|
|
|
var tableDef = '<table cellpadding="0px" cellspacing="0px">\r\n';
|
|
var i = 0;
|
|
var j = 0;
|
|
for(i = 0; i < Math.ceil((height + tileHeight - 1) / tileHeight); i++) {
|
|
var rowHeight = Math.min(height - i*tileHeight, tileHeight);
|
|
tableDef += '<tr style="height:' + rowHeight + 'px">\r\n';
|
|
|
|
for(j = 0; j < Math.ceil((width + tileWidth - 1) / tileWidth); j++) {
|
|
var colWidth = Math.min(width - j*tileWidth, tileWidth);
|
|
tableDef += '<td width="' + colWidth + 'px"></td>\r\n';
|
|
}
|
|
tableDef += '</tr>\r\n';
|
|
}
|
|
tableDef += '</table>\r\n';
|
|
|
|
return $(tableDef).appendTo(canvasParent);
|
|
},
|
|
|
|
getTile: function(cell, name) {
|
|
var clonedDiv = cell.data(name);
|
|
if(!clonedDiv) {
|
|
var offset = cell.offset();
|
|
var divDef = "<div class=\"canvas_tile\" style=\"z-index:1;position:absolute;overflow:hidden;width:" + cell.width() + "px;height:"
|
|
+ cell.height() + "px;left:" + offset.left + "px;top:" + offset.top+"px\"></div>";
|
|
|
|
clonedDiv = $(divDef).appendTo($(document.body));
|
|
cell.data(name, clonedDiv);
|
|
}
|
|
|
|
return clonedDiv;
|
|
},
|
|
|
|
initCell: function(cell) {
|
|
if(!cell.data("init")) {
|
|
cell.data("init", true);
|
|
|
|
cell.data("current", 0);
|
|
this.getTile(cell, "tile2");
|
|
this.getTile(cell, "tile");
|
|
}
|
|
},
|
|
|
|
displayCell: function(cell, bg) {
|
|
var div;
|
|
var divPrev;
|
|
if(!cell.data("current")) {
|
|
cell.data("current", 1);
|
|
|
|
divPrev = this.getTile(cell, "tile");
|
|
div = this.getTile(cell, "tile2");
|
|
} else {
|
|
cell.data("current", 0);
|
|
divPrev = this.getTile(cell, "tile2");
|
|
div = this.getTile(cell, "tile");
|
|
}
|
|
|
|
var zIndex = parseInt(divPrev.css("z-index")) + 1;
|
|
this.maxTileZIndex = Math.max(this.maxTileZIndex, zIndex);
|
|
div.css("z-index", zIndex);
|
|
div.css("background", bg);
|
|
},
|
|
|
|
updateTile: function() {
|
|
if(this.dirty) {
|
|
var ajaxViewer = this;
|
|
var tileWidth = this.tileWidth;
|
|
var tileHeight = this.tileHeight;
|
|
var imgUrl = this.imgUrl;
|
|
var panel = this.panel;
|
|
|
|
if(this.fullImage) {
|
|
$.each(this.tileMap, function() {
|
|
var i = $(this)[0];
|
|
var j = $(this)[1];
|
|
var row = $("TR:eq("+i+")", panel);
|
|
var cell = $("TD:eq("+j+")", row);
|
|
var attr = "url(" + imgUrl + ") -"+j*tileWidth+"px -"+i*tileHeight + "px";
|
|
|
|
ajaxViewer.initCell(cell);
|
|
ajaxViewer.displayCell(cell, attr);
|
|
});
|
|
} else {
|
|
$.each(this.tileMap, function(index) {
|
|
var i = $(this)[0];
|
|
var j = $(this)[1];
|
|
var offset = index*tileWidth;
|
|
var attr = "url(" + imgUrl + ") no-repeat -"+offset+"px 0px";
|
|
var row = $("TR:eq("+i+")", panel);
|
|
var cell = $("TD:eq("+j+")", row);
|
|
|
|
ajaxViewer.initCell(cell);
|
|
ajaxViewer.displayCell(cell, attr);
|
|
});
|
|
}
|
|
|
|
this.dirty = false;
|
|
}
|
|
},
|
|
|
|
heartbeat: function() {
|
|
this.checkEventQueue();
|
|
this.checkUpdate();
|
|
},
|
|
|
|
checkUpdate: function() {
|
|
if(!this.isDirty())
|
|
return;
|
|
|
|
if(this.isImageLoaded()) {
|
|
this.updateTile();
|
|
var url = this.updateUrl;
|
|
var ajaxViewer = this;
|
|
|
|
window.onStatusNotify(AjaxViewer.STATUS_RECEIVING);
|
|
$.getScript(url, function(data, textStatus) {
|
|
if(/^<html>/.test(data)) {
|
|
ajaxViewer.stop();
|
|
$(document.body).html(data);
|
|
} else {
|
|
eval(data);
|
|
ajaxViewer.setDirty(true);
|
|
window.onStatusNotify(AjaxViewer.STATUS_RECEIVED);
|
|
|
|
ajaxViewer.checkUpdate();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
ptInPanel: function(pageX, pageY) {
|
|
var mainPanel = this.panel;
|
|
|
|
var offset = mainPanel.offset();
|
|
var x = pageX - offset.left;
|
|
var y = pageY - offset.top;
|
|
|
|
if(x < 0 || y < 0 || x > mainPanel.width() - 1 || y > mainPanel.height() - 1)
|
|
return false;
|
|
return true;
|
|
},
|
|
|
|
pageToPanel: function(pageX, pageY) {
|
|
var mainPanel = this.panel;
|
|
|
|
var offset = mainPanel.offset();
|
|
var x = pageX - offset.left;
|
|
var y = pageY - offset.top;
|
|
|
|
if(x < 0)
|
|
x = 0;
|
|
if(x > mainPanel.width() - 1)
|
|
x = mainPanel.width() - 1;
|
|
|
|
if(y < 0)
|
|
y = 0;
|
|
if(y > mainPanel.height() - 1)
|
|
y = mainPanel.height() - 1;
|
|
|
|
return { x: Math.ceil(x), y: Math.ceil(y) };
|
|
},
|
|
|
|
installMouseHook: function() {
|
|
var ajaxViewer = this;
|
|
var target = $(document.body);
|
|
|
|
target.mousemove(function(e) {
|
|
if(!ajaxViewer.ptInPanel(e.pageX, e.pageY))
|
|
return true;
|
|
|
|
var pt = ajaxViewer.pageToPanel(e.pageX, e.pageY);
|
|
ajaxViewer.onMouseMove(pt.x, pt.y);
|
|
|
|
e.stopPropagation();
|
|
return false;
|
|
});
|
|
|
|
target.mousedown(function(e) {
|
|
ajaxViewer.panel.parent().focus();
|
|
|
|
if(!ajaxViewer.ptInPanel(e.pageX, e.pageY))
|
|
return true;
|
|
|
|
var modifiers = ajaxViewer.getKeyModifiers(e);
|
|
var whichButton = e.button;
|
|
|
|
var pt = ajaxViewer.pageToPanel(e.pageX, e.pageY);
|
|
ajaxViewer.onMouseDown(pt.x, pt.y, whichButton, modifiers);
|
|
|
|
e.stopPropagation();
|
|
return false;
|
|
});
|
|
|
|
target.mouseup(function(e) {
|
|
if(!ajaxViewer.ptInPanel(e.pageX, e.pageY))
|
|
return true;
|
|
|
|
var modifiers = ajaxViewer.getKeyModifiers(e);
|
|
var whichButton = e.button;
|
|
|
|
var pt = ajaxViewer.pageToPanel(e.pageX, e.pageY);
|
|
|
|
ajaxViewer.onMouseUp(pt.x, pt.y, whichButton, modifiers);
|
|
e.stopPropagation();
|
|
return false;
|
|
});
|
|
|
|
// disable browser right-click context menu
|
|
target.bind("contextmenu", function() { return false; });
|
|
},
|
|
|
|
uninstallMouseHook : function() {
|
|
var target = $(document);
|
|
target.unbind("mousemove");
|
|
target.unbind("mousedown");
|
|
target.unbind("mouseup");
|
|
target.unbind("contextmenu");
|
|
},
|
|
|
|
requiresDefaultKeyProcess : function(e) {
|
|
switch(e.which) {
|
|
case 8 : // backspace
|
|
case 9 : // TAB
|
|
case 19 : // PAUSE/BREAK
|
|
case 20 : // CAPSLOCK
|
|
case 27 : // ESCAPE
|
|
case 16 : // SHIFT key
|
|
case 17 : // CTRL key
|
|
case 18 : // ALT key
|
|
case 33 : // PGUP
|
|
case 34 : // PGDN
|
|
case 35 : // END
|
|
case 36 : // HOME
|
|
case 37 : // LEFT
|
|
case 38 : // UP
|
|
case 39 : // RIGHT
|
|
case 40 : // DOWN
|
|
return false;
|
|
}
|
|
|
|
if(this.getKeyModifiers(e) == AjaxViewer.SHIFT_KEY_MASK)
|
|
return true;
|
|
|
|
if(this.getKeyModifiers(e) != 0)
|
|
return false;
|
|
|
|
return true;
|
|
},
|
|
|
|
installKeyboardHook: function() {
|
|
var ajaxViewer = this;
|
|
var target = $(document);
|
|
|
|
target.keypress(function(e) {
|
|
ajaxViewer.onKeyPress(e.which, ajaxViewer.getKeyModifiers(e));
|
|
|
|
e.stopPropagation();
|
|
if(ajaxViewer.requiresDefaultKeyProcess(e))
|
|
return true;
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
});
|
|
|
|
target.keydown(function(e) {
|
|
ajaxViewer.onKeyDown(e.which, ajaxViewer.getKeyModifiers(e));
|
|
|
|
e.stopPropagation();
|
|
if(ajaxViewer.requiresDefaultKeyProcess(e))
|
|
return true;
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
});
|
|
|
|
target.keyup(function(e) {
|
|
ajaxViewer.onKeyUp(e.which, ajaxViewer.getKeyModifiers(e));
|
|
|
|
e.stopPropagation();
|
|
if(ajaxViewer.requiresDefaultKeyProcess(e))
|
|
return true;
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
});
|
|
},
|
|
|
|
uninstallKeyboardHook : function() {
|
|
var target = $(document);
|
|
target.unbind("keypress");
|
|
target.unbind("keydown");
|
|
target.unbind("keyup");
|
|
},
|
|
|
|
onMouseMove: function(x, y) {
|
|
this.sendMouseEvent(AjaxViewer.MOUSE_MOVE, x, y, 0, 0);
|
|
},
|
|
|
|
onMouseDown: function(x, y, whichButton, modifiers) {
|
|
this.sendMouseEvent(AjaxViewer.MOUSE_DOWN, x, y, whichButton, modifiers);
|
|
},
|
|
|
|
onMouseUp: function(x, y, whichButton, modifiers) {
|
|
this.sendMouseEvent(AjaxViewer.MOUSE_UP, x, y, whichButton, modifiers);
|
|
|
|
var curTick = new Date().getTime();
|
|
if(this.lastClickEvent.time && (curTick - this.lastClickEvent.time < 300)) {
|
|
this.onMouseDblClick(this.lastClickEvent.x, this.lastClickEvent.y,
|
|
this.lastClickEvent.button, this.lastClickEvent.modifiers);
|
|
}
|
|
|
|
this.lastClickEvent.x = x;
|
|
this.lastClickEvent.y = y;
|
|
this.lastClickEvent.button = whichButton;
|
|
this.lastClickEvent.modifiers = modifiers;
|
|
this.lastClickEvent.time = curTick;
|
|
},
|
|
|
|
onMouseDblClick: function(x, y, whichButton, modifiers) {
|
|
this.sendMouseEvent(AjaxViewer.MOUSE_DBLCLK, x, y, whichButton, modifiers);
|
|
},
|
|
|
|
onKeyPress: function(code, modifiers) {
|
|
g_logger.log(Logger.LEVEL_WARN, "RAW KEYBOARD EVENT. KEY-PRESS: " + code + ", modifers: " + modifiers);
|
|
|
|
this.dispatchKeyboardInput(AjaxViewer.KEY_PRESS, code, modifiers);
|
|
},
|
|
|
|
onKeyDown: function(code, modifiers) {
|
|
g_logger.log(Logger.LEVEL_WARN, "RAW KEYBOARD EVENT. KEY-DOWN: " + code + ", modifers: " + modifiers);
|
|
|
|
this.dispatchKeyboardInput(AjaxViewer.KEY_DOWN, code, modifiers);
|
|
},
|
|
|
|
onKeyUp: function(code, modifiers) {
|
|
g_logger.log(Logger.LEVEL_WARN, "RAW KEYBOARD EVENT. KEY-UP: " + code + ", modifers: " + modifiers);
|
|
|
|
this.dispatchKeyboardInput(AjaxViewer.KEY_UP, code, modifiers);
|
|
},
|
|
|
|
dispatchKeyboardInput : function(event, code, modifiers) {
|
|
var keyboardMapper = ajaxViewer.getCurrentKeyboardMapper();
|
|
keyboardMapper.inputFeed(event, code, modifiers, this.guestos, $.browser, $.browser.version);
|
|
this.dispatchMappedKeyboardInput(keyboardMapper.getMappedInput());
|
|
},
|
|
|
|
dispatchMappedKeyboardInput : function(mappedInput) {
|
|
for(var i = 0; i < mappedInput.length; i++) {
|
|
switch(mappedInput[i].type) {
|
|
case AjaxViewer.KEY_DOWN :
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_DOWN, mappedInput[i].code, mappedInput[i].modifiers);
|
|
break;
|
|
|
|
case AjaxViewer.KEY_UP :
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_UP, mappedInput[i].code, mappedInput[i].modifiers);
|
|
break;
|
|
|
|
case AjaxViewer.KEY_PRESS :
|
|
this.sendKeyboardEvent(AjaxViewer.KEY_PRESS, mappedInput[i].code, mappedInput[i].modifiers);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
getKeyModifiers: function(e) {
|
|
var modifiers = 0;
|
|
if(e.altKey)
|
|
modifiers |= AjaxViewer.ALT_KEY_MASK;
|
|
|
|
if(e.altLeft)
|
|
modifiers |= AjaxViewer.LEFT_ALT_MASK;
|
|
|
|
if(e.ctrlKey)
|
|
modifiers |= AjaxViewer.CTRL_KEY_MASK;
|
|
|
|
if(e.ctrlLeft)
|
|
modifiers |= AjaxViewer.LEFT_CTRL_MASK;
|
|
|
|
if(e.shiftKey)
|
|
modifiers |= AjaxViewer.SHIFT_KEY_MASK;
|
|
|
|
if(e.shiftLeft)
|
|
modifiers |= AjaxViewer.LEFT_SHIFT_MASK;
|
|
|
|
if(e.metaKey)
|
|
modifiers |= AjaxViewer.META_KEY_MASK;
|
|
|
|
return modifiers;
|
|
}
|
|
};
|
|
|