mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
All (almost) files belonging to the systemvm aer now centralize in the systemvm directory. The code for the separate functions is still in the services directory. This will make the code easier to understand and makes it clear that the systemvm is a separate item. It alos means that it can be excluded from the build entirely by not adding the systemvm profile, this will speed up the compiles somewhat.
1384 lines
44 KiB
JavaScript
1384 lines
44 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.prototype = {
|
|
|
|
setKeyboardType : function(keyboardType) {
|
|
this.keyboardType = keyboardType;
|
|
if(keyboardType == KeyboardMapper.KEYBOARD_TYPE_COOKED || keyboardType == KeyboardMapper.KEYBOARD_TYPE_UK) {
|
|
// 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) {
|
|
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 {
|
|
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) {
|
|
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});
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
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;
|
|
}
|
|
|
|
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, 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.dirty = true;
|
|
this.width = width;
|
|
this.height = height;
|
|
this.tileWidth = tileWidth;
|
|
this.tileHeight = tileHeight;
|
|
this.maxTileZIndex = 1;
|
|
|
|
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.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);
|
|
|
|
// 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;
|
|
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;
|
|
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 == "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;
|
|
}
|
|
};
|
|
|