diff --git a/guacamole/src/main/webapp/app/client/directives/guacClient.js b/guacamole/src/main/webapp/app/client/directives/guacClient.js
index 6d608cba6..6911609dd 100644
--- a/guacamole/src/main/webapp/app/client/directives/guacClient.js
+++ b/guacamole/src/main/webapp/app/client/directives/guacClient.js
@@ -119,6 +119,14 @@ angular.module('client').directive('guacClient', [function guacClient() {
*/
var touchPad = new Guacamole.Mouse.Touchpad(displayContainer);
+ /**
+ * Guacamole touch event handling object, wrapped around the main
+ * client dislay.
+ *
+ * @type Guacamole.Touch
+ */
+ var touch = new Guacamole.Touch(displayContainer);
+
/**
* Updates the scale of the attached Guacamole.Client based on current window
* size and "auto-fit" setting.
@@ -232,6 +240,27 @@ angular.module('client').directive('guacClient', [function guacClient() {
};
+ /**
+ * Handles a touch event originating from the user's device.
+ *
+ * @param {Guacamole.Touch.Event} touchEvent
+ * The touch event.
+ */
+ var handleTouchEvent = function handleTouchEvent(event) {
+
+ // Do not attempt to handle touch state changes if the client
+ // or display are not yet available
+ if (!client || !display)
+ return;
+
+ event.preventDefault();
+
+ // Send touch state, hiding local cursor
+ display.showCursor(false);
+ client.sendTouchState(event.state, true);
+
+ };
+
// Attach any given managed client
$scope.$watch('client', function attachManagedClient(managedClient) {
@@ -287,39 +316,42 @@ angular.module('client').directive('guacClient', [function guacClient() {
localCursor = mouse.setCursor(cursor.canvas, cursor.x, cursor.y);
});
- // Swap mouse emulation modes depending on absolute mode flag
- $scope.$watch('client.clientProperties.emulateAbsoluteMouse',
- function mouseEmulationModeChanged(emulateAbsoluteMouse) {
+ // Update touch event handling depending on remote multi-touch
+ // support and mouse emulation mode
+ $scope.$watchGroup([
+ 'client.multiTouchSupport',
+ 'client.clientProperties.emulateAbsoluteMouse'
+ ], function touchBehaviorChanged(emulateAbsoluteMouse) {
- var newMode, oldMode;
+ // Clear existing event handling
+ touch.offEach(['touchstart', 'touchmove', 'touchend'], handleTouchEvent);
- // Switch to touchscreen if absolute
- if (emulateAbsoluteMouse) {
- newMode = touchScreen;
- oldMode = touchPad;
+ touchScreen.onmousedown =
+ touchScreen.onmouseup =
+ touchScreen.onmousemove = null;
+
+ touchPad.onmousedown =
+ touchPad.onmouseup =
+ touchPad.onmousemove = null;
+
+ // Directly forward local touch events
+ if ($scope.client.multiTouchSupport)
+ touch.onEach(['touchstart', 'touchmove', 'touchend'], handleTouchEvent);
+
+ // Switch to touchscreen if mouse emulation is required and
+ // absolute mouse emulation is preferred
+ else if ($scope.client.clientProperties.emulateAbsoluteMouse) {
+ touchScreen.onmousedown =
+ touchScreen.onmouseup =
+ touchScreen.onmousemove = handleEmulatedMouseState;
}
- // Switch to touchpad if not absolute (relative)
+ // Use touchpad for mouse emulation if absolute mouse emulation
+ // is not preferred
else {
- newMode = touchPad;
- oldMode = touchScreen;
- }
-
- // Set applicable mouse emulation object, unset the old one
- if (newMode) {
-
- // Clear old handlers and copy state to new emulation mode
- if (oldMode) {
- oldMode.onmousedown = oldMode.onmouseup = oldMode.onmousemove = null;
- newMode.currentState.x = oldMode.currentState.x;
- newMode.currentState.y = oldMode.currentState.y;
- }
-
- // Handle emulated events only from the new emulation mode
- newMode.onmousedown =
- newMode.onmouseup =
- newMode.onmousemove = handleEmulatedMouseState;
-
+ touchPad.onmousedown =
+ touchPad.onmouseup =
+ touchPad.onmousemove = handleEmulatedMouseState;
}
});
diff --git a/guacamole/src/main/webapp/app/client/templates/client.html b/guacamole/src/main/webapp/app/client/templates/client.html
index 1270efc38..20d711ee6 100644
--- a/guacamole/src/main/webapp/app/client/templates/client.html
+++ b/guacamole/src/main/webapp/app/client/templates/client.html
@@ -155,7 +155,7 @@
-