mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-30 00:23:21 +00:00 
			
		
		
		
	Merge pull request #26 from glyptodon/guac-input
GUAC-810: Complete implementation of text input
This commit is contained in:
		| @@ -23,4 +23,4 @@ | |||||||
| /** | /** | ||||||
|  * The module for code used to connect to a connection or balancing group. |  * The module for code used to connect to a connection or balancing group. | ||||||
|  */ |  */ | ||||||
| angular.module('client', ['auth', 'history', 'osk', 'rest']); | angular.module('client', ['auth', 'history', 'osk', 'rest', 'textInput']); | ||||||
|   | |||||||
| @@ -204,8 +204,9 @@ angular.module('home').controller('clientController', ['$scope', '$routeParams', | |||||||
|     // Show/hide UI elements depending on input method |     // Show/hide UI elements depending on input method | ||||||
|     $scope.$watch('inputMethod', function setInputMethod(inputMethod) { |     $scope.$watch('inputMethod', function setInputMethod(inputMethod) { | ||||||
|  |  | ||||||
|         // Show on-screen keyboard only if selected |         // Show input methods only if selected | ||||||
|         $scope.showOSK = (inputMethod === 'osk'); |         $scope.showOSK       = (inputMethod === 'osk'); | ||||||
|  |         $scope.showTextInput = (inputMethod === 'text'); | ||||||
|  |  | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -115,6 +115,13 @@ angular.module('client').directive('guacClient', [function guacClient() { | |||||||
|              */ |              */ | ||||||
|             var main = $element[0]; |             var main = $element[0]; | ||||||
|  |  | ||||||
|  |             /** | ||||||
|  |              * The element which functions as a detector for size changes. | ||||||
|  |              *  | ||||||
|  |              * @type Element | ||||||
|  |              */ | ||||||
|  |             var resizeSensor = $element.find('.resize-sensor')[0]; | ||||||
|  |  | ||||||
|             /** |             /** | ||||||
|              * Guacamole mouse event object, wrapped around the main client |              * Guacamole mouse event object, wrapped around the main client | ||||||
|              * display. |              * display. | ||||||
| @@ -491,8 +498,8 @@ angular.module('client').directive('guacClient', [function guacClient() { | |||||||
|                     $scope.clientProperties.scale = $scope.clientProperties.minScale; |                     $scope.clientProperties.scale = $scope.clientProperties.minScale; | ||||||
|             }); |             }); | ||||||
|              |              | ||||||
|             // If the window is resized, attempt to resize client |             // If the element is resized, attempt to resize client | ||||||
|             $window.addEventListener('resize', function onResizeWindow() { |             resizeSensor.contentWindow.addEventListener('resize', function mainElementResized() { | ||||||
|  |  | ||||||
|                 // Send new display size, if changed |                 // Send new display size, if changed | ||||||
|                 if (client && display) { |                 if (client && display) { | ||||||
| @@ -529,6 +536,16 @@ angular.module('client').directive('guacClient', [function guacClient() { | |||||||
|                     event.preventDefault(); |                     event.preventDefault(); | ||||||
|                 }    |                 }    | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|  |             // Universally handle all synthetic keydown events | ||||||
|  |             $scope.$on('guacSyntheticKeydown', function syntheticKeydownListener(event, keysym) { | ||||||
|  |                 client.sendKeyEvent(1, keysym); | ||||||
|  |             }); | ||||||
|  |              | ||||||
|  |             // Universally handle all synthetic keyup events | ||||||
|  |             $scope.$on('guacSyntheticKeyup', function syntheticKeyupListener(event, keysym) { | ||||||
|  |                 client.sendKeyEvent(0, keysym); | ||||||
|  |             }); | ||||||
|              |              | ||||||
|             /** |             /** | ||||||
|              * Converts the given bytes to a base64-encoded string. |              * Converts the given bytes to a base64-encoded string. | ||||||
|   | |||||||
| @@ -27,18 +27,6 @@ body.client { | |||||||
|     overflow: hidden; |     overflow: hidden; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Viewport Clone */ |  | ||||||
|  |  | ||||||
| #viewportClone { |  | ||||||
|     display: table; |  | ||||||
|     height: 100%; |  | ||||||
|     width: 100%; |  | ||||||
|     position: fixed; |  | ||||||
|     left: 0; |  | ||||||
|     top: 0; |  | ||||||
|     visibility: hidden; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #preload { | #preload { | ||||||
|     visibility: hidden; |     visibility: hidden; | ||||||
|     position: absolute; |     position: absolute; | ||||||
| @@ -48,3 +36,21 @@ body.client { | |||||||
|     height: 0; |     height: 0; | ||||||
|     overflow: hidden; |     overflow: hidden; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .client-view { | ||||||
|  |     display: table; | ||||||
|  |     position: fixed; | ||||||
|  |     top: 0; | ||||||
|  |     left: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     height: 100%; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .client-view .client-body { | ||||||
|  |     display: table-row; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .client-view .client-bottom { | ||||||
|  |     display: table-row; | ||||||
|  |     height: 0; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -32,11 +32,21 @@ | |||||||
|  |  | ||||||
| div.main { | div.main { | ||||||
|     overflow: auto; |     overflow: auto; | ||||||
|     position: fixed; |     width: 100%; | ||||||
|     top: 0; |     height: 100%; | ||||||
|     bottom: 0; |     position: relative; | ||||||
|     right: 0; | } | ||||||
|  |  | ||||||
|  | .resize-sensor { | ||||||
|  |     height: 100%; | ||||||
|  |     width: 100%; | ||||||
|  |     position: absolute; | ||||||
|     left: 0; |     left: 0; | ||||||
|  |     top: 0; | ||||||
|  |     overflow: hidden; | ||||||
|  |     border: none; | ||||||
|  |     opacity: 0; | ||||||
|  |     z-index: -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| div.displayOuter { | div.displayOuter { | ||||||
|   | |||||||
| @@ -19,17 +19,4 @@ | |||||||
|    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|    THE SOFTWARE. |    THE SOFTWARE. | ||||||
| --> | --> | ||||||
| 
 | <html><body></body></html> | ||||||
| <div ng-show="errorPresent" class="dialogOuter guac-error"> |  | ||||||
|     <div class="dialogMiddle"> |  | ||||||
|         <div class="dialog"> |  | ||||||
|             <p class="title">{{'client.error.connectionErrorTitle' | translate}}</p> |  | ||||||
| 
 |  | ||||||
|             <p class="status">{{errorStatus}}</p> |  | ||||||
| 
 |  | ||||||
|             <div class="reconnect"> |  | ||||||
|                 <button ng-click="reconnect()">{{'client.error.reconnect' | translate}}</button> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| @@ -20,99 +20,107 @@ | |||||||
|    THE SOFTWARE. |    THE SOFTWARE. | ||||||
| --> | --> | ||||||
|  |  | ||||||
| <div id="clientContainer"> | <!-- Client view --> | ||||||
|      | <div class="client-view"> | ||||||
|     <!-- Client --> |  | ||||||
|     <guac-client  |  | ||||||
|         client-properties="clientProperties" |  | ||||||
|         id="id" |  | ||||||
|         connection-parameters="connectionParameters" |  | ||||||
|     ></guac-client> |  | ||||||
|  |  | ||||||
|     <!-- Text input target --> |     <!-- Central portion of view --> | ||||||
|     <div id="text-input"><div id="text-input-field"><div id="sent-history"></div><textarea rows="1" id="target"></textarea></div><div id="text-input-buttons"><button class="key" data-keysym="0xFFE3" data-sticky="true">{{'client.ctrl' | translate}}</button><button class="key" data-keysym="0xFFE9" data-sticky="true">{{'client.alt' | translate}}</button><button class="key" data-keysym="0xFF1B">{{'client.esc' | translate}}</button><button class="key" data-keysym="0xFF09">{{'client.tab' | translate}}</button></div></div> |     <div class="client-body"> | ||||||
|  |  | ||||||
|     <!-- Dimensional clone of viewport --> |         <!-- Client --> | ||||||
|     <div id="viewportClone"></div> |         <guac-client  | ||||||
|  |             client-properties="clientProperties" | ||||||
|  |             id="id" | ||||||
|  |             connection-parameters="connectionParameters"/></guac-client> | ||||||
|  |  | ||||||
|     <!-- Menu --> |  | ||||||
|     <div ng-class="{open: menuShown}" id="menu"> |  | ||||||
|         <h2>{{'client.clipboard' | translate}}</h2> |  | ||||||
|         <div class="content" id="clipboard-settings"> |  | ||||||
|             <p class="description">{{'client.copiedText' | translate}}</p> |  | ||||||
|             <textarea ng-model="clipboardData" rows="10" cols="40" id="clipboard"></textarea> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <h2>{{'client.inputMethod' | translate}}</h2> |  | ||||||
|         <div class="content" id="keyboard-settings"> |  | ||||||
|  |  | ||||||
|             <!-- No IME --> |  | ||||||
|             <div class="choice"> |  | ||||||
|                 <label><input name="input-method" ng-change="closeMenu()" ng-model="inputMethod" type="radio" value="none"/> {{'client.none' | translate}}</label> |  | ||||||
|                 <p class="caption"><label for="ime-none">{{'client.noneDesc' | translate}}</label></p> |  | ||||||
|             </div> |  | ||||||
|  |  | ||||||
|             <!-- Text input --> |  | ||||||
|             <div class="choice"> |  | ||||||
|                 <div class="figure"><label for="ime-text"><img src="images/settings/tablet-keys.png" alt=""/></label></div> |  | ||||||
|                 <label><input name="input-method" ng-change="closeMenu()" ng-model="inputMethod" type="radio" value="text"/> {{'client.textInput' | translate}}</label> |  | ||||||
|                 <p class="caption"><label for="ime-text">{{'client.textInputDesc' | translate}} </label></p> |  | ||||||
|             </div> |  | ||||||
|  |  | ||||||
|             <!-- Guac OSK --> |  | ||||||
|             <div class="choice"> |  | ||||||
|                 <label><input name="input-method" ng-change="closeMenu()" ng-model="inputMethod" type="radio" value="osk"/> {{'client.osk' | translate}}</label> |  | ||||||
|                 <p class="caption"><label for="ime-osk">{{'client.oskDesc' | translate}}</label></p> |  | ||||||
|             </div> |  | ||||||
|  |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <h2>{{'client.mouseMode' | translate}}</h2> |  | ||||||
|         <div class="content" id="mouse-settings"> |  | ||||||
|             <p class="description">{{'client.mouseModeDesc' | translate}}</p> |  | ||||||
|  |  | ||||||
|             <!-- Touchscreen --> |  | ||||||
|             <div class="choice"> |  | ||||||
|                 <input name="mouse-mode" ng-change="closeMenu()" ng-model="clientProperties.emulateAbsoluteMouse" type="radio" ng-value="true" checked="checked" id="absolute"/> |  | ||||||
|                 <div class="figure"> |  | ||||||
|                     <label for="absolute"><img src="images/settings/touchscreen.png" alt="{{'client.touchscreen' | translate}}"/></label> |  | ||||||
|                     <p class="caption"><label for="absolute">{{'client.touchscreenDesc' | translate}}</label></p> |  | ||||||
|                 </div> |  | ||||||
|             </div> |  | ||||||
|  |  | ||||||
|             <!-- Touchpad --> |  | ||||||
|             <div class="choice"> |  | ||||||
|                 <input name="mouse-mode" ng-change="closeMenu()" ng-model="clientProperties.emulateAbsoluteMouse" type="radio" ng-value="false" id="relative"/> |  | ||||||
|                 <div class="figure"> |  | ||||||
|                     <label for="relative"><img src="images/settings/touchpad.png" alt="{{'client.touchpad' | translate}}"/></label> |  | ||||||
|                     <p class="caption"><label for="relative">{{'client.touchpadDesc' | translate}}</label></p> |  | ||||||
|                 </div> |  | ||||||
|             </div> |  | ||||||
|  |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <h2>{{'client.display' | translate}}</h2> |  | ||||||
|         <div class="content"> |  | ||||||
|             <div id="zoom-settings"> |  | ||||||
|                 <div ng-click="zoomOut()" id="zoom-out"><img src="images/settings/zoom-out.png" alt="-"/></div> |  | ||||||
|                 <div id="zoom-state">{{formattedScale()}}%</div> |  | ||||||
|                 <div ng-click="zoomIn()" id="zoom-in"><img src="images/settings/zoom-in.png" alt="+"/></div> |  | ||||||
|             </div> |  | ||||||
|             <div><label><input ng-model="autoFit" ng-change="changeAutoFit()" ng-disabled="autoFitDisabled()" type="checkbox" id="auto-fit"/> {{'client.autoFit' | translate}}</label></div> |  | ||||||
|         </div> |  | ||||||
|          |  | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|     <!-- On-screen keyboard --> |     <!-- Bottom portion of view --> | ||||||
|     <div class="keyboard-container" ng-class="{shown: showOSK}"> |     <div class="client-bottom"> | ||||||
|         <guac-osk layout="'client.oskLayout' | translate"/> |  | ||||||
|  |         <!-- Text input --> | ||||||
|  |         <div class="text-input-container" ng-show="showTextInput"> | ||||||
|  |             <guac-text-input needs-focus="showTextInput"></guac-text-input> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|     <!-- Images which should be preloaded --> | </div> | ||||||
|     <div id="preload"> |  | ||||||
|         <img src="images/action-icons/guac-close.png" alt=""/> | <!-- On-screen keyboard --> | ||||||
|         <img src="images/progress.png" alt=""/> | <div class="keyboard-container" ng-class="{shown: showOSK}"> | ||||||
|  |     <guac-osk layout="'client.oskLayout' | translate"/> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <!-- Menu --> | ||||||
|  | <div ng-class="{open: menuShown}" id="menu"> | ||||||
|  |     <h2>{{'client.clipboard' | translate}}</h2> | ||||||
|  |     <div class="content" id="clipboard-settings"> | ||||||
|  |         <p class="description">{{'client.copiedText' | translate}}</p> | ||||||
|  |         <textarea ng-model="clipboardData" rows="10" cols="40" id="clipboard"></textarea> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <h2>{{'client.inputMethod' | translate}}</h2> | ||||||
|  |     <div class="content" id="keyboard-settings"> | ||||||
|  |  | ||||||
|  |         <!-- No IME --> | ||||||
|  |         <div class="choice"> | ||||||
|  |             <label><input name="input-method" ng-change="closeMenu()" ng-model="inputMethod" type="radio" value="none"/> {{'client.none' | translate}}</label> | ||||||
|  |             <p class="caption"><label for="ime-none">{{'client.noneDesc' | translate}}</label></p> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <!-- Text input --> | ||||||
|  |         <div class="choice"> | ||||||
|  |             <div class="figure"><label for="ime-text"><img src="images/settings/tablet-keys.png" alt=""/></label></div> | ||||||
|  |             <label><input name="input-method" ng-change="closeMenu()" ng-model="inputMethod" type="radio" value="text"/> {{'client.textInput' | translate}}</label> | ||||||
|  |             <p class="caption"><label for="ime-text">{{'client.textInputDesc' | translate}} </label></p> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <!-- Guac OSK --> | ||||||
|  |         <div class="choice"> | ||||||
|  |             <label><input name="input-method" ng-change="closeMenu()" ng-model="inputMethod" type="radio" value="osk"/> {{'client.osk' | translate}}</label> | ||||||
|  |             <p class="caption"><label for="ime-osk">{{'client.oskDesc' | translate}}</label></p> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <h2>{{'client.mouseMode' | translate}}</h2> | ||||||
|  |     <div class="content" id="mouse-settings"> | ||||||
|  |         <p class="description">{{'client.mouseModeDesc' | translate}}</p> | ||||||
|  |  | ||||||
|  |         <!-- Touchscreen --> | ||||||
|  |         <div class="choice"> | ||||||
|  |             <input name="mouse-mode" ng-change="closeMenu()" ng-model="clientProperties.emulateAbsoluteMouse" type="radio" ng-value="true" checked="checked" id="absolute"/> | ||||||
|  |             <div class="figure"> | ||||||
|  |                 <label for="absolute"><img src="images/settings/touchscreen.png" alt="{{'client.touchscreen' | translate}}"/></label> | ||||||
|  |                 <p class="caption"><label for="absolute">{{'client.touchscreenDesc' | translate}}</label></p> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |         <!-- Touchpad --> | ||||||
|  |         <div class="choice"> | ||||||
|  |             <input name="mouse-mode" ng-change="closeMenu()" ng-model="clientProperties.emulateAbsoluteMouse" type="radio" ng-value="false" id="relative"/> | ||||||
|  |             <div class="figure"> | ||||||
|  |                 <label for="relative"><img src="images/settings/touchpad.png" alt="{{'client.touchpad' | translate}}"/></label> | ||||||
|  |                 <p class="caption"><label for="relative">{{'client.touchpadDesc' | translate}}</label></p> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |  | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <h2>{{'client.display' | translate}}</h2> | ||||||
|  |     <div class="content"> | ||||||
|  |         <div id="zoom-settings"> | ||||||
|  |             <div ng-click="zoomOut()" id="zoom-out"><img src="images/settings/zoom-out.png" alt="-"/></div> | ||||||
|  |             <div id="zoom-state">{{formattedScale()}}%</div> | ||||||
|  |             <div ng-click="zoomIn()" id="zoom-in"><img src="images/settings/zoom-in.png" alt="+"/></div> | ||||||
|  |         </div> | ||||||
|  |         <div><label><input ng-model="autoFit" ng-change="changeAutoFit()" ng-disabled="autoFitDisabled()" type="checkbox" id="auto-fit"/> {{'client.autoFit' | translate}}</label></div> | ||||||
|     </div> |     </div> | ||||||
|      |      | ||||||
|     <ng-include src="app/client/template/clientError.html"/> | </div> | ||||||
| </div> |  | ||||||
|  | <!-- Images which should be preloaded --> | ||||||
|  | <div id="preload"> | ||||||
|  |     <img src="images/action-icons/guac-close.png" alt=""/> | ||||||
|  |     <img src="images/progress.png" alt=""/> | ||||||
|  | </div> | ||||||
|   | |||||||
| @@ -21,6 +21,9 @@ | |||||||
|        THE SOFTWARE. |        THE SOFTWARE. | ||||||
|     --> |     --> | ||||||
|  |  | ||||||
|  |     <!-- Resize sensor --> | ||||||
|  |     <iframe class="resize-sensor" src="app/client/templates/blank.html"></iframe> | ||||||
|  |      | ||||||
|     <!-- Display --> |     <!-- Display --> | ||||||
|     <div class="displayOuter"> |     <div class="displayOuter"> | ||||||
|         <div class="displayMiddle"> |         <div class="displayMiddle"> | ||||||
|   | |||||||
| @@ -193,19 +193,35 @@ angular.module('index').controller('indexController', ['$scope', '$injector', | |||||||
|      |      | ||||||
|     // Try to load them now |     // Try to load them now | ||||||
|     $scope.loadBasicPermissions(); |     $scope.loadBasicPermissions(); | ||||||
|      |  | ||||||
|     // Create event listeners at the global level |     // Create event listeners at the global level | ||||||
|     var keyboard = new Guacamole.Keyboard($document[0]); |     var keyboard = new Guacamole.Keyboard($document[0]); | ||||||
|  |  | ||||||
|     // Broadcast keydown events down the scope heirarchy |     // Broadcast keydown events | ||||||
|     keyboard.onkeydown = function onkeydown(keysym) { |     keyboard.onkeydown = function onkeydown(keysym) { | ||||||
|  |  | ||||||
|  |         // Warn of pending keydown | ||||||
|  |         var guacBeforeKeydownEvent = $scope.$broadcast('guacBeforeKeydown', keysym, keyboard); | ||||||
|  |         if (guacBeforeKeydownEvent.defaultPrevented) | ||||||
|  |             return true; | ||||||
|  |  | ||||||
|  |         // If not prevented via guacBeforeKeydown, fire corresponding keydown event | ||||||
|         var guacKeydownEvent = $scope.$broadcast('guacKeydown', keysym, keyboard); |         var guacKeydownEvent = $scope.$broadcast('guacKeydown', keysym, keyboard); | ||||||
|         return !guacKeydownEvent.defaultPrevented; |         return !guacKeydownEvent.defaultPrevented; | ||||||
|  |  | ||||||
|     }; |     }; | ||||||
|      |      | ||||||
|     // Broadcast keyup events down the scope heirarchy |     // Broadcast keyup events | ||||||
|     keyboard.onkeyup = function onkeyup(keysym) { |     keyboard.onkeyup = function onkeyup(keysym) { | ||||||
|  |  | ||||||
|  |         // Warn of pending keyup | ||||||
|  |         var guacBeforeKeydownEvent = $scope.$broadcast('guacBeforeKeyup', keysym, keyboard); | ||||||
|  |         if (guacBeforeKeydownEvent.defaultPrevented) | ||||||
|  |             return; | ||||||
|  |  | ||||||
|  |         // If not prevented via guacBeforeKeyup, fire corresponding keydown event | ||||||
|         $scope.$broadcast('guacKeyup', keysym, keyboard); |         $scope.$broadcast('guacKeyup', keysym, keyboard); | ||||||
|  |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     // Release all keys when window loses focus |     // Release all keys when window loses focus | ||||||
|   | |||||||
| @@ -88,12 +88,12 @@ angular.module('osk').directive('guacOsk', [function guacOsk() { | |||||||
|  |  | ||||||
|                     // Broadcast keydown for each key pressed |                     // Broadcast keydown for each key pressed | ||||||
|                     keyboard.onkeydown = function(keysym) { |                     keyboard.onkeydown = function(keysym) { | ||||||
|                         $rootScope.$broadcast('guacKeydown', keysym); |                         $rootScope.$broadcast('guacSyntheticKeydown', keysym); | ||||||
|                     }; |                     }; | ||||||
|                      |                      | ||||||
|                     // Broadcast keydown for each key released  |                     // Broadcast keydown for each key released  | ||||||
|                     keyboard.onkeyup = function(keysym) { |                     keyboard.onkeyup = function(keysym) { | ||||||
|                         $rootScope.$broadcast('guacKeyup', keysym); |                         $rootScope.$broadcast('guacSyntheticKeyup', keysym); | ||||||
|                     }; |                     }; | ||||||
|  |  | ||||||
|                     // Resize keyboard whenever window changes size |                     // Resize keyboard whenever window changes size | ||||||
|   | |||||||
| @@ -90,8 +90,8 @@ angular.module('textInput').directive('guacKey', [function guacKey() { | |||||||
|  |  | ||||||
|                 // For all non-sticky keys, press and release key immediately |                 // For all non-sticky keys, press and release key immediately | ||||||
|                 else { |                 else { | ||||||
|                     $rootScope.$broadcast('guacKeydown', $scope.keysym); |                     $rootScope.$broadcast('guacSyntheticKeydown', $scope.keysym); | ||||||
|                     $rootScope.$broadcast('guacKeyup', $scope.keysym); |                     $rootScope.$broadcast('guacSyntheticKeyup', $scope.keysym); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|             }; |             }; | ||||||
| @@ -101,11 +101,11 @@ angular.module('textInput').directive('guacKey', [function guacKey() { | |||||||
|  |  | ||||||
|                 // If the key is pressed now, send keydown |                 // If the key is pressed now, send keydown | ||||||
|                 if (isPressed) |                 if (isPressed) | ||||||
|                     $rootScope.$broadcast('guacKeydown', $scope.keysym); |                     $rootScope.$broadcast('guacSyntheticKeydown', $scope.keysym); | ||||||
|  |  | ||||||
|                 // If the key was pressed, but is not pressed any longer, send keyup |                 // If the key was pressed, but is not pressed any longer, send keyup | ||||||
|                 else if (wasPressed) |                 else if (wasPressed) | ||||||
|                     $rootScope.$broadcast('guacKeyup', $scope.keysym); |                     $rootScope.$broadcast('guacSyntheticKeyup', $scope.keysym); | ||||||
|  |  | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -28,7 +28,17 @@ angular.module('textInput').directive('guacTextInput', [function guacTextInput() | |||||||
|     return { |     return { | ||||||
|         restrict: 'E', |         restrict: 'E', | ||||||
|         replace: true, |         replace: true, | ||||||
|         scope: {}, |         scope: { | ||||||
|  |  | ||||||
|  |             /** | ||||||
|  |              * Whether the text input UI should have focus. Setting this value | ||||||
|  |              * is not guaranteed to work, due to browser limitations. | ||||||
|  |              *  | ||||||
|  |              * @type Boolean | ||||||
|  |              */ | ||||||
|  |             needsFocus : '=?' | ||||||
|  |  | ||||||
|  |         }, | ||||||
|  |  | ||||||
|         templateUrl: 'app/textInput/templates/guacTextInput.html', |         templateUrl: 'app/textInput/templates/guacTextInput.html', | ||||||
|         controller: ['$scope', '$rootScope', '$element', '$timeout', |         controller: ['$scope', '$rootScope', '$element', '$timeout', | ||||||
| @@ -50,6 +60,47 @@ angular.module('textInput').directive('guacTextInput', [function guacTextInput() | |||||||
|              */ |              */ | ||||||
|             var TEXT_INPUT_PADDING_CODEPOINT = 0x200B; |             var TEXT_INPUT_PADDING_CODEPOINT = 0x200B; | ||||||
|  |  | ||||||
|  |             /** | ||||||
|  |              * Keys which should be allowed through to the client when in text | ||||||
|  |              * input mode, providing corresponding key events are received. | ||||||
|  |              * Keys in this set will be allowed through to the server. | ||||||
|  |              *  | ||||||
|  |              * @type Object.<Number, Boolean> | ||||||
|  |              */ | ||||||
|  |             var ALLOWED_KEYS = { | ||||||
|  |                 0xFE03: true, /* AltGr */ | ||||||
|  |                 0xFF08: true, /* Backspace */ | ||||||
|  |                 0xFF09: true, /* Tab */ | ||||||
|  |                 0xFF0D: true, /* Enter */ | ||||||
|  |                 0xFF1B: true, /* Escape */ | ||||||
|  |                 0xFF50: true, /* Home */ | ||||||
|  |                 0xFF51: true, /* Left */ | ||||||
|  |                 0xFF52: true, /* Up */ | ||||||
|  |                 0xFF53: true, /* Right */ | ||||||
|  |                 0xFF54: true, /* Down */ | ||||||
|  |                 0xFF57: true, /* End */ | ||||||
|  |                 0xFF64: true, /* Insert */ | ||||||
|  |                 0xFFBE: true, /* F1 */ | ||||||
|  |                 0xFFBF: true, /* F2 */ | ||||||
|  |                 0xFFC0: true, /* F3 */ | ||||||
|  |                 0xFFC1: true, /* F4 */ | ||||||
|  |                 0xFFC2: true, /* F5 */ | ||||||
|  |                 0xFFC3: true, /* F6 */ | ||||||
|  |                 0xFFC4: true, /* F7 */ | ||||||
|  |                 0xFFC5: true, /* F8 */ | ||||||
|  |                 0xFFC6: true, /* F9 */ | ||||||
|  |                 0xFFC7: true, /* F10 */ | ||||||
|  |                 0xFFC8: true, /* F11 */ | ||||||
|  |                 0xFFC9: true, /* F12 */ | ||||||
|  |                 0xFFE1: true, /* Left shift */ | ||||||
|  |                 0xFFE2: true, /* Right shift */ | ||||||
|  |                 0xFFE3: true, /* Left ctrl */ | ||||||
|  |                 0xFFE4: true, /* Right ctrl */ | ||||||
|  |                 0xFFE9: true, /* Left alt */ | ||||||
|  |                 0xFFEA: true, /* Right alt */ | ||||||
|  |                 0xFFFF: true  /* Delete */ | ||||||
|  |             }; | ||||||
|  |  | ||||||
|             /** |             /** | ||||||
|              * Recently-sent text, ordered from oldest to most recent. |              * Recently-sent text, ordered from oldest to most recent. | ||||||
|              * |              * | ||||||
| @@ -151,8 +202,8 @@ angular.module('textInput').directive('guacTextInput', [function guacTextInput() | |||||||
|              * @param {Number} keysym The keysym of the key to send. |              * @param {Number} keysym The keysym of the key to send. | ||||||
|              */ |              */ | ||||||
|             var sendKeysym = function sendKeysym(keysym) { |             var sendKeysym = function sendKeysym(keysym) { | ||||||
|                 $rootScope.$broadcast('guacKeydown', keysym); |                 $rootScope.$broadcast('guacSyntheticKeydown', keysym); | ||||||
|                 $rootScope.$broadcast('guacKeyup', keysym); |                 $rootScope.$broadcast('guacSyntheticKeyup', keysym); | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             /** |             /** | ||||||
| @@ -283,6 +334,28 @@ angular.module('textInput').directive('guacTextInput', [function guacTextInput() | |||||||
|                 e.preventDefault(); |                 e.preventDefault(); | ||||||
|             }, false); |             }, false); | ||||||
|  |  | ||||||
|  |             // Attempt to change focus depending on need | ||||||
|  |             $scope.$watch('needsFocus', function focusDesireChanged(focusNeeded) { | ||||||
|  |  | ||||||
|  |                 if (focusNeeded) | ||||||
|  |                     target.focus(); | ||||||
|  |                 else | ||||||
|  |                     target.blur(); | ||||||
|  |  | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             // If the text input UI has focus, prevent keydown events | ||||||
|  |             $scope.$on('guacBeforeKeydown', function filterKeydown(event, keysym) { | ||||||
|  |                 if (hasFocus && !ALLOWED_KEYS[keysym]) | ||||||
|  |                     event.preventDefault(); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             // If the text input UI has focus, prevent keyup events | ||||||
|  |             $scope.$on('guacBeforeKeyup', function filterKeyup(event, keysym) { | ||||||
|  |                 if (hasFocus && !ALLOWED_KEYS[keysym]) | ||||||
|  |                     event.preventDefault(); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|         }] |         }] | ||||||
|  |  | ||||||
|     }; |     }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user