xcb: remove fragile and unnecessary missing-latin-keymap workaround
... which was trying to fix a rarely occurring situation where system
settings from a desktop environment does not set any latin keymap on
X. This is a DE bug and it has a simple workaround (details in the patch).
Ubuntu has fixed this issue sometime between 12.10 -> 14.04. Gnome 3
always appends 'us' layout, even if you have only e.g. 'gr' listed in
keyboard layouts (can be checked via setxkbmap -query). In KDE, the
global system shorcuts seem to stop working as soon as latin keymap
is not the first in the list, which means that KDE users won't be
affected as they will likely always have a latin keymap present in
the list.
This patch removes parts of 2b666d9576
,
the parts that in the commit message I was referring to by this quote:
"lookupLatinKeysym() also handles the cases that did not work in Qt4
with XLookupString".
Since finding a latin key is not working by XLookupString() in this
rare case, then it would not work pretty much across the whole desktop.
And users would be more interested at finding a solution that works
across the desktop. We should not workaround this issue. Desktops that
are doing it wrong should learn about this and not repeat the same mistakes
on Wayland systems, where XKB keymap is assembled by compositor and passed
to clients. Clients should work with the provided keymap as is.
The missing-latin-keymap workaround is considered fragile for several
reasons - it might not work with legacy or enterprise X server key codes
and it relies on global _XKB_RULES_NAMES (there might be several connected
keyboards). And theoretical limitation: client might be running in a
restricted environment where we don't have access to keymaps on the
file system.
Change-Id: Ib445b2ea46174248cfa0e5da0eb642cd2a5cf2f6
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
parent
ff169e8859
commit
1aec1a2d8d
@ -112,6 +112,7 @@ Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen")
|
||||
Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events")
|
||||
Q_LOGGING_CATEGORY(lcQpaXcb, "qt.qpa.xcb") // for general (uncategorized) XCB logging
|
||||
Q_LOGGING_CATEGORY(lcQpaPeeker, "qt.qpa.peeker")
|
||||
Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard")
|
||||
|
||||
// this event type was added in libxcb 1.10,
|
||||
// but we support also older version
|
||||
|
@ -92,6 +92,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaXcb)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaPeeker)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaKeyboard)
|
||||
|
||||
class QXcbVirtualDesktop;
|
||||
class QXcbScreen;
|
||||
|
@ -1267,27 +1267,32 @@ static bool isLatin(xkb_keysym_t sym)
|
||||
return ((sym >= 'a' && sym <= 'z') || (sym >= 'A' && sym <= 'Z'));
|
||||
}
|
||||
|
||||
void QXcbKeyboard::checkForLatinLayout()
|
||||
void QXcbKeyboard::checkForLatinLayout() const
|
||||
{
|
||||
m_hasLatinLayout = false;
|
||||
const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(xkb_keymap);
|
||||
const xcb_keycode_t minKeycode = connection()->setup()->min_keycode;
|
||||
const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode;
|
||||
struct xkb_state *kb_state = xkb_state_new(xkb_keymap);
|
||||
|
||||
ScopedXKBState state(xkb_state_new(xkb_keymap));
|
||||
for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) {
|
||||
xkb_state_update_mask(kb_state, 0, 0, 0, 0, 0, layout);
|
||||
xkb_state_update_mask(state.get(), 0, 0, 0, 0, 0, layout);
|
||||
for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) {
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, code);
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(state.get(), code);
|
||||
// if layout can produce any of these latin letters (chosen
|
||||
// arbitrarily) then it must be a latin key based layout
|
||||
if (sym == XK_q || sym == XK_a || sym == XK_e) {
|
||||
m_hasLatinLayout = true;
|
||||
xkb_state_unref(kb_state);
|
||||
if (sym == XK_q || sym == XK_a || sym == XK_e)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
xkb_state_unref(kb_state);
|
||||
// This means that lookupLatinKeysym() will not find anything and latin
|
||||
// key shortcuts might not work. This is a bug in the affected desktop
|
||||
// environment. Usually can be solved via system settings by adding e.g. 'us'
|
||||
// layout to the list of seleced layouts, or by using command line, "setxkbmap
|
||||
// -layout rus,en". The position of latin key based layout in the list of the
|
||||
// selected layouts is irrelevant. Properly functioning desktop environments
|
||||
// handle this behind the scenes, even if no latin key based layout has been
|
||||
// explicitly listed in the selected layouts.
|
||||
qCWarning(lcQpaKeyboard, "no keyboard layouts with latin keys present");
|
||||
}
|
||||
|
||||
xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const
|
||||
@ -1310,39 +1315,13 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If user layouts don't contain any layout that results in a latin key, we query a
|
||||
// key from "US" layout, this allows for latin-key-based shorcuts to work even when
|
||||
// users have only one (non-latin) layout set.
|
||||
// But don't do this if using keymap obtained through the core protocol, as the key
|
||||
// codes may not match up with those expected by the XKB keymap.
|
||||
xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED);
|
||||
xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED);
|
||||
if (sym == XKB_KEY_NoSymbol && !m_hasLatinLayout && !m_keymap_is_core) {
|
||||
if (!latin_keymap) {
|
||||
const struct xkb_rule_names names = { xkb_names.rules, xkb_names.model, "us", 0, 0 };
|
||||
latin_keymap = xkb_keymap_new_from_names(xkb_context, &names, (xkb_keymap_compile_flags)0);
|
||||
static bool printFailure = true;
|
||||
if (!latin_keymap && printFailure) {
|
||||
// print message about failure to compile US keymap only once,
|
||||
// no need to do this on every key press.
|
||||
printFailure = false;
|
||||
printKeymapError("Qt: Failed to compile US keymap, shortcut handling with "
|
||||
"non-Latin keyboard layouts may not be fully functional!");
|
||||
}
|
||||
}
|
||||
if (latin_keymap) {
|
||||
struct xkb_state *latin_state = xkb_state_new(latin_keymap);
|
||||
if (latin_state) {
|
||||
xkb_state_update_mask(latin_state, 0, latchedMods, lockedMods, 0, 0, 0);
|
||||
sym = xkb_state_key_get_one_sym(latin_state, keycode);
|
||||
xkb_state_unref(latin_state);
|
||||
} else {
|
||||
qWarning("QXcbKeyboard: failed to create a state for US keymap!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sym == XKB_KEY_NoSymbol)
|
||||
return sym;
|
||||
|
||||
xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED);
|
||||
xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED);
|
||||
|
||||
// Check for uniqueness, consider the following setup:
|
||||
// setxkbmap -layout us,ru,us -variant dvorak,, -option 'grp:ctrl_alt_toggle' (set 'ru' as active).
|
||||
// In this setup, the user would expect to trigger a ctrl+q shortcut by pressing ctrl+<physical x key>,
|
||||
@ -1353,18 +1332,18 @@ xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const
|
||||
// generate the same shortcut event in this case.
|
||||
const xcb_keycode_t minKeycode = connection()->setup()->min_keycode;
|
||||
const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode;
|
||||
struct xkb_state *kb_state = xkb_state_new(xkb_keymap);
|
||||
ScopedXKBState state(xkb_state_new(xkb_keymap));
|
||||
for (xkb_layout_index_t prevLayout = 0; prevLayout < layout; ++prevLayout) {
|
||||
xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, 0, 0, prevLayout);
|
||||
xkb_state_update_mask(state.get(), 0, latchedMods, lockedMods, 0, 0, prevLayout);
|
||||
for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) {
|
||||
xkb_keysym_t prevSym = xkb_state_key_get_one_sym(kb_state, code);
|
||||
xkb_keysym_t prevSym = xkb_state_key_get_one_sym(state.get(), code);
|
||||
if (prevSym == sym) {
|
||||
sym = XKB_KEY_NoSymbol;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
xkb_state_unref(kb_state);
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
@ -1563,7 +1542,6 @@ QXcbKeyboard::~QXcbKeyboard()
|
||||
xkb_state_unref(xkb_state);
|
||||
xkb_keymap_unref(xkb_keymap);
|
||||
xkb_context_unref(xkb_context);
|
||||
xkb_keymap_unref(latin_keymap);
|
||||
if (!connection()->hasXKB())
|
||||
xcb_key_symbols_free(m_key_symbols);
|
||||
clearXKBConfig();
|
||||
|
@ -106,7 +106,7 @@ protected:
|
||||
void updateVModToRModMapping();
|
||||
|
||||
xkb_keysym_t lookupLatinKeysym(xkb_keycode_t keycode) const;
|
||||
void checkForLatinLayout();
|
||||
void checkForLatinLayout() const;
|
||||
|
||||
private:
|
||||
void updateXKBStateFromState(struct xkb_state *kb_state, quint16 state);
|
||||
@ -119,7 +119,6 @@ private:
|
||||
struct xkb_keymap *xkb_keymap = nullptr;
|
||||
struct xkb_state *xkb_state = nullptr;
|
||||
struct xkb_rule_names xkb_names;
|
||||
mutable struct xkb_keymap *latin_keymap = nullptr;
|
||||
|
||||
struct _mod_masks {
|
||||
uint alt;
|
||||
@ -149,7 +148,11 @@ private:
|
||||
_mod_masks vmod_masks;
|
||||
int core_device_id;
|
||||
#endif
|
||||
bool m_hasLatinLayout = false;
|
||||
|
||||
struct XKBStateDeleter {
|
||||
void operator()(struct xkb_state *state) const { return xkb_state_unref(state); }
|
||||
};
|
||||
using ScopedXKBState = std::unique_ptr<struct xkb_state, XKBStateDeleter>;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
Loading…
Reference in New Issue
Block a user