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/14 16:14:26 UTC

[openmeetings] branch 4.0.x updated: [OPENMEETINGS-2078] shortcuts are refactored, shortcut for start quick-poll is added

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

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


The following commit(s) were added to refs/heads/4.0.x by this push:
     new 1f8feba  [OPENMEETINGS-2078] shortcuts are refactored, shortcut for start quick-poll is added
1f8feba is described below

commit 1f8feba387bf5e16bed80736d8c05f168cb87902
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Sun Jul 14 22:55:47 2019 +0700

    [OPENMEETINGS-2078] shortcuts are refactored, shortcut for start quick-poll is added
---
 .../db/dao/basic/ConfigurationDao.java             |  23 +++-
 .../db/entity/basic/Configuration.java             |  12 +-
 .../apache/openmeetings/backup/BackupImport.java   | 103 ++++++++------
 .../installation/ImportInitvalues.java             | 153 +++++++++++----------
 .../openmeetings/util/OpenmeetingsVariables.java   |   1 +
 .../web/admin/configurations/ConfigForm.java       |  43 +++---
 .../web/admin/configurations/ConfigsPanel.html     |  27 ++++
 .../openmeetings/web/room/menu/PollsSubMenu.java   |   5 +-
 .../org/apache/openmeetings/web/room/raw-room.js   |  40 +++---
 9 files changed, 240 insertions(+), 167 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 48056ad..9d2a85f 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
@@ -44,8 +44,9 @@ import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_GOOGLE_A
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_HEADER_CSP;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_HEADER_XFRAME;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_ARRANGE;
-import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_MUTE_OTHERS;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_MUTE;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_MUTE_OTHERS;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_QUICKPOLL;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_LNAME_MIN_LENGTH;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_LOGIN_MIN_LENGTH;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_MAX_UPLOAD_SIZE;
@@ -112,8 +113,10 @@ import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Properties;
+import java.util.Set;
 import java.util.TimeZone;
 
 import javax.persistence.EntityManager;
@@ -325,6 +328,7 @@ public class ConfigurationDao implements IDataProviderDao<Configuration> {
 			case CONFIG_KEYCODE_ARRANGE:
 			case CONFIG_KEYCODE_MUTE_OTHERS:
 			case CONFIG_KEYCODE_MUTE:
+			case CONFIG_KEYCODE_QUICKPOLL:
 				reloadRoomSettings();
 				break;
 			case CONFIG_MAX_UPLOAD_SIZE:
@@ -577,6 +581,16 @@ public class ConfigurationDao implements IDataProviderDao<Configuration> {
 		reloadDisplayNameEditable();
 	}
 
+	private static JSONObject getHotkey(String value) {
+		List<String> partList = Arrays.asList(value.split("\\+"));
+		Set<String> parts = new HashSet<>(partList);
+		return new JSONObject()
+				.put("alt", parts.contains("Alt"))
+				.put("shift", parts.contains("Shift"))
+				.put("ctrl", parts.contains("Ctrl"))
+				.put("key", partList.get(partList.size() - 1));
+	}
+
 	private JSONObject reloadRoomSettings() {
 		try {
 			Properties props = new Properties();
@@ -595,9 +609,10 @@ public class ConfigurationDao implements IDataProviderDao<Configuration> {
 				.put(FLASH_ECHO_PATH, getLong(CONFIG_FLASH_ECHO_PATH, 128L))
 				.put(FLASH_MIC_RATE, getLong(CONFIG_FLASH_MIC_RATE, 22L))
 				.put("keycode", new JSONObject()
-						.put("arrange", getLong(CONFIG_KEYCODE_ARRANGE, 119L))
-						.put("muteothers", getLong(CONFIG_KEYCODE_MUTE_OTHERS, 123L))
-						.put("mute", getLong(CONFIG_KEYCODE_MUTE, 118L))
+						.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")))
 						)
 				);
 		} catch (Exception e) {
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Configuration.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Configuration.java
index 6d17e8d..430da59 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Configuration.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Configuration.java
@@ -22,6 +22,8 @@ import static java.lang.Boolean.TRUE;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
 import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
@@ -53,9 +55,10 @@ public class Configuration extends HistoricalEntity {
 	private static final long serialVersionUID = 1L;
 
 	public enum Type {
-		string
-		, number
-		, bool
+		STRING
+		, NUMBER
+		, BOOL
+		, HOTKEY
 	}
 	@Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -65,7 +68,8 @@ public class Configuration extends HistoricalEntity {
 
 	@Column(name = "type")
 	@Element(name = "type", data = true, required = false)
-	private Type type = Type.string;
+	@Enumerated(EnumType.STRING)
+	private Type type = Type.STRING;
 
 	@Column(name = "om_key", unique = true)
 	@Element(name = "key", data = true, required = false)
diff --git a/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupImport.java b/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupImport.java
index ed7b527..3a333cf 100644
--- a/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupImport.java
+++ b/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupImport.java
@@ -103,6 +103,7 @@ import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_USE
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getMinLoginLength;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
 
+import java.awt.event.KeyEvent;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -111,6 +112,7 @@ import java.io.InputStream;
 import java.io.StringReader;
 import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -131,6 +133,7 @@ import javax.xml.transform.stream.StreamResult;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.text.WordUtils;
 import org.apache.openmeetings.backup.converter.AppointmentConverter;
 import org.apache.openmeetings.backup.converter.AppointmentReminderTypeConverter;
 import org.apache.openmeetings.backup.converter.BaseFileItemConverter;
@@ -250,46 +253,46 @@ public class BackupImport {
 		outdatedConfigKeys.put("swftools_zoom", CONFIG_DOCUMENT_DPI);
 		outdatedConfigKeys.put("swftools_jpegquality", CONFIG_DOCUMENT_QUALITY);
 		outdatedConfigKeys.put("sms.subject", CONFIG_REMINDER_MESSAGE);
-		configTypes.put(CONFIG_REGISTER_FRONTEND, Configuration.Type.bool);
-		configTypes.put(CONFIG_REGISTER_SOAP, Configuration.Type.bool);
-		configTypes.put(CONFIG_REGISTER_OAUTH, Configuration.Type.bool);
-		configTypes.put(CONFIG_SMTP_TLS, Configuration.Type.bool);
-		configTypes.put(CONFIG_EMAIL_AT_REGISTER, Configuration.Type.bool);
-		configTypes.put(CONFIG_EMAIL_VERIFICATION, Configuration.Type.bool);
-		configTypes.put(CONFIG_SIP_ENABLED, Configuration.Type.bool);
-		configTypes.put(CONFIG_SCREENSHARING_FPS_SHOW, Configuration.Type.bool);
-		configTypes.put(CONFIG_SCREENSHARING_ALLOW_REMOTE, Configuration.Type.bool);
-		configTypes.put(CONFIG_DASHBOARD_SHOW_MYROOMS, Configuration.Type.bool);
-		configTypes.put(CONFIG_DASHBOARD_SHOW_CHAT, Configuration.Type.bool);
-		configTypes.put(CONFIG_DASHBOARD_SHOW_RSS, Configuration.Type.bool);
-		configTypes.put(CONFIG_REPLY_TO_ORGANIZER, Configuration.Type.bool);
-		configTypes.put(CONFIG_IGNORE_BAD_SSL, Configuration.Type.bool);
-		configTypes.put(CONFIG_FLASH_SECURE, Configuration.Type.bool);
-		configTypes.put(CONFIG_MYROOMS_ENABLED, Configuration.Type.bool);
-		configTypes.put(CONFIG_DEFAULT_GROUP_ID, Configuration.Type.number);
-		configTypes.put(CONFIG_SMTP_PORT, Configuration.Type.number);
-		configTypes.put(CONFIG_SMTP_TIMEOUT_CON, Configuration.Type.number);
-		configTypes.put(CONFIG_SMTP_TIMEOUT, Configuration.Type.number);
-		configTypes.put(CONFIG_DEFAULT_LANG, Configuration.Type.number);
-		configTypes.put(CONFIG_DOCUMENT_DPI, Configuration.Type.number);
-		configTypes.put(CONFIG_DOCUMENT_QUALITY, Configuration.Type.number);
-		configTypes.put(CONFIG_SCREENSHARING_QUALITY, Configuration.Type.number);
-		configTypes.put(CONFIG_SCREENSHARING_FPS, Configuration.Type.number);
-		configTypes.put(CONFIG_MAX_UPLOAD_SIZE, Configuration.Type.number);
-		configTypes.put(CONFIG_APPOINTMENT_REMINDER_MINUTES, Configuration.Type.number);
-		configTypes.put(CONFIG_LOGIN_MIN_LENGTH, Configuration.Type.number);
-		configTypes.put(CONFIG_PASS_MIN_LENGTH, Configuration.Type.number);
-		configTypes.put(CONFIG_CALENDAR_ROOM_CAPACITY, Configuration.Type.number);
-		configTypes.put(CONFIG_KEYCODE_ARRANGE, Configuration.Type.number);
-		configTypes.put(CONFIG_KEYCODE_MUTE_OTHERS, Configuration.Type.number);
-		configTypes.put(CONFIG_KEYCODE_MUTE, Configuration.Type.number);
-		configTypes.put(CONFIG_DEFAULT_LDAP_ID, Configuration.Type.number);
-		configTypes.put(CONFIG_FLASH_VIDEO_FPS, Configuration.Type.number);
-		configTypes.put(CONFIG_FLASH_VIDEO_BANDWIDTH, Configuration.Type.number);
-		configTypes.put(CONFIG_FLASH_CAM_QUALITY, Configuration.Type.number);
-		configTypes.put(CONFIG_FLASH_MIC_RATE, Configuration.Type.number);
-		configTypes.put(CONFIG_FLASH_ECHO_PATH, Configuration.Type.number);
-		configTypes.put(CONFIG_EXT_PROCESS_TTL, Configuration.Type.number);
+		configTypes.put(CONFIG_FLASH_SECURE, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_FLASH_VIDEO_FPS, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_FLASH_VIDEO_BANDWIDTH, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_FLASH_CAM_QUALITY, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_FLASH_MIC_RATE, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_FLASH_ECHO_PATH, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_REGISTER_FRONTEND, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_REGISTER_SOAP, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_REGISTER_OAUTH, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_SMTP_TLS, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_EMAIL_AT_REGISTER, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_EMAIL_VERIFICATION, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_SIP_ENABLED, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_SCREENSHARING_FPS_SHOW, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_SCREENSHARING_ALLOW_REMOTE, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_DASHBOARD_SHOW_MYROOMS, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_DASHBOARD_SHOW_CHAT, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_DASHBOARD_SHOW_RSS, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_REPLY_TO_ORGANIZER, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_IGNORE_BAD_SSL, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_MYROOMS_ENABLED, Configuration.Type.BOOL);
+		configTypes.put(CONFIG_DEFAULT_GROUP_ID, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_SMTP_PORT, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_SMTP_TIMEOUT_CON, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_SMTP_TIMEOUT, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_DEFAULT_LANG, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_DOCUMENT_DPI, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_DOCUMENT_QUALITY, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_SCREENSHARING_QUALITY, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_SCREENSHARING_FPS, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_MAX_UPLOAD_SIZE, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_APPOINTMENT_REMINDER_MINUTES, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_LOGIN_MIN_LENGTH, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_PASS_MIN_LENGTH, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_CALENDAR_ROOM_CAPACITY, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_KEYCODE_ARRANGE, Configuration.Type.HOTKEY);
+		configTypes.put(CONFIG_KEYCODE_MUTE_OTHERS, Configuration.Type.HOTKEY);
+		configTypes.put(CONFIG_KEYCODE_MUTE, Configuration.Type.HOTKEY);
+		configTypes.put(CONFIG_DEFAULT_LDAP_ID, Configuration.Type.NUMBER);
+		configTypes.put(CONFIG_EXT_PROCESS_TTL, Configuration.Type.NUMBER);
 	}
 
 	@Autowired
@@ -466,6 +469,17 @@ public class BackupImport {
 		registry.bind(Date.class, DateConverter.class);
 		registry.bind(User.class, new UserConverter(userDao, userMap));
 
+		final Map<Integer, String> keyMap = new HashMap<>();
+		Arrays.asList(KeyEvent.class.getDeclaredFields()).stream()
+				.filter(fld -> fld.getName().startsWith("VK_"))
+				.forEach(fld -> {
+					try {
+						keyMap.put(fld.getInt(null), "Shift+" + WordUtils.capitalizeFully(fld.getName().substring(3)));
+					} catch (IllegalArgumentException|IllegalAccessException e) {
+						log.error("Unexpected exception while building KEY map {}", fld);
+					}
+				});
+
 		List<Configuration> list = readList(serializer, f, "configs.xml", "configs", Configuration.class, null, true);
 		for (Configuration c : list) {
 			if (c.getKey() == null || c.isDeleted()) {
@@ -478,8 +492,15 @@ public class BackupImport {
 			Configuration.Type type = configTypes.get(c.getKey());
 			if (type != null) {
 				c.setType(type);
-				if (Configuration.Type.bool == type) {
+				if (Configuration.Type.BOOL == type) {
 					c.setValue(String.valueOf("1".equals(c.getValue()) || "yes".equals(c.getValue()) || "true".equals(c.getValue())));
+				} else if (Configuration.Type.HOTKEY == type) {
+					try {
+						int val = c.getValueN().intValue();
+						c.setValue(keyMap.get(val));
+					} catch(Exception e) {
+						//no-op, value is already HOTKEY
+					}
 				}
 			}
 			Configuration cfg = cfgDao.forceGet(c.getKey());
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 caa5e79..46d2d61 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
@@ -61,6 +61,7 @@ import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_IGNORE_B
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_ARRANGE;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_MUTE;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_MUTE_OTHERS;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_QUICKPOLL;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_LNAME_MIN_LENGTH;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_LOGIN_MIN_LENGTH;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_MAX_UPLOAD_SIZE;
@@ -191,174 +192,176 @@ public class ImportInitvalues {
 	 */
 	public static List<Configuration> initialCfgs(InstallationConfig cfg) {
 		List<Configuration> list = new ArrayList<>();
-		addCfg(list, CONFIG_CRYPT, cfg.getCryptClassName(), Configuration.Type.string,
+		addCfg(list, CONFIG_CRYPT, cfg.getCryptClassName(), Configuration.Type.STRING,
 				"This Class is used for Authentification-Crypting. "
 						+ "Be carefull what you do here! If you change it while "
 						+ "running previous Pass of users will not be workign anymore! "
 						+ "for more Information see https://openmeetings.apache.org/CustomCryptMechanism.html"
 						, VER_1_9);
 
-		addCfg(list, CONFIG_REGISTER_FRONTEND, String.valueOf(cfg.isAllowFrontendRegister()), Configuration.Type.bool
+		addCfg(list, CONFIG_REGISTER_FRONTEND, String.valueOf(cfg.isAllowFrontendRegister()), Configuration.Type.BOOL
 				, "Is user register available on login screen", VER_1_8);
-		addCfg(list, CONFIG_REGISTER_SOAP, String.valueOf(true), Configuration.Type.bool, "Is user register available via SOAP/REST", VER_3_0);
-		addCfg(list, CONFIG_REGISTER_OAUTH, String.valueOf(true), Configuration.Type.bool, "Is user register available via OAuth", VER_3_0);
+		addCfg(list, CONFIG_REGISTER_SOAP, String.valueOf(true), Configuration.Type.BOOL, "Is user register available via SOAP/REST", VER_3_0);
+		addCfg(list, CONFIG_REGISTER_OAUTH, String.valueOf(true), Configuration.Type.BOOL, "Is user register available via OAuth", VER_3_0);
 		// this group_id is the Group of users who register through the frontend or SOAP
-		addCfg(list, CONFIG_DEFAULT_GROUP_ID, String.valueOf(getDefaultGroup()), Configuration.Type.number, "", VER_1_8);
+		addCfg(list, CONFIG_DEFAULT_GROUP_ID, String.valueOf(getDefaultGroup()), Configuration.Type.NUMBER, "", VER_1_8);
 
-		addCfg(list, CONFIG_SMTP_SERVER, cfg.getSmtpServer(), Configuration.Type.string, "this is the smtp server to send messages", VER_1_9);
+		addCfg(list, CONFIG_SMTP_SERVER, cfg.getSmtpServer(), Configuration.Type.STRING, "this is the smtp server to send messages", VER_1_9);
 
-		addCfg(list, CONFIG_SMTP_PORT, String.valueOf(cfg.getSmtpPort()), Configuration.Type.number, "this is the smtp server port normally 25", VER_1_9);
+		addCfg(list, CONFIG_SMTP_PORT, String.valueOf(cfg.getSmtpPort()), Configuration.Type.NUMBER, "this is the smtp server port normally 25", VER_1_9);
 
-		addCfg(list, CONFIG_SMTP_SYSTEM_EMAIL, cfg.getMailReferer(), Configuration.Type.string, "all send e-mails by the system will have this address", VER_1_9);
+		addCfg(list, CONFIG_SMTP_SYSTEM_EMAIL, cfg.getMailReferer(), Configuration.Type.STRING, "all send e-mails by the system will have this address", VER_1_9);
 
-		addCfg(list, CONFIG_SMTP_USER, cfg.getMailAuthName(), Configuration.Type.string, "System auth email username", VER_1_9);
+		addCfg(list, CONFIG_SMTP_USER, cfg.getMailAuthName(), Configuration.Type.STRING, "System auth email username", VER_1_9);
 
-		addCfg(list, CONFIG_SMTP_PASS, cfg.getMailAuthPass(), Configuration.Type.string, "System auth email password", VER_1_9);
+		addCfg(list, CONFIG_SMTP_PASS, cfg.getMailAuthPass(), Configuration.Type.STRING, "System auth email password", VER_1_9);
 
-		addCfg(list, CONFIG_SMTP_TLS, String.valueOf(cfg.isMailUseTls()), Configuration.Type.bool, "Enable TLS", VER_1_9);
+		addCfg(list, CONFIG_SMTP_TLS, String.valueOf(cfg.isMailUseTls()), Configuration.Type.BOOL, "Enable TLS", VER_1_9);
 
-		addCfg(list, CONFIG_SMTP_TIMEOUT_CON, "30000", Configuration.Type.number,
+		addCfg(list, CONFIG_SMTP_TIMEOUT_CON, "30000", Configuration.Type.NUMBER,
 				"Socket connection timeout value in milliseconds. Default is 30 seconds (30000).", VER_1_9);
 
-		addCfg(list, CONFIG_SMTP_TIMEOUT, "30000", Configuration.Type.number,
+		addCfg(list, CONFIG_SMTP_TIMEOUT, "30000", Configuration.Type.NUMBER,
 				"Socket I/O timeout value in milliseconds. Default is 30 seconds (30000).", VER_1_9);
 
-		addCfg(list, CONFIG_APPLICATION_NAME, DEFAULT_APP_NAME, Configuration.Type.string, "Name of the Browser Title window", VER_3_0);
+		addCfg(list, CONFIG_APPLICATION_NAME, DEFAULT_APP_NAME, Configuration.Type.STRING, "Name of the Browser Title window", VER_3_0);
 
 		// "1" == "EN"
-		addCfg(list, CONFIG_DEFAULT_LANG, String.valueOf(cfg.getDefaultLangId()), Configuration.Type.number, "Default System Language ID see languages.xml", VER_1_8);
+		addCfg(list, CONFIG_DEFAULT_LANG, String.valueOf(cfg.getDefaultLangId()), Configuration.Type.NUMBER, "Default System Language ID see languages.xml", VER_1_8);
 
-		addCfg(list, CONFIG_DOCUMENT_DPI, String.valueOf(cfg.getDocDpi()), Configuration.Type.number,
+		addCfg(list, CONFIG_DOCUMENT_DPI, String.valueOf(cfg.getDocDpi()), Configuration.Type.NUMBER,
 				"dpi for conversion of PDF to images (should be an integer between 50 and  600 with a default value of 150 dpi)", VER_2_0);
 
-		addCfg(list, CONFIG_DOCUMENT_QUALITY, String.valueOf(cfg.getDocQuality()), Configuration.Type.number,
+		addCfg(list, CONFIG_DOCUMENT_QUALITY, String.valueOf(cfg.getDocQuality()), Configuration.Type.NUMBER,
 				"compression quality for conversion of PDF to images (should be an integer between 1 and 100, with a default value of 90)", VER_2_0);
 
-		addCfg(list, CONFIG_PATH_IMAGEMAGIC, cfg.getImageMagicPath(), Configuration.Type.string, "Path to ImageMagick tools", VER_2_0);
+		addCfg(list, CONFIG_PATH_IMAGEMAGIC, cfg.getImageMagicPath(), Configuration.Type.STRING, "Path to ImageMagick tools", VER_2_0);
 
-		addCfg(list, CONFIG_PATH_SOX, cfg.getSoxPath(), Configuration.Type.string, "Path To SoX-Tools", VER_2_0);
+		addCfg(list, CONFIG_PATH_SOX, cfg.getSoxPath(), Configuration.Type.STRING, "Path To SoX-Tools", VER_2_0);
 
-		addCfg(list, CONFIG_PATH_FFMPEG, cfg.getFfmpegPath(), Configuration.Type.string, "Path To FFMPEG", VER_2_0);
-		addCfg(list, CONFIG_PATH_OFFICE, cfg.getOfficePath(), Configuration.Type.string,
+		addCfg(list, CONFIG_PATH_FFMPEG, cfg.getFfmpegPath(), Configuration.Type.STRING, "Path To FFMPEG", VER_2_0);
+		addCfg(list, CONFIG_PATH_OFFICE, cfg.getOfficePath(), Configuration.Type.STRING,
 				"The path to OpenOffice/LibreOffice (optional) please set this to the real path in case jodconverter is unable to find OpenOffice/LibreOffice installation automatically", VER_2_0);
 
-		addCfg(list, CONFIG_DASHBOARD_RSS_FEED1, cfg.getUrlFeed(), Configuration.Type.string, "Feed URL 1", VER_1_9);
+		addCfg(list, CONFIG_DASHBOARD_RSS_FEED1, cfg.getUrlFeed(), Configuration.Type.STRING, "Feed URL 1", VER_1_9);
 
-		addCfg(list, CONFIG_DASHBOARD_RSS_FEED2, cfg.getUrlFeed2(), Configuration.Type.string, "Feed URL 2", VER_1_9);
+		addCfg(list, CONFIG_DASHBOARD_RSS_FEED2, cfg.getUrlFeed2(), Configuration.Type.STRING, "Feed URL 2", VER_1_9);
 
-		addCfg(list, CONFIG_EMAIL_AT_REGISTER, String.valueOf(cfg.isSendEmailAtRegister()), Configuration.Type.bool,
+		addCfg(list, CONFIG_EMAIL_AT_REGISTER, String.valueOf(cfg.isSendEmailAtRegister()), Configuration.Type.BOOL,
 				"User get a EMail with their Account data.", VER_2_0);
 
-		addCfg(list, CONFIG_EMAIL_VERIFICATION, String.valueOf(cfg.isSendEmailWithVerficationCode()), Configuration.Type.bool,
+		addCfg(list, CONFIG_EMAIL_VERIFICATION, String.valueOf(cfg.isSendEmailWithVerficationCode()), Configuration.Type.BOOL,
 				String.format("User must activate their account by clicking on the "
 						+ "activation-link in the registering Email "
 						+ "It makes no sense to make this(%s) 'true' while "
 						+ "%s is 'false' cause you need to send a EMail.", CONFIG_EMAIL_VERIFICATION, CONFIG_EMAIL_AT_REGISTER), VER_2_0);
 
-		addCfg(list, CONFIG_APPLICATION_BASE_URL, cfg.getBaseUrl(), Configuration.Type.string, "Base URL your OPenmeetings installation will be accessible at.", "3.0.2");
+		addCfg(list, CONFIG_APPLICATION_BASE_URL, cfg.getBaseUrl(), Configuration.Type.STRING, "Base URL your OPenmeetings installation will be accessible at.", "3.0.2");
 
 		// ***************************************
 		// ***************************************
 		// SIP Integration Coniguration Values
 		// ***************************************
 
-		addCfg(list, CONFIG_SIP_ENABLED, String.valueOf(cfg.isSipEnable()), Configuration.Type.bool, "Enable to enable the red5SIP integration ", VER_1_9);
-		addCfg(list, CONFIG_SIP_ROOM_PREFIX, cfg.getSipRoomPrefix(), Configuration.Type.string, "Numerical prefix for OM rooms created inside the SIP", VER_1_9);
-		addCfg(list, CONFIG_SIP_EXTEN_CONTEXT, cfg.getSipExtenContext(), Configuration.Type.string, "Enable to enable the red5SIP integration ", VER_1_9);
+		addCfg(list, CONFIG_SIP_ENABLED, String.valueOf(cfg.isSipEnable()), Configuration.Type.BOOL, "Enable to enable the red5SIP integration ", VER_1_9);
+		addCfg(list, CONFIG_SIP_ROOM_PREFIX, cfg.getSipRoomPrefix(), Configuration.Type.STRING, "Numerical prefix for OM rooms created inside the SIP", VER_1_9);
+		addCfg(list, CONFIG_SIP_EXTEN_CONTEXT, cfg.getSipExtenContext(), Configuration.Type.STRING, "Enable to enable the red5SIP integration ", VER_1_9);
 
 		// ***************************************
 		// ***************************************
 		// Timezone settings
 		// ***************************************
 
-		addCfg(list, CONFIG_DEFAULT_TIMEZONE, cfg.getTimeZone(), Configuration.Type.string, "This is the default timezone if nothing is specified", VER_1_9);
+		addCfg(list, CONFIG_DEFAULT_TIMEZONE, cfg.getTimeZone(), Configuration.Type.STRING, "This is the default timezone if nothing is specified", VER_1_9);
 
 		// ***************************************
 		// ***************************************
 		// additional settings
 		// ***************************************
 
-		addCfg(list, CONFIG_SCREENSHARING_QUALITY, "1", Configuration.Type.number,
+		addCfg(list, CONFIG_SCREENSHARING_QUALITY, "1", Configuration.Type.NUMBER,
 				"Default selection in ScreenSharing Quality:\n 0 - bigger frame rate, no resize\n 1 - no resize\n 2 - size == 1/2 of selected area\n 3 - size == 3/8 of selected area", VER_3_0_3);
 
-		addCfg(list, CONFIG_SCREENSHARING_FPS, "10", Configuration.Type.number, "Default selection in ScreenSharing FPS", VER_3_0_3);
-		addCfg(list, CONFIG_SCREENSHARING_FPS_SHOW, String.valueOf(true), Configuration.Type.bool, "Is screensharing FPS should be displayed or not", VER_3_0_3);
-		addCfg(list, CONFIG_SCREENSHARING_ALLOW_REMOTE, String.valueOf(true), Configuration.Type.bool
+		addCfg(list, CONFIG_SCREENSHARING_FPS, "10", Configuration.Type.NUMBER, "Default selection in ScreenSharing FPS", VER_3_0_3);
+		addCfg(list, CONFIG_SCREENSHARING_FPS_SHOW, String.valueOf(true), Configuration.Type.BOOL, "Is screensharing FPS should be displayed or not", VER_3_0_3);
+		addCfg(list, CONFIG_SCREENSHARING_ALLOW_REMOTE, String.valueOf(true), Configuration.Type.BOOL
 				, "Is remote control will be enabled while screensharing. Allowing remote control will be not possible in case it is set to 'false'", "3.0.4");
 
-		addCfg(list, CONFIG_DASHBOARD_SHOW_MYROOMS, String.valueOf(true), Configuration.Type.bool, "Show 'My Rooms' widget on dashboard", VER_1_9);
+		addCfg(list, CONFIG_DASHBOARD_SHOW_MYROOMS, String.valueOf(true), Configuration.Type.BOOL, "Show 'My Rooms' widget on dashboard", VER_1_9);
 
-		addCfg(list, CONFIG_DASHBOARD_SHOW_CHAT, String.valueOf(true), Configuration.Type.bool, "Show 'Global Chat' outside the room", VER_1_9);
+		addCfg(list, CONFIG_DASHBOARD_SHOW_CHAT, String.valueOf(true), Configuration.Type.BOOL, "Show 'Global Chat' outside the room", VER_1_9);
 
-		addCfg(list, CONFIG_DASHBOARD_SHOW_RSS, String.valueOf(false), Configuration.Type.bool, "Show RSS widget on dashboard", VER_1_9);
+		addCfg(list, CONFIG_DASHBOARD_SHOW_RSS, String.valueOf(false), Configuration.Type.BOOL, "Show RSS widget on dashboard", VER_1_9);
 
-		addCfg(list, CONFIG_MAX_UPLOAD_SIZE, String.valueOf(DEFAULT_MAX_UPLOAD_SIZE), Configuration.Type.number,
+		addCfg(list, CONFIG_MAX_UPLOAD_SIZE, String.valueOf(DEFAULT_MAX_UPLOAD_SIZE), Configuration.Type.NUMBER,
 				"Maximum size of upload file (bytes)", VER_1_8);
 
-		addCfg(list, CONFIG_APPOINTMENT_REMINDER_MINUTES, "15", Configuration.Type.number,
+		addCfg(list, CONFIG_APPOINTMENT_REMINDER_MINUTES, "15", Configuration.Type.NUMBER,
 				"The number of minutes before reminder emails are send. Set to 0 to disable reminder emails", VER_1_9);
 
-		addCfg(list, CONFIG_LOGIN_MIN_LENGTH, String.valueOf(USER_LOGIN_MINIMUM_LENGTH), Configuration.Type.number,
+		addCfg(list, CONFIG_LOGIN_MIN_LENGTH, String.valueOf(USER_LOGIN_MINIMUM_LENGTH), Configuration.Type.NUMBER,
 				"Number of chars needed in a user login", VER_1_9);
 
-		addCfg(list, CONFIG_PASS_MIN_LENGTH, String.valueOf(USER_PASSWORD_MINIMUM_LENGTH), Configuration.Type.number,
+		addCfg(list, CONFIG_PASS_MIN_LENGTH, String.valueOf(USER_PASSWORD_MINIMUM_LENGTH), Configuration.Type.NUMBER,
 				"Number of chars needed in a user password", VER_1_9);
 
-		addCfg(list, CONFIG_CALENDAR_ROOM_CAPACITY, "50", Configuration.Type.number,
+		addCfg(list, CONFIG_CALENDAR_ROOM_CAPACITY, "50", Configuration.Type.NUMBER,
 				"Default number of participants conference room created via calendar", VER_1_9);
 
-		addCfg(list, CONFIG_KEYCODE_ARRANGE, "119", Configuration.Type.number
-				, "A hot key code for arrange video windows functionality. Should be used with Shift key. (Keycode 119 is F8)", VER_2_0);
-		addCfg(list, CONFIG_KEYCODE_MUTE_OTHERS, "123", Configuration.Type.number
-				, "A hot key code for the 'mute others' functionality. Should be used with Shift key. (Keycode 123 is F12)", VER_2_0);
-		addCfg(list, CONFIG_KEYCODE_MUTE, "118", Configuration.Type.number
-				, "A hot key code for the 'mute/unmute audio' functionality. Should be used with Shift key. (Keycode 118 is F7)", VER_2_0);
+		addCfg(list, CONFIG_KEYCODE_ARRANGE, "Shift+F8", Configuration.Type.HOTKEY
+				, "A hot key code for arrange video windows functionality", VER_2_0);
+		addCfg(list, CONFIG_KEYCODE_MUTE_OTHERS, "Shift+F12", Configuration.Type.HOTKEY
+				, "A hot key code for the 'mute others' functionality", VER_2_0);
+		addCfg(list, CONFIG_KEYCODE_MUTE, "Shift+F7", Configuration.Type.HOTKEY
+				, "A hot key code for the 'mute/unmute audio' functionality", VER_2_0);
 
 		// system-wide ldap params
-		addCfg(list, CONFIG_DEFAULT_LDAP_ID, "0", Configuration.Type.number, "Ldap domain selected by default in the login screen", VER_1_9);
+		addCfg(list, CONFIG_DEFAULT_LDAP_ID, "0", Configuration.Type.NUMBER, "Ldap domain selected by default in the login screen", VER_1_9);
 
 		// set inviter's email address as ReplyTo in email invitations
-		addCfg(list, CONFIG_REPLY_TO_ORGANIZER, String.valueOf(cfg.isReplyToOrganizer()), Configuration.Type.bool,
+		addCfg(list, CONFIG_REPLY_TO_ORGANIZER, String.valueOf(cfg.isReplyToOrganizer()), Configuration.Type.BOOL,
 				"Set inviter's email address as ReplyTo in email invitations", VER_2_0);
 
-		addCfg(list, CONFIG_DEFAULT_LANDING_ZONE, "user/dashboard", Configuration.Type.string
+		addCfg(list, CONFIG_DEFAULT_LANDING_ZONE, "user/dashboard", Configuration.Type.STRING
 				, "Area to be shown to the user after login. Possible values are: "
 						+ "user/dashboard, user/calendar, user/record, rooms/my, rooms/group, rooms/public, admin/user, admin/connection"
 						+ ", admin/group, admin/room, admin/config, admin/lang, admin/ldap, admin/backup, admin/server, admin/oauth2", "2.1.x");
 
 		// oauth2 params
-		addCfg(list, CONFIG_IGNORE_BAD_SSL, String.valueOf(false), Configuration.Type.bool,
+		addCfg(list, CONFIG_IGNORE_BAD_SSL, String.valueOf(false), Configuration.Type.BOOL,
 				"Set \"yes\" or \"no\" to enable/disable ssl certifications checking for OAuth2", VER_3_0);
 
-		addCfg(list, CONFIG_REDIRECT_URL_FOR_EXTERNAL, "", Configuration.Type.string,
+		addCfg(list, CONFIG_REDIRECT_URL_FOR_EXTERNAL, "", Configuration.Type.STRING,
 				"Users entered the room via invitationHash or secureHash will be redirected to this URL on connection lost", VER_3_0);
-		addCfg(list, CONFIG_GOOGLE_ANALYTICS_CODE, null, Configuration.Type.string, "Code for Google Analytics", "3.1.0");
-		addCfg(list, CONFIG_FLASH_SECURE, String.valueOf(false), Configuration.Type.bool, "Wether it should try to connect to rtmps first or not", VER_4_0_0);
-		addCfg(list, CONFIG_FLASH_SECURE_PROXY, "none", Configuration.Type.string, "The setting for the NetConnection default settings is 'none'\n set to value 'best' if you are trying to use rtmp over native SSL", VER_4_0_0);
-		addCfg(list, CONFIG_FLASH_VIDEO_CODEC, "h263", Configuration.Type.string, "Camera codecType, possible values: 'h263', 'h264'", VER_4_0_0);
-		addCfg(list, CONFIG_FLASH_VIDEO_FPS, "30", Configuration.Type.number, "Camera FPS, should be positive number in range (0, 60]", VER_4_0_0);
-		addCfg(list, CONFIG_FLASH_VIDEO_BANDWIDTH, "0", Configuration.Type.number, "An integer that specifies the maximum amount of bandwidth that the current outgoing video feed can use, in bytes per second. To specify that Flash video can use as much bandwidth as needed to maintain the value of frameQuality, pass 0 for bandwidth.", VER_4_0_0);
-		addCfg(list, CONFIG_FLASH_CAM_QUALITY, "90", Configuration.Type.number, "An integer that specifies the required level of picture quality, as determined by the amount of compression being applied to each video frame. Acceptable values range from 1 (lowest quality, maximum compression) to 100 (highest quality, no compression). To specify that picture quality can vary as needed to avoid exceeding bandwidth, pass 0 for quality.", VER_4_0_0);
-		addCfg(list, CONFIG_FLASH_MIC_RATE, "22", Configuration.Type.number, "The rate at which the microphone should capture sound, in kHz. Acceptable values are 5, 8, 11, 22, and 44. The default value is 22 kHz if your sound capture device supports this value.", VER_4_0_0);
-		addCfg(list, CONFIG_FLASH_ECHO_PATH, "128", Configuration.Type.number, "Specifies the echo path length (in milliseconds). A longer echo path means better echo cancellation but also introduces longer delays and requires more processing power. The default value is 128; the only other possible value is 256. To disable AEC please specify 0.", VER_4_0_0);
-		addCfg(list, CONFIG_HEADER_XFRAME, HEADER_XFRAME_SAMEORIGIN, Configuration.Type.string, "Value for 'X-Frame-Options' header (default: DENY), more info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options", VER_3_3_0);
-		addCfg(list, CONFIG_HEADER_CSP, HEADER_CSP_SELF, Configuration.Type.string, String.format("Value for 'Content-Security-Policy' header (default: %s), have to be modified to enable Google analytics site: https://content-security-policy.com/", HEADER_CSP_SELF), VER_3_3_0);
-		addCfg(list, CONFIG_EXT_PROCESS_TTL, String.valueOf(getExtProcessTtl()), Configuration.Type.number, String.format("Time to live in minutes for external processes such as conversion via ffmpeg (default %s minutes)", getExtProcessTtl()), VER_3_3_0);
-		addCfg(list, CONFIG_MYROOMS_ENABLED, String.valueOf(true), Configuration.Type.bool, "Users are allowed to create personal rooms", "3.3.2");
-		addCfg(list, CONFIG_REMINDER_MESSAGE, null, Configuration.Type.string, "Reminder message to notify about upcoming appointment, generated message will be used if not set", VER_2_0);
-		addCfg(list, CONFIG_MP4_AUDIO_RATE, String.valueOf(getAudioRate()), Configuration.Type.number, "Audio sampling rate (in Hz) for MP4 video", "4.0.1");
-		addCfg(list, CONFIG_MP4_AUDIO_BITRATE, String.valueOf(getAudioBitrate()), Configuration.Type.string, "Audio bitrate for MP4 video", "4.0.1");
-		addCfg(list, CONFIG_REST_ALLOW_ORIGIN, null, Configuration.Type.string, "List of addresses browser Ajax REST requests are allowed from", "4.0.2");
-		addCfg(list, CONFIG_FNAME_MIN_LENGTH, String.valueOf(USER_LOGIN_MINIMUM_LENGTH), Configuration.Type.number,
+		addCfg(list, CONFIG_GOOGLE_ANALYTICS_CODE, null, Configuration.Type.STRING, "Code for Google Analytics", "3.1.0");
+		addCfg(list, CONFIG_FLASH_SECURE, String.valueOf(false), Configuration.Type.BOOL, "Wether it should try to connect to rtmps first or not", VER_4_0_0);
+		addCfg(list, CONFIG_FLASH_SECURE_PROXY, "none", Configuration.Type.STRING, "The setting for the NetConnection default settings is 'none'\n set to value 'best' if you are trying to use rtmp over native SSL", VER_4_0_0);
+		addCfg(list, CONFIG_FLASH_VIDEO_CODEC, "h263", Configuration.Type.STRING, "Camera codecType, possible values: 'h263', 'h264'", VER_4_0_0);
+		addCfg(list, CONFIG_FLASH_VIDEO_FPS, "30", Configuration.Type.NUMBER, "Camera FPS, should be positive number in range (0, 60]", VER_4_0_0);
+		addCfg(list, CONFIG_FLASH_VIDEO_BANDWIDTH, "0", Configuration.Type.NUMBER, "An integer that specifies the maximum amount of bandwidth that the current outgoing video feed can use, in bytes per second. To specify that Flash video can use as much bandwidth as needed to maintain the value of frameQuality, pass 0 for bandwidth.", VER_4_0_0);
+		addCfg(list, CONFIG_FLASH_CAM_QUALITY, "90", Configuration.Type.NUMBER, "An integer that specifies the required level of picture quality, as determined by the amount of compression being applied to each video frame. Acceptable values range from 1 (lowest quality, maximum compression) to 100 (highest quality, no compression). To specify that picture quality can vary as needed to avoid exceeding bandwidth, pass 0 for quality.", VER_4_0_0);
+		addCfg(list, CONFIG_FLASH_MIC_RATE, "22", Configuration.Type.NUMBER, "The rate at which the microphone should capture sound, in kHz. Acceptable values are 5, 8, 11, 22, and 44. The default value is 22 kHz if your sound capture device supports this value.", VER_4_0_0);
+		addCfg(list, CONFIG_FLASH_ECHO_PATH, "128", Configuration.Type.NUMBER, "Specifies the echo path length (in milliseconds). A longer echo path means better echo cancellation but also introduces longer delays and requires more processing power. The default value is 128; the only other possible value is 256. To disable AEC please specify 0.", VER_4_0_0);
+		addCfg(list, CONFIG_HEADER_XFRAME, HEADER_XFRAME_SAMEORIGIN, Configuration.Type.STRING, "Value for 'X-Frame-Options' header (default: DENY), more info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options", VER_3_3_0);
+		addCfg(list, CONFIG_HEADER_CSP, HEADER_CSP_SELF, Configuration.Type.STRING, String.format("Value for 'Content-Security-Policy' header (default: %s), have to be modified to enable Google analytics site: https://content-security-policy.com/", HEADER_CSP_SELF), VER_3_3_0);
+		addCfg(list, CONFIG_EXT_PROCESS_TTL, String.valueOf(getExtProcessTtl()), Configuration.Type.NUMBER, String.format("Time to live in minutes for external processes such as conversion via ffmpeg (default %s minutes)", getExtProcessTtl()), VER_3_3_0);
+		addCfg(list, CONFIG_MYROOMS_ENABLED, String.valueOf(true), Configuration.Type.BOOL, "Users are allowed to create personal rooms", "3.3.2");
+		addCfg(list, CONFIG_REMINDER_MESSAGE, null, Configuration.Type.STRING, "Reminder message to notify about upcoming appointment, generated message will be used if not set", VER_2_0);
+		addCfg(list, CONFIG_MP4_AUDIO_RATE, String.valueOf(getAudioRate()), Configuration.Type.NUMBER, "Audio sampling rate (in Hz) for MP4 video", "4.0.1");
+		addCfg(list, CONFIG_MP4_AUDIO_BITRATE, String.valueOf(getAudioBitrate()), Configuration.Type.STRING, "Audio bitrate for MP4 video", "4.0.1");
+		addCfg(list, CONFIG_REST_ALLOW_ORIGIN, null, Configuration.Type.STRING, "List of addresses browser Ajax REST requests are allowed from", "4.0.2");
+		addCfg(list, CONFIG_FNAME_MIN_LENGTH, String.valueOf(USER_LOGIN_MINIMUM_LENGTH), Configuration.Type.NUMBER,
 				"Number of chars needed in a user first name", "4.0.4");
-		addCfg(list, CONFIG_LNAME_MIN_LENGTH, String.valueOf(USER_LOGIN_MINIMUM_LENGTH), Configuration.Type.number,
+		addCfg(list, CONFIG_LNAME_MIN_LENGTH, String.valueOf(USER_LOGIN_MINIMUM_LENGTH), Configuration.Type.NUMBER,
 				"Number of chars needed in a user last name", "4.0.4");
-		addCfg(list, CONFIG_CHAT_SEND_ON_ENTER, String.valueOf(false), Configuration.Type.bool,
+		addCfg(list, CONFIG_CHAT_SEND_ON_ENTER, String.valueOf(false), Configuration.Type.BOOL,
 				"Controls if chat message will be set on Enter (default: send on Ctrl+Enter)", "4.0.5");
-		addCfg(list, CONFIG_MP4_VIDEO_PRESET, "medium", Configuration.Type.bool,
+		addCfg(list, CONFIG_MP4_VIDEO_PRESET, "medium", Configuration.Type.BOOL,
 				"Preset (encoder optimization settings) to be used while performing mp4 conversion."
 						+ "Valid values are: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow", "4.0.5");
-		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_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
+				, "A hot key code to start quick poll", "4.0.10");
 		return list;
 	}
 	public void loadConfiguration(InstallationConfig cfg) {
diff --git a/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java b/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java
index f2eb151..13ac101 100644
--- a/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java
+++ b/openmeetings-util/src/main/java/org/apache/openmeetings/util/OpenmeetingsVariables.java
@@ -99,6 +99,7 @@ public class OpenmeetingsVariables {
 	public static final String CONFIG_LNAME_MIN_LENGTH = "user.lname.minimum.length";
 	public static final String CONFIG_CHAT_SEND_ON_ENTER = "chat.send.on.enter";
 	public static final String CONFIG_DISPLAY_NAME_EDITABLE = "display.name.editable";
+	public static final String CONFIG_KEYCODE_QUICKPOLL = "start.quickpoll.keycode";
 
 	public static final String HEADER_XFRAME_SAMEORIGIN = "SAMEORIGIN";
 	public static final String HEADER_CSP_SELF = "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:;";
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigForm.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigForm.java
index 4bf1943..fa73797 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigForm.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigForm.java
@@ -56,28 +56,22 @@ import org.apache.wicket.validation.ValidationError;
 public class ConfigForm extends AdminBaseForm<Configuration> {
 	private static final long serialVersionUID = 1L;
 	private final WebMarkupContainer listContainer;
-	private final TextArea<String> valueS;
-	private final TextField<Long> valueN;
-	private final CheckBox valueB;
+	private final TextArea<String> valueS = new TextArea<>("valueS");
+	private final TextField<Long> valueN = new TextField<Long>("valueN") {
+		private static final long serialVersionUID = 1L;
+
+		@Override
+		protected String[] getInputTypes() {
+			return new String[] {"number"};
+		}
+	};
+	private final CheckBox valueB = new CheckBox("valueB");
+	private final TextField<String> valueH = new TextField<>("value");
 
 	public ConfigForm(String id, WebMarkupContainer listContainer, Configuration configuration) {
 		super(id, new CompoundPropertyModel<>(configuration));
 		setOutputMarkupId(true);
 		this.listContainer = listContainer;
-		valueS = new TextArea<>("valueS");
-		valueN = new TextField<Long>("valueN") {
-			private static final long serialVersionUID = 1L;
-
-			@Override
-			protected String[] getInputTypes() {
-				return new String[] {"number"};
-			}
-		};
-		valueB = new CheckBox("valueB");
-		add(new DateLabel("updated"));
-		add(new Label("user.login"));
-		add(new TextArea<String>("comment"));
-		update(null);
 	}
 
 	private void refresh(AjaxRequestTarget target) {
@@ -87,11 +81,12 @@ public class ConfigForm extends AdminBaseForm<Configuration> {
 
 	private void update(AjaxRequestTarget target) {
 		Configuration c = getModelObject();
-		valueS.setVisible(Type.string == c.getType());
-		valueN.setVisible(Type.number == c.getType());
-		valueB.setVisible(Type.bool == c.getType());
+		valueS.setVisible(Type.STRING == c.getType());
+		valueN.setVisible(Type.NUMBER == c.getType());
+		valueB.setVisible(Type.BOOL == c.getType());
+		valueH.setVisible(Type.HOTKEY == c.getType());
 		if (target != null) {
-			target.add(valueS, valueN, valueB);
+			target.add(valueS, valueN, valueB, valueH);
 		}
 	}
 
@@ -104,6 +99,11 @@ public class ConfigForm extends AdminBaseForm<Configuration> {
 	@Override
 	protected void onInitialize() {
 		super.onInitialize();
+		add(new DateLabel("updated"));
+		add(new Label("user.login"));
+		add(new TextArea<String>("comment"));
+		update(null);
+
 		add(new DropDownChoice<>("type", Arrays.asList(Type.values()), new IChoiceRenderer<Type>() {
 			private static final long serialVersionUID = 1L;
 
@@ -148,6 +148,7 @@ public class ConfigForm extends AdminBaseForm<Configuration> {
 		add(valueS.setLabel(new ResourceModel("271")).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
 		add(valueN.setLabel(new ResourceModel("271")).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
 		add(valueB.setLabel(new ResourceModel("271")).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
+		add(valueH.setLabel(new ResourceModel("271")).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
 	}
 
 	@Override
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 420d7f5..9807f38 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
@@ -19,6 +19,29 @@
 
 -->
 <html xmlns:wicket="http://wicket.apache.org">
+<wicket:head>
+	<script>
+		function configHandleKey(evt) {
+			const inp = $(evt.target);
+			evt.preventDefault();
+			let val = '';
+			if (evt.ctrlKey) {
+				val += 'Ctrl+';
+			}
+			if (evt.altKey) {
+				val += 'Alt+';
+			}
+			if (evt.shiftKey) {
+				val += 'Shift+';
+			}
+			val += evt.key;
+			console.info(val);
+			if (evt.keyCode !== 16 && evt.keyCode !== 17 && evt.keyCode !== 18 && inp.length == 1) {
+				inp.val(val);
+			}
+		}
+	</script>
+</wicket:head>
 <wicket:extend>
 	<div class="adminPanelColumnTable">
 		<span wicket:id="navigator">[dataview navigator]</span>
@@ -77,6 +100,10 @@
 								</label>
 							</div>
 						</div>
+						<div wicket:enclosure="value">
+							<label wicket:for="value"><wicket:message key="271" /></label>
+							<input type="text" onkeydown="configHandleKey(event)" onpaste="return false;" wicket:id="value"/>
+						</div>
 					</div>
 					<div class="formelement">
 						<label><wicket:message key="268" /></label><span wicket:id="updated"/>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/PollsSubMenu.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/PollsSubMenu.java
index a51d9a7..724ac11 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/PollsSubMenu.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/PollsSubMenu.java
@@ -52,6 +52,7 @@ public class PollsSubMenu implements Serializable {
 	private static final String FUNC_QPOLL_ACTION = "quickPollAction";
 	private static final String PARAM_VOTE = "vote";
 	private static final String ACTION_CLOSE = "close";
+	private static final String ACTION_OPEN = "open";
 	private final RoomPanel room;
 	private final RoomMenuPanel mp;
 	private final CreatePollDialog createPoll;
@@ -74,7 +75,9 @@ public class PollsSubMenu implements Serializable {
 				String action = mp.getRequest().getRequestParameters().getParameterValue(PARAM_ACTION).toString();
 				QuickPollManager qm = getBean(QuickPollManager.class);
 				Client c = room.getClient();
-				if (ACTION_CLOSE.equals(action)) {
+				if (ACTION_OPEN.equals(action)) {
+					qm.start(room.getClient());
+				} else if (ACTION_CLOSE.equals(action)) {
 					qm.close(c);
 				} else if (PARAM_VOTE.equals(action)) {
 					boolean vote = mp.getRequest().getRequestParameters().getParameterValue(PARAM_VOTE).toBoolean();
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 355a29a..e4693fc 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
@@ -73,29 +73,27 @@ var Room = (function() {
 				return false;
 		}
 	}
+	function __keyPressed(hotkey, e) {
+		return hotkey.alt === e.altKey
+			&& hotkey.ctrl === e.ctrlKey
+			&& hotkey.shift === e.shiftKey
+			&& hotkey.key.toUpperCase() === e.key.toUpperCase();
+	}
 	function _keyHandler(e) {
-		if (e.shiftKey) {
-			switch (e.which) {
-				case options.keycode.arrange: // Shift+F8 by default
-					VideoUtil.arrange();
-					break;
-				case options.keycode.muteothers: // Shift+F12 by default
-				{
-					const v = _getSelfAudioClient();
-					if (v !== null) {
-						VideoManager.clickMuteOthers(Room.getOptions().uid);
-					}
-				}
-					break;
-				case options.keycode.mute: // Shift+F7 by default
-				{
-					const v = _getSelfAudioClient();
-					if (v !== null) {
-						v.mute(!v.isMuted());
-					}
-				}
-					break;
+		if (__keyPressed(options.keycode.arrange, e)) {
+			VideoUtil.arrange();
+		} else if (__keyPressed(options.keycode.muteothers, e)) {
+			const v = _getSelfAudioClient();
+			if (v !== null) {
+				VideoManager.clickMuteOthers(Room.getOptions().uid);
+			}
+		} else if (__keyPressed(options.keycode.mute, e)) {
+			const v = _getSelfAudioClient();
+			if (v !== null) {
+				v.mute(!v.isMuted());
 			}
+		} else if (__keyPressed(options.keycode.quickpoll, e)) {
+			quickPollAction('open');
 		}
 		if (e.which === 27) {
 			$('#wb-rename-menu').hide();