mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
Further cleanup. Implement long-press for right click.
This commit is contained in:
@@ -683,11 +683,11 @@ Guacamole.Mouse.Touchpad = function(element) {
|
||||
|
||||
/**
|
||||
* Provides cross-browser absolute touch event translation for a given element.
|
||||
*
|
||||
*
|
||||
* Touch events are translated into mouse events as if the touches occurred
|
||||
* on a touchscreen (tapping anywhere on the screen clicks at that point,
|
||||
* long-press to right-click).
|
||||
*
|
||||
*
|
||||
* @constructor
|
||||
* @param {Element} element The Element to use to provide touch events.
|
||||
*/
|
||||
@@ -700,22 +700,33 @@ Guacamole.Mouse.Touchscreen = function(element) {
|
||||
var guac_touchscreen = this;
|
||||
|
||||
/**
|
||||
* The start X location of a click (tap) gesture.
|
||||
* @private
|
||||
* Whether a gesture is known to be in progress. If false, touch events
|
||||
* will be ignored.
|
||||
*/
|
||||
var click_start_x = null;
|
||||
var gesture_in_progress = false;
|
||||
|
||||
/**
|
||||
* The start Y location of a click (tap) gesture.
|
||||
* The start X location of a gesture.
|
||||
* @private
|
||||
*/
|
||||
var click_start_y = null;
|
||||
var gesture_start_x = null;
|
||||
|
||||
/**
|
||||
* The start Y location of a gesture.
|
||||
* @private
|
||||
*/
|
||||
var gesture_start_y = null;
|
||||
|
||||
/**
|
||||
* The timeout associated with the delayed, cancellable click release.
|
||||
*/
|
||||
var click_release_timeout = null;
|
||||
|
||||
/**
|
||||
* The timeout associated with long-press for right click.
|
||||
*/
|
||||
var long_press_timeout = null;
|
||||
|
||||
/**
|
||||
* The distance a two-finger touch must move per scrollwheel event, in
|
||||
* pixels.
|
||||
@@ -732,17 +743,23 @@ Guacamole.Mouse.Touchscreen = function(element) {
|
||||
* The maximum number of pixels to allow a touch to move for the gesture to
|
||||
* be considered a click.
|
||||
*/
|
||||
this.clickMoveThreshold = 10 * (window.devicePixelRatio || 1);
|
||||
this.clickMoveThreshold = 16 * (window.devicePixelRatio || 1);
|
||||
|
||||
/**
|
||||
* The amount of time a press must be held for long press to be
|
||||
* detected.
|
||||
*/
|
||||
this.longPressThreshold = 500;
|
||||
|
||||
/**
|
||||
* The current mouse state. The properties of this state are updated when
|
||||
* mouse events fire. This state object is also passed in as a parameter to
|
||||
* the handler of any mouse events.
|
||||
*
|
||||
*
|
||||
* @type Guacamole.Mouse.State
|
||||
*/
|
||||
this.currentState = new Guacamole.Mouse.State(
|
||||
0, 0,
|
||||
0, 0,
|
||||
false, false, false, false, false
|
||||
);
|
||||
|
||||
@@ -751,7 +768,7 @@ Guacamole.Mouse.Touchscreen = function(element) {
|
||||
* as part of a "mousedown" gesture initiated by the user by pressing one
|
||||
* finger over the touchscreen element, as part of a "scroll" gesture
|
||||
* initiated by dragging two fingers up or down, etc.
|
||||
*
|
||||
*
|
||||
* @event
|
||||
* @param {Guacamole.Mouse.State} state The current mouse state.
|
||||
*/
|
||||
@@ -762,7 +779,7 @@ Guacamole.Mouse.Touchscreen = function(element) {
|
||||
* as part of a "mouseup" gesture initiated by the user by removing the
|
||||
* finger pressed against the touchscreen element, or as part of a "scroll"
|
||||
* gesture initiated by dragging two fingers up or down, etc.
|
||||
*
|
||||
*
|
||||
* @event
|
||||
* @param {Guacamole.Mouse.State} state The current mouse state.
|
||||
*/
|
||||
@@ -773,50 +790,120 @@ Guacamole.Mouse.Touchscreen = function(element) {
|
||||
* the touchscreen element. Note that unlike Guacamole.Mouse.Touchpad,
|
||||
* dragging a finger over the touchscreen element will always cause
|
||||
* the mouse button to be effectively down, as if clicking-and-dragging.
|
||||
*
|
||||
*
|
||||
* @event
|
||||
* @param {Guacamole.Mouse.State} state The current mouse state.
|
||||
*/
|
||||
this.onmousemove = null;
|
||||
|
||||
/**
|
||||
* Presses the given mouse button, if it isn't already pressed. Valid
|
||||
* button values are "left", "middle", "right", "up", and "down".
|
||||
*
|
||||
* @private
|
||||
* @param {String} button The mouse button to press.
|
||||
*/
|
||||
function press_button(button) {
|
||||
if (!guac_touchscreen.currentState[button]) {
|
||||
guac_touchscreen.currentState[button] = true;
|
||||
if (guac_touchscreen.onmousedown)
|
||||
guac_touchscreen.onmousedown(guac_touchscreen.currentState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the given mouse button, if it isn't already released. Valid
|
||||
* button values are "left", "middle", "right", "up", and "down".
|
||||
*
|
||||
* @private
|
||||
* @param {String} button The mouse button to release.
|
||||
*/
|
||||
function release_button(button) {
|
||||
if (guac_touchscreen.currentState[button]) {
|
||||
guac_touchscreen.currentState[button] = false;
|
||||
if (guac_touchscreen.onmouseup)
|
||||
guac_touchscreen.onmouseup(guac_touchscreen.currentState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks (presses and releases) the given mouse button. Valid button
|
||||
* values are "left", "middle", "right", "up", and "down".
|
||||
*
|
||||
* @private
|
||||
* @param {String} button The mouse button to click.
|
||||
*/
|
||||
function click_button(button) {
|
||||
press_button(button);
|
||||
release_button(button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the mouse to the given coordinates. These coordinates must be
|
||||
* relative to the browser window, as they will be translated based on
|
||||
* the touch event target's location within the browser window.
|
||||
*
|
||||
* @private
|
||||
* @param {Number} x The X coordinate of the mouse pointer.
|
||||
* @param {Number} y The Y coordinate of the mouse pointer.
|
||||
*/
|
||||
function move_mouse(x, y) {
|
||||
guac_touchscreen.currentState.fromClientPosition(element, x, y);
|
||||
if (guac_touchscreen.onmousemove)
|
||||
guac_touchscreen.onmousemove(guac_touchscreen.currentState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given touch event exceeds the movement threshold for
|
||||
* clicking, based on where the touch gesture began.
|
||||
*
|
||||
* @private
|
||||
* @param {TouchEvent} e The touch event to check.
|
||||
* @return {Boolean} true if the movement threshold is exceeded, false
|
||||
* otherwise.
|
||||
*/
|
||||
function finger_moved(e) {
|
||||
var touch = e.touches[0] || e.changedTouches[0];
|
||||
return Math.abs(touch.clientX - gesture_start_x) >= guac_touchscreen.clickMoveThreshold
|
||||
&& Math.abs(touch.clientY - gesture_start_y) >= guac_touchscreen.clickMoveThreshold;
|
||||
}
|
||||
|
||||
element.addEventListener("touchend", function(e) {
|
||||
|
||||
|
||||
// Do not handle if no gesture
|
||||
if (!gesture_in_progress)
|
||||
return;
|
||||
|
||||
// Ignore if more than one touch
|
||||
if (e.touches.length !== 0 || e.changedTouches.length !== 1)
|
||||
return;
|
||||
|
||||
// Long-press, if any, is over
|
||||
window.clearTimeout(long_press_timeout);
|
||||
long_press_timeout = null;
|
||||
|
||||
// Always release mouse button if pressed
|
||||
if (guac_touchscreen.currentState.left) {
|
||||
guac_touchscreen.currentState.left = false;
|
||||
if (guac_touchscreen.onmouseup)
|
||||
guac_touchscreen.onmouseup(guac_touchscreen.currentState);
|
||||
}
|
||||
release_button("left");
|
||||
|
||||
// If finger hasn't moved enough to cancel the click
|
||||
var touch = e.changedTouches[0];
|
||||
if ( Math.abs(touch.clientX - click_start_x) < guac_touchscreen.clickMoveThreshold
|
||||
&& Math.abs(touch.clientY - click_start_y) < guac_touchscreen.clickMoveThreshold) {
|
||||
if (!finger_moved(e)) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
// If not yet pressed, press and start delay release
|
||||
if (!guac_touchscreen.currentState.left) {
|
||||
|
||||
// Press button
|
||||
guac_touchscreen.currentState.left = true;
|
||||
if (guac_touchscreen.onmousedown)
|
||||
guac_touchscreen.onmousedown(guac_touchscreen.currentState);
|
||||
press_button("left");
|
||||
|
||||
// Release button after a delay, if not canceled
|
||||
click_release_timeout = window.setTimeout(function() {
|
||||
guac_touchscreen.currentState.left = false;
|
||||
if (guac_touchscreen.onmouseup)
|
||||
guac_touchscreen.onmouseup(guac_touchscreen.currentState);
|
||||
release_button("left");
|
||||
gesture_in_progress = false;
|
||||
}, guac_touchscreen.clickTimingThreshold);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} // end if finger not moved
|
||||
|
||||
}, false);
|
||||
|
||||
@@ -830,44 +917,56 @@ Guacamole.Mouse.Touchscreen = function(element) {
|
||||
|
||||
// Update state
|
||||
var touch = e.touches[0];
|
||||
guac_touchscreen.currentState.fromClientPosition(element, touch.clientX, touch.clientY);
|
||||
move_mouse(touch.clientX, touch.clientY);
|
||||
|
||||
click_start_x = touch.clientX;
|
||||
click_start_y = touch.clientY;
|
||||
// New touch begins a new gesture
|
||||
gesture_in_progress = true;
|
||||
gesture_start_x = touch.clientX;
|
||||
gesture_start_y = touch.clientY;
|
||||
|
||||
// Clear timeout, if set
|
||||
// Keep button pressed if tap after left click
|
||||
if (click_release_timeout) {
|
||||
window.clearTimeout(click_release_timeout);
|
||||
click_release_timeout = null;
|
||||
}
|
||||
|
||||
// Click right button if this turns into a long-press
|
||||
long_press_timeout = window.setTimeout(function() {
|
||||
click_button("right");
|
||||
long_press_timeout = null;
|
||||
gesture_in_progress = false;
|
||||
}, guac_touchscreen.longPressThreshold);
|
||||
|
||||
}, false);
|
||||
|
||||
element.addEventListener("touchmove", function(e) {
|
||||
|
||||
// Do not handle if no gesture
|
||||
if (!gesture_in_progress)
|
||||
return;
|
||||
|
||||
// Cancel long press if finger moved
|
||||
if (long_press_timeout && finger_moved(e)) {
|
||||
window.clearTimeout(long_press_timeout);
|
||||
long_press_timeout = null;
|
||||
}
|
||||
|
||||
// Ignore if more than one touch
|
||||
if (e.touches.length !== 1)
|
||||
return;
|
||||
|
||||
// Only handle move if in process of drag
|
||||
// Update mouse position if dragging
|
||||
if (guac_touchscreen.currentState.left) {
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// Get touch
|
||||
var touch = e.touches[0];
|
||||
|
||||
// Update state
|
||||
guac_touchscreen.currentState.fromClientPosition(element, touch.clientX, touch.clientY);
|
||||
|
||||
// Fire movement event, if defined
|
||||
if (guac_touchscreen.onmousemove)
|
||||
guac_touchscreen.onmousemove(guac_touchscreen.currentState);
|
||||
var touch = e.touches[0];
|
||||
move_mouse(touch.clientX, touch.clientY);
|
||||
|
||||
}
|
||||
|
||||
}, false);
|
||||
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user