GUACAMOLE-518: Track and update modifier states based on overall flags, not keysyms.
This commit is contained in:
parent
120be65dbc
commit
ce0982fefd
@ -28,6 +28,39 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Translates the given keysym into the corresponding modifier flag, as defined
|
||||
* by keymap.h. If the given keysym does not represent a modifier key, zero is
|
||||
* returned.
|
||||
*
|
||||
* @param keysym
|
||||
* The keysym to translate into a modifier flag.
|
||||
*
|
||||
* @return
|
||||
* The modifier flag which corresponds to the given keysym, or zero if the
|
||||
* given keysym does not represent a modifier key.
|
||||
*/
|
||||
static int guac_rdp_keyboard_modifier_flag(int keysym) {
|
||||
|
||||
/* Translate keysym into corresponding modifier flag */
|
||||
switch (keysym) {
|
||||
|
||||
/* Shift */
|
||||
case 0xFFE1:
|
||||
case 0xFFE2:
|
||||
return GUAC_RDP_KEYMAP_MODIFIER_SHIFT;
|
||||
|
||||
/* AltGr */
|
||||
case 0xFE03:
|
||||
return GUAC_RDP_KEYMAP_MODIFIER_ALTGR;
|
||||
|
||||
}
|
||||
|
||||
/* Not a modifier */
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the given keysym into the corresponding lock flag, as would be
|
||||
* required by the RDP synchronize event. If the given keysym does not
|
||||
@ -328,38 +361,15 @@ int guac_rdp_keyboard_send_event(guac_rdp_keyboard* keyboard,
|
||||
keysym_desc->set_locks,
|
||||
keysym_desc->clear_locks);
|
||||
|
||||
/* If defined, send any prerequesite keys that must be set */
|
||||
if (keysym_desc->set_keysyms != NULL)
|
||||
guac_rdp_keyboard_send_events(keyboard,
|
||||
keysym_desc->set_keysyms,
|
||||
GUAC_RDP_KEY_RELEASED,
|
||||
GUAC_RDP_KEY_PRESSED);
|
||||
|
||||
/* If defined, release any keys that must be cleared */
|
||||
if (keysym_desc->clear_keysyms != NULL)
|
||||
guac_rdp_keyboard_send_events(keyboard,
|
||||
keysym_desc->clear_keysyms,
|
||||
GUAC_RDP_KEY_PRESSED,
|
||||
GUAC_RDP_KEY_RELEASED);
|
||||
/* 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);
|
||||
|
||||
/* If defined, release any keys that were originally released */
|
||||
if (keysym_desc->set_keysyms != NULL)
|
||||
guac_rdp_keyboard_send_events(keyboard,
|
||||
keysym_desc->set_keysyms,
|
||||
GUAC_RDP_KEY_RELEASED,
|
||||
GUAC_RDP_KEY_RELEASED);
|
||||
|
||||
/* If defined, send any keys that were originally set */
|
||||
if (keysym_desc->clear_keysyms != NULL)
|
||||
guac_rdp_keyboard_send_events(keyboard,
|
||||
keysym_desc->clear_keysyms,
|
||||
GUAC_RDP_KEY_PRESSED,
|
||||
GUAC_RDP_KEY_PRESSED);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -398,28 +408,6 @@ int guac_rdp_keyboard_send_event(guac_rdp_keyboard* keyboard,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void guac_rdp_keyboard_send_events(guac_rdp_keyboard* keyboard,
|
||||
const int* keysym_string, guac_rdp_key_state from,
|
||||
guac_rdp_key_state to) {
|
||||
|
||||
int keysym;
|
||||
|
||||
/* Send all keysyms in string, NULL terminated */
|
||||
while ((keysym = *keysym_string) != 0) {
|
||||
|
||||
/* If key is currently in given state, send event for changing it to
|
||||
* specified "to" state */
|
||||
guac_rdp_key* key = guac_rdp_keyboard_get_key(keyboard, keysym);
|
||||
if (key != NULL && key->state == from)
|
||||
guac_rdp_keyboard_send_event(keyboard, *keysym_string, to);
|
||||
|
||||
/* Next keysym */
|
||||
keysym_string++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_rdp_keyboard_update_locks(guac_rdp_keyboard* keyboard,
|
||||
int set_flags, int clear_flags) {
|
||||
|
||||
@ -437,9 +425,50 @@ void guac_rdp_keyboard_update_locks(guac_rdp_keyboard* keyboard,
|
||||
|
||||
}
|
||||
|
||||
void guac_rdp_keyboard_update_modifiers(guac_rdp_keyboard* keyboard,
|
||||
int set_flags, int clear_flags) {
|
||||
|
||||
/* Only clear modifiers that are set */
|
||||
clear_flags &= keyboard->modifier_flags;
|
||||
|
||||
/* Only set modifiers that are currently cleared */
|
||||
set_flags &= ~keyboard->modifier_flags;
|
||||
|
||||
/* Press/release Shift as needed */
|
||||
if (set_flags & GUAC_RDP_KEYMAP_MODIFIER_SHIFT) {
|
||||
guac_rdp_keyboard_update_keysym(keyboard, 0xFFE1, 1);
|
||||
}
|
||||
else if (clear_flags & GUAC_RDP_KEYMAP_MODIFIER_SHIFT) {
|
||||
guac_rdp_keyboard_update_keysym(keyboard, 0xFFE1, 0);
|
||||
guac_rdp_keyboard_update_keysym(keyboard, 0xFFE2, 0);
|
||||
}
|
||||
|
||||
/* Press/release AltGr as needed */
|
||||
if (set_flags & GUAC_RDP_KEYMAP_MODIFIER_ALTGR) {
|
||||
guac_rdp_keyboard_update_keysym(keyboard, 0xFE03, 1);
|
||||
}
|
||||
else if (clear_flags & GUAC_RDP_KEYMAP_MODIFIER_ALTGR) {
|
||||
guac_rdp_keyboard_update_keysym(keyboard, 0xFE03, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int guac_rdp_keyboard_update_keysym(guac_rdp_keyboard* keyboard,
|
||||
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 */
|
||||
if (!keyboard->synchronized) {
|
||||
|
||||
@ -452,14 +481,15 @@ int guac_rdp_keyboard_update_keysym(guac_rdp_keyboard* keyboard,
|
||||
|
||||
}
|
||||
|
||||
/* Toggle lock flag, if any */
|
||||
if (pressed)
|
||||
/* Toggle locks and set modifiers on keydown */
|
||||
if (pressed) {
|
||||
keyboard->lock_flags ^= guac_rdp_keyboard_lock_flag(keysym);
|
||||
keyboard->modifier_flags |= guac_rdp_keyboard_modifier_flag(keysym);
|
||||
}
|
||||
|
||||
/* Update keysym state */
|
||||
guac_rdp_key* key = guac_rdp_keyboard_get_key(keyboard, keysym);
|
||||
if (key != NULL)
|
||||
key->state = pressed ? GUAC_RDP_KEY_PRESSED : GUAC_RDP_KEY_RELEASED;
|
||||
/* Clear modifiers on keyup */
|
||||
else
|
||||
keyboard->modifier_flags &= ~guac_rdp_keyboard_modifier_flag(keysym);
|
||||
|
||||
return guac_rdp_keyboard_send_event(keyboard, keysym, pressed);
|
||||
|
||||
|
@ -79,6 +79,15 @@ typedef struct guac_rdp_keyboard {
|
||||
*/
|
||||
guac_client* client;
|
||||
|
||||
/**
|
||||
* The local state of all known modifier keys, as a bitwise OR of the
|
||||
* modified flags used by the keymaps.
|
||||
*
|
||||
* @see GUAC_RDP_KEYMAP_MODIFIER_SHIFT
|
||||
* @see GUAC_RDP_KEYMAP_MODIFIER_ALTGR
|
||||
*/
|
||||
int modifier_flags;
|
||||
|
||||
/**
|
||||
* The local state of all known lock keys, as a bitwise OR of all RDP lock
|
||||
* key flags. Legal flags are KBD_SYNC_SCROLL_LOCK, KBD_SYNC_NUM_LOCK,
|
||||
@ -177,33 +186,6 @@ 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);
|
||||
|
||||
/**
|
||||
* For every keysym in the given NULL-terminated array of keysyms, send the RDP
|
||||
* key events required to update the remote state of those keys as specified,
|
||||
* depending on the current local state of those keysyms. For each key in the
|
||||
* "from" state, that key will be updated to the "to" state. The locally-stored
|
||||
* state of each key is remains untouched.
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_rdp_keyboard associated with the current RDP session.
|
||||
*
|
||||
* @param keysym_string
|
||||
* A NULL-terminated array of keysyms, each of which will be updated.
|
||||
*
|
||||
* @param from
|
||||
* GUAC_RDP_KEY_RELEASED if the state of currently-released keys should be
|
||||
* updated, or GUAC_RDP_KEY_PRESSED if the state of currently-pressed keys
|
||||
* should be updated.
|
||||
*
|
||||
* @param to
|
||||
* GUAC_RDP_KEY_RELEASED if the keys being updated should be marked as
|
||||
* released, or GUAC_RDP_KEY_PRESSED if the keys being updated should be
|
||||
* marked as pressed.
|
||||
*/
|
||||
void guac_rdp_keyboard_send_events(guac_rdp_keyboard* keyboard,
|
||||
const int* keysym_string, guac_rdp_key_state from,
|
||||
guac_rdp_key_state to);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -224,6 +206,26 @@ void guac_rdp_keyboard_send_events(guac_rdp_keyboard* keyboard,
|
||||
void guac_rdp_keyboard_update_locks(guac_rdp_keyboard* keyboard,
|
||||
int set_flags, int clear_flags);
|
||||
|
||||
/**
|
||||
* Updates the local state of the modifier keys (such as Shift or AltGr),
|
||||
* synchronizing the remote state of those keys if it is expected to differ.
|
||||
* Valid modifier flags are defined by keymap.h.
|
||||
*
|
||||
* @see GUAC_RDP_KEYMAP_MODIFIER_SHIFT
|
||||
* @see GUAC_RDP_KEYMAP_MODIFIER_ALTGR
|
||||
*
|
||||
* @param keyboard
|
||||
* The guac_rdp_keyboard associated with the current RDP session.
|
||||
*
|
||||
* @param set_flags
|
||||
* The modifier key flags which should be set.
|
||||
*
|
||||
* @param clear_flags
|
||||
* The modifier key flags which should be cleared.
|
||||
*/
|
||||
void guac_rdp_keyboard_update_modifiers(guac_rdp_keyboard* keyboard,
|
||||
int set_flags, int clear_flags);
|
||||
|
||||
/**
|
||||
* Updates the local state of the given keysym, sending the key events required
|
||||
* to replicate that state remotely (on the RDP server). The key events sent
|
||||
|
@ -22,6 +22,16 @@
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
/**
|
||||
* Bitwise flag value representing the Shift modifier.
|
||||
*/
|
||||
#define GUAC_RDP_KEYMAP_MODIFIER_SHIFT 1
|
||||
|
||||
/**
|
||||
* Bitwise flag value representing the AltGr modifier.
|
||||
*/
|
||||
#define GUAC_RDP_KEYMAP_MODIFIER_ALTGR 2
|
||||
|
||||
/**
|
||||
* Represents a keysym-to-scancode mapping for RDP, with extra information
|
||||
* about the state of prerequisite keysyms.
|
||||
@ -39,29 +49,44 @@ typedef struct guac_rdp_keysym_desc {
|
||||
int scancode;
|
||||
|
||||
/**
|
||||
* Required RDP-specific flags.
|
||||
* Required RDP-specific flags that must be sent along with the scancode.
|
||||
*/
|
||||
int flags;
|
||||
|
||||
/**
|
||||
* Null-terminated list of keysyms which must be down for this keysym
|
||||
* to be properly typed.
|
||||
* Bitwise-OR of the flags of any modifiers that must be active for the
|
||||
* associated scancode to be interpreted as this keysym.
|
||||
*
|
||||
* If the associated keysym is pressed, and any of these modifiers are not
|
||||
* currently active, Guacamole's RDP support must send additional events to
|
||||
* activate these modifiers prior to sending the scancode for this keysym.
|
||||
*
|
||||
* @see GUAC_RDP_KEYMAP_MODIFIER_SHIFT
|
||||
* @see GUAC_RDP_KEYMAP_MODIFIER_ALTGR
|
||||
*/
|
||||
const int* set_keysyms;
|
||||
const int set_modifiers;
|
||||
|
||||
/**
|
||||
* Null-terminated list of keysyms which must be up for this keysym
|
||||
* to be properly typed.
|
||||
* Bitwise-OR of the flags of any modifiers that must NOT be active for the
|
||||
* associated scancode to be interpreted as this keysym.
|
||||
*
|
||||
* If the associated keysym is pressed, and any of these modifiers are
|
||||
* currently active, Guacamole's RDP support must send additional events to
|
||||
* deactivate these modifiers prior to sending the scancode for this
|
||||
* keysym.
|
||||
*
|
||||
* @see GUAC_RDP_KEYMAP_MODIFIER_SHIFT
|
||||
* @see GUAC_RDP_KEYMAP_MODIFIER_ALTGR
|
||||
*/
|
||||
const int* clear_keysyms;
|
||||
const int clear_modifiers;
|
||||
|
||||
/**
|
||||
* Bitwise OR of the flags of all lock keys (ie: Caps lock, Num lock, etc.)
|
||||
* which must be active for this keysym to be properly typed. Legal flags
|
||||
* are KBD_SYNC_SCROLL_LOCK, KBD_SYNC_NUM_LOCK, KBD_SYNC_CAPS_LOCK, and
|
||||
* KBD_SYNC_KANA_LOCK.
|
||||
*/
|
||||
int set_locks;
|
||||
*/
|
||||
const int set_locks;
|
||||
|
||||
/**
|
||||
* Bitwise OR of the flags of all lock keys (ie: Caps lock, Num lock, etc.)
|
||||
@ -69,7 +94,7 @@ typedef struct guac_rdp_keysym_desc {
|
||||
* are KBD_SYNC_SCROLL_LOCK, KBD_SYNC_NUM_LOCK, KBD_SYNC_CAPS_LOCK, and
|
||||
* KBD_SYNC_KANA_LOCK.
|
||||
*/
|
||||
int clear_locks;
|
||||
const int clear_locks;
|
||||
|
||||
} guac_rdp_keysym_desc;
|
||||
|
||||
@ -110,63 +135,6 @@ struct guac_rdp_keymap {
|
||||
*/
|
||||
#define GUAC_DEFAULT_KEYMAP "en-us-qwerty"
|
||||
|
||||
/**
|
||||
* Keysym string containing only the left "shift" key.
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_SHIFT[];
|
||||
|
||||
/**
|
||||
* Keysym string containing both "shift" keys.
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_ALL_SHIFT[];
|
||||
|
||||
/**
|
||||
* Keysym string containing only the right "alt" key (AltGr).
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_ALTGR[];
|
||||
|
||||
/**
|
||||
* Keysym string containing the right "alt" key (AltGr) and
|
||||
* left shift.
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_SHIFT_ALTGR[];
|
||||
|
||||
/**
|
||||
* Keysym string containing the right "alt" key (AltGr) and
|
||||
* both shift keys.
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_ALL_SHIFT_ALTGR[];
|
||||
|
||||
/**
|
||||
* Keysym string containing only the left "ctrl" key.
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_CTRL[];
|
||||
|
||||
/**
|
||||
* Keysym string containing both "ctrl" keys.
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_ALL_CTRL[];
|
||||
|
||||
/**
|
||||
* Keysym string containing only the left "alt" key.
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_ALT[];
|
||||
|
||||
/**
|
||||
* Keysym string containing both "alt" keys.
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_ALL_ALT[];
|
||||
|
||||
/**
|
||||
* Keysym string containing the left "alt" and left "ctrl" keys
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_CTRL_ALT[];
|
||||
|
||||
/**
|
||||
* Keysym string containing all modifier keys.
|
||||
*/
|
||||
extern const int GUAC_KEYSYMS_ALL_MODIFIERS[];
|
||||
|
||||
/**
|
||||
* NULL-terminated array of all keymaps.
|
||||
*/
|
||||
|
@ -92,10 +92,12 @@ for my $filename (@ARGV) {
|
||||
my $ext_flags = 0;
|
||||
my $set_shift = 0;
|
||||
my $set_altgr = 0;
|
||||
my $set_caps = 0;
|
||||
my $set_num = 0;
|
||||
|
||||
my $clear_shift = 0;
|
||||
my $clear_altgr = 0;
|
||||
my $clear_caps = 0;
|
||||
my $clear_num = 0;
|
||||
|
||||
# Parse ranges and options
|
||||
@ -105,6 +107,7 @@ for my $filename (@ARGV) {
|
||||
if ((my $opt) = m/^\+([a-z]+)$/) {
|
||||
if ($opt eq "shift") { $set_shift = 1; }
|
||||
elsif ($opt eq "altgr") { $set_altgr = 1; }
|
||||
elsif ($opt eq "caps") { $set_caps = 1; }
|
||||
elsif ($opt eq "num") { $set_num = 1; }
|
||||
elsif ($opt eq "ext") { $ext_flags = 1; }
|
||||
else {
|
||||
@ -117,6 +120,7 @@ for my $filename (@ARGV) {
|
||||
elsif ((my $opt) = m/^-([a-z]+)$/) {
|
||||
if ($opt eq "shift") { $clear_shift = 1; }
|
||||
elsif ($opt eq "altgr") { $clear_altgr = 1; }
|
||||
elsif ($opt eq "caps") { $clear_caps = 1; }
|
||||
elsif ($opt eq "num") { $clear_num = 1; }
|
||||
else {
|
||||
die "$filename: $.: ERROR: "
|
||||
@ -175,37 +179,25 @@ for my $filename (@ARGV) {
|
||||
. " .keysym = " . $keysyms[$i] . ","
|
||||
. " .scancode = " . $scancodes[$i];
|
||||
|
||||
# Set requirements
|
||||
if ($set_shift && !$set_altgr) {
|
||||
$content .= ", .set_keysyms = GUAC_KEYSYMS_SHIFT";
|
||||
}
|
||||
elsif (!$set_shift && $set_altgr) {
|
||||
$content .= ", .set_keysyms = GUAC_KEYSYMS_ALTGR";
|
||||
}
|
||||
elsif ($set_shift && $set_altgr) {
|
||||
$content .= ", .set_keysyms = GUAC_KEYSYMS_SHIFT_ALTGR";
|
||||
}
|
||||
# Modifiers that must be active
|
||||
$content .= ", .set_modifiers = 0";
|
||||
$content .= " | GUAC_RDP_KEYMAP_MODIFIER_SHIFT" if $set_shift;
|
||||
$content .= " | GUAC_RDP_KEYMAP_MODIFIER_ALTGR" if $set_altgr;
|
||||
|
||||
# Clear requirements
|
||||
if ($clear_shift && !$clear_altgr) {
|
||||
$content .= ", .clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT";
|
||||
}
|
||||
elsif (!$clear_shift && $clear_altgr) {
|
||||
$content .= ", .clear_keysyms = GUAC_KEYSYMS_ALTGR";
|
||||
}
|
||||
elsif ($clear_shift && $clear_altgr) {
|
||||
$content .= ", .clear_keysyms = GUAC_KEYSYMS_ALL_SHIFT_ALTGR";
|
||||
}
|
||||
# Modifiers that must be inactive
|
||||
$content .= ", .clear_modifiers = 0";
|
||||
$content .= " | GUAC_RDP_KEYMAP_MODIFIER_SHIFT" if $clear_shift;
|
||||
$content .= " | GUAC_RDP_KEYMAP_MODIFIER_ALTGR" if $clear_altgr;
|
||||
|
||||
# Set locks
|
||||
if ($set_num) {
|
||||
$content .= ", .set_locks = KBD_SYNC_NUM_LOCK";
|
||||
}
|
||||
# Locks that must be set
|
||||
$content .= ", .set_locks = 0";
|
||||
$content .= " | KBD_SYNC_NUM_LOCK" if $set_num;
|
||||
$content .= " | KBD_SYNC_CAPS_LOCK" if $set_caps;
|
||||
|
||||
# Clear locks
|
||||
if ($clear_num) {
|
||||
$content .= ", .clear_locks = KBD_SYNC_NUM_LOCK";
|
||||
}
|
||||
# Locks that must NOT be set
|
||||
$content .= ", .clear_locks = 0";
|
||||
$content .= " | KBD_SYNC_NUM_LOCK" if $clear_num;
|
||||
$content .= " | KBD_SYNC_CAPS_LOCK" if $clear_caps;
|
||||
|
||||
# Flags
|
||||
if ($ext_flags) {
|
||||
|
Loading…
Reference in New Issue
Block a user