Applied slightly modified patch #220 that fixes

hash collisions with keysyms.



git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/rdesktop/trunk@1802 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
Henrik Andersson 2014-05-20 10:43:03 +00:00
parent e597ef4e90
commit cb06fe1863
2 changed files with 122 additions and 16 deletions

11
types.h
View File

@ -2,6 +2,7 @@
rdesktop: A Remote Desktop Protocol client.
Common data types
Copyright (C) Matthew Chapman 1999-2008
Copyright 2014 Henrik Andersson <hean01@cendio.se> for Cendio AB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -136,6 +137,16 @@ typedef struct _key_translation
}
key_translation;
typedef struct _key_translation_entry
{
key_translation *tr;
/* The full KeySym for this entry, not KEYMAP_MASKed */
uint32 keysym;
/* This will be non-NULL if there has been a hash collision */
struct _key_translation_entry *next;
}
key_translation_entry;
typedef struct _VCHANNEL
{
uint16 mcs_id;

127
xkeymap.c
View File

@ -4,6 +4,7 @@
Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
Copyright 2003-2008 Peter Astrand <astrand@cendio.se> for Cendio AB
Copyright 2014 Henrik Andersson <hean01@cendio.se> for Cendio AB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -51,7 +52,7 @@ extern RDP_VERSION g_rdp_version;
extern RD_BOOL g_numlock_sync;
static RD_BOOL keymap_loaded;
static key_translation *keymap[KEYMAP_SIZE];
static key_translation_entry *keymap[KEYMAP_SIZE];
static KeySym keypress_keysyms[256];
static int min_keycode;
static uint16 remote_modifier_state = 0;
@ -73,11 +74,93 @@ free_key_translation(key_translation * ptr)
}
}
/* Free the key_translation_entry for a given keysym and remove from the table */
static void
delete_key_translation_entry(KeySym keysym)
{
uint32 hash;
key_translation_entry *ptr;
key_translation_entry *next;
key_translation_entry *prev;
key_translation_entry tmp;
/* Faking a prev node allows us to keep the algorithm simple */
hash = keysym & KEYMAP_MASK;
ptr = keymap[hash];
tmp.next = ptr;
prev = &tmp;
while (ptr)
{
next = ptr->next;
if (ptr->keysym == keysym)
{
free_key_translation(ptr->tr);
prev->next = next;
xfree(ptr);
}
else
{
prev = ptr;
}
ptr = next;
}
/* Copy pointer back from our fake node */
keymap[hash] = tmp.next;
}
/* Allocate and return a new entry in the translation table */
static key_translation_entry *
new_key_translation_entry(KeySym keysym)
{
uint32 hash;
key_translation_entry *entry;
/* Clear out any existing entry */
delete_key_translation_entry(keysym);
/* Allocate the new one */
entry = (key_translation_entry *) xmalloc(sizeof(key_translation_entry));
memset(entry, 0, sizeof(key_translation_entry));
entry->keysym = keysym;
/* And insert it at head of list */
hash = keysym & KEYMAP_MASK;
entry->next = keymap[hash];
keymap[hash] = entry;
return entry;
}
/* Retrieve the key_translation_entry for a given keysym */
static key_translation_entry *
get_key_translation_entry(uint32 keysym)
{
key_translation_entry *ptr;
key_translation_entry *next;
ptr = keymap[keysym & KEYMAP_MASK];
while (ptr)
{
next = ptr->next;
if (ptr->keysym == keysym)
return ptr;
ptr = next;
}
/* Not found */
return NULL;
}
static void
add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
{
KeySym keysym;
key_translation *tr;
key_translation_entry *entry;
keysym = XStringToKeysym(keyname);
if (keysym == NoSymbol)
@ -89,12 +172,14 @@ add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
"modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
tr = (key_translation *) xmalloc(sizeof(key_translation));
memset(tr, 0, sizeof(key_translation));
tr->scancode = scancode;
tr->modifiers = modifiers;
free_key_translation(keymap[keysym & KEYMAP_MASK]);
keymap[keysym & KEYMAP_MASK] = tr;
/* Make a new entry in the table */
entry = new_key_translation_entry(keysym);
/* And add the new translation to it */
entry->tr = (key_translation *) xmalloc(sizeof(key_translation));
memset(entry->tr, 0, sizeof(key_translation));
entry->tr->scancode = scancode;
entry->tr->modifiers = modifiers;
return;
}
@ -103,6 +188,8 @@ static void
add_sequence(char *rest, char *mapname)
{
KeySym keysym;
KeySym seq_keysym;
key_translation_entry *entry;
key_translation *tr, **prev_next;
size_t chars;
char keyname[KEYMAP_MAX_LINE_LENGTH];
@ -123,11 +210,10 @@ add_sequence(char *rest, char *mapname)
return;
}
DEBUG_KBD(("Adding sequence for keysym (0x%lx, %s) -> ", keysym, keyname));
free_key_translation(keymap[keysym & KEYMAP_MASK]);
prev_next = &keymap[keysym & KEYMAP_MASK];
entry = new_key_translation_entry(keysym);
prev_next = &(entry->tr);
while (*rest)
{
@ -140,22 +226,28 @@ add_sequence(char *rest, char *mapname)
STRNCPY(keyname, rest, chars + 1);
rest += chars;
keysym = XStringToKeysym(keyname);
if (keysym == NoSymbol)
seq_keysym = XStringToKeysym(keyname);
if (seq_keysym == NoSymbol)
{
DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring line)\n", keyname,
mapname));
delete_key_translation_entry(keysym);
return;
}
/* Allocate space for key_translation structure */
tr = (key_translation *) xmalloc(sizeof(key_translation));
memset(tr, 0, sizeof(key_translation));
/* Do this straight away so the key_translation won't get orphaned on error */
if (!entry->tr)
entry->tr = tr;
*prev_next = tr;
prev_next = &tr->next;
tr->seq_keysym = keysym;
tr->seq_keysym = seq_keysym;
DEBUG_KBD(("0x%x, ", (unsigned int) keysym));
DEBUG_KBD(("0x%x, ", (unsigned int) seq_keysym));
}
DEBUG_KBD(("\n"));
}
@ -638,8 +730,11 @@ xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
{
key_translation tr = { 0, 0, 0, 0 };
key_translation *ptr;
key_translation_entry *entry;
entry = get_key_translation_entry(keysym);
ptr = entry ? entry->tr : NULL;
ptr = keymap[keysym & KEYMAP_MASK];
if (ptr)
{
tr = *ptr;