You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2019/07/22 05:36:28 UTC

[openmeetings] branch master updated: [OPENMEETINGS-2078] hotkeys should be layout-independent

This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git


The following commit(s) were added to refs/heads/master by this push:
     new 6629afc  [OPENMEETINGS-2078] hotkeys should be layout-independent
6629afc is described below

commit 6629afc8f78f6bb5d738ffe9e519b9587ce4a794
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Mon Jul 22 12:25:31 2019 +0700

    [OPENMEETINGS-2078] hotkeys should be layout-independent
---
 .../db/dao/basic/ConfigurationDao.java             |    4 +-
 .../installation/ImportInitvalues.java             |    2 +-
 .../web/admin/configurations/ConfigsPanel.html     |    7 +-
 .../org/apache/openmeetings/web/common/main.js     | 1267 ++++++++++----------
 .../org/apache/openmeetings/web/room/raw-room.js   |    3 +-
 5 files changed, 650 insertions(+), 633 deletions(-)

diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java
index da48610..f3636df 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java
@@ -565,7 +565,7 @@ public class ConfigurationDao implements IDataProviderDao<Configuration> {
 				.put("alt", parts.contains("Alt"))
 				.put("shift", parts.contains("Shift"))
 				.put("ctrl", parts.contains("Ctrl"))
-				.put("key", partList.get(partList.size() - 1));
+				.put("code", partList.get(partList.size() - 1));
 	}
 
 	private JSONObject reloadRoomSettings() {
@@ -575,7 +575,7 @@ public class ConfigurationDao implements IDataProviderDao<Configuration> {
 							.put("arrange", getHotkey(getString(CONFIG_KEYCODE_ARRANGE, "Shift+F8")))
 							.put("muteothers", getHotkey(getString(CONFIG_KEYCODE_MUTE_OTHERS, "Shift+F12")))
 							.put("mute", getHotkey(getString(CONFIG_KEYCODE_MUTE, "Shift+F7")))
-							.put("quickpoll", getHotkey(getString(CONFIG_KEYCODE_QUICKPOLL, "Ctrl+Alt+Q")))
+							.put("quickpoll", getHotkey(getString(CONFIG_KEYCODE_QUICKPOLL, "Ctrl+Alt+KeyQ")))
 							)
 					.put("camera", new JSONObject().put("fps", getLong(CONFIG_CAM_FPS, 30L)))
 					.put("microphone", new JSONObject()
diff --git a/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java b/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java
index 4628e8f..5e11f5b 100644
--- a/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java
+++ b/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java
@@ -352,7 +352,7 @@ public class ImportInitvalues {
 		addCfg(list, CONFIG_MIC_NOISE, String.valueOf(true), Configuration.Type.BOOL, "Whether noise suppression is preferred and/or required.", VER_5_0_0);
 		addCfg(list, CONFIG_CSP_XFRAME, HEADER_XFRAME_SELF, Configuration.Type.STRING, String.format("Value for 'frame-src' directive of 'Content-Security-Policy' header (default: %s), more info: https://w3c.github.io/webappsec-csp/", HEADER_XFRAME_SELF), VER_5_0_0);
 		addCfg(list, CONFIG_DISPLAY_NAME_EDITABLE, String.valueOf(false), Configuration.Type.BOOL, "Is user will be able to edit his/her display name (default false).", "4.0.7");
-		addCfg(list, CONFIG_KEYCODE_QUICKPOLL, "Ctrl+Alt+Q", Configuration.Type.HOTKEY
+		addCfg(list, CONFIG_KEYCODE_QUICKPOLL, "Ctrl+Alt+KeyQ", Configuration.Type.HOTKEY
 				, "A hot key code to start quick poll", "4.0.10");
 		return list;
 	}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigsPanel.html b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigsPanel.html
index 52b651e..6f27562 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigsPanel.html
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigsPanel.html
@@ -35,8 +35,11 @@
 			if (evt.shiftKey) {
 				val += 'Shift+';
 			}
-			val += evt.key;
-			console.info(val);
+			const code = OmUtil.getKeyCode(evt);
+			if (typeof(code) === 'undefined') {
+				return;
+			}
+			val += code;
 			if (evt.keyCode !== 16 && evt.keyCode !== 17 && evt.keyCode !== 18 && inp.length == 1) {
 				inp.val(val);
 			}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/main.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/main.js
index ec9e83d..04b306d 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/main.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/main.js
@@ -6,7 +6,7 @@ var Settings = (function() {
 		try {
 			s = JSON.parse(localStorage.getItem(key)) || s;
 		} catch (e) {
-			//no-op
+			// no-op
 		}
 		return s;
 	}
@@ -17,7 +17,7 @@ var Settings = (function() {
 	}
 
 	return {
-		isRtl: "rtl" === $('html').attr('dir')
+		isRtl: 'rtl' === $('html').attr('dir')
 		, load: _load
 		, save: _save
 	};
@@ -33,21 +33,18 @@ var OmUtil = (function() {
 		const confirm = $('#' + _id);
 		confirm.dialog({
 			modal: true
-			, buttons: [
-				{
-					text: confirm.data('btn-ok')
-					, click: function() {
-						okHandler();
-						$(this).dialog('close');
-					}
+			, buttons: [{
+				text: confirm.data('btn-ok'),
+				click: function() {
+					okHandler();
+					$(this).dialog('close');
 				}
-				, {
-					text: confirm.data('btn-cancel')
-					, click: function() {
-						$(this).dialog('close');
-					}
+			}, {
+				text: confirm.data('btn-cancel'),
+				click: function() {
+					$(this).dialog('close');
 				}
-			]
+			}]
 		});
 		return confirm;
 	}
@@ -56,7 +53,7 @@ var OmUtil = (function() {
 	}
 	function _error(msg) {
 		if (typeof(msg) === 'object') {
-			msg = msg.name + ": " + msg.message;
+			msg = msg.name + ': ' + msg.message;
 		}
 		if (!!errs && errs.length > 0) {
 			errs.getKendoNotification().error(msg);
@@ -92,13 +89,25 @@ var OmUtil = (function() {
 			, msg = JSON.stringify($.extend({}, base, m));
 		Wicket.WebSocket.send(msg);
 	};
-	self.initErrs = function(_e) { errs = _e; };
+	self.initErrs = function(_e) {
+		errs = _e;
+	};
 	self.error = _error;
 	self.info = _info;
 	self.log = _log;
 	self.wbAction = function(_m) {
 		self.sendMessage(_m, {area: 'room', type: 'wb'});
 	};
+	self.getKeyCode = function(evt) {
+		let code = evt.code;
+		if (typeof (code) === 'undefined') {
+			const codeInfo = window.keyCodeToInfoTable[evt.keyCode];
+			if (typeof(codeInfo) === 'object') {
+				code = codeInfo.code;
+			}
+		}
+		return code;
+	};
 	return self;
 })();
 Wicket.BrowserInfo.collectExtraInfo = function(info) {
@@ -106,629 +115,633 @@ Wicket.BrowserInfo.collectExtraInfo = function(info) {
 	info.codebase = l.origin + l.pathname;
 	info.settings = Settings.load();
 };
-// https://github.com/inexorabletash/polyfill/blob/master/LICENSE.md
-// Licensed MIT
-// the below helper table is taken from here https://inexorabletash.github.io/polyfill/demos/keyboard.html
-var keyCodeToInfoTable = {
-	// 0x01 - VK_LBUTTON
-	// 0x02 - VK_RBUTTON
-	0x03 : {
-		code : 'Cancel'
-	}, // [USB: 0x9b] char \x0018 ??? (Not in D3E)
-	// 0x04 - VK_MBUTTON
-	// 0x05 - VK_XBUTTON1
-	// 0x06 - VK_XBUTTON2
-	0x06 : {
-		code : 'Help'
-	}, // [USB: 0x75] ???
-	// 0x07 - undefined
-	0x08 : {
-		code : 'Backspace'
-	}, // [USB: 0x2a] Labelled Delete on Macintosh keyboards.
-	0x09 : {
-		code : 'Tab'
-	}, // [USB: 0x2b]
-	// 0x0A-0x0B - reserved
-	0X0C : {
-		code : 'Clear'
-	}, // [USB: 0x9c] NumPad Center (Not in D3E)
-	0X0D : {
-		code : 'Enter'
-	}, // [USB: 0x28]
-	// 0x0E-0x0F - undefined
+(function() {
+	// https://github.com/inexorabletash/polyfill/blob/master/LICENSE.md
+	// Licensed MIT
+	// the below helper table is taken from here https://inexorabletash.github.io/polyfill/demos/keyboard.html
+	var STANDARD = KeyboardEvent.DOM_KEY_LOCATION_STANDARD, LEFT = KeyboardEvent.DOM_KEY_LOCATION_LEFT, RIGHT = KeyboardEvent.DOM_KEY_LOCATION_RIGHT, NUMPAD = KeyboardEvent.DOM_KEY_LOCATION_NUMPAD;
 
-	0x10 : {
-		code : 'Shift'
-	},
-	0x11 : {
-		code : 'Control'
-	},
-	0x12 : {
-		code : 'Alt'
-	},
-	0x13 : {
-		code : 'Pause'
-	}, // [USB: 0x48]
-	0x14 : {
-		code : 'CapsLock'
-	}, // [USB: 0x39]
-	0x15 : {
-		code : 'KanaMode'
-	}, // [USB: 0x88]
-	0x16 : {
-		code : 'Lang1'
-	}, // [USB: 0x90]
-	// 0x17: VK_JUNJA
-	// 0x18: VK_FINAL
-	0x19 : {
-		code : 'Lang2'
-	}, // [USB: 0x91]
-	// 0x1A - undefined
-	0x1B : {
-		code : 'Escape'
-	}, // [USB: 0x29]
-	0x1C : {
-		code : 'Convert'
-	}, // [USB: 0x8a]
-	0x1D : {
-		code : 'NonConvert'
-	}, // [USB: 0x8b]
-	0x1E : {
-		code : 'Accept'
-	}, // [USB: ????]
-	0x1F : {
-		code : 'ModeChange'
-	}, // [USB: ????]
+	window.keyCodeToInfoTable = {
+		// 0x01 - VK_LBUTTON
+		// 0x02 - VK_RBUTTON
+		0x03: {
+			code: 'Cancel'
+		}, // [USB: 0x9b] char \x0018 ??? (Not in D3E)
+		// 0x04 - VK_MBUTTON
+		// 0x05 - VK_XBUTTON1
+		// 0x06 - VK_XBUTTON2
+		0x06: {
+			code: 'Help'
+		}, // [USB: 0x75] ???
+		// 0x07 - undefined
+		0x08: {
+			code: 'Backspace'
+		}, // [USB: 0x2a] Labelled Delete on Macintosh keyboards.
+		0x09: {
+			code: 'Tab'
+		}, // [USB: 0x2b]
+		// 0x0A-0x0B - reserved
+		0X0C: {
+			code: 'Clear'
+		}, // [USB: 0x9c] NumPad Center (Not in D3E)
+		0X0D: {
+			code: 'Enter'
+		}, // [USB: 0x28]
+		// 0x0E-0x0F - undefined
 
-	0x20 : {
-		code : 'Space'
-	}, // [USB: 0x2c]
-	0x21 : {
-		code : 'PageUp'
-	}, // [USB: 0x4b]
-	0x22 : {
-		code : 'PageDown'
-	}, // [USB: 0x4e]
-	0x23 : {
-		code : 'End'
-	}, // [USB: 0x4d]
-	0x24 : {
-		code : 'Home'
-	}, // [USB: 0x4a]
-	0x25 : {
-		code : 'ArrowLeft'
-	}, // [USB: 0x50]
-	0x26 : {
-		code : 'ArrowUp'
-	}, // [USB: 0x52]
-	0x27 : {
-		code : 'ArrowRight'
-	}, // [USB: 0x4f]
-	0x28 : {
-		code : 'ArrowDown'
-	}, // [USB: 0x51]
-	0x29 : {
-		code : 'Select'
-	}, // (Not in D3E)
-	0x2A : {
-		code : 'Print'
-	}, // (Not in D3E)
-	0x2B : {
-		code : 'Execute'
-	}, // [USB: 0x74] (Not in D3E)
-	0x2C : {
-		code : 'PrintScreen'
-	}, // [USB: 0x46]
-	0x2D : {
-		code : 'Insert'
-	}, // [USB: 0x49]
-	0x2E : {
-		code : 'Delete'
-	}, // [USB: 0x4c]
-	0x2F : {
-		code : 'Help'
-	}, // [USB: 0x75] ???
+		0x10: {
+			code: 'Shift'
+		},
+		0x11: {
+			code: 'Control'
+		},
+		0x12: {
+			code: 'Alt'
+		},
+		0x13: {
+			code: 'Pause'
+		}, // [USB: 0x48]
+		0x14: {
+			code: 'CapsLock'
+		}, // [USB: 0x39]
+		0x15: {
+			code: 'KanaMode'
+		}, // [USB: 0x88]
+		0x16: {
+			code: 'Lang1'
+		}, // [USB: 0x90]
+		// 0x17: VK_JUNJA
+		// 0x18: VK_FINAL
+		0x19: {
+			code: 'Lang2'
+		}, // [USB: 0x91]
+		// 0x1A - undefined
+		0x1B: {
+			code: 'Escape'
+		}, // [USB: 0x29]
+		0x1C: {
+			code: 'Convert'
+		}, // [USB: 0x8a]
+		0x1D: {
+			code: 'NonConvert'
+		}, // [USB: 0x8b]
+		0x1E: {
+			code: 'Accept'
+		}, // [USB: ????]
+		0x1F: {
+			code: 'ModeChange'
+		}, // [USB: ????]
 
-	0x30 : {
-		code : 'Digit0',
-		keyCap : '0'
-	}, // [USB: 0x27] 0)
-	0x31 : {
-		code : 'Digit1',
-		keyCap : '1'
-	}, // [USB: 0x1e] 1!
-	0x32 : {
-		code : 'Digit2',
-		keyCap : '2'
-	}, // [USB: 0x1f] 2@
-	0x33 : {
-		code : 'Digit3',
-		keyCap : '3'
-	}, // [USB: 0x20] 3#
-	0x34 : {
-		code : 'Digit4',
-		keyCap : '4'
-	}, // [USB: 0x21] 4$
-	0x35 : {
-		code : 'Digit5',
-		keyCap : '5'
-	}, // [USB: 0x22] 5%
-	0x36 : {
-		code : 'Digit6',
-		keyCap : '6'
-	}, // [USB: 0x23] 6^
-	0x37 : {
-		code : 'Digit7',
-		keyCap : '7'
-	}, // [USB: 0x24] 7&
-	0x38 : {
-		code : 'Digit8',
-		keyCap : '8'
-	}, // [USB: 0x25] 8*
-	0x39 : {
-		code : 'Digit9',
-		keyCap : '9'
-	}, // [USB: 0x26] 9(
-	// 0x3A-0x40 - undefined
+		0x20: {
+			code: 'Space'
+		}, // [USB: 0x2c]
+		0x21: {
+			code: 'PageUp'
+		}, // [USB: 0x4b]
+		0x22: {
+			code: 'PageDown'
+		}, // [USB: 0x4e]
+		0x23: {
+			code: 'End'
+		}, // [USB: 0x4d]
+		0x24: {
+			code: 'Home'
+		}, // [USB: 0x4a]
+		0x25: {
+			code: 'ArrowLeft'
+		}, // [USB: 0x50]
+		0x26: {
+			code: 'ArrowUp'
+		}, // [USB: 0x52]
+		0x27: {
+			code: 'ArrowRight'
+		}, // [USB: 0x4f]
+		0x28: {
+			code: 'ArrowDown'
+		}, // [USB: 0x51]
+		0x29: {
+			code: 'Select'
+		}, // (Not in D3E)
+		0x2A: {
+			code: 'Print'
+		}, // (Not in D3E)
+		0x2B: {
+			code: 'Execute'
+		}, // [USB: 0x74] (Not in D3E)
+		0x2C: {
+			code: 'PrintScreen'
+		}, // [USB: 0x46]
+		0x2D: {
+			code: 'Insert'
+		}, // [USB: 0x49]
+		0x2E: {
+			code: 'Delete'
+		}, // [USB: 0x4c]
+		0x2F: {
+			code: 'Help'
+		}, // [USB: 0x75] ???
 
-	0x41 : {
-		code : 'KeyA',
-		keyCap : 'a'
-	}, // [USB: 0x04]
-	0x42 : {
-		code : 'KeyB',
-		keyCap : 'b'
-	}, // [USB: 0x05]
-	0x43 : {
-		code : 'KeyC',
-		keyCap : 'c'
-	}, // [USB: 0x06]
-	0x44 : {
-		code : 'KeyD',
-		keyCap : 'd'
-	}, // [USB: 0x07]
-	0x45 : {
-		code : 'KeyE',
-		keyCap : 'e'
-	}, // [USB: 0x08]
-	0x46 : {
-		code : 'KeyF',
-		keyCap : 'f'
-	}, // [USB: 0x09]
-	0x47 : {
-		code : 'KeyG',
-		keyCap : 'g'
-	}, // [USB: 0x0a]
-	0x48 : {
-		code : 'KeyH',
-		keyCap : 'h'
-	}, // [USB: 0x0b]
-	0x49 : {
-		code : 'KeyI',
-		keyCap : 'i'
-	}, // [USB: 0x0c]
-	0x4A : {
-		code : 'KeyJ',
-		keyCap : 'j'
-	}, // [USB: 0x0d]
-	0x4B : {
-		code : 'KeyK',
-		keyCap : 'k'
-	}, // [USB: 0x0e]
-	0x4C : {
-		code : 'KeyL',
-		keyCap : 'l'
-	}, // [USB: 0x0f]
-	0x4D : {
-		code : 'KeyM',
-		keyCap : 'm'
-	}, // [USB: 0x10]
-	0x4E : {
-		code : 'KeyN',
-		keyCap : 'n'
-	}, // [USB: 0x11]
-	0x4F : {
-		code : 'KeyO',
-		keyCap : 'o'
-	}, // [USB: 0x12]
+		0x30: {
+			code: 'Digit0',
+			keyCap: '0'
+		}, // [USB: 0x27] 0)
+		0x31: {
+			code: 'Digit1',
+			keyCap: '1'
+		}, // [USB: 0x1e] 1!
+		0x32: {
+			code: 'Digit2',
+			keyCap: '2'
+		}, // [USB: 0x1f] 2@
+		0x33: {
+			code: 'Digit3',
+			keyCap: '3'
+		}, // [USB: 0x20] 3#
+		0x34: {
+			code: 'Digit4',
+			keyCap: '4'
+		}, // [USB: 0x21] 4$
+		0x35: {
+			code: 'Digit5',
+			keyCap: '5'
+		}, // [USB: 0x22] 5%
+		0x36: {
+			code: 'Digit6',
+			keyCap: '6'
+		}, // [USB: 0x23] 6^
+		0x37: {
+			code: 'Digit7',
+			keyCap: '7'
+		}, // [USB: 0x24] 7&
+		0x38: {
+			code: 'Digit8',
+			keyCap: '8'
+		}, // [USB: 0x25] 8*
+		0x39: {
+			code: 'Digit9',
+			keyCap: '9'
+		}, // [USB: 0x26] 9(
+		// 0x3A-0x40 - undefined
 
-	0x50 : {
-		code : 'KeyP',
-		keyCap : 'p'
-	}, // [USB: 0x13]
-	0x51 : {
-		code : 'KeyQ',
-		keyCap : 'q'
-	}, // [USB: 0x14]
-	0x52 : {
-		code : 'KeyR',
-		keyCap : 'r'
-	}, // [USB: 0x15]
-	0x53 : {
-		code : 'KeyS',
-		keyCap : 's'
-	}, // [USB: 0x16]
-	0x54 : {
-		code : 'KeyT',
-		keyCap : 't'
-	}, // [USB: 0x17]
-	0x55 : {
-		code : 'KeyU',
-		keyCap : 'u'
-	}, // [USB: 0x18]
-	0x56 : {
-		code : 'KeyV',
-		keyCap : 'v'
-	}, // [USB: 0x19]
-	0x57 : {
-		code : 'KeyW',
-		keyCap : 'w'
-	}, // [USB: 0x1a]
-	0x58 : {
-		code : 'KeyX',
-		keyCap : 'x'
-	}, // [USB: 0x1b]
-	0x59 : {
-		code : 'KeyY',
-		keyCap : 'y'
-	}, // [USB: 0x1c]
-	0x5A : {
-		code : 'KeyZ',
-		keyCap : 'z'
-	}, // [USB: 0x1d]
-	0x5B : {
-		code : 'MetaLeft',
-		location : LEFT
-	}, // [USB: 0xe3]
-	0x5C : {
-		code : 'MetaRight',
-		location : RIGHT
-	}, // [USB: 0xe7]
-	0x5D : {
-		code : 'ContextMenu'
-	}, // [USB: 0x65] Context Menu
-	// 0x5E - reserved
-	0x5F : {
-		code : 'Standby'
-	}, // [USB: 0x82] Sleep
+		0x41: {
+			code: 'KeyA',
+			keyCap: 'a'
+		}, // [USB: 0x04]
+		0x42: {
+			code: 'KeyB',
+			keyCap: 'b'
+		}, // [USB: 0x05]
+		0x43: {
+			code: 'KeyC',
+			keyCap: 'c'
+		}, // [USB: 0x06]
+		0x44: {
+			code: 'KeyD',
+			keyCap: 'd'
+		}, // [USB: 0x07]
+		0x45: {
+			code: 'KeyE',
+			keyCap: 'e'
+		}, // [USB: 0x08]
+		0x46: {
+			code: 'KeyF',
+			keyCap: 'f'
+		}, // [USB: 0x09]
+		0x47: {
+			code: 'KeyG',
+			keyCap: 'g'
+		}, // [USB: 0x0a]
+		0x48: {
+			code: 'KeyH',
+			keyCap: 'h'
+		}, // [USB: 0x0b]
+		0x49: {
+			code: 'KeyI',
+			keyCap: 'i'
+		}, // [USB: 0x0c]
+		0x4A: {
+			code: 'KeyJ',
+			keyCap: 'j'
+		}, // [USB: 0x0d]
+		0x4B: {
+			code: 'KeyK',
+			keyCap: 'k'
+		}, // [USB: 0x0e]
+		0x4C: {
+			code: 'KeyL',
+			keyCap: 'l'
+		}, // [USB: 0x0f]
+		0x4D: {
+			code: 'KeyM',
+			keyCap: 'm'
+		}, // [USB: 0x10]
+		0x4E: {
+			code: 'KeyN',
+			keyCap: 'n'
+		}, // [USB: 0x11]
+		0x4F: {
+			code: 'KeyO',
+			keyCap: 'o'
+		}, // [USB: 0x12]
 
-	0x60 : {
-		code : 'Numpad0',
-		keyCap : '0',
-		location : NUMPAD
-	}, // [USB: 0x62]
-	0x61 : {
-		code : 'Numpad1',
-		keyCap : '1',
-		location : NUMPAD
-	}, // [USB: 0x59]
-	0x62 : {
-		code : 'Numpad2',
-		keyCap : '2',
-		location : NUMPAD
-	}, // [USB: 0x5a]
-	0x63 : {
-		code : 'Numpad3',
-		keyCap : '3',
-		location : NUMPAD
-	}, // [USB: 0x5b]
-	0x64 : {
-		code : 'Numpad4',
-		keyCap : '4',
-		location : NUMPAD
-	}, // [USB: 0x5c]
-	0x65 : {
-		code : 'Numpad5',
-		keyCap : '5',
-		location : NUMPAD
-	}, // [USB: 0x5d]
-	0x66 : {
-		code : 'Numpad6',
-		keyCap : '6',
-		location : NUMPAD
-	}, // [USB: 0x5e]
-	0x67 : {
-		code : 'Numpad7',
-		keyCap : '7',
-		location : NUMPAD
-	}, // [USB: 0x5f]
-	0x68 : {
-		code : 'Numpad8',
-		keyCap : '8',
-		location : NUMPAD
-	}, // [USB: 0x60]
-	0x69 : {
-		code : 'Numpad9',
-		keyCap : '9',
-		location : NUMPAD
-	}, // [USB: 0x61]
-	0x6A : {
-		code : 'NumpadMultiply',
-		keyCap : '*',
-		location : NUMPAD
-	}, // [USB: 0x55]
-	0x6B : {
-		code : 'NumpadAdd',
-		keyCap : '+',
-		location : NUMPAD
-	}, // [USB: 0x57]
-	0x6C : {
-		code : 'NumpadComma',
-		keyCap : ',',
-		location : NUMPAD
-	}, // [USB: 0x85]
-	0x6D : {
-		code : 'NumpadSubtract',
-		keyCap : '-',
-		location : NUMPAD
-	}, // [USB: 0x56]
-	0x6E : {
-		code : 'NumpadDecimal',
-		keyCap : '.',
-		location : NUMPAD
-	}, // [USB: 0x63]
-	0x6F : {
-		code : 'NumpadDivide',
-		keyCap : '/',
-		location : NUMPAD
-	}, // [USB: 0x54]
+		0x50: {
+			code: 'KeyP',
+			keyCap: 'p'
+		}, // [USB: 0x13]
+		0x51: {
+			code: 'KeyQ',
+			keyCap: 'q'
+		}, // [USB: 0x14]
+		0x52: {
+			code: 'KeyR',
+			keyCap: 'r'
+		}, // [USB: 0x15]
+		0x53: {
+			code: 'KeyS',
+			keyCap: 's'
+		}, // [USB: 0x16]
+		0x54: {
+			code: 'KeyT',
+			keyCap: 't'
+		}, // [USB: 0x17]
+		0x55: {
+			code: 'KeyU',
+			keyCap: 'u'
+		}, // [USB: 0x18]
+		0x56: {
+			code: 'KeyV',
+			keyCap: 'v'
+		}, // [USB: 0x19]
+		0x57: {
+			code: 'KeyW',
+			keyCap: 'w'
+		}, // [USB: 0x1a]
+		0x58: {
+			code: 'KeyX',
+			keyCap: 'x'
+		}, // [USB: 0x1b]
+		0x59: {
+			code: 'KeyY',
+			keyCap: 'y'
+		}, // [USB: 0x1c]
+		0x5A: {
+			code: 'KeyZ',
+			keyCap: 'z'
+		}, // [USB: 0x1d]
+		0x5B: {
+			code: 'MetaLeft',
+			location: LEFT
+		}, // [USB: 0xe3]
+		0x5C: {
+			code: 'MetaRight',
+			location: RIGHT
+		}, // [USB: 0xe7]
+		0x5D: {
+			code: 'ContextMenu'
+		}, // [USB: 0x65] Context Menu
+		// 0x5E - reserved
+		0x5F: {
+			code: 'Standby'
+		}, // [USB: 0x82] Sleep
 
-	0x70 : {
-		code : 'F1'
-	}, // [USB: 0x3a]
-	0x71 : {
-		code : 'F2'
-	}, // [USB: 0x3b]
-	0x72 : {
-		code : 'F3'
-	}, // [USB: 0x3c]
-	0x73 : {
-		code : 'F4'
-	}, // [USB: 0x3d]
-	0x74 : {
-		code : 'F5'
-	}, // [USB: 0x3e]
-	0x75 : {
-		code : 'F6'
-	}, // [USB: 0x3f]
-	0x76 : {
-		code : 'F7'
-	}, // [USB: 0x40]
-	0x77 : {
-		code : 'F8'
-	}, // [USB: 0x41]
-	0x78 : {
-		code : 'F9'
-	}, // [USB: 0x42]
-	0x79 : {
-		code : 'F10'
-	}, // [USB: 0x43]
-	0x7A : {
-		code : 'F11'
-	}, // [USB: 0x44]
-	0x7B : {
-		code : 'F12'
-	}, // [USB: 0x45]
-	0x7C : {
-		code : 'F13'
-	}, // [USB: 0x68]
-	0x7D : {
-		code : 'F14'
-	}, // [USB: 0x69]
-	0x7E : {
-		code : 'F15'
-	}, // [USB: 0x6a]
-	0x7F : {
-		code : 'F16'
-	}, // [USB: 0x6b]
+		0x60: {
+			code: 'Numpad0',
+			keyCap: '0',
+			location: NUMPAD
+		}, // [USB: 0x62]
+		0x61: {
+			code: 'Numpad1',
+			keyCap: '1',
+			location: NUMPAD
+		}, // [USB: 0x59]
+		0x62: {
+			code: 'Numpad2',
+			keyCap: '2',
+			location: NUMPAD
+		}, // [USB: 0x5a]
+		0x63: {
+			code: 'Numpad3',
+			keyCap: '3',
+			location: NUMPAD
+		}, // [USB: 0x5b]
+		0x64: {
+			code: 'Numpad4',
+			keyCap: '4',
+			location: NUMPAD
+		}, // [USB: 0x5c]
+		0x65: {
+			code: 'Numpad5',
+			keyCap: '5',
+			location: NUMPAD
+		}, // [USB: 0x5d]
+		0x66: {
+			code: 'Numpad6',
+			keyCap: '6',
+			location: NUMPAD
+		}, // [USB: 0x5e]
+		0x67: {
+			code: 'Numpad7',
+			keyCap: '7',
+			location: NUMPAD
+		}, // [USB: 0x5f]
+		0x68: {
+			code: 'Numpad8',
+			keyCap: '8',
+			location: NUMPAD
+		}, // [USB: 0x60]
+		0x69: {
+			code: 'Numpad9',
+			keyCap: '9',
+			location: NUMPAD
+		}, // [USB: 0x61]
+		0x6A: {
+			code: 'NumpadMultiply',
+			keyCap: '*',
+			location: NUMPAD
+		}, // [USB: 0x55]
+		0x6B: {
+			code: 'NumpadAdd',
+			keyCap: '+',
+			location: NUMPAD
+		}, // [USB: 0x57]
+		0x6C: {
+			code: 'NumpadComma',
+			keyCap: ',',
+			location: NUMPAD
+		}, // [USB: 0x85]
+		0x6D: {
+			code: 'NumpadSubtract',
+			keyCap: '-',
+			location: NUMPAD
+		}, // [USB: 0x56]
+		0x6E: {
+			code: 'NumpadDecimal',
+			keyCap: '.',
+			location: NUMPAD
+		}, // [USB: 0x63]
+		0x6F: {
+			code: 'NumpadDivide',
+			keyCap: '/',
+			location: NUMPAD
+		}, // [USB: 0x54]
 
-	0x80 : {
-		code : 'F17'
-	}, // [USB: 0x6c]
-	0x81 : {
-		code : 'F18'
-	}, // [USB: 0x6d]
-	0x82 : {
-		code : 'F19'
-	}, // [USB: 0x6e]
-	0x83 : {
-		code : 'F20'
-	}, // [USB: 0x6f]
-	0x84 : {
-		code : 'F21'
-	}, // [USB: 0x70]
-	0x85 : {
-		code : 'F22'
-	}, // [USB: 0x71]
-	0x86 : {
-		code : 'F23'
-	}, // [USB: 0x72]
-	0x87 : {
-		code : 'F24'
-	}, // [USB: 0x73]
-	// 0x88-0x8F - unassigned
+		0x70: {
+			code: 'F1'
+		}, // [USB: 0x3a]
+		0x71: {
+			code: 'F2'
+		}, // [USB: 0x3b]
+		0x72: {
+			code: 'F3'
+		}, // [USB: 0x3c]
+		0x73: {
+			code: 'F4'
+		}, // [USB: 0x3d]
+		0x74: {
+			code: 'F5'
+		}, // [USB: 0x3e]
+		0x75: {
+			code: 'F6'
+		}, // [USB: 0x3f]
+		0x76: {
+			code: 'F7'
+		}, // [USB: 0x40]
+		0x77: {
+			code: 'F8'
+		}, // [USB: 0x41]
+		0x78: {
+			code: 'F9'
+		}, // [USB: 0x42]
+		0x79: {
+			code: 'F10'
+		}, // [USB: 0x43]
+		0x7A: {
+			code: 'F11'
+		}, // [USB: 0x44]
+		0x7B: {
+			code: 'F12'
+		}, // [USB: 0x45]
+		0x7C: {
+			code: 'F13'
+		}, // [USB: 0x68]
+		0x7D: {
+			code: 'F14'
+		}, // [USB: 0x69]
+		0x7E: {
+			code: 'F15'
+		}, // [USB: 0x6a]
+		0x7F: {
+			code: 'F16'
+		}, // [USB: 0x6b]
 
-	0x90 : {
-		code : 'NumLock',
-		location : NUMPAD
-	}, // [USB: 0x53]
-	0x91 : {
-		code : 'ScrollLock'
-	}, // [USB: 0x47]
-	// 0x92-0x96 - OEM specific
-	// 0x97-0x9F - unassigned
+		0x80: {
+			code: 'F17'
+		}, // [USB: 0x6c]
+		0x81: {
+			code: 'F18'
+		}, // [USB: 0x6d]
+		0x82: {
+			code: 'F19'
+		}, // [USB: 0x6e]
+		0x83: {
+			code: 'F20'
+		}, // [USB: 0x6f]
+		0x84: {
+			code: 'F21'
+		}, // [USB: 0x70]
+		0x85: {
+			code: 'F22'
+		}, // [USB: 0x71]
+		0x86: {
+			code: 'F23'
+		}, // [USB: 0x72]
+		0x87: {
+			code: 'F24'
+		}, // [USB: 0x73]
+		// 0x88-0x8F - unassigned
 
-	// NOTE: 0xA0-0xA5 usually mapped to 0x10-0x12 in browsers
-	0xA0 : {
-		code : 'ShiftLeft',
-		location : LEFT
-	}, // [USB: 0xe1]
-	0xA1 : {
-		code : 'ShiftRight',
-		location : RIGHT
-	}, // [USB: 0xe5]
-	0xA2 : {
-		code : 'ControlLeft',
-		location : LEFT
-	}, // [USB: 0xe0]
-	0xA3 : {
-		code : 'ControlRight',
-		location : RIGHT
-	}, // [USB: 0xe4]
-	0xA4 : {
-		code : 'AltLeft',
-		location : LEFT
-	}, // [USB: 0xe2]
-	0xA5 : {
-		code : 'AltRight',
-		location : RIGHT
-	}, // [USB: 0xe6]
+		0x90: {
+			code: 'NumLock',
+			location: NUMPAD
+		}, // [USB: 0x53]
+		0x91: {
+			code: 'ScrollLock'
+		}, // [USB: 0x47]
+		// 0x92-0x96 - OEM specific
+		// 0x97-0x9F - unassigned
 
-	0xA6 : {
-		code : 'BrowserBack'
-	}, // [USB: 0x0c/0x0224]
-	0xA7 : {
-		code : 'BrowserForward'
-	}, // [USB: 0x0c/0x0225]
-	0xA8 : {
-		code : 'BrowserRefresh'
-	}, // [USB: 0x0c/0x0227]
-	0xA9 : {
-		code : 'BrowserStop'
-	}, // [USB: 0x0c/0x0226]
-	0xAA : {
-		code : 'BrowserSearch'
-	}, // [USB: 0x0c/0x0221]
-	0xAB : {
-		code : 'BrowserFavorites'
-	}, // [USB: 0x0c/0x0228]
-	0xAC : {
-		code : 'BrowserHome'
-	}, // [USB: 0x0c/0x0222]
-	0xAD : {
-		code : 'AudioVolumeMute'
-	}, // [USB: 0x7f]
-	0xAE : {
-		code : 'AudioVolumeDown'
-	}, // [USB: 0x81]
-	0xAF : {
-		code : 'AudioVolumeUp'
-	}, // [USB: 0x80]
+		// NOTE: 0xA0-0xA5 usually mapped to 0x10-0x12 in browsers
+		0xA0: {
+			code: 'ShiftLeft',
+			location: LEFT
+		}, // [USB: 0xe1]
+		0xA1: {
+			code: 'ShiftRight',
+			location: RIGHT
+		}, // [USB: 0xe5]
+		0xA2: {
+			code: 'ControlLeft',
+			location: LEFT
+		}, // [USB: 0xe0]
+		0xA3: {
+			code: 'ControlRight',
+			location: RIGHT
+		}, // [USB: 0xe4]
+		0xA4: {
+			code: 'AltLeft',
+			location: LEFT
+		}, // [USB: 0xe2]
+		0xA5: {
+			code: 'AltRight',
+			location: RIGHT
+		}, // [USB: 0xe6]
 
-	0xB0 : {
-		code : 'MediaTrackNext'
-	}, // [USB: 0x0c/0x00b5]
-	0xB1 : {
-		code : 'MediaTrackPrevious'
-	}, // [USB: 0x0c/0x00b6]
-	0xB2 : {
-		code : 'MediaStop'
-	}, // [USB: 0x0c/0x00b7]
-	0xB3 : {
-		code : 'MediaPlayPause'
-	}, // [USB: 0x0c/0x00cd]
-	0xB4 : {
-		code : 'LaunchMail'
-	}, // [USB: 0x0c/0x018a]
-	0xB5 : {
-		code : 'MediaSelect'
-	},
-	0xB6 : {
-		code : 'LaunchApp1'
-	},
-	0xB7 : {
-		code : 'LaunchApp2'
-	},
-	// 0xB8-0xB9 - reserved
-	0xBA : {
-		code : 'Semicolon',
-		keyCap : ';'
-	}, // [USB: 0x33] ;: (US Standard 101)
-	0xBB : {
-		code : 'Equal',
-		keyCap : '='
-	}, // [USB: 0x2e] =+
-	0xBC : {
-		code : 'Comma',
-		keyCap : ','
-	}, // [USB: 0x36] ,<
-	0xBD : {
-		code : 'Minus',
-		keyCap : '-'
-	}, // [USB: 0x2d] -_
-	0xBE : {
-		code : 'Period',
-		keyCap : '.'
-	}, // [USB: 0x37] .>
-	0xBF : {
-		code : 'Slash',
-		keyCap : '/'
-	}, // [USB: 0x38] /? (US Standard 101)
+		0xA6: {
+			code: 'BrowserBack'
+		}, // [USB: 0x0c/0x0224]
+		0xA7: {
+			code: 'BrowserForward'
+		}, // [USB: 0x0c/0x0225]
+		0xA8: {
+			code: 'BrowserRefresh'
+		}, // [USB: 0x0c/0x0227]
+		0xA9: {
+			code: 'BrowserStop'
+		}, // [USB: 0x0c/0x0226]
+		0xAA: {
+			code: 'BrowserSearch'
+		}, // [USB: 0x0c/0x0221]
+		0xAB: {
+			code: 'BrowserFavorites'
+		}, // [USB: 0x0c/0x0228]
+		0xAC: {
+			code: 'BrowserHome'
+		}, // [USB: 0x0c/0x0222]
+		0xAD: {
+			code: 'AudioVolumeMute'
+		}, // [USB: 0x7f]
+		0xAE: {
+			code: 'AudioVolumeDown'
+		}, // [USB: 0x81]
+		0xAF: {
+			code: 'AudioVolumeUp'
+		}, // [USB: 0x80]
 
-	0xC0 : {
-		code : 'Backquote',
-		keyCap : '`'
-	}, // [USB: 0x35] `~ (US Standard 101)
-	// 0xC1-0xCF - reserved
+		0xB0: {
+			code: 'MediaTrackNext'
+		}, // [USB: 0x0c/0x00b5]
+		0xB1: {
+			code: 'MediaTrackPrevious'
+		}, // [USB: 0x0c/0x00b6]
+		0xB2: {
+			code: 'MediaStop'
+		}, // [USB: 0x0c/0x00b7]
+		0xB3: {
+			code: 'MediaPlayPause'
+		}, // [USB: 0x0c/0x00cd]
+		0xB4: {
+			code: 'LaunchMail'
+		}, // [USB: 0x0c/0x018a]
+		0xB5: {
+			code: 'MediaSelect'
+		},
+		0xB6: {
+			code: 'LaunchApp1'
+		},
+		0xB7: {
+			code: 'LaunchApp2'
+		},
+		// 0xB8-0xB9 - reserved
+		0xBA: {
+			code: 'Semicolon',
+			keyCap: ';'
+		}, // [USB: 0x33] ;: (US Standard 101)
+		0xBB: {
+			code: 'Equal',
+			keyCap: '='
+		}, // [USB: 0x2e] =+
+		0xBC: {
+			code: 'Comma',
+			keyCap: ','
+		}, // [USB: 0x36] ,<
+		0xBD: {
+			code: 'Minus',
+			keyCap: '-'
+		}, // [USB: 0x2d] -_
+		0xBE: {
+			code: 'Period',
+			keyCap: '.'
+		}, // [USB: 0x37] .>
+		0xBF: {
+			code: 'Slash',
+			keyCap: '/'
+		}, // [USB: 0x38] /? (US Standard 101)
 
-	// 0xD0-0xD7 - reserved
-	// 0xD8-0xDA - unassigned
-	0xDB : {
-		code : 'BracketLeft',
-		keyCap : '['
-	}, // [USB: 0x2f] [{ (US Standard 101)
-	0xDC : {
-		code : 'Backslash',
-		keyCap : '\\'
-	}, // [USB: 0x31] \| (US Standard 101)
-	0xDD : {
-		code : 'BracketRight',
-		keyCap : ']'
-	}, // [USB: 0x30] ]} (US Standard 101)
-	0xDE : {
-		code : 'Quote',
-		keyCap : '\''
-	}, // [USB: 0x34] '" (US Standard 101)
-	// 0xDF - miscellaneous/varies
+		0xC0: {
+			code: 'Backquote',
+			keyCap: '`'
+		}, // [USB: 0x35] `~ (US Standard 101)
+		// 0xC1-0xCF - reserved
 
-	// 0xE0 - reserved
-	// 0xE1 - OEM specific
-	0xE2 : {
-		code : 'IntlBackslash',
-		keyCap : '\\'
-	}, // [USB: 0x64] \| (UK Standard 102)
-	// 0xE3-0xE4 - OEM specific
-	0xE5 : {
-		code : 'Process'
-	}, // (Not in D3E)
-	// 0xE6 - OEM specific
-	// 0xE7 - VK_PACKET
-	// 0xE8 - unassigned
-	// 0xE9-0xEF - OEM specific
+		// 0xD0-0xD7 - reserved
+		// 0xD8-0xDA - unassigned
+		0xDB: {
+			code: 'BracketLeft',
+			keyCap: '['
+		}, // [USB: 0x2f] [{ (US Standard 101)
+		0xDC: {
+			code: 'Backslash',
+			keyCap: '\\'
+		}, // [USB: 0x31] \| (US Standard 101)
+		0xDD: {
+			code: 'BracketRight',
+			keyCap: ']'
+		}, // [USB: 0x30] ]} (US Standard 101)
+		0xDE: {
+			code: 'Quote',
+			keyCap: '\''
+		}, // [USB: 0x34] '" (US Standard 101)
+		// 0xDF - miscellaneous/varies
 
-	// 0xF0-0xF5 - OEM specific
-	0xF6 : {
-		code : 'Attn'
-	}, // [USB: 0x9a] (Not in D3E)
-	0xF7 : {
-		code : 'CrSel'
-	}, // [USB: 0xa3] (Not in D3E)
-	0xF8 : {
-		code : 'ExSel'
-	}, // [USB: 0xa4] (Not in D3E)
-	0xF9 : {
-		code : 'EraseEof'
-	}, // (Not in D3E)
-	0xFA : {
-		code : 'Play'
-	}, // (Not in D3E)
-	0xFB : {
-		code : 'ZoomToggle'
-	}, // (Not in D3E)
-	// 0xFC - VK_NONAME - reserved
-	// 0xFD - VK_PA1
-	0xFE : {
-		code : 'Clear'
-	}
-// [USB: 0x9c] (Not in D3E)
-};
+		// 0xE0 - reserved
+		// 0xE1 - OEM specific
+		0xE2: {
+			code: 'IntlBackslash',
+			keyCap: '\\'
+		}, // [USB: 0x64] \| (UK Standard 102)
+		// 0xE3-0xE4 - OEM specific
+		0xE5: {
+			code: 'Process'
+		}, // (Not in D3E)
+		// 0xE6 - OEM specific
+		// 0xE7 - VK_PACKET
+		// 0xE8 - unassigned
+		// 0xE9-0xEF - OEM specific
+
+		// 0xF0-0xF5 - OEM specific
+		0xF6: {
+			code: 'Attn'
+		}, // [USB: 0x9a] (Not in D3E)
+		0xF7: {
+			code: 'CrSel'
+		}, // [USB: 0xa3] (Not in D3E)
+		0xF8: {
+			code: 'ExSel'
+		}, // [USB: 0xa4] (Not in D3E)
+		0xF9: {
+			code: 'EraseEof'
+		}, // (Not in D3E)
+		0xFA: {
+			code: 'Play'
+		}, // (Not in D3E)
+		0xFB: {
+			code: 'ZoomToggle'
+		}, // (Not in D3E)
+		// 0xFC - VK_NONAME - reserved
+		// 0xFD - VK_PA1
+		0xFE: {
+			code: 'Clear'
+		}
+	// [USB: 0x9c] (Not in D3E)
+	};
+})();
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js
index 023f176..148e77d 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js
@@ -67,10 +67,11 @@ var Room = (function() {
 		}
 	}
 	function __keyPressed(hotkey, e) {
+		const code = OmUtil.getKeyCode(e);
 		return hotkey.alt === e.altKey
 			&& hotkey.ctrl === e.ctrlKey
 			&& hotkey.shift === e.shiftKey
-			&& hotkey.key.toUpperCase() === e.key.toUpperCase();
+			&& hotkey.code.toUpperCase() === (code ? code.toUpperCase() : '');
 	}
 	function _keyHandler(e) {
 		if (__keyPressed(options.keycode.arrange, e)) {