Skip to content

Commit 6af78b6

Browse files
committed
Filter out button mask in XIM key state before sending it to XKB common
Fix #1106
1 parent c453e95 commit 6af78b6

File tree

1 file changed

+55
-13
lines changed

1 file changed

+55
-13
lines changed

src/frontend/xim/xim.cpp

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,47 @@
66
*/
77

88
#include "xim.h"
9+
#include <sys/types.h>
910
#include <unistd.h>
1011
#include <cstdarg>
12+
#include <cstdint>
1113
#include <cstdio>
14+
#include <cstdlib>
15+
#include <cstring>
16+
#include <iterator>
17+
#include <memory>
18+
#include <string>
19+
#include <unordered_map>
20+
#include <unordered_set>
21+
#include <vector>
1222
#include <xcb-imdkit/encoding.h>
23+
#include <xcb-imdkit/imdkit.h>
24+
#include <xcb-imdkit/ximproto.h>
25+
#include <xcb/xcb.h>
1326
#include <xcb/xcb_aux.h>
27+
#include <xcb/xcb_ewmh.h>
28+
#include <xcb/xproto.h>
1429
#include <xkbcommon/xkbcommon.h>
30+
#include "fcitx-config/iniparser.h"
31+
#include "fcitx-utils/capabilityflags.h"
32+
#include "fcitx-utils/handlertable.h"
33+
#include "fcitx-utils/key.h"
34+
#include "fcitx-utils/keysym.h"
35+
#include "fcitx-utils/log.h"
36+
#include "fcitx-utils/macros.h"
1537
#include "fcitx-utils/misc.h"
1638
#include "fcitx-utils/misc_p.h"
39+
#include "fcitx-utils/rect.h"
1740
#include "fcitx-utils/stringutils.h"
41+
#include "fcitx-utils/textformatflags.h"
1842
#include "fcitx-utils/utf8.h"
43+
#include "fcitx/addonfactory.h"
44+
#include "fcitx/addoninstance.h"
45+
#include "fcitx/event.h"
1946
#include "fcitx/inputcontext.h"
2047
#include "fcitx/instance.h"
2148
#include "fcitx/userinterface.h"
49+
#include "xcb_public.h"
2250

2351
FCITX_DEFINE_LOG_CATEGORY(xim, "xim")
2452
FCITX_DEFINE_LOG_CATEGORY(xim_key, "xim_key")
@@ -104,7 +132,7 @@ class XIMServer {
104132
conn, XCB_COPY_FROM_PARENT, serverWindow_, screen->root, 0, 0, 1, 1,
105133
1, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, 0, nullptr);
106134

107-
auto inputStyles =
135+
auto *inputStyles =
108136
(*parent_->config().useOnTheSpot ? &onthespot_styles : &styles);
109137
for (uint32_t i = 0; i < inputStyles->nStyles; i++) {
110138
supportedStyles_.insert(inputStyles->styles[i]);
@@ -152,7 +180,7 @@ class XIMServer {
152180
}
153181
}
154182

155-
static void callback(xcb_im_t *, xcb_im_client_t *client,
183+
static void callback(xcb_im_t * /*unused*/, xcb_im_client_t *client,
156184
xcb_im_input_context_t *xic,
157185
const xcb_im_packet_header_fr_t *hdr, void *frame,
158186
void *arg, void *user_data) {
@@ -378,7 +406,8 @@ class XIMInputContext final : public InputContext {
378406
xcb_im_commit_string(server_->im(), xic_, XCB_XIM_LOOKUP_CHARS, commit,
379407
length, 0);
380408
}
381-
void deleteSurroundingTextImpl(int, unsigned int) override {}
409+
void deleteSurroundingTextImpl(int /*offset*/,
410+
unsigned int /*size*/) override {}
382411
void forwardKeyImpl(const ForwardKeyEvent &key) override {
383412
xcb_key_press_event_t xcbEvent;
384413
memset(&xcbEvent, 0, sizeof(xcb_key_press_event_t));
@@ -392,8 +421,8 @@ class XIMInputContext final : public InputContext {
392421
xkb_state *xkbState = server_->xkbState();
393422
if (xkbState) {
394423
auto *map = xkb_state_get_keymap(xkbState);
395-
auto min = xkb_keymap_min_keycode(map),
396-
max = xkb_keymap_max_keycode(map);
424+
auto min = xkb_keymap_min_keycode(map);
425+
auto max = xkb_keymap_max_keycode(map);
397426
for (auto keyCode = min; keyCode < max; keyCode++) {
398427
if (xkb_state_key_get_one_sym(xkbState, keyCode) ==
399428
static_cast<uint32_t>(key.rawKey().sym())) {
@@ -405,8 +434,7 @@ class XIMInputContext final : public InputContext {
405434
}
406435
xcbEvent.root = server_->root();
407436
xcbEvent.event = xcb_im_input_context_get_focus_window(xic_);
408-
if ((xcbEvent.event = xcb_im_input_context_get_focus_window(xic_)) ==
409-
XCB_WINDOW_NONE) {
437+
if (xcbEvent.event == XCB_WINDOW_NONE) {
410438
xcbEvent.event = xcb_im_input_context_get_client_window(xic_);
411439
}
412440
xcbEvent.child = XCB_WINDOW_NONE;
@@ -532,6 +560,8 @@ void XIMServer::callback(xcb_im_client_t *client, xcb_im_input_context_t *xic,
532560
XIM_DEBUG() << "Client disconnect: " << client;
533561
clientEncodingMapping_.erase(client);
534562
return;
563+
default:
564+
break;
535565
}
536566

537567
if (!xic) {
@@ -551,7 +581,7 @@ void XIMServer::callback(xcb_im_client_t *client, xcb_im_input_context_t *xic,
551581
switch (hdr->major_opcode) {
552582
case XCB_XIM_CREATE_IC: {
553583
bool useUtf8 = false;
554-
if (auto entry = findValue(clientEncodingMapping_, client);
584+
if (auto *entry = findValue(clientEncodingMapping_, client);
555585
entry && *entry) {
556586
useUtf8 = true;
557587
}
@@ -576,14 +606,22 @@ void XIMServer::callback(xcb_im_client_t *client, xcb_im_input_context_t *xic,
576606
xkb_state_get_keymap(state)) {
577607
localState_.reset(xkb_state_new(keymap));
578608
}
579-
xcb_key_press_event_t *xevent =
580-
static_cast<xcb_key_press_event_t *>(arg);
609+
auto *xevent = static_cast<xcb_key_press_event_t *>(arg);
581610
auto layout =
582611
xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE);
583612
// Always use the state that is forwarded by client.
584613
// For xkb_state_key_get_one_sym, no need to distinguish
585614
// depressed/latched/locked.
586-
xkb_state_update_mask(localState_.get(), xevent->state, 0, 0, 0, 0,
615+
616+
// Remove all button mask before send to XKB.
617+
// XKB May have internal virtual state bit, which collides with this
618+
// bits. See: https://github.com/fcitx/fcitx5/issues/1106
619+
constexpr uint16_t button_mask = XCB_BUTTON_MASK_1 | XCB_BUTTON_MASK_2 |
620+
XCB_BUTTON_MASK_3 | XCB_BUTTON_MASK_4 |
621+
XCB_BUTTON_MASK_5;
622+
623+
xkb_state_update_mask(localState_.get(),
624+
(xevent->state & (~button_mask)), 0, 0, 0, 0,
587625
layout);
588626
KeyEvent event(ic,
589627
Key(static_cast<KeySym>(xkb_state_key_get_one_sym(
@@ -594,6 +632,8 @@ void XIMServer::callback(xcb_im_client_t *client, xcb_im_input_context_t *xic,
594632
XIM_KEY_DEBUG() << "XIM Key Event: "
595633
<< static_cast<int>(xevent->response_type) << " "
596634
<< event.rawKey().toString() << " time:" << xevent->time
635+
<< " detail: " << static_cast<int>(xevent->detail)
636+
<< " state: " << xevent->state
597637
<< " sequence:" << xevent->sequence;
598638
if (!ic->hasFocus()) {
599639
ic->focusIn();
@@ -620,6 +660,8 @@ void XIMServer::callback(xcb_im_client_t *client, xcb_im_input_context_t *xic,
620660
ic->resetAutoRepeatState();
621661
ic->focusOut();
622662
break;
663+
default:
664+
break;
623665
}
624666
}
625667

@@ -642,10 +684,10 @@ XIMModule::XIMModule(Instance *instance) : instance_(instance) {
642684
EventType::InputContextFlushUI, EventWatcherPhase::PreInputMethod,
643685
[](Event &event) {
644686
auto &uiEvent = static_cast<InputContextFlushUIEvent &>(event);
645-
auto ic = uiEvent.inputContext();
687+
auto *ic = uiEvent.inputContext();
646688
if (uiEvent.component() == UserInterfaceComponent::InputPanel &&
647689
ic->frontendName() == "xim") {
648-
auto xic = static_cast<XIMInputContext *>(ic);
690+
auto *xic = static_cast<XIMInputContext *>(ic);
649691
xic->maybeUpdateCursorLocationForRootStyle();
650692
}
651693
});

0 commit comments

Comments
 (0)