diff --git a/guacamole/src/main/webapp/app/client/clientModule.js b/guacamole/src/main/webapp/app/client/clientModule.js
index c27957115..944189dd4 100644
--- a/guacamole/src/main/webapp/app/client/clientModule.js
+++ b/guacamole/src/main/webapp/app/client/clientModule.js
@@ -23,4 +23,4 @@
/**
* The module for code used to connect to a connection or balancing group.
*/
-angular.module('client', ['auth', 'history', 'rest']);
+angular.module('client', ['auth', 'history', 'osk', 'rest']);
diff --git a/guacamole/src/main/webapp/app/client/controllers/clientController.js b/guacamole/src/main/webapp/app/client/controllers/clientController.js
index 5e134f64d..ec2690ee6 100644
--- a/guacamole/src/main/webapp/app/client/controllers/clientController.js
+++ b/guacamole/src/main/webapp/app/client/controllers/clientController.js
@@ -145,7 +145,10 @@ angular.module('home').controller('clientController', ['$scope', '$routeParams',
// Hide menu by default
$scope.menuShown = false;
-
+
+ // Use physical keyboard by default
+ $scope.inputMethod = 'none';
+
// Convenience method for closing the menu
$scope.closeMenu = function closeMenu() {
$scope.menuShown = false;
@@ -198,6 +201,14 @@ angular.module('home').controller('clientController', ['$scope', '$routeParams',
return true;
}
+ // Show/hide UI elements depending on input method
+ $scope.$watch('inputMethod', function setInputMethod(inputMethod) {
+
+ // Show on-screen keyboard only if selected
+ $scope.showOSK = (inputMethod === 'osk');
+
+ });
+
$scope.$watch('menuShown', function setKeyboardEnabled(menuShown, menuShownPreviousState) {
// Send clipboard data if menu is hidden
diff --git a/guacamole/src/main/webapp/app/client/styles/keyboard.css b/guacamole/src/main/webapp/app/client/styles/keyboard.css
index f10472ec9..270153a4d 100644
--- a/guacamole/src/main/webapp/app/client/styles/keyboard.css
+++ b/guacamole/src/main/webapp/app/client/styles/keyboard.css
@@ -34,120 +34,10 @@
background: #222;
opacity: 0.85;
+ visibility: hidden;
z-index: 1;
}
-.guac-keyboard {
- display: inline-block;
- width: 100%;
-
- margin: 0;
- padding: 0;
- cursor: default;
-
- text-align: left;
- vertical-align: middle;
-}
-
-.guac-keyboard .guac-keyboard-key-container {
- display: inline-block;
-}
-
-.guac-keyboard .guac-keyboard-key {
- background: #444;
- border: 1px outset #888;
- -moz-border-radius: 0.1em;
- -webkit-border-radius: 0.1em;
- -khtml-border-radius: 0.1em;
- border-radius: 0.1em;
-}
-
-.guac-keyboard .guac-keyboard-cap {
- color: white;
- font-family: sans-serif;
- font-size: 50%;
- font-weight: lighter;
- text-align: center;
- white-space: pre;
-}
-
-.guac-keyboard .guac-keyboard-key:hover {
- cursor: pointer;
-}
-
-.guac-keyboard .guac-keyboard-key.highlight {
- background: #666;
- border-color: #666;
-}
-
-.guac-keyboard.guac-keyboard-modifier-shift .guac-keyboard-key.shift,
-.guac-keyboard.guac-keyboard-modifier-numsym .guac-keyboard-key.numsym {
- background: #882;
- border-color: #DD4;
-}
-
-.guac-keyboard.guac-keyboard-modifier-control .guac-keyboard-key.control,
-.guac-keyboard.guac-keyboard-modifier-numsym .guac-keyboard-key.numsym {
- background: #882;
- border-color: #DD4;
-}
-
-.guac-keyboard.guac-keyboard-modifier-alt .guac-keyboard-key.alt,
-.guac-keyboard.guac-keyboard-modifier-numsym .guac-keyboard-key.numsym {
- background: #882;
- border-color: #DD4;
-}
-
-.guac-keyboard.guac-keyboard-modifier-super .guac-keyboard-key.super,
-.guac-keyboard.guac-keyboard-modifier-numsym .guac-keyboard-key.numsym {
- background: #882;
- border-color: #DD4;
-}
-
-.guac-keyboard .guac-keyboard-key.guac-keyboard-pressed {
- background: #822;
- border-color: #D44;
- border-style: inset;
-}
-
-.guac-keyboard .guac-keyboard-row {
- line-height: 0;
-}
-
-.guac-keyboard .guac-keyboard-column {
- display: inline-block;
- text-align: center;
- vertical-align: top;
-}
-
-.guac-keyboard .guac-keyboard-gap {
- display: inline-block;
-}
-
-/* Hide keycaps requiring modifiers which are NOT currently active. */
-.guac-keyboard:not(.guac-keyboard-modifier-caps)
-.guac-keyboard-cap.guac-keyboard-requires-caps,
-
-.guac-keyboard:not(.guac-keyboard-modifier-numsym)
-.guac-keyboard-cap.guac-keyboard-requires-numsym,
-
-.guac-keyboard:not(.guac-keyboard-modifier-shift)
-.guac-keyboard-cap.guac-keyboard-requires-shift,
-
-/* Hide keycaps NOT requiring modifiers which ARE currently active, where that
- modifier is used to determine which cap is displayed for the current key. */
-.guac-keyboard.guac-keyboard-modifier-shift
-.guac-keyboard-key.guac-keyboard-uses-shift
-.guac-keyboard-cap:not(.guac-keyboard-requires-shift),
-
-.guac-keyboard.guac-keyboard-modifier-numsym
-.guac-keyboard-key.guac-keyboard-uses-numsym
-.guac-keyboard-cap:not(.guac-keyboard-requires-numsym),
-
-.guac-keyboard.guac-keyboard-modifier-caps
-.guac-keyboard-key.guac-keyboard-uses-caps
-.guac-keyboard-cap:not(.guac-keyboard-requires-caps) {
-
- display: none;
-
+.keyboard-container.shown {
+ visibility: visible;
}
diff --git a/guacamole/src/main/webapp/app/client/templates/client.html b/guacamole/src/main/webapp/app/client/templates/client.html
index 4402a0bbc..460e71641 100644
--- a/guacamole/src/main/webapp/app/client/templates/client.html
+++ b/guacamole/src/main/webapp/app/client/templates/client.html
@@ -48,20 +48,20 @@

diff --git a/guacamole/src/main/webapp/app/osk/directives/guacOsk.js b/guacamole/src/main/webapp/app/osk/directives/guacOsk.js
new file mode 100644
index 000000000..6b7cf529c
--- /dev/null
+++ b/guacamole/src/main/webapp/app/osk/directives/guacOsk.js
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * A directive which displays the Guacamole on-screen keyboard.
+ */
+angular.module('osk').directive('guacOsk', [function guacOsk() {
+
+ return {
+ restrict: 'E',
+ replace: true,
+ scope: {
+
+ /**
+ * The URL for the Guacamole on-screen keyboard layout to use.
+ *
+ * @type String
+ */
+ layout : '='
+
+ },
+
+ templateUrl: 'app/osk/templates/guacOsk.html',
+ controller: ['$scope', '$rootScope', '$window', '$element',
+ function guacOsk($scope, $rootScope, $window, $element) {
+
+ /**
+ * The current on-screen keyboard, if any.
+ *
+ * @type Guacamole.OnScreenKeyboard
+ */
+ var keyboard = null;
+
+ /**
+ * The main containing element for the entire directive.
+ *
+ * @type Element
+ */
+ var main = $element[0];
+
+ /**
+ * Event listener which resizes the current keyboard, if any, such
+ * that it fits within available space.
+ */
+ var resizeListener = function resizeListener() {
+
+ // Resize keyboard, if defined
+ if (keyboard)
+ keyboard.resize(main.offsetWidth);
+
+ };
+
+ // Set layout whenever URL changes
+ $scope.$watch("layout", function setLayout(layout) {
+
+ // Remove current keyboard
+ keyboard = null;
+ main.innerHTML = "";
+
+ // Load new keyboard
+ if (layout) {
+
+ // Add OSK element
+ keyboard = new Guacamole.OnScreenKeyboard(layout);
+ main.appendChild(keyboard.getElement());
+
+ // Init size
+ keyboard.resize(main.offsetWidth);
+
+ // Broadcast keydown for each key pressed
+ keyboard.onkeydown = function(keysym) {
+ $rootScope.$broadcast('guacKeydown', keysym);
+ };
+
+ // Broadcast keydown for each key released
+ keyboard.onkeyup = function(keysym) {
+ $rootScope.$broadcast('guacKeyup', keysym);
+ };
+
+ // Resize keyboard whenever window changes size
+ $window.addEventListener('resize', resizeListener);
+
+ }
+
+ }); // end layout scope watch
+
+ // Clean up event listeners upon destroy
+ $scope.$on('$destroy', function destroyKeyboard() {
+ $window.removeEventListener('resize', resizeListener);
+ });
+
+ }]
+
+ };
+}]);
diff --git a/guacamole/src/main/webapp/app/osk/oskModule.js b/guacamole/src/main/webapp/app/osk/oskModule.js
new file mode 100644
index 000000000..36cc8ea69
--- /dev/null
+++ b/guacamole/src/main/webapp/app/osk/oskModule.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Module for displaying the Guacamole on-screen keyboard.
+ */
+angular.module('osk', []);
diff --git a/guacamole/src/main/webapp/app/osk/styles/osk.css b/guacamole/src/main/webapp/app/osk/styles/osk.css
new file mode 100644
index 000000000..ae5d26bf9
--- /dev/null
+++ b/guacamole/src/main/webapp/app/osk/styles/osk.css
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+.guac-keyboard {
+ display: inline-block;
+ width: 100%;
+
+ margin: 0;
+ padding: 0;
+ cursor: default;
+
+ text-align: left;
+ vertical-align: middle;
+}
+
+.guac-keyboard .guac-keyboard-key-container {
+ display: inline-block;
+}
+
+.guac-keyboard .guac-keyboard-key {
+ background: #444;
+ border: 1px outset #888;
+ -moz-border-radius: 0.1em;
+ -webkit-border-radius: 0.1em;
+ -khtml-border-radius: 0.1em;
+ border-radius: 0.1em;
+}
+
+.guac-keyboard .guac-keyboard-cap {
+ color: white;
+ font-family: sans-serif;
+ font-size: 50%;
+ font-weight: lighter;
+ text-align: center;
+ white-space: pre;
+}
+
+.guac-keyboard .guac-keyboard-key:hover {
+ cursor: pointer;
+}
+
+.guac-keyboard .guac-keyboard-key.highlight {
+ background: #666;
+ border-color: #666;
+}
+
+.guac-keyboard.guac-keyboard-modifier-shift .guac-keyboard-key.shift,
+.guac-keyboard.guac-keyboard-modifier-numsym .guac-keyboard-key.numsym {
+ background: #882;
+ border-color: #DD4;
+}
+
+.guac-keyboard.guac-keyboard-modifier-control .guac-keyboard-key.control,
+.guac-keyboard.guac-keyboard-modifier-numsym .guac-keyboard-key.numsym {
+ background: #882;
+ border-color: #DD4;
+}
+
+.guac-keyboard.guac-keyboard-modifier-alt .guac-keyboard-key.alt,
+.guac-keyboard.guac-keyboard-modifier-numsym .guac-keyboard-key.numsym {
+ background: #882;
+ border-color: #DD4;
+}
+
+.guac-keyboard.guac-keyboard-modifier-super .guac-keyboard-key.super,
+.guac-keyboard.guac-keyboard-modifier-numsym .guac-keyboard-key.numsym {
+ background: #882;
+ border-color: #DD4;
+}
+
+.guac-keyboard .guac-keyboard-key.guac-keyboard-pressed {
+ background: #822;
+ border-color: #D44;
+ border-style: inset;
+}
+
+.guac-keyboard .guac-keyboard-row {
+ line-height: 0;
+}
+
+.guac-keyboard .guac-keyboard-column {
+ display: inline-block;
+ text-align: center;
+ vertical-align: top;
+}
+
+.guac-keyboard .guac-keyboard-gap {
+ display: inline-block;
+}
+
+/* Hide keycaps requiring modifiers which are NOT currently active. */
+.guac-keyboard:not(.guac-keyboard-modifier-caps)
+.guac-keyboard-cap.guac-keyboard-requires-caps,
+
+.guac-keyboard:not(.guac-keyboard-modifier-numsym)
+.guac-keyboard-cap.guac-keyboard-requires-numsym,
+
+.guac-keyboard:not(.guac-keyboard-modifier-shift)
+.guac-keyboard-cap.guac-keyboard-requires-shift,
+
+/* Hide keycaps NOT requiring modifiers which ARE currently active, where that
+ modifier is used to determine which cap is displayed for the current key. */
+.guac-keyboard.guac-keyboard-modifier-shift
+.guac-keyboard-key.guac-keyboard-uses-shift
+.guac-keyboard-cap:not(.guac-keyboard-requires-shift),
+
+.guac-keyboard.guac-keyboard-modifier-numsym
+.guac-keyboard-key.guac-keyboard-uses-numsym
+.guac-keyboard-cap:not(.guac-keyboard-requires-numsym),
+
+.guac-keyboard.guac-keyboard-modifier-caps
+.guac-keyboard-key.guac-keyboard-uses-caps
+.guac-keyboard-cap:not(.guac-keyboard-requires-caps) {
+
+ display: none;
+
+}
diff --git a/guacamole/src/main/webapp/app/osk/templates/guacOsk.html b/guacamole/src/main/webapp/app/osk/templates/guacOsk.html
new file mode 100644
index 000000000..42a73462c
--- /dev/null
+++ b/guacamole/src/main/webapp/app/osk/templates/guacOsk.html
@@ -0,0 +1,24 @@
+
+
+
+
diff --git a/guacamole/src/main/webapp/translations/en_US.json b/guacamole/src/main/webapp/translations/en_US.json
index fd7f20e06..16d282093 100644
--- a/guacamole/src/main/webapp/translations/en_US.json
+++ b/guacamole/src/main/webapp/translations/en_US.json
@@ -206,6 +206,7 @@
}
},
"client": {
+ "oskLayout" : "layouts/en-us-qwerty.xml",
"ctrl" : "Ctrl",
"alt" : "Alt",
"esc" : "Esc",