mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 05:31:22 +00:00
GUACAMOLE-1204: Merge addition of client-side support for multi-touch events.
This commit is contained in:
@@ -463,6 +463,11 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
|
||||
// Zoom and pan client via pinch gestures
|
||||
$scope.clientPinch = function clientPinch(inProgress, startLength, currentLength, centerX, centerY) {
|
||||
|
||||
// Do not handle pinch gestures if they would conflict with remote
|
||||
// handling of similar gestures
|
||||
if ($scope.client.multiTouchSupport > 1)
|
||||
return false;
|
||||
|
||||
// Do not handle pinch gestures while relative mouse is in use
|
||||
if (!$scope.client.clientProperties.emulateAbsoluteMouse)
|
||||
return false;
|
||||
|
@@ -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.
|
||||
@@ -185,29 +193,6 @@ angular.module('client').directive('guacClient', [function guacClient() {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends the given mouse state to the current client.
|
||||
*
|
||||
* @param {Guacamole.Mouse.State} mouseState The mouse state to
|
||||
* send.
|
||||
*/
|
||||
var sendScaledMouseState = function sendScaledMouseState(mouseState) {
|
||||
|
||||
// Scale event by current scale
|
||||
var scaledState = new Guacamole.Mouse.State(
|
||||
mouseState.x / display.getScale(),
|
||||
mouseState.y / display.getScale(),
|
||||
mouseState.left,
|
||||
mouseState.middle,
|
||||
mouseState.right,
|
||||
mouseState.up,
|
||||
mouseState.down);
|
||||
|
||||
// Send mouse event
|
||||
client.sendMouseState(scaledState);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a mouse event originating from the user's actual mouse.
|
||||
* This differs from handleEmulatedMouseState() in that the
|
||||
@@ -226,7 +211,7 @@ angular.module('client').directive('guacClient', [function guacClient() {
|
||||
|
||||
// Send mouse state, show cursor if necessary
|
||||
display.showCursor(!localCursor);
|
||||
sendScaledMouseState(mouseState);
|
||||
client.sendMouseState(mouseState, true);
|
||||
|
||||
};
|
||||
|
||||
@@ -251,7 +236,28 @@ angular.module('client').directive('guacClient', [function guacClient() {
|
||||
|
||||
// Send mouse state, ensure cursor is visible
|
||||
scrollToMouse(mouseState);
|
||||
sendScaledMouseState(mouseState);
|
||||
client.sendMouseState(mouseState, true);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
};
|
||||
|
||||
@@ -310,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;
|
||||
}
|
||||
|
||||
});
|
||||
|
@@ -155,7 +155,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Mouse mode -->
|
||||
<div class="menu-section" id="mouse-settings">
|
||||
<div class="menu-section" id="mouse-settings" ng-hide="client.multiTouchSupport">
|
||||
<h3>{{'CLIENT.SECTION_HEADER_MOUSE_MODE' | translate}}</h3>
|
||||
<div class="content">
|
||||
<p class="description">{{'CLIENT.HELP_MOUSE_MODE' | translate}}</p>
|
||||
|
@@ -203,6 +203,15 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
||||
*/
|
||||
this.shareLinks = template.shareLinks || {};
|
||||
|
||||
/**
|
||||
* The number of simultaneous touch contacts supported by the remote
|
||||
* desktop. Unless explicitly declared otherwise by the remote desktop
|
||||
* after connecting, this will be 0 (multi-touch unsupported).
|
||||
*
|
||||
* @type Number
|
||||
*/
|
||||
this.multiTouchSupport = template.multiTouchSupport || 0;
|
||||
|
||||
/**
|
||||
* The current state of the Guacamole client (idle, connecting,
|
||||
* connected, terminated with error, etc.).
|
||||
@@ -578,6 +587,11 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
||||
|
||||
};
|
||||
|
||||
// Update level of multi-touch support when known
|
||||
client.onmultitouch = function multiTouchSupportDeclared(layer, touches) {
|
||||
managedClient.multiTouchSupport = touches;
|
||||
};
|
||||
|
||||
// Update title when a "name" instruction is received
|
||||
client.onname = function clientNameReceived(name) {
|
||||
$rootScope.$apply(function updateClientTitle() {
|
||||
|
@@ -124,8 +124,6 @@ angular.module('touch').directive('guacTouchDrag', [function guacTouchDrag() {
|
||||
element.addEventListener("touchmove", function dragTouchMove(e) {
|
||||
if (e.touches.length === 1) {
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
// Get touch location
|
||||
var x = e.touches[0].clientX;
|
||||
var y = e.touches[0].clientY;
|
||||
@@ -163,8 +161,6 @@ angular.module('touch').directive('guacTouchDrag', [function guacTouchDrag() {
|
||||
|
||||
if (startX && startY && e.touches.length === 0) {
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
// Signal end of drag gesture
|
||||
if (inProgress && guacTouchDrag) {
|
||||
$scope.$apply(function dragComplete() {
|
||||
|
@@ -159,8 +159,6 @@ angular.module('touch').directive('guacTouchPinch', [function guacTouchPinch() {
|
||||
element.addEventListener("touchmove", function pinchTouchMove(e) {
|
||||
if (e.touches.length === 2) {
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
// Calculate current zoom level
|
||||
currentLength = pinchDistance(e);
|
||||
|
||||
@@ -188,8 +186,6 @@ angular.module('touch').directive('guacTouchPinch', [function guacTouchPinch() {
|
||||
|
||||
if (startLength && e.touches.length < 2) {
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
// Notify of pinch end
|
||||
if (guacTouchPinch) {
|
||||
$scope.$apply(function pinchComplete() {
|
||||
|
@@ -480,6 +480,7 @@
|
||||
"FIELD_HEADER_ENABLE_PRINTING" : "Enable printing:",
|
||||
"FIELD_HEADER_ENABLE_SFTP" : "Enable SFTP:",
|
||||
"FIELD_HEADER_ENABLE_THEMING" : "Enable theming:",
|
||||
"FIELD_HEADER_ENABLE_TOUCH" : "Enable multi-touch:",
|
||||
"FIELD_HEADER_ENABLE_WALLPAPER" : "Enable wallpaper:",
|
||||
"FIELD_HEADER_GATEWAY_DOMAIN" : "Domain:",
|
||||
"FIELD_HEADER_GATEWAY_HOSTNAME" : "Hostname:",
|
||||
@@ -499,6 +500,7 @@
|
||||
"FIELD_HEADER_READ_ONLY" : "Read-only:",
|
||||
"FIELD_HEADER_RECORDING_EXCLUDE_MOUSE" : "Exclude mouse:",
|
||||
"FIELD_HEADER_RECORDING_EXCLUDE_OUTPUT" : "Exclude graphics/streams:",
|
||||
"FIELD_HEADER_RECORDING_EXCLUDE_TOUCH" : "Exclude touch events:",
|
||||
"FIELD_HEADER_RECORDING_INCLUDE_KEYS" : "Include key events:",
|
||||
"FIELD_HEADER_RECORDING_NAME" : "Recording name:",
|
||||
"FIELD_HEADER_RECORDING_PATH" : "Recording path:",
|
||||
|
Reference in New Issue
Block a user