GUACAMOLE-1204: Merge addition of server-side support for multi-touch events.
This commit is contained in:
commit
ca1fbd5e98
@ -71,6 +71,15 @@ typedef struct guac_common_recording {
|
|||||||
*/
|
*/
|
||||||
int include_mouse;
|
int include_mouse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-zero if multi-touch events should be included in the session
|
||||||
|
* recording, zero otherwise. Depending on whether the remote desktop will
|
||||||
|
* automatically provide graphical feedback for touches, including touch
|
||||||
|
* events may be necessary for multi-touch interactions to be rendered in
|
||||||
|
* any resulting video.
|
||||||
|
*/
|
||||||
|
int include_touch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Non-zero if keys pressed and released should be included in the session
|
* Non-zero if keys pressed and released should be included in the session
|
||||||
* recording, zero otherwise. Including key events within the recording may
|
* recording, zero otherwise. Including key events within the recording may
|
||||||
@ -119,6 +128,13 @@ typedef struct guac_common_recording {
|
|||||||
* otherwise. Including mouse state is necessary for the mouse cursor to be
|
* otherwise. Including mouse state is necessary for the mouse cursor to be
|
||||||
* rendered in any resulting video.
|
* rendered in any resulting video.
|
||||||
*
|
*
|
||||||
|
* @param include_touch
|
||||||
|
* Non-zero if touch events should be included in the session recording,
|
||||||
|
* zero otherwise. Depending on whether the remote desktop will
|
||||||
|
* automatically provide graphical feedback for touches, including touch
|
||||||
|
* events may be necessary for multi-touch interactions to be rendered in
|
||||||
|
* any resulting video.
|
||||||
|
*
|
||||||
* @param include_keys
|
* @param include_keys
|
||||||
* Non-zero if keys pressed and released should be included in the session
|
* Non-zero if keys pressed and released should be included in the session
|
||||||
* recording, zero otherwise. Including key events within the recording may
|
* recording, zero otherwise. Including key events within the recording may
|
||||||
@ -133,7 +149,8 @@ typedef struct guac_common_recording {
|
|||||||
*/
|
*/
|
||||||
guac_common_recording* guac_common_recording_create(guac_client* client,
|
guac_common_recording* guac_common_recording_create(guac_client* client,
|
||||||
const char* path, const char* name, int create_path,
|
const char* path, const char* name, int create_path,
|
||||||
int include_output, int include_mouse, int include_keys);
|
int include_output, int include_mouse, int include_touch,
|
||||||
|
int include_keys);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees the resources associated with the given in-progress recording. Note
|
* Frees the resources associated with the given in-progress recording. Note
|
||||||
@ -174,6 +191,44 @@ void guac_common_recording_free(guac_common_recording* recording);
|
|||||||
void guac_common_recording_report_mouse(guac_common_recording* recording,
|
void guac_common_recording_report_mouse(guac_common_recording* recording,
|
||||||
int x, int y, int button_mask);
|
int x, int y, int button_mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports the current state of a touch contact within the recording.
|
||||||
|
*
|
||||||
|
* @param recording
|
||||||
|
* The guac_common_recording associated with the touch contact that
|
||||||
|
* has changed state.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* An arbitrary integer ID which uniquely identifies this contact relative
|
||||||
|
* to other active contacts.
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* The X coordinate of the center of the touch contact.
|
||||||
|
*
|
||||||
|
* @param y
|
||||||
|
* The Y coordinate of the center of the touch contact.
|
||||||
|
*
|
||||||
|
* @param x_radius
|
||||||
|
* The X radius of the ellipse covering the general area of the touch
|
||||||
|
* contact, in pixels.
|
||||||
|
*
|
||||||
|
* @param y_radius
|
||||||
|
* The Y radius of the ellipse covering the general area of the touch
|
||||||
|
* contact, in pixels.
|
||||||
|
*
|
||||||
|
* @param angle
|
||||||
|
* The rough angle of clockwise rotation of the general area of the touch
|
||||||
|
* contact, in degrees.
|
||||||
|
*
|
||||||
|
* @param force
|
||||||
|
* The relative force exerted by the touch contact, where 0 is no force
|
||||||
|
* (the touch has been lifted) and 1 is maximum force (the maximum amount
|
||||||
|
* of force representable by the device).
|
||||||
|
*/
|
||||||
|
void guac_common_recording_report_touch(guac_common_recording* recording,
|
||||||
|
int id, int x, int y, int x_radius, int y_radius,
|
||||||
|
double angle, double force);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reports a change in the state of an individual key within the recording.
|
* Reports a change in the state of an individual key within the recording.
|
||||||
*
|
*
|
||||||
|
@ -120,6 +120,12 @@ typedef struct guac_common_surface {
|
|||||||
*/
|
*/
|
||||||
guac_socket* socket;
|
guac_socket* socket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of simultaneous touches that this surface can accept, where 0
|
||||||
|
* indicates that the surface does not support touch events at all.
|
||||||
|
*/
|
||||||
|
int touches;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The X coordinate of the upper-left corner of this layer, in pixels,
|
* The X coordinate of the upper-left corner of this layer, in pixels,
|
||||||
* relative to its parent layer. This is only applicable to visible
|
* relative to its parent layer. This is only applicable to visible
|
||||||
@ -486,5 +492,23 @@ void guac_common_surface_flush(guac_common_surface* surface);
|
|||||||
void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
|
void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
|
||||||
guac_socket* socket);
|
guac_socket* socket);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares that the given surface should receive touch events. By default,
|
||||||
|
* surfaces are assumed to not expect touch events. This value is advisory, and
|
||||||
|
* the client is not required to honor the declared level of touch support.
|
||||||
|
* Implementations are expected to safely handle or ignore any received touch
|
||||||
|
* events, regardless of the level of touch support declared. regardless of
|
||||||
|
* the level of touch support declared.
|
||||||
|
*
|
||||||
|
* @param surface
|
||||||
|
* The surface to modify.
|
||||||
|
*
|
||||||
|
* @param touches
|
||||||
|
* The number of simultaneous touches that this surface can accept, where 0
|
||||||
|
* indicates that the surface does not support touch events at all.
|
||||||
|
*/
|
||||||
|
void guac_common_surface_set_multitouch(guac_common_surface* surface,
|
||||||
|
int touches);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -137,7 +137,8 @@ static int guac_common_recording_open(const char* path,
|
|||||||
|
|
||||||
guac_common_recording* guac_common_recording_create(guac_client* client,
|
guac_common_recording* guac_common_recording_create(guac_client* client,
|
||||||
const char* path, const char* name, int create_path,
|
const char* path, const char* name, int create_path,
|
||||||
int include_output, int include_mouse, int include_keys) {
|
int include_output, int include_mouse, int include_touch,
|
||||||
|
int include_keys) {
|
||||||
|
|
||||||
char filename[GUAC_COMMON_RECORDING_MAX_NAME_LENGTH];
|
char filename[GUAC_COMMON_RECORDING_MAX_NAME_LENGTH];
|
||||||
|
|
||||||
@ -165,6 +166,7 @@ guac_common_recording* guac_common_recording_create(guac_client* client,
|
|||||||
recording->socket = guac_socket_open(fd);
|
recording->socket = guac_socket_open(fd);
|
||||||
recording->include_output = include_output;
|
recording->include_output = include_output;
|
||||||
recording->include_mouse = include_mouse;
|
recording->include_mouse = include_mouse;
|
||||||
|
recording->include_touch = include_touch;
|
||||||
recording->include_keys = include_keys;
|
recording->include_keys = include_keys;
|
||||||
|
|
||||||
/* Replace client socket with wrapped recording socket only if including
|
/* Replace client socket with wrapped recording socket only if including
|
||||||
@ -203,6 +205,17 @@ void guac_common_recording_report_mouse(guac_common_recording* recording,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void guac_common_recording_report_touch(guac_common_recording* recording,
|
||||||
|
int id, int x, int y, int x_radius, int y_radius,
|
||||||
|
double angle, double force) {
|
||||||
|
|
||||||
|
/* Report touches only if recording should contain touch events */
|
||||||
|
if (recording->include_touch)
|
||||||
|
guac_protocol_send_touch(recording->socket, id, x, y,
|
||||||
|
x_radius, y_radius, angle, force, guac_timestamp_current());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void guac_common_recording_report_key(guac_common_recording* recording,
|
void guac_common_recording_report_key(guac_common_recording* recording,
|
||||||
int keysym, int pressed) {
|
int keysym, int pressed) {
|
||||||
|
|
||||||
|
@ -103,6 +103,19 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_SURFACE_WEBP_BLOCK_SIZE 8
|
#define GUAC_SURFACE_WEBP_BLOCK_SIZE 8
|
||||||
|
|
||||||
|
void guac_common_surface_set_multitouch(guac_common_surface* surface,
|
||||||
|
int touches) {
|
||||||
|
|
||||||
|
pthread_mutex_lock(&surface->_lock);
|
||||||
|
|
||||||
|
surface->touches = touches;
|
||||||
|
guac_protocol_send_set_int(surface->socket, surface->layer,
|
||||||
|
GUAC_PROTOCOL_LAYER_PARAMETER_MULTI_TOUCH, touches);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&surface->_lock);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void guac_common_surface_move(guac_common_surface* surface, int x, int y) {
|
void guac_common_surface_move(guac_common_surface* surface, int x, int y) {
|
||||||
|
|
||||||
pthread_mutex_lock(&surface->_lock);
|
pthread_mutex_lock(&surface->_lock);
|
||||||
@ -1981,6 +1994,11 @@ void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
|
|||||||
guac_protocol_send_move(socket, surface->layer,
|
guac_protocol_send_move(socket, surface->layer,
|
||||||
surface->parent, surface->x, surface->y, surface->z);
|
surface->parent, surface->x, surface->y, surface->z);
|
||||||
|
|
||||||
|
/* Synchronize multi-touch support level */
|
||||||
|
guac_protocol_send_set_int(surface->socket, surface->layer,
|
||||||
|
GUAC_PROTOCOL_LAYER_PARAMETER_MULTI_TOUCH,
|
||||||
|
surface->touches);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sync size to new socket */
|
/* Sync size to new socket */
|
||||||
|
@ -49,5 +49,20 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_PROTOCOL_BLOB_MAX_LENGTH 6048
|
#define GUAC_PROTOCOL_BLOB_MAX_LENGTH 6048
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the layer parameter defining the number of simultaneous points
|
||||||
|
* of contact supported by a layer. This parameter should be set to a non-zero
|
||||||
|
* value if the associated layer should receive touch events ("touch"
|
||||||
|
* instructions).
|
||||||
|
*
|
||||||
|
* This value specified for this parameter is advisory, and the client is not
|
||||||
|
* required to honor the declared level of touch support. Implementations are
|
||||||
|
* expected to safely handle or ignore any received touch events, regardless of
|
||||||
|
* the level of touch support declared.
|
||||||
|
*
|
||||||
|
* @see guac_protocol_send_set_int()
|
||||||
|
*/
|
||||||
|
#define GUAC_PROTOCOL_LAYER_PARAMETER_MULTI_TOUCH "multi-touch"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -209,6 +209,53 @@ int vguac_protocol_send_log(guac_socket* socket, const char* format,
|
|||||||
int guac_protocol_send_mouse(guac_socket* socket, int x, int y,
|
int guac_protocol_send_mouse(guac_socket* socket, int x, int y,
|
||||||
int button_mask, guac_timestamp timestamp);
|
int button_mask, guac_timestamp timestamp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a touch instruction over the given guac_socket connection.
|
||||||
|
*
|
||||||
|
* If an error occurs sending the instruction, a non-zero value is
|
||||||
|
* returned, and guac_error is set appropriately.
|
||||||
|
*
|
||||||
|
* @param socket
|
||||||
|
* The guac_socket connection to use.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* An arbitrary integer ID which uniquely identifies this contact relative
|
||||||
|
* to other active contacts.
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* The X coordinate of the center of the touch contact.
|
||||||
|
*
|
||||||
|
* @param y
|
||||||
|
* The Y coordinate of the center of the touch contact.
|
||||||
|
*
|
||||||
|
* @param x_radius
|
||||||
|
* The X radius of the ellipse covering the general area of the touch
|
||||||
|
* contact, in pixels.
|
||||||
|
*
|
||||||
|
* @param y_radius
|
||||||
|
* The Y radius of the ellipse covering the general area of the touch
|
||||||
|
* contact, in pixels.
|
||||||
|
*
|
||||||
|
* @param angle
|
||||||
|
* The rough angle of clockwise rotation of the general area of the touch
|
||||||
|
* contact, in degrees.
|
||||||
|
*
|
||||||
|
* @param force
|
||||||
|
* The relative force exerted by the touch contact, where 0 is no force
|
||||||
|
* (the touch has been lifted) and 1 is maximum force (the maximum amount
|
||||||
|
* of force representable by the device).
|
||||||
|
*
|
||||||
|
* @param timestamp
|
||||||
|
* The server timestamp (in milliseconds) at the point in time this touch
|
||||||
|
* event was acknowledged.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on error.
|
||||||
|
*/
|
||||||
|
int guac_protocol_send_touch(guac_socket* socket, int id, int x, int y,
|
||||||
|
int x_radius, int y_radius, double angle, double force,
|
||||||
|
guac_timestamp timestamp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a nest instruction over the given guac_socket connection.
|
* Sends a nest instruction over the given guac_socket connection.
|
||||||
*
|
*
|
||||||
@ -271,6 +318,32 @@ int guac_protocol_send_ready(guac_socket* socket, const char* id);
|
|||||||
int guac_protocol_send_set(guac_socket* socket, const guac_layer* layer,
|
int guac_protocol_send_set(guac_socket* socket, const guac_layer* layer,
|
||||||
const char* name, const char* value);
|
const char* name, const char* value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a set instruction over the given guac_socket connection. This function
|
||||||
|
* behavies identically to guac_protocol_send_set() except that the provided
|
||||||
|
* parameter value is an integer, rather than a string.
|
||||||
|
*
|
||||||
|
* If an error occurs sending the instruction, a non-zero value is
|
||||||
|
* returned, and guac_error is set appropriately.
|
||||||
|
*
|
||||||
|
* @param socket
|
||||||
|
* The guac_socket connection to use.
|
||||||
|
*
|
||||||
|
* @param layer
|
||||||
|
* The layer to set the parameter of.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the parameter to set.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The value to set the parameter to.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on error.
|
||||||
|
*/
|
||||||
|
int guac_protocol_send_set_int(guac_socket* socket, const guac_layer* layer,
|
||||||
|
const char* name, int value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a select instruction over the given guac_socket connection.
|
* Sends a select instruction over the given guac_socket connection.
|
||||||
*
|
*
|
||||||
|
@ -95,6 +95,51 @@ typedef void* guac_user_callback(guac_user* user, void* data);
|
|||||||
typedef int guac_user_mouse_handler(guac_user* user, int x, int y,
|
typedef int guac_user_mouse_handler(guac_user* user, int x, int y,
|
||||||
int button_mask);
|
int button_mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for Guacamole touch events, invoked when a "touch" instruction has
|
||||||
|
* been received from a user.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user that sent the touch event.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* An arbitrary integer ID which uniquely identifies this contact relative
|
||||||
|
* to other active contacts.
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* The X coordinate of the center of the touch contact within the display
|
||||||
|
* when the event occurred, in pixels. This value is not guaranteed to be
|
||||||
|
* within the bounds of the display area.
|
||||||
|
*
|
||||||
|
* @param y
|
||||||
|
* The Y coordinate of the center of the touch contact within the display
|
||||||
|
* when the event occurred, in pixels. This value is not guaranteed to be
|
||||||
|
* within the bounds of the display area.
|
||||||
|
*
|
||||||
|
* @param x_radius
|
||||||
|
* The X radius of the ellipse covering the general area of the touch
|
||||||
|
* contact, in pixels.
|
||||||
|
*
|
||||||
|
* @param y_radius
|
||||||
|
* The Y radius of the ellipse covering the general area of the touch
|
||||||
|
* contact, in pixels.
|
||||||
|
*
|
||||||
|
* @param angle
|
||||||
|
* The rough angle of clockwise rotation of the general area of the touch
|
||||||
|
* contact, in degrees.
|
||||||
|
*
|
||||||
|
* @param force
|
||||||
|
* The relative force exerted by the touch contact, where 0 is no force
|
||||||
|
* (the touch has been lifted) and 1 is maximum force (the maximum amount
|
||||||
|
* of force representable by the device).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero if the touch event was handled successfully, or non-zero if an
|
||||||
|
* error occurred.
|
||||||
|
*/
|
||||||
|
typedef int guac_user_touch_handler(guac_user* user, int id, int x, int y,
|
||||||
|
int x_radius, int y_radius, double angle, double force);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for Guacamole key events, invoked when a "key" event has been
|
* Handler for Guacamole key events, invoked when a "key" event has been
|
||||||
* received from a user.
|
* received from a user.
|
||||||
|
@ -509,6 +509,27 @@ struct guac_user {
|
|||||||
*/
|
*/
|
||||||
guac_user_argv_handler* argv_handler;
|
guac_user_argv_handler* argv_handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for touch events sent by the Guacamole web-client.
|
||||||
|
*
|
||||||
|
* The handler takes the integer X and Y coordinates representing the
|
||||||
|
* center of the touch contact, as well as several parameters describing
|
||||||
|
* the general shape of the contact area. The force parameter indicates the
|
||||||
|
* amount of force exerted by the contact, including whether the contact
|
||||||
|
* has been lifted.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* @code
|
||||||
|
* int touch_handler(guac_user* user, int id, int x, int y,
|
||||||
|
* int x_radius, int y_radius, double angle, double force);
|
||||||
|
*
|
||||||
|
* int guac_user_init(guac_user* user, int argc, char** argv) {
|
||||||
|
* user->touch_handler = touch_handler;
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
guac_user_touch_handler* touch_handler;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -820,6 +820,37 @@ int guac_protocol_send_mouse(guac_socket* socket, int x, int y,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_protocol_send_touch(guac_socket* socket, int id, int x, int y,
|
||||||
|
int x_radius, int y_radius, double angle, double force,
|
||||||
|
guac_timestamp timestamp) {
|
||||||
|
|
||||||
|
int ret_val;
|
||||||
|
|
||||||
|
guac_socket_instruction_begin(socket);
|
||||||
|
ret_val =
|
||||||
|
guac_socket_write_string(socket, "5.touch,")
|
||||||
|
|| __guac_socket_write_length_int(socket, id)
|
||||||
|
|| guac_socket_write_string(socket, ",")
|
||||||
|
|| __guac_socket_write_length_int(socket, x)
|
||||||
|
|| guac_socket_write_string(socket, ",")
|
||||||
|
|| __guac_socket_write_length_int(socket, y)
|
||||||
|
|| guac_socket_write_string(socket, ",")
|
||||||
|
|| __guac_socket_write_length_int(socket, x_radius)
|
||||||
|
|| guac_socket_write_string(socket, ",")
|
||||||
|
|| __guac_socket_write_length_int(socket, y_radius)
|
||||||
|
|| guac_socket_write_string(socket, ",")
|
||||||
|
|| __guac_socket_write_length_double(socket, angle)
|
||||||
|
|| guac_socket_write_string(socket, ",")
|
||||||
|
|| __guac_socket_write_length_double(socket, force)
|
||||||
|
|| guac_socket_write_string(socket, ",")
|
||||||
|
|| __guac_socket_write_length_int(socket, timestamp)
|
||||||
|
|| guac_socket_write_string(socket, ";");
|
||||||
|
|
||||||
|
guac_socket_instruction_end(socket);
|
||||||
|
return ret_val;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int guac_protocol_send_move(guac_socket* socket, const guac_layer* layer,
|
int guac_protocol_send_move(guac_socket* socket, const guac_layer* layer,
|
||||||
const guac_layer* parent, int x, int y, int z) {
|
const guac_layer* parent, int x, int y, int z) {
|
||||||
|
|
||||||
@ -1057,6 +1088,26 @@ int guac_protocol_send_set(guac_socket* socket, const guac_layer* layer,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_protocol_send_set_int(guac_socket* socket, const guac_layer* layer,
|
||||||
|
const char* name, int value) {
|
||||||
|
|
||||||
|
int ret_val;
|
||||||
|
|
||||||
|
guac_socket_instruction_begin(socket);
|
||||||
|
ret_val =
|
||||||
|
guac_socket_write_string(socket, "3.set,")
|
||||||
|
|| __guac_socket_write_length_int(socket, layer->index)
|
||||||
|
|| guac_socket_write_string(socket, ",")
|
||||||
|
|| __guac_socket_write_length_string(socket, name)
|
||||||
|
|| guac_socket_write_string(socket, ",")
|
||||||
|
|| __guac_socket_write_length_int(socket, value)
|
||||||
|
|| guac_socket_write_string(socket, ";");
|
||||||
|
|
||||||
|
guac_socket_instruction_end(socket);
|
||||||
|
return ret_val;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int guac_protocol_send_select(guac_socket* socket, const char* protocol) {
|
int guac_protocol_send_select(guac_socket* socket, const char* protocol) {
|
||||||
|
|
||||||
int ret_val;
|
int ret_val;
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
__guac_instruction_handler_mapping __guac_instruction_handler_map[] = {
|
__guac_instruction_handler_mapping __guac_instruction_handler_map[] = {
|
||||||
{"sync", __guac_handle_sync},
|
{"sync", __guac_handle_sync},
|
||||||
|
{"touch", __guac_handle_touch},
|
||||||
{"mouse", __guac_handle_mouse},
|
{"mouse", __guac_handle_mouse},
|
||||||
{"key", __guac_handle_key},
|
{"key", __guac_handle_key},
|
||||||
{"clipboard", __guac_handle_clipboard},
|
{"clipboard", __guac_handle_clipboard},
|
||||||
@ -150,6 +151,21 @@ int __guac_handle_sync(guac_user* user, int argc, char** argv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __guac_handle_touch(guac_user* user, int argc, char** argv) {
|
||||||
|
if (user->touch_handler)
|
||||||
|
return user->touch_handler(
|
||||||
|
user,
|
||||||
|
atoi(argv[0]), /* id */
|
||||||
|
atoi(argv[1]), /* x */
|
||||||
|
atoi(argv[2]), /* y */
|
||||||
|
atoi(argv[3]), /* x_radius */
|
||||||
|
atoi(argv[4]), /* y_radius */
|
||||||
|
atof(argv[5]), /* angle */
|
||||||
|
atof(argv[6]) /* force */
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int __guac_handle_mouse(guac_user* user, int argc, char** argv) {
|
int __guac_handle_mouse(guac_user* user, int argc, char** argv) {
|
||||||
if (user->mouse_handler)
|
if (user->mouse_handler)
|
||||||
return user->mouse_handler(
|
return user->mouse_handler(
|
||||||
|
@ -85,6 +85,13 @@ __guac_instruction_handler __guac_handle_sync;
|
|||||||
*/
|
*/
|
||||||
__guac_instruction_handler __guac_handle_mouse;
|
__guac_instruction_handler __guac_handle_mouse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal initial handler for the touch instruction. When a touch instruction
|
||||||
|
* is received, this handler will be called. The client's touch handler will
|
||||||
|
* be invoked if defined.
|
||||||
|
*/
|
||||||
|
__guac_instruction_handler __guac_handle_touch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal initial handler for the key instruction. When a key instruction
|
* Internal initial handler for the key instruction. When a key instruction
|
||||||
* is received, this handler will be called. The client's key handler will
|
* is received, this handler will be called. The client's key handler will
|
||||||
|
@ -234,6 +234,7 @@ void* guac_kubernetes_client_thread(void* data) {
|
|||||||
settings->create_recording_path,
|
settings->create_recording_path,
|
||||||
!settings->recording_exclude_output,
|
!settings->recording_exclude_output,
|
||||||
!settings->recording_exclude_mouse,
|
!settings->recording_exclude_mouse,
|
||||||
|
0, /* Touch events not supported */
|
||||||
settings->recording_include_keys);
|
settings->recording_include_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ libguac_client_rdp_la_SOURCES = \
|
|||||||
channels/rdpdr/rdpdr-messages.c \
|
channels/rdpdr/rdpdr-messages.c \
|
||||||
channels/rdpdr/rdpdr-printer.c \
|
channels/rdpdr/rdpdr-printer.c \
|
||||||
channels/rdpdr/rdpdr.c \
|
channels/rdpdr/rdpdr.c \
|
||||||
|
channels/rdpei.c \
|
||||||
channels/rdpsnd/rdpsnd-messages.c \
|
channels/rdpsnd/rdpsnd-messages.c \
|
||||||
channels/rdpsnd/rdpsnd.c \
|
channels/rdpsnd/rdpsnd.c \
|
||||||
client.c \
|
client.c \
|
||||||
@ -101,6 +102,7 @@ noinst_HEADERS = \
|
|||||||
channels/rdpdr/rdpdr-messages.h \
|
channels/rdpdr/rdpdr-messages.h \
|
||||||
channels/rdpdr/rdpdr-printer.h \
|
channels/rdpdr/rdpdr-printer.h \
|
||||||
channels/rdpdr/rdpdr.h \
|
channels/rdpdr/rdpdr.h \
|
||||||
|
channels/rdpei.h \
|
||||||
channels/rdpsnd/rdpsnd-messages.h \
|
channels/rdpsnd/rdpsnd-messages.h \
|
||||||
channels/rdpsnd/rdpsnd.h \
|
channels/rdpsnd/rdpsnd.h \
|
||||||
client.h \
|
client.h \
|
||||||
|
170
src/protocols/rdp/channels/rdpei.c
Normal file
170
src/protocols/rdp/channels/rdpei.c
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "channels/rdpei.h"
|
||||||
|
#include "common/surface.h"
|
||||||
|
#include "plugins/channels.h"
|
||||||
|
#include "rdp.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#include <freerdp/client/rdpei.h>
|
||||||
|
#include <freerdp/freerdp.h>
|
||||||
|
#include <freerdp/event.h>
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/timestamp.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
guac_rdp_rdpei* guac_rdp_rdpei_alloc() {
|
||||||
|
|
||||||
|
guac_rdp_rdpei* rdpei = malloc(sizeof(guac_rdp_rdpei));
|
||||||
|
|
||||||
|
/* Not yet connected */
|
||||||
|
rdpei->rdpei = NULL;
|
||||||
|
|
||||||
|
/* No active touches */
|
||||||
|
for (int i = 0; i < GUAC_RDP_RDPEI_MAX_TOUCHES; i++)
|
||||||
|
rdpei->touch[i].active = 0;
|
||||||
|
|
||||||
|
return rdpei;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_rdp_rdpei_free(guac_rdp_rdpei* rdpei) {
|
||||||
|
free(rdpei);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback which associates handlers specific to Guacamole with the
|
||||||
|
* RdpeiClientContext instance allocated by FreeRDP to deal with received
|
||||||
|
* RDPEI (multi-touch input) messages.
|
||||||
|
*
|
||||||
|
* This function is called whenever a channel connects via the PubSub event
|
||||||
|
* system within FreeRDP, but only has any effect if the connected channel is
|
||||||
|
* the RDPEI channel. This specific callback is registered with the
|
||||||
|
* PubSub system of the relevant rdpContext when guac_rdp_rdpei_load_plugin() is
|
||||||
|
* called.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* The rdpContext associated with the active RDP session.
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
|
* Event-specific arguments, mainly the name of the channel, and a
|
||||||
|
* reference to the associated plugin loaded for that channel by FreeRDP.
|
||||||
|
*/
|
||||||
|
static void guac_rdp_rdpei_channel_connected(rdpContext* context,
|
||||||
|
ChannelConnectedEventArgs* e) {
|
||||||
|
|
||||||
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
guac_rdp_rdpei* guac_rdpei = rdp_client->rdpei;
|
||||||
|
|
||||||
|
/* Ignore connection event if it's not for the RDPEI channel */
|
||||||
|
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Store reference to the RDPEI plugin once it's connected */
|
||||||
|
RdpeiClientContext* rdpei = (RdpeiClientContext*) e->pInterface;
|
||||||
|
guac_rdpei->rdpei = rdpei;
|
||||||
|
|
||||||
|
/* Declare level of multi-touch support */
|
||||||
|
guac_common_surface_set_multitouch(rdp_client->display->default_surface,
|
||||||
|
GUAC_RDP_RDPEI_MAX_TOUCHES);
|
||||||
|
|
||||||
|
guac_client_log(client, GUAC_LOG_DEBUG, "RDPEI channel will be used for "
|
||||||
|
"multi-touch support.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_rdp_rdpei_load_plugin(rdpContext* context) {
|
||||||
|
|
||||||
|
/* Subscribe to and handle channel connected events */
|
||||||
|
PubSub_SubscribeChannelConnected(context->pubSub,
|
||||||
|
(pChannelConnectedEventHandler) guac_rdp_rdpei_channel_connected);
|
||||||
|
|
||||||
|
/* Add "rdpei" channel */
|
||||||
|
guac_freerdp_dynamic_channel_collection_add(context->settings, "rdpei", NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_rdp_rdpei_touch_update(guac_rdp_rdpei* rdpei, int id, int x, int y,
|
||||||
|
double force) {
|
||||||
|
|
||||||
|
int contact_id; /* Ignored */
|
||||||
|
|
||||||
|
/* Track touches only if channel is connected */
|
||||||
|
RdpeiClientContext* context = rdpei->rdpei;
|
||||||
|
if (context == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Locate active touch having provided ID */
|
||||||
|
guac_rdp_rdpei_touch* touch = NULL;
|
||||||
|
for (int i = 0; i < GUAC_RDP_RDPEI_MAX_TOUCHES; i++) {
|
||||||
|
if (rdpei->touch[i].active && rdpei->touch[i].id == id) {
|
||||||
|
touch = &rdpei->touch[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no such touch exists, add it */
|
||||||
|
if (touch == NULL) {
|
||||||
|
for (int i = 0; i < GUAC_RDP_RDPEI_MAX_TOUCHES; i++) {
|
||||||
|
if (!rdpei->touch[i].active) {
|
||||||
|
touch = &rdpei->touch[i];
|
||||||
|
touch->id = id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the touch couldn't be added, we're already at maximum touch capacity.
|
||||||
|
* Drop the event. */
|
||||||
|
if (touch == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Signal the end of an established touch if touch force has become zero
|
||||||
|
* (this should be a safe comparison, as zero has an exact representation
|
||||||
|
* in floating point, and the client side will use an exact value to
|
||||||
|
* represent the absence of a touch) */
|
||||||
|
if (force == 0.0) {
|
||||||
|
|
||||||
|
/* Ignore release of touches that we aren't tracking */
|
||||||
|
if (!touch->active)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
context->TouchEnd(context, id, x, y, &contact_id);
|
||||||
|
touch->active = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Signal the start of a touch if this is the first we've seen it */
|
||||||
|
else if (!touch->active) {
|
||||||
|
context->TouchBegin(context, id, x, y, &contact_id);
|
||||||
|
touch->active = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Established touches need only be updated */
|
||||||
|
else
|
||||||
|
context->TouchUpdate(context, id, x, y, &contact_id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
154
src/protocols/rdp/channels/rdpei.h
Normal file
154
src/protocols/rdp/channels/rdpei.h
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GUAC_RDP_CHANNELS_RDPEI_H
|
||||||
|
#define GUAC_RDP_CHANNELS_RDPEI_H
|
||||||
|
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#include <freerdp/client/rdpei.h>
|
||||||
|
#include <freerdp/freerdp.h>
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/timestamp.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of simultaneously-tracked touches.
|
||||||
|
*/
|
||||||
|
#define GUAC_RDP_RDPEI_MAX_TOUCHES 10
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single, tracked touch contact.
|
||||||
|
*/
|
||||||
|
typedef struct guac_rdp_rdpei_touch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this touch is active (1) or inactive (0). An active touch is
|
||||||
|
* being tracked, while an inactive touch is simple an empty space awaiting
|
||||||
|
* use by some future touch event.
|
||||||
|
*/
|
||||||
|
int active;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique ID representing this touch contact.
|
||||||
|
*/
|
||||||
|
int id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The X-coordinate of this touch, in pixels.
|
||||||
|
*/
|
||||||
|
int x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Y-coordinate of this touch, in pixels.
|
||||||
|
*/
|
||||||
|
int y;
|
||||||
|
|
||||||
|
} guac_rdp_rdpei_touch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multi-touch input module.
|
||||||
|
*/
|
||||||
|
typedef struct guac_rdp_rdpei {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RDPEI control interface.
|
||||||
|
*/
|
||||||
|
RdpeiClientContext* rdpei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All currently-tracked touches.
|
||||||
|
*/
|
||||||
|
guac_rdp_rdpei_touch touch[GUAC_RDP_RDPEI_MAX_TOUCHES];
|
||||||
|
|
||||||
|
} guac_rdp_rdpei;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates a new RDPEI module, which will ultimately control the RDPEI
|
||||||
|
* channel once connected. The RDPEI channel allows multi-touch input
|
||||||
|
* events to be sent to the RDP server.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A newly-allocated RDPEI module.
|
||||||
|
*/
|
||||||
|
guac_rdp_rdpei* guac_rdp_rdpei_alloc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the resources associated with support for the RDPEI channel. Only
|
||||||
|
* resources specific to Guacamole are freed. Resources specific to FreeRDP's
|
||||||
|
* handling of the RDPEI channel will be freed by FreeRDP. If no resources are
|
||||||
|
* currently allocated for RDPEI, this function has no effect.
|
||||||
|
*
|
||||||
|
* @param rdpei
|
||||||
|
* The RDPEI module to free.
|
||||||
|
*/
|
||||||
|
void guac_rdp_rdpei_free(guac_rdp_rdpei* rdpei);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds FreeRDP's "rdpei" plugin to the list of dynamic virtual channel plugins
|
||||||
|
* to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will
|
||||||
|
* automatically be assicated with the guac_rdp_rdpei instance pointed to by the
|
||||||
|
* current guac_rdp_client. The plugin will only be loaded once the "drdynvc"
|
||||||
|
* plugin is loaded. The "rdpei" plugin ultimately adds support for multi-touch
|
||||||
|
* input via the RDPEI channel.
|
||||||
|
*
|
||||||
|
* If failures occur, messages noting the specifics of those failures will be
|
||||||
|
* logged, and the RDP side of multi-touch support will not be functional.
|
||||||
|
*
|
||||||
|
* This MUST be called within the PreConnect callback of the freerdp instance
|
||||||
|
* for multi-touch support to be loaded.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* The rdpContext associated with the active RDP session.
|
||||||
|
*/
|
||||||
|
void guac_rdp_rdpei_load_plugin(rdpContext* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reports to the RDP server that the status of a single touch contact has
|
||||||
|
* changed. Depending on the amount of force associated with the touch and
|
||||||
|
* whether the touch has been encountered before, this will result a new touch
|
||||||
|
* contact, updates to an existing contact, or removal of an existing contact.
|
||||||
|
* If the RDPEI channel has not yet been connected, touches will be ignored and
|
||||||
|
* dropped until it is connected.
|
||||||
|
*
|
||||||
|
* @param rdpei
|
||||||
|
* The RDPEI module associated with the RDP session.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* An arbitrary integer ID unique to the touch being updated.
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* The X-coordinate of the touch, in pixels.
|
||||||
|
*
|
||||||
|
* @param y
|
||||||
|
* The Y-coordinate of the touch, in pixels.
|
||||||
|
*
|
||||||
|
* @param force
|
||||||
|
* The amount of force currently being exerted on the device by the touch
|
||||||
|
* contact in question, where 1.0 is the maximum amount of force
|
||||||
|
* representable and 0.0 indicates the contact has been lifted.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero if the touch event was successfully processed, non-zero if the
|
||||||
|
* touch event had to be dropped.
|
||||||
|
*/
|
||||||
|
int guac_rdp_rdpei_touch_update(guac_rdp_rdpei* rdpei, int id, int x, int y,
|
||||||
|
double force);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -147,6 +147,9 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
|
|||||||
/* Init display update module */
|
/* Init display update module */
|
||||||
rdp_client->disp = guac_rdp_disp_alloc();
|
rdp_client->disp = guac_rdp_disp_alloc();
|
||||||
|
|
||||||
|
/* Init multi-touch support module (RDPEI) */
|
||||||
|
rdp_client->rdpei = guac_rdp_rdpei_alloc();
|
||||||
|
|
||||||
/* Redirect FreeRDP log messages to guac_client_log() */
|
/* Redirect FreeRDP log messages to guac_client_log() */
|
||||||
guac_rdp_redirect_wlog(client);
|
guac_rdp_redirect_wlog(client);
|
||||||
|
|
||||||
@ -187,6 +190,9 @@ int guac_rdp_client_free_handler(guac_client* client) {
|
|||||||
/* Free display update module */
|
/* Free display update module */
|
||||||
guac_rdp_disp_free(rdp_client->disp);
|
guac_rdp_disp_free(rdp_client->disp);
|
||||||
|
|
||||||
|
/* Free multi-touch support module (RDPEI) */
|
||||||
|
guac_rdp_rdpei_free(rdp_client->rdpei);
|
||||||
|
|
||||||
/* Clean up filesystem, if allocated */
|
/* Clean up filesystem, if allocated */
|
||||||
if (rdp_client->filesystem != NULL)
|
if (rdp_client->filesystem != NULL)
|
||||||
guac_rdp_fs_free(rdp_client->filesystem);
|
guac_rdp_fs_free(rdp_client->filesystem);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "channels/disp.h"
|
#include "channels/disp.h"
|
||||||
|
#include "channels/rdpei.h"
|
||||||
#include "common/cursor.h"
|
#include "common/cursor.h"
|
||||||
#include "common/display.h"
|
#include "common/display.h"
|
||||||
#include "common/recording.h"
|
#include "common/recording.h"
|
||||||
@ -122,6 +123,33 @@ complete:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_rdp_user_touch_handler(guac_user* user, int id, int x, int y,
|
||||||
|
int x_radius, int y_radius, double angle, double force) {
|
||||||
|
|
||||||
|
guac_client* client = user->client;
|
||||||
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
|
||||||
|
pthread_rwlock_rdlock(&(rdp_client->lock));
|
||||||
|
|
||||||
|
/* Skip if not yet connected */
|
||||||
|
freerdp* rdp_inst = rdp_client->rdp_inst;
|
||||||
|
if (rdp_inst == NULL)
|
||||||
|
goto complete;
|
||||||
|
|
||||||
|
/* Report touch event within recording */
|
||||||
|
if (rdp_client->recording != NULL)
|
||||||
|
guac_common_recording_report_touch(rdp_client->recording, id, x, y,
|
||||||
|
x_radius, y_radius, angle, force);
|
||||||
|
|
||||||
|
/* Forward touch event along RDPEI channel */
|
||||||
|
guac_rdp_rdpei_touch_update(rdp_client->rdpei, id, x, y, force);
|
||||||
|
|
||||||
|
complete:
|
||||||
|
pthread_rwlock_unlock(&(rdp_client->lock));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int guac_rdp_user_key_handler(guac_user* user, int keysym, int pressed) {
|
int guac_rdp_user_key_handler(guac_user* user, int keysym, int pressed) {
|
||||||
|
|
||||||
guac_client* client = user->client;
|
guac_client* client = user->client;
|
||||||
|
@ -27,6 +27,11 @@
|
|||||||
*/
|
*/
|
||||||
guac_user_mouse_handler guac_rdp_user_mouse_handler;
|
guac_user_mouse_handler guac_rdp_user_mouse_handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for Guacamole user touch events.
|
||||||
|
*/
|
||||||
|
guac_user_touch_handler guac_rdp_user_touch_handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for Guacamole user key events.
|
* Handler for Guacamole user key events.
|
||||||
*/
|
*/
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "channels/pipe-svc.h"
|
#include "channels/pipe-svc.h"
|
||||||
#include "channels/rail.h"
|
#include "channels/rail.h"
|
||||||
#include "channels/rdpdr/rdpdr.h"
|
#include "channels/rdpdr/rdpdr.h"
|
||||||
|
#include "channels/rdpei.h"
|
||||||
#include "channels/rdpsnd/rdpsnd.h"
|
#include "channels/rdpsnd/rdpsnd.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
@ -100,6 +101,10 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE)
|
if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE)
|
||||||
guac_rdp_disp_load_plugin(context);
|
guac_rdp_disp_load_plugin(context);
|
||||||
|
|
||||||
|
/* Load "rdpei" plugin for multi-touch support */
|
||||||
|
if (settings->enable_touch)
|
||||||
|
guac_rdp_rdpei_load_plugin(context);
|
||||||
|
|
||||||
/* Load "AUDIO_INPUT" plugin for audio input*/
|
/* Load "AUDIO_INPUT" plugin for audio input*/
|
||||||
if (settings->enable_audio_input) {
|
if (settings->enable_audio_input) {
|
||||||
rdp_client->audio_input = guac_rdp_audio_buffer_alloc();
|
rdp_client->audio_input = guac_rdp_audio_buffer_alloc();
|
||||||
@ -421,6 +426,7 @@ static int guac_rdp_handle_connection(guac_client* client) {
|
|||||||
settings->create_recording_path,
|
settings->create_recording_path,
|
||||||
!settings->recording_exclude_output,
|
!settings->recording_exclude_output,
|
||||||
!settings->recording_exclude_mouse,
|
!settings->recording_exclude_mouse,
|
||||||
|
!settings->recording_exclude_touch,
|
||||||
settings->recording_include_keys);
|
settings->recording_include_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "channels/audio-input/audio-buffer.h"
|
#include "channels/audio-input/audio-buffer.h"
|
||||||
#include "channels/cliprdr.h"
|
#include "channels/cliprdr.h"
|
||||||
#include "channels/disp.h"
|
#include "channels/disp.h"
|
||||||
|
#include "channels/rdpei.h"
|
||||||
#include "common/clipboard.h"
|
#include "common/clipboard.h"
|
||||||
#include "common/display.h"
|
#include "common/display.h"
|
||||||
#include "common/list.h"
|
#include "common/list.h"
|
||||||
@ -148,6 +149,11 @@ typedef struct guac_rdp_client {
|
|||||||
*/
|
*/
|
||||||
guac_rdp_disp* disp;
|
guac_rdp_disp* disp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multi-touch support module (RDPEI).
|
||||||
|
*/
|
||||||
|
guac_rdp_rdpei* rdpei;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of all available static virtual channels.
|
* List of all available static virtual channels.
|
||||||
*/
|
*/
|
||||||
|
@ -104,10 +104,12 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {
|
|||||||
"recording-name",
|
"recording-name",
|
||||||
"recording-exclude-output",
|
"recording-exclude-output",
|
||||||
"recording-exclude-mouse",
|
"recording-exclude-mouse",
|
||||||
|
"recording-exclude-touch",
|
||||||
"recording-include-keys",
|
"recording-include-keys",
|
||||||
"create-recording-path",
|
"create-recording-path",
|
||||||
"resize-method",
|
"resize-method",
|
||||||
"enable-audio-input",
|
"enable-audio-input",
|
||||||
|
"enable-touch",
|
||||||
"read-only",
|
"read-only",
|
||||||
|
|
||||||
"gateway-hostname",
|
"gateway-hostname",
|
||||||
@ -499,6 +501,13 @@ enum RDP_ARGS_IDX {
|
|||||||
*/
|
*/
|
||||||
IDX_RECORDING_EXCLUDE_MOUSE,
|
IDX_RECORDING_EXCLUDE_MOUSE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether changes to touch contact state should NOT be included in the
|
||||||
|
* session recording. Touch state is included by default, as it may be
|
||||||
|
* necessary for touch interactions to be rendered in any resulting video.
|
||||||
|
*/
|
||||||
|
IDX_RECORDING_EXCLUDE_TOUCH,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether keys pressed and released should be included in the session
|
* Whether keys pressed and released should be included in the session
|
||||||
* recording. Key events are NOT included by default within the recording,
|
* recording. Key events are NOT included by default within the recording,
|
||||||
@ -527,6 +536,12 @@ enum RDP_ARGS_IDX {
|
|||||||
*/
|
*/
|
||||||
IDX_ENABLE_AUDIO_INPUT,
|
IDX_ENABLE_AUDIO_INPUT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "true" if multi-touch support should be enabled for the RDP connection,
|
||||||
|
* "false" or blank otherwise.
|
||||||
|
*/
|
||||||
|
IDX_ENABLE_TOUCH,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "true" if this connection should be read-only (user input should be
|
* "true" if this connection should be read-only (user input should be
|
||||||
* dropped), "false" or blank otherwise.
|
* dropped), "false" or blank otherwise.
|
||||||
@ -1050,6 +1065,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
|
|||||||
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
||||||
IDX_RECORDING_EXCLUDE_MOUSE, 0);
|
IDX_RECORDING_EXCLUDE_MOUSE, 0);
|
||||||
|
|
||||||
|
/* Parse touch exclusion flag */
|
||||||
|
settings->recording_exclude_touch =
|
||||||
|
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
||||||
|
IDX_RECORDING_EXCLUDE_TOUCH, 0);
|
||||||
|
|
||||||
/* Parse key event inclusion flag */
|
/* Parse key event inclusion flag */
|
||||||
settings->recording_include_keys =
|
settings->recording_include_keys =
|
||||||
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
||||||
@ -1085,6 +1105,11 @@ guac_rdp_settings* guac_rdp_parse_args(guac_user* user,
|
|||||||
settings->resize_method = GUAC_RESIZE_NONE;
|
settings->resize_method = GUAC_RESIZE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Multi-touch input enable/disable */
|
||||||
|
settings->enable_touch =
|
||||||
|
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
||||||
|
IDX_ENABLE_TOUCH, 0);
|
||||||
|
|
||||||
/* Audio input enable/disable */
|
/* Audio input enable/disable */
|
||||||
settings->enable_audio_input =
|
settings->enable_audio_input =
|
||||||
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
guac_user_parse_args_boolean(user, GUAC_RDP_CLIENT_ARGS, argv,
|
||||||
|
@ -505,6 +505,14 @@ typedef struct guac_rdp_settings {
|
|||||||
*/
|
*/
|
||||||
int recording_exclude_mouse;
|
int recording_exclude_mouse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-zero if changes to touch state should NOT be included in the session
|
||||||
|
* recording, zero otherwise. Touch state is included by default, as it may
|
||||||
|
* be necessary for touch interactions to be rendered in any resulting
|
||||||
|
* video.
|
||||||
|
*/
|
||||||
|
int recording_exclude_touch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Non-zero if keys pressed and released should be included in the session
|
* Non-zero if keys pressed and released should be included in the session
|
||||||
* recording, zero otherwise. Key events are NOT included by default within
|
* recording, zero otherwise. Key events are NOT included by default within
|
||||||
@ -525,6 +533,11 @@ typedef struct guac_rdp_settings {
|
|||||||
*/
|
*/
|
||||||
int enable_audio_input;
|
int enable_audio_input;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether multi-touch support is enabled.
|
||||||
|
*/
|
||||||
|
int enable_touch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The hostname of the remote desktop gateway that should be used as an
|
* The hostname of the remote desktop gateway that should be used as an
|
||||||
* intermediary for the remote desktop connection. If no gateway should
|
* intermediary for the remote desktop connection. If no gateway should
|
||||||
|
@ -105,6 +105,10 @@ int guac_rdp_user_join_handler(guac_user* user, int argc, char** argv) {
|
|||||||
user->mouse_handler = guac_rdp_user_mouse_handler;
|
user->mouse_handler = guac_rdp_user_mouse_handler;
|
||||||
user->key_handler = guac_rdp_user_key_handler;
|
user->key_handler = guac_rdp_user_key_handler;
|
||||||
|
|
||||||
|
/* Multi-touch events */
|
||||||
|
if (settings->enable_touch)
|
||||||
|
user->touch_handler = guac_rdp_user_touch_handler;
|
||||||
|
|
||||||
/* Inbound (client to server) clipboard transfer */
|
/* Inbound (client to server) clipboard transfer */
|
||||||
if (!settings->disable_paste)
|
if (!settings->disable_paste)
|
||||||
user->clipboard_handler = guac_rdp_clipboard_handler;
|
user->clipboard_handler = guac_rdp_clipboard_handler;
|
||||||
|
@ -234,6 +234,7 @@ void* ssh_client_thread(void* data) {
|
|||||||
settings->create_recording_path,
|
settings->create_recording_path,
|
||||||
!settings->recording_exclude_output,
|
!settings->recording_exclude_output,
|
||||||
!settings->recording_exclude_mouse,
|
!settings->recording_exclude_mouse,
|
||||||
|
0, /* Touch events not supported */
|
||||||
settings->recording_include_keys);
|
settings->recording_include_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,6 +581,7 @@ void* guac_telnet_client_thread(void* data) {
|
|||||||
settings->create_recording_path,
|
settings->create_recording_path,
|
||||||
!settings->recording_exclude_output,
|
!settings->recording_exclude_output,
|
||||||
!settings->recording_exclude_mouse,
|
!settings->recording_exclude_mouse,
|
||||||
|
0, /* Touch events not supported */
|
||||||
settings->recording_include_keys);
|
settings->recording_include_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,6 +427,7 @@ void* guac_vnc_client_thread(void* data) {
|
|||||||
settings->create_recording_path,
|
settings->create_recording_path,
|
||||||
!settings->recording_exclude_output,
|
!settings->recording_exclude_output,
|
||||||
!settings->recording_exclude_mouse,
|
!settings->recording_exclude_mouse,
|
||||||
|
0, /* Touch events not supported */
|
||||||
settings->recording_include_keys);
|
settings->recording_include_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user