mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 05:31:22 +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.
|
* Provides cross-browser absolute touch event translation for a given element.
|
||||||
*
|
*
|
||||||
* Touch events are translated into mouse events as if the touches occurred
|
* Touch events are translated into mouse events as if the touches occurred
|
||||||
* on a touchscreen (tapping anywhere on the screen clicks at that point,
|
* on a touchscreen (tapping anywhere on the screen clicks at that point,
|
||||||
* long-press to right-click).
|
* long-press to right-click).
|
||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {Element} element The Element to use to provide touch events.
|
* @param {Element} element The Element to use to provide touch events.
|
||||||
*/
|
*/
|
||||||
@@ -700,22 +700,33 @@ Guacamole.Mouse.Touchscreen = function(element) {
|
|||||||
var guac_touchscreen = this;
|
var guac_touchscreen = this;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The start X location of a click (tap) gesture.
|
* Whether a gesture is known to be in progress. If false, touch events
|
||||||
* @private
|
* 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
|
* @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.
|
* The timeout associated with the delayed, cancellable click release.
|
||||||
*/
|
*/
|
||||||
var click_release_timeout = null;
|
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
|
* The distance a two-finger touch must move per scrollwheel event, in
|
||||||
* pixels.
|
* 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
|
* The maximum number of pixels to allow a touch to move for the gesture to
|
||||||
* be considered a click.
|
* 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
|
* 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
|
* mouse events fire. This state object is also passed in as a parameter to
|
||||||
* the handler of any mouse events.
|
* the handler of any mouse events.
|
||||||
*
|
*
|
||||||
* @type Guacamole.Mouse.State
|
* @type Guacamole.Mouse.State
|
||||||
*/
|
*/
|
||||||
this.currentState = new Guacamole.Mouse.State(
|
this.currentState = new Guacamole.Mouse.State(
|
||||||
0, 0,
|
0, 0,
|
||||||
false, false, false, false, false
|
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
|
* as part of a "mousedown" gesture initiated by the user by pressing one
|
||||||
* finger over the touchscreen element, as part of a "scroll" gesture
|
* finger over the touchscreen element, as part of a "scroll" gesture
|
||||||
* initiated by dragging two fingers up or down, etc.
|
* initiated by dragging two fingers up or down, etc.
|
||||||
*
|
*
|
||||||
* @event
|
* @event
|
||||||
* @param {Guacamole.Mouse.State} state The current mouse state.
|
* @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
|
* 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"
|
* finger pressed against the touchscreen element, or as part of a "scroll"
|
||||||
* gesture initiated by dragging two fingers up or down, etc.
|
* gesture initiated by dragging two fingers up or down, etc.
|
||||||
*
|
*
|
||||||
* @event
|
* @event
|
||||||
* @param {Guacamole.Mouse.State} state The current mouse state.
|
* @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,
|
* the touchscreen element. Note that unlike Guacamole.Mouse.Touchpad,
|
||||||
* dragging a finger over the touchscreen element will always cause
|
* dragging a finger over the touchscreen element will always cause
|
||||||
* the mouse button to be effectively down, as if clicking-and-dragging.
|
* the mouse button to be effectively down, as if clicking-and-dragging.
|
||||||
*
|
*
|
||||||
* @event
|
* @event
|
||||||
* @param {Guacamole.Mouse.State} state The current mouse state.
|
* @param {Guacamole.Mouse.State} state The current mouse state.
|
||||||
*/
|
*/
|
||||||
this.onmousemove = null;
|
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) {
|
element.addEventListener("touchend", function(e) {
|
||||||
|
|
||||||
|
// Do not handle if no gesture
|
||||||
|
if (!gesture_in_progress)
|
||||||
|
return;
|
||||||
|
|
||||||
// Ignore if more than one touch
|
// Ignore if more than one touch
|
||||||
if (e.touches.length !== 0 || e.changedTouches.length !== 1)
|
if (e.touches.length !== 0 || e.changedTouches.length !== 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Long-press, if any, is over
|
||||||
|
window.clearTimeout(long_press_timeout);
|
||||||
|
long_press_timeout = null;
|
||||||
|
|
||||||
// Always release mouse button if pressed
|
// Always release mouse button if pressed
|
||||||
if (guac_touchscreen.currentState.left) {
|
release_button("left");
|
||||||
guac_touchscreen.currentState.left = false;
|
|
||||||
if (guac_touchscreen.onmouseup)
|
|
||||||
guac_touchscreen.onmouseup(guac_touchscreen.currentState);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If finger hasn't moved enough to cancel the click
|
// If finger hasn't moved enough to cancel the click
|
||||||
var touch = e.changedTouches[0];
|
if (!finger_moved(e)) {
|
||||||
if ( Math.abs(touch.clientX - click_start_x) < guac_touchscreen.clickMoveThreshold
|
|
||||||
&& Math.abs(touch.clientY - click_start_y) < guac_touchscreen.clickMoveThreshold) {
|
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// If not yet pressed, press and start delay release
|
// If not yet pressed, press and start delay release
|
||||||
if (!guac_touchscreen.currentState.left) {
|
if (!guac_touchscreen.currentState.left) {
|
||||||
|
|
||||||
// Press button
|
press_button("left");
|
||||||
guac_touchscreen.currentState.left = true;
|
|
||||||
if (guac_touchscreen.onmousedown)
|
|
||||||
guac_touchscreen.onmousedown(guac_touchscreen.currentState);
|
|
||||||
|
|
||||||
// Release button after a delay, if not canceled
|
// Release button after a delay, if not canceled
|
||||||
click_release_timeout = window.setTimeout(function() {
|
click_release_timeout = window.setTimeout(function() {
|
||||||
guac_touchscreen.currentState.left = false;
|
release_button("left");
|
||||||
if (guac_touchscreen.onmouseup)
|
gesture_in_progress = false;
|
||||||
guac_touchscreen.onmouseup(guac_touchscreen.currentState);
|
|
||||||
}, guac_touchscreen.clickTimingThreshold);
|
}, guac_touchscreen.clickTimingThreshold);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // end if finger not moved
|
||||||
|
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
@@ -830,44 +917,56 @@ Guacamole.Mouse.Touchscreen = function(element) {
|
|||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
var touch = e.touches[0];
|
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;
|
// New touch begins a new gesture
|
||||||
click_start_y = touch.clientY;
|
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) {
|
if (click_release_timeout) {
|
||||||
window.clearTimeout(click_release_timeout);
|
window.clearTimeout(click_release_timeout);
|
||||||
click_release_timeout = null;
|
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);
|
}, false);
|
||||||
|
|
||||||
element.addEventListener("touchmove", function(e) {
|
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
|
// Ignore if more than one touch
|
||||||
if (e.touches.length !== 1)
|
if (e.touches.length !== 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Only handle move if in process of drag
|
// Update mouse position if dragging
|
||||||
if (guac_touchscreen.currentState.left) {
|
if (guac_touchscreen.currentState.left) {
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
// Get touch
|
|
||||||
var touch = e.touches[0];
|
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
guac_touchscreen.currentState.fromClientPosition(element, touch.clientX, touch.clientY);
|
var touch = e.touches[0];
|
||||||
|
move_mouse(touch.clientX, touch.clientY);
|
||||||
// Fire movement event, if defined
|
|
||||||
if (guac_touchscreen.onmousemove)
|
|
||||||
guac_touchscreen.onmousemove(guac_touchscreen.currentState);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user