diff --git a/compositor.h b/compositor.h
index 80aa4f3..a0eff35 100644
--- a/compositor.h
+++ b/compositor.h
@@ -1595,8 +1595,7 @@ extern void XLSeatSetTextInputFuncs (TextInputFuncs *);
extern int XLSeatGetKeyboardDevice (Seat *);
extern int XLSeatGetPointerDevice (Seat *);
extern Seat *XLSeatGetInputMethodSeat (void);
-extern void XLSeatDispatchCoreKeyEvent (Seat *, Surface *, XEvent *,
- KeySym);
+extern void XLSeatDispatchCoreKeyEvent (Seat *, Surface *, XEvent *);
extern Seat *XLPointerGetSeat (Pointer *);
extern void XLSeatGetMouseData (Seat *, Surface **, double *, double *,
double *, double *);
@@ -1610,6 +1609,7 @@ extern SwipeGesture *XLSeatGetSwipeGesture (Seat *, struct wl_resource *);
extern PinchGesture *XLSeatGetPinchGesture (Seat *, struct wl_resource *);
extern void XLSeatDestroySwipeGesture (SwipeGesture *);
extern void XLSeatDestroyPinchGesture (PinchGesture *);
+extern KeyCode XLKeysymToKeycode (KeySym, XEvent *);
extern Cursor InitDefaultCursor (void);
diff --git a/seat.c b/seat.c
index 2fecdd3..a60da7d 100644
--- a/seat.c
+++ b/seat.c
@@ -6154,14 +6154,10 @@ XLSeatGetInputMethodSeat (void)
}
void
-XLSeatDispatchCoreKeyEvent (Seat *seat, Surface *surface, XEvent *event,
- KeySym keysym)
+XLSeatDispatchCoreKeyEvent (Seat *seat, Surface *surface, XEvent *event)
{
unsigned int effective;
unsigned int state, group;
- unsigned int mods_return;
- KeyCode keycode;
- KeySym sym_return;
/* Dispatch a core event generated by an input method to SEAT. If
SURFACE is no longer the focus surface, refrain from doing
@@ -6178,33 +6174,6 @@ XLSeatDispatchCoreKeyEvent (Seat *seat, Surface *surface, XEvent *event,
/* Get the effective state of the seat. */
effective = seat->base | seat->latched | seat->locked;
- /* Determine what keycode to use. If a keysym was provided, try to
- find a corresponding keycode. */
-
- if (keysym)
- {
- /* If looking up the event keycode also results in the keysym,
- then just use the keycode specified in the event. This is
- because French keyboard layouts have multiple keycodes that
- decode to the same keysym, which causes problems later on
- when Wayland clients keep repeating the "a" key, as a keysym
- was looked up for the key press but not for the corresponding
- key release. */
- if (XkbLookupKeySym (compositor.display, event->xkey.keycode,
- event->xkey.state, &mods_return, &sym_return)
- && keysym == sym_return)
- keycode = event->xkey.keycode;
- else
- keycode = XKeysymToKeycode (compositor.display, keysym);
-
- /* But if no corresponding keycode could be found, use the
- keycode provided in the event. */
- if (!keycode)
- keycode = event->xkey.keycode;
- }
- else
- keycode = event->xkey.keycode;
-
if (group != seat->effective_group || state != effective)
/* The modifiers in the provided core event are different from
what the focus surface was previously sent. Send a new
@@ -6215,11 +6184,11 @@ XLSeatDispatchCoreKeyEvent (Seat *seat, Surface *surface, XEvent *event,
/* Then send the event. */
if (event->xkey.type == KeyPress)
SendKeyboardKey (seat, seat->focus_surface, event->xkey.time,
- WaylandKeycode (keycode),
+ WaylandKeycode (event->xkey.keycode),
WL_KEYBOARD_KEY_STATE_PRESSED);
else
SendKeyboardKey (seat, seat->focus_surface, event->xkey.time,
- WaylandKeycode (keycode),
+ WaylandKeycode (event->xkey.keycode),
WL_KEYBOARD_KEY_STATE_RELEASED);
/* Restore the modifiers. */
@@ -6432,6 +6401,29 @@ XLSeatCancelExternalGrab (Seat *seat)
seat->external_grab_time);
}
+KeyCode
+XLKeysymToKeycode (KeySym keysym, XEvent *event)
+{
+ unsigned int i, mods_return;
+ KeySym keysym_return;
+
+ if (!xkb_desc)
+ return 0;
+
+ /* Look up the keycode correspnding to the given keysym. Return 0
+ if there is none. */
+
+ for (i = xkb_desc->min_key_code; i <= xkb_desc->max_key_code; ++i)
+ {
+ if (XkbTranslateKeyCode (xkb_desc, i, event->xkey.state,
+ &mods_return, &keysym_return)
+ && keysym_return == keysym)
+ return i;
+ }
+
+ return 0;
+}
+
/* This is a particularly ugly hack, but there is no other way to
expose all the internals needed by test_seat.c. */
diff --git a/text_input.c b/text_input.c
index e5b44fe..272ff3e 100644
--- a/text_input.c
+++ b/text_input.c
@@ -32,6 +32,7 @@ along with 12to11. If not, see . */
#include "text-input-unstable-v3.h"
#include
+#include
/* X Input Method (XIM) support.
@@ -94,7 +95,7 @@ typedef struct _TextInput TextInput;
typedef struct _TextInputState TextInputState;
typedef struct _TextPosition TextPosition;
typedef struct _PreeditBuffer PreeditBuffer;
-typedef struct _KeysymMap KeysymMap;
+typedef struct _KeycodeMap KeycodeMap;
typedef enum _XimStyleKind XimStyleKind;
@@ -114,15 +115,17 @@ enum
PendingSurroundingText = (1 << 2),
};
-struct _KeysymMap
+struct _KeycodeMap
{
- /* Packed map between keycodes and keysyms. */
+ /* Packed map between keycodes specified in KeyPress events and
+ keycodes that were actually sent to applications. */
KeyCode *keycodes;
- /* The keysyms. */
- KeySym *keysyms;
+ /* The keycodes that were computed from keysyms and actually sent to
+ applications. */
+ KeyCode *keysyms;
- /* The number of keycodes and keysyms in this map. */
+ /* The number of keycodes and used keycodes in this map. */
int key_count;
};
@@ -204,7 +207,7 @@ struct _TextInput
/* Map between keys currently held down and keysyms they looked up
to. */
- KeysymMap keysym_map;
+ KeycodeMap keysym_map;
};
/* Structure describing a list of TextInput resources associated with
@@ -261,7 +264,7 @@ static XimStyleKind xim_style_order[5];
static void
-ClearKeysymMap (KeysymMap *map)
+ClearKeycodeMap (KeycodeMap *map)
{
XLFree (map->keycodes);
XLFree (map->keysyms);
@@ -271,18 +274,18 @@ ClearKeysymMap (KeysymMap *map)
}
static void
-InsertKeysym (KeysymMap *map, KeyCode keycode, KeySym keysym)
+InsertKeycode (KeycodeMap *map, KeyCode keycode, KeyCode keycode_used)
{
int i;
- /* Insert keysym into map, under keycode. See if map already
+ /* Insert keycode_used into map, under keycode. See if map already
contains the given keycode. */
for (i = 0; i < map->key_count; ++i)
{
if (map->keycodes[i] == keycode)
{
- map->keysyms[i] = keysym;
+ map->keysyms[i] = keycode_used;
return;
}
}
@@ -296,11 +299,11 @@ InsertKeysym (KeysymMap *map, KeyCode keycode, KeySym keysym)
= XLRealloc (map->keysyms,
map->key_count * sizeof *map->keysyms);
map->keycodes[map->key_count - 1] = keycode;
- map->keysyms[map->key_count - 1] = keysym;
+ map->keysyms[map->key_count - 1] = keycode_used;
}
static void
-RemoveKeysym (KeysymMap *map, KeyCode keycode)
+RemoveKeysym (KeycodeMap *map, KeyCode keycode)
{
int i;
@@ -329,8 +332,8 @@ RemoveKeysym (KeysymMap *map, KeyCode keycode)
}
}
-static KeySym
-GetKeysym (KeysymMap *map, KeyCode keycode)
+static KeyCode
+GetKeycode (KeycodeMap *map, KeyCode keycode)
{
int i;
@@ -1033,10 +1036,10 @@ InputDoLeave (TextInput *input, Surface *old_surface)
if (input->current_state.surrounding_text)
XLFree (input->current_state.surrounding_text);
- /* Clear the keysym-keycode table. Correlating key release with key
- press events is no longer important, as a leave event has been
- sent to the seat. */
- ClearKeysymMap (&input->keysym_map);
+ /* Clear the keycode-keycode table. Correlating key release with
+ key press events is no longer important, as a leave event has
+ been sent to the seat. */
+ ClearKeycodeMap (&input->keysym_map);
memset (&input->current_state, 0, sizeof input->current_state);
}
@@ -1095,8 +1098,8 @@ HandleResourceDestroy (struct wl_resource *resource)
if (input->buffer)
FreePreeditBuffer (input->buffer);
- /* Destroy the map of pressed keycodes to keysyms. */
- ClearKeysymMap (&input->keysym_map);
+ /* Destroy the map of pressed keycodes to keycodes. */
+ ClearKeycodeMap (&input->keysym_map);
/* Free the text input itself. */
XLFree (input);
@@ -1854,7 +1857,7 @@ ScanForwardWord (const char *string, size_t string_size,
caret.charpos++;
caret.bytepos++;
}
-
+
while (start < string + string_size)
{
punct_found = False;
@@ -2021,7 +2024,7 @@ ScanBackwardWord (const char *string, size_t string_size,
return caret_before;
}
}
-
+
return caret;
}
@@ -3357,6 +3360,35 @@ static TextInputFuncs input_funcs =
.filter_input = FilterInputCallback,
};
+static KeyCode
+CalculateKeycodeForEvent (XEvent *event, KeySym keysym)
+{
+ KeySym sym_return;
+ unsigned int mods_return;
+
+ /* Calculate the keycode to actually send clients along with an
+ event, given the keysym specified by the input method. Return 0
+ if no special treatment is required. */
+
+ if (!keysym)
+ return 0;
+
+ /* If looking up the event keycode also results in the keysym,
+ then just use the keycode specified in the event. This is
+ because French keyboard layouts have multiple keycodes that
+ decode to the same keysym, which causes problems later on
+ when Wayland clients keep repeating the "a" key, as a keysym
+ was looked up for the key press but not for the corresponding
+ key release. */
+ if (XkbLookupKeySym (compositor.display, event->xkey.keycode,
+ event->xkey.state, &mods_return, &sym_return)
+ && keysym == sym_return)
+ return 0;
+
+ /* Otherwise, convert the keysym to a keycode and use that. */
+ return XLKeysymToKeycode (keysym, event);
+}
+
void
XLTextInputDispatchCoreEvent (Surface *surface, XEvent *event)
{
@@ -3364,6 +3396,7 @@ XLTextInputDispatchCoreEvent (Surface *surface, XEvent *event)
TextInputClientInfo *info;
TextInput *input;
KeySym keysym;
+ KeyCode effective_keycode;
DebugPrint ("dispatching core event to surface %p:\n"
"\ttype: %d\n"
@@ -3429,23 +3462,31 @@ XLTextInputDispatchCoreEvent (Surface *surface, XEvent *event)
DebugPrint ("lookup failed; dispatching event to seat; "
"keysym is: %lu", keysym);
+ /* First, clear effective_keycode. */
+ effective_keycode = 0;
+
/* If the event is a KeyPress event and a keysym was
- looked up, record the keysym in the text input's
- keycode-keysym table, so the correct keycode can be
- looked up upon the next KeyRelease event. X input
- methods tend not to filter the KeyRelease events, so
- the KeyRelease event for an event that changed the
- keysym will be sent with the wrong keycode, which
- does not matter much with X programs, but leads to
- Wayland programs constantly autorepeating the keycode
- for which a KeyPress event was sent. */
+ looked up, calculate a keycode for the keysym, and
+ record in the text input's keycode-keycode table, so
+ the correct keycode can be looked up upon the next
+ KeyRelease event. X input methods tend not to filter
+ the KeyRelease events, so the KeyRelease event for an
+ event that changed the keysym will be sent with the
+ wrong keycode, which does not matter much with X
+ programs, but leads to Wayland programs constantly
+ autorepeating the keycode for which a KeyPress event
+ was sent. */
if (event->xkey.type == KeyPress && keysym)
{
- DebugPrint ("inserting keysym %lu into map under %u",
- keysym, event->xkey.keycode);
- InsertKeysym (&input->keysym_map, event->xkey.keycode,
- keysym);
+ /* Compute the keycode. */
+ effective_keycode
+ = CalculateKeycodeForEvent (event, keysym);
+
+ DebugPrint ("inserting keycode %lu into map under %u",
+ effective_keycode, event->xkey.keycode);
+ InsertKeycode (&input->keysym_map, event->xkey.keycode,
+ effective_keycode);
}
else if (event->xkey.type == KeyRelease)
{
@@ -3454,23 +3495,35 @@ XLTextInputDispatchCoreEvent (Surface *surface, XEvent *event)
event for the keycode. Otherwise, the input
method probably knows better than us, so use the
keysym provided by the input method. */
+
if (!keysym)
{
- keysym = GetKeysym (&input->keysym_map,
- event->xkey.keycode);
- DebugPrint ("obtained keysym %lu for keycode %u"
+ effective_keycode
+ = GetKeycode (&input->keysym_map,
+ event->xkey.keycode);
+ DebugPrint ("obtained keycode %lu for keycode %u"
" while processing KeyRelease event",
keysym, event->xkey.keycode);
}
+ else
+ effective_keycode
+ = CalculateKeycodeForEvent (event, keysym);
DebugPrint ("removing keycode %u from map",
event->xkey.keycode);
- /* Remove the keycode from the keysym map. */
+ /* Remove the keycode from the keycode-keysym
+ map. */
RemoveKeysym (&input->keysym_map, event->xkey.keycode);
}
- XLSeatDispatchCoreKeyEvent (im_seat, surface, event, keysym);
+ /* Finally, if an effective keycode was calculated,
+ replace the keycode in the event with it. */
+
+ if (effective_keycode)
+ event->xkey.keycode = effective_keycode;
+
+ XLSeatDispatchCoreKeyEvent (im_seat, surface, event);
}
}
}
@@ -3556,7 +3609,7 @@ InitInputStyles (void)
string = value.addr;
end = string + strlen (string);
i = 0;
-
+
while (string < end)
{
/* Find the next comma. */