GUACAMOLE-518: Ensure keyboard state is always updated for all keys pressed/released.
This commit is contained in:
parent
7fd54c56a8
commit
96c4c208b4
@ -162,12 +162,12 @@ int guac_rdp_decompose_keysym(guac_rdp_keyboard* keyboard, int keysym) {
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Press dead key */
|
/* Press dead key */
|
||||||
guac_rdp_keyboard_send_event(keyboard, key->dead_keysym, 1);
|
guac_rdp_keyboard_update_keysym(keyboard, key->dead_keysym, 1);
|
||||||
guac_rdp_keyboard_send_event(keyboard, key->dead_keysym, 0);
|
guac_rdp_keyboard_update_keysym(keyboard, key->dead_keysym, 0);
|
||||||
|
|
||||||
/* Press base key */
|
/* Press base key */
|
||||||
guac_rdp_keyboard_send_event(keyboard, key->base_keysym, 1);
|
guac_rdp_keyboard_update_keysym(keyboard, key->base_keysym, 1);
|
||||||
guac_rdp_keyboard_send_event(keyboard, key->base_keysym, 0);
|
guac_rdp_keyboard_update_keysym(keyboard, key->base_keysym, 0);
|
||||||
|
|
||||||
/* Decomposed key successfully typed */
|
/* Decomposed key successfully typed */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -340,72 +340,95 @@ int guac_rdp_keyboard_is_defined(guac_rdp_keyboard* keyboard, int keysym) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int guac_rdp_keyboard_send_event(guac_rdp_keyboard* keyboard,
|
/**
|
||||||
int keysym, int pressed) {
|
* Presses/releases the requested key by sending one or more RDP key events, as
|
||||||
|
* defined within the keymap defining that key.
|
||||||
|
*
|
||||||
|
* @param keyboard
|
||||||
|
* The guac_rdp_keyboard associated with the current RDP session.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* The guac_rdp_keysym_desc of the key being pressed or released, as
|
||||||
|
* retrieved from the relevant keymap.
|
||||||
|
*
|
||||||
|
* @param pressed
|
||||||
|
* Zero if the key is being released, non-zero otherwise.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero if the key was successfully pressed/released, non-zero if the key
|
||||||
|
* cannot be sent using RDP key events.
|
||||||
|
*/
|
||||||
|
static int guac_rdp_keyboard_send_defined_key(guac_rdp_keyboard* keyboard,
|
||||||
|
guac_rdp_key* key, int pressed) {
|
||||||
|
|
||||||
guac_client* client = keyboard->client;
|
guac_client* client = keyboard->client;
|
||||||
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
|
||||||
/* If keysym is actually defined within keyboard */
|
if (key->definition->scancode == 0)
|
||||||
guac_rdp_key* key = guac_rdp_keyboard_get_key(keyboard, keysym);
|
return 1;
|
||||||
if (key != NULL) {
|
|
||||||
|
|
||||||
/* Look up scancode mapping */
|
const guac_rdp_keysym_desc* keysym_desc = key->definition;
|
||||||
const guac_rdp_keysym_desc* keysym_desc = key->definition;
|
|
||||||
|
|
||||||
/* If defined, send event */
|
/* Update state of required locks and modifiers only when key is just
|
||||||
if (keysym_desc->scancode != 0) {
|
* now being pressed */
|
||||||
|
|
||||||
/* Update remote lock state as necessary */
|
|
||||||
guac_rdp_keyboard_update_locks(keyboard,
|
|
||||||
keysym_desc->set_locks,
|
|
||||||
keysym_desc->clear_locks);
|
|
||||||
|
|
||||||
/* Update remote modifier states as necessary */
|
|
||||||
guac_rdp_keyboard_update_modifiers(keyboard,
|
|
||||||
keysym_desc->set_modifiers,
|
|
||||||
keysym_desc->clear_modifiers);
|
|
||||||
|
|
||||||
/* Fire actual key event for target key */
|
|
||||||
guac_rdp_send_key_event(rdp_client, keysym_desc->scancode,
|
|
||||||
keysym_desc->flags, pressed);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fall back to dead keys or Unicode events if otherwise undefined inside
|
|
||||||
* current keymap (note that we only handle "pressed" here, as neither
|
|
||||||
* Unicode events nor dead keys can have a pressed/released state) */
|
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
|
guac_rdp_keyboard_update_locks(keyboard,
|
||||||
|
keysym_desc->set_locks,
|
||||||
|
keysym_desc->clear_locks);
|
||||||
|
|
||||||
/* Attempt to type using dead keys */
|
guac_rdp_keyboard_update_modifiers(keyboard,
|
||||||
if (!guac_rdp_decompose_keysym(keyboard, keysym))
|
keysym_desc->set_modifiers,
|
||||||
return 0;
|
keysym_desc->clear_modifiers);
|
||||||
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
|
||||||
"Sending keysym 0x%x as Unicode", keysym);
|
|
||||||
|
|
||||||
/* Translate keysym into codepoint */
|
|
||||||
int codepoint;
|
|
||||||
if (keysym <= 0xFF)
|
|
||||||
codepoint = keysym;
|
|
||||||
else if (keysym >= 0x1000000)
|
|
||||||
codepoint = keysym & 0xFFFFFF;
|
|
||||||
else {
|
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG,
|
|
||||||
"Unmapped keysym has no equivalent unicode "
|
|
||||||
"value: 0x%x", keysym);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send as Unicode event */
|
|
||||||
guac_rdp_send_unicode_event(rdp_client, codepoint);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fire actual key event for target key */
|
||||||
|
guac_rdp_send_key_event(rdp_client, keysym_desc->scancode,
|
||||||
|
keysym_desc->flags, pressed);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Presses and releases the requested key by sending one or more RDP events,
|
||||||
|
* without relying on a keymap for that key. This will typically involve either
|
||||||
|
* sending the key using a Unicode event or decomposing the key into a series
|
||||||
|
* of keypresses involving deadkeys.
|
||||||
|
*
|
||||||
|
* @param keyboard
|
||||||
|
* The guac_rdp_keyboard associated with the current RDP session.
|
||||||
|
*
|
||||||
|
* @param keysym
|
||||||
|
* The keysym of the key to press and release.
|
||||||
|
*/
|
||||||
|
static void guac_rdp_keyboard_send_missing_key(guac_rdp_keyboard* keyboard,
|
||||||
|
int keysym) {
|
||||||
|
|
||||||
|
guac_client* client = keyboard->client;
|
||||||
|
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
|
||||||
|
|
||||||
|
/* Attempt to type using dead keys */
|
||||||
|
if (!guac_rdp_decompose_keysym(keyboard, keysym))
|
||||||
|
return;
|
||||||
|
|
||||||
|
guac_client_log(client, GUAC_LOG_DEBUG, "Sending keysym 0x%x as "
|
||||||
|
"Unicode", keysym);
|
||||||
|
|
||||||
|
/* Translate keysym into codepoint */
|
||||||
|
int codepoint;
|
||||||
|
if (keysym <= 0xFF)
|
||||||
|
codepoint = keysym;
|
||||||
|
else if (keysym >= 0x1000000)
|
||||||
|
codepoint = keysym & 0xFFFFFF;
|
||||||
|
else {
|
||||||
|
guac_client_log(client, GUAC_LOG_DEBUG, "Unmapped keysym has no "
|
||||||
|
"equivalent unicode value: 0x%x", keysym);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send as Unicode event */
|
||||||
|
guac_rdp_send_unicode_event(rdp_client, codepoint);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_rdp_keyboard_update_locks(guac_rdp_keyboard* keyboard,
|
void guac_rdp_keyboard_update_locks(guac_rdp_keyboard* keyboard,
|
||||||
@ -456,19 +479,6 @@ void guac_rdp_keyboard_update_modifiers(guac_rdp_keyboard* keyboard,
|
|||||||
int guac_rdp_keyboard_update_keysym(guac_rdp_keyboard* keyboard,
|
int guac_rdp_keyboard_update_keysym(guac_rdp_keyboard* keyboard,
|
||||||
int keysym, int pressed) {
|
int keysym, int pressed) {
|
||||||
|
|
||||||
guac_rdp_key* key = guac_rdp_keyboard_get_key(keyboard, keysym);
|
|
||||||
if (key != NULL) {
|
|
||||||
|
|
||||||
/* Ignore event if state is not changing */
|
|
||||||
guac_rdp_key_state new_state = pressed ? GUAC_RDP_KEY_PRESSED : GUAC_RDP_KEY_RELEASED;
|
|
||||||
if (key->state == new_state)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Update keysym state */
|
|
||||||
key->state = new_state;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Synchronize lock keys states, if this has not yet been done */
|
/* Synchronize lock keys states, if this has not yet been done */
|
||||||
if (!keyboard->synchronized) {
|
if (!keyboard->synchronized) {
|
||||||
|
|
||||||
@ -481,6 +491,19 @@ int guac_rdp_keyboard_update_keysym(guac_rdp_keyboard* keyboard,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If key is known, update stored state, ignoring the key event entirely if
|
||||||
|
* state is not actually changing */
|
||||||
|
guac_rdp_key* key = guac_rdp_keyboard_get_key(keyboard, keysym);
|
||||||
|
if (key != NULL) {
|
||||||
|
|
||||||
|
guac_rdp_key_state new_state = pressed ? GUAC_RDP_KEY_PRESSED : GUAC_RDP_KEY_RELEASED;
|
||||||
|
if (key->state == new_state)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
key->state = new_state;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Toggle locks and set modifiers on keydown */
|
/* Toggle locks and set modifiers on keydown */
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
keyboard->lock_flags ^= guac_rdp_keyboard_lock_flag(keysym);
|
keyboard->lock_flags ^= guac_rdp_keyboard_lock_flag(keysym);
|
||||||
@ -488,10 +511,21 @@ int guac_rdp_keyboard_update_keysym(guac_rdp_keyboard* keyboard,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Clear modifiers on keyup */
|
/* Clear modifiers on keyup */
|
||||||
else
|
else {
|
||||||
keyboard->modifier_flags &= ~guac_rdp_keyboard_modifier_flag(keysym);
|
keyboard->modifier_flags &= ~guac_rdp_keyboard_modifier_flag(keysym);
|
||||||
|
}
|
||||||
|
|
||||||
return guac_rdp_keyboard_send_event(keyboard, keysym, pressed);
|
/* Attempt to send using normal RDP key events */
|
||||||
|
if (key == NULL && !guac_rdp_keyboard_send_defined_key(keyboard, key, pressed))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Fall back to dead keys or Unicode events if otherwise undefined inside
|
||||||
|
* current keymap (note that we only handle "pressed" here, as neither
|
||||||
|
* Unicode events nor dead keys can have a pressed/released state) */
|
||||||
|
if (pressed)
|
||||||
|
guac_rdp_keyboard_send_missing_key(keyboard, keysym);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,26 +166,6 @@ void guac_rdp_keyboard_free(guac_rdp_keyboard* keyboard);
|
|||||||
*/
|
*/
|
||||||
int guac_rdp_keyboard_is_defined(guac_rdp_keyboard* keyboard, int keysym);
|
int guac_rdp_keyboard_is_defined(guac_rdp_keyboard* keyboard, int keysym);
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends one or more RDP key events, effectively pressing or releasing the
|
|
||||||
* given keysym on the remote side. The key events sent will depend on the
|
|
||||||
* current keymap. The locally-stored state of each key is remains untouched.
|
|
||||||
*
|
|
||||||
* @param keyboard
|
|
||||||
* The guac_rdp_keyboard associated with the current RDP session.
|
|
||||||
*
|
|
||||||
* @param keysym
|
|
||||||
* The keysym being pressed or released.
|
|
||||||
*
|
|
||||||
* @param pressed
|
|
||||||
* Zero if the keysym is being released, non-zero otherwise.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* Zero if the keys were successfully sent, non-zero otherwise.
|
|
||||||
*/
|
|
||||||
int guac_rdp_keyboard_send_event(guac_rdp_keyboard* keyboard,
|
|
||||||
int keysym, int pressed);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the local state of the lock keys (such as Caps lock or Num lock),
|
* Updates the local state of the lock keys (such as Caps lock or Num lock),
|
||||||
* synchronizing the remote state of those keys if it is expected to differ.
|
* synchronizing the remote state of those keys if it is expected to differ.
|
||||||
|
Loading…
Reference in New Issue
Block a user