mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1418 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1418 lines
		
	
	
		
			48 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.prototype = {
 | |
| 		
 | |
| 	setKeyboardType : function(keyboardType) {
 | |
| 		this.keyboardType = keyboardType;
 | |
| 		
 | |
| 		if(keyboardType == KeyboardMapper.KEYBOARD_TYPE_RAW) {
 | |
| 			// intialize keyboard mapping for RAW 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_GRAVE_ACCENT] 	= AjaxViewer.X11_KEY_GRAVE_ACCENT;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_SUBSTRACT] 		= AjaxViewer.X11_KEY_SUBSTRACT;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_ADD] 				= AjaxViewer.X11_KEY_ADD;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_OPEN_BRACKET] 	= AjaxViewer.X11_KEY_OPEN_BRACKET;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_CLOSE_BRACKET] 	= AjaxViewer.X11_KEY_CLOSE_BRACKET;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_BACK_SLASH] 		= AjaxViewer.X11_KEY_BACK_SLASH;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_SINGLE_QUOTE] 	= AjaxViewer.X11_KEY_SINGLE_QUOTE;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_COMMA] 			= AjaxViewer.X11_KEY_COMMA;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_PERIOD] 			= AjaxViewer.X11_KEY_PERIOD;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_FORWARD_SLASH] 	= AjaxViewer.X11_KEY_FORWARD_SLASH;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_DASH] 			= AjaxViewer.X11_KEY_DASH;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_SEMI_COLON] 		= AjaxViewer.X11_KEY_SEMI_COLON;
 | |
| 
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD0] 			= AjaxViewer.X11_KEY_NUMPAD0;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD1] 			= AjaxViewer.X11_KEY_NUMPAD1;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD2] 			= AjaxViewer.X11_KEY_NUMPAD2;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD3] 			= AjaxViewer.X11_KEY_NUMPAD3;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD4] 			= AjaxViewer.X11_KEY_NUMPAD4;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD5] 			= AjaxViewer.X11_KEY_NUMPAD5;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD6] 			= AjaxViewer.X11_KEY_NUMPAD6;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD7] 			= AjaxViewer.X11_KEY_NUMPAD7;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD8] 			= AjaxViewer.X11_KEY_NUMPAD8;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_NUMPAD9] 			= AjaxViewer.X11_KEY_NUMPAD9;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_DECIMAL_POINT] 	= AjaxViewer.X11_KEY_DECIMAL_POINT;
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_DIVIDE] 			= AjaxViewer.X11_KEY_DIVIDE;
 | |
| 			
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_MULTIPLY] = [
 | |
| 			    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0 },
 | |
| 			    {type: AjaxViewer.KEY_DOWN, code: AjaxViewer.X11_KEY_ASTERISK, modifiers: 0 },
 | |
| 			    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_ASTERISK, modifiers: 0 },
 | |
| 			    {type: AjaxViewer.KEY_UP, code: AjaxViewer.X11_KEY_SHIFT, modifiers: 0 }
 | |
| 			];
 | |
| 			
 | |
| 			this.jsX11KeysymMap[AjaxViewer.JS_KEY_ADD] = false;
 | |
| 			this.jsKeyPressX11KeysymMap = [];
 | |
| 			this.jsKeyPressX11KeysymMap[61] = [
 | |
| 			    {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 }
 | |
| 			];
 | |
| 			this.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 }
 | |
| 			];
 | |
| 		} else {
 | |
| 			// 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;
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	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++) {
 | |
| 						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.setupKeyboardTranslationTable();
 | |
| 	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_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_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();
 | |
| 	},
 | |
| 	
 | |
| 	setupKeyboardTranslationTable : function() {
 | |
| 		this.keyboardMappers = [];
 | |
| 		
 | |
| 		var mapper = new KeyboardMapper();
 | |
| 		this.keyboardMappers[AjaxViewer.KEYBOARD_TYPE_ENGLISH] = mapper;
 | |
| 		mapper.setKeyboardType(KeyboardMapper.KEYBOARD_TYPE_COOKED);
 | |
| 		
 | |
| 		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 }
 | |
|         ];
 | |
| */		
 | |
| 		
 | |
| 		// 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 },
 | |
|         ];
 | |
| 	},
 | |
| 	
 | |
| 	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 == "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;
 | |
| 	}
 | |
| };
 | |
| 
 |