Skip to content

Commit

Permalink
Filter out button mask in XIM key state before sending it to XKB common
Browse files Browse the repository at this point in the history
Fix #1106
  • Loading branch information
wengxt committed Jul 31, 2024
1 parent c453e95 commit 6af78b6
Showing 1 changed file with 55 additions and 13 deletions.
68 changes: 55 additions & 13 deletions src/frontend/xim/xim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,47 @@
*/

#include "xim.h"
#include <sys/types.h>
#include <unistd.h>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <xcb-imdkit/encoding.h>
#include <xcb-imdkit/imdkit.h>
#include <xcb-imdkit/ximproto.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xcb_ewmh.h>
#include <xcb/xproto.h>
#include <xkbcommon/xkbcommon.h>
#include "fcitx-config/iniparser.h"
#include "fcitx-utils/capabilityflags.h"
#include "fcitx-utils/handlertable.h"
#include "fcitx-utils/key.h"
#include "fcitx-utils/keysym.h"
#include "fcitx-utils/log.h"
#include "fcitx-utils/macros.h"
#include "fcitx-utils/misc.h"
#include "fcitx-utils/misc_p.h"
#include "fcitx-utils/rect.h"
#include "fcitx-utils/stringutils.h"
#include "fcitx-utils/textformatflags.h"
#include "fcitx-utils/utf8.h"
#include "fcitx/addonfactory.h"
#include "fcitx/addoninstance.h"
#include "fcitx/event.h"
#include "fcitx/inputcontext.h"
#include "fcitx/instance.h"
#include "fcitx/userinterface.h"
#include "xcb_public.h"

FCITX_DEFINE_LOG_CATEGORY(xim, "xim")
FCITX_DEFINE_LOG_CATEGORY(xim_key, "xim_key")
Expand Down Expand Up @@ -104,7 +132,7 @@ class XIMServer {
conn, XCB_COPY_FROM_PARENT, serverWindow_, screen->root, 0, 0, 1, 1,
1, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, 0, nullptr);

auto inputStyles =
auto *inputStyles =
(*parent_->config().useOnTheSpot ? &onthespot_styles : &styles);
for (uint32_t i = 0; i < inputStyles->nStyles; i++) {
supportedStyles_.insert(inputStyles->styles[i]);
Expand Down Expand Up @@ -152,7 +180,7 @@ class XIMServer {
}
}

static void callback(xcb_im_t *, xcb_im_client_t *client,
static void callback(xcb_im_t * /*unused*/, xcb_im_client_t *client,
xcb_im_input_context_t *xic,
const xcb_im_packet_header_fr_t *hdr, void *frame,
void *arg, void *user_data) {
Expand Down Expand Up @@ -378,7 +406,8 @@ class XIMInputContext final : public InputContext {
xcb_im_commit_string(server_->im(), xic_, XCB_XIM_LOOKUP_CHARS, commit,
length, 0);
}
void deleteSurroundingTextImpl(int, unsigned int) override {}
void deleteSurroundingTextImpl(int /*offset*/,
unsigned int /*size*/) override {}
void forwardKeyImpl(const ForwardKeyEvent &key) override {
xcb_key_press_event_t xcbEvent;
memset(&xcbEvent, 0, sizeof(xcb_key_press_event_t));
Expand All @@ -392,8 +421,8 @@ class XIMInputContext final : public InputContext {
xkb_state *xkbState = server_->xkbState();
if (xkbState) {
auto *map = xkb_state_get_keymap(xkbState);
auto min = xkb_keymap_min_keycode(map),
max = xkb_keymap_max_keycode(map);
auto min = xkb_keymap_min_keycode(map);
auto max = xkb_keymap_max_keycode(map);
for (auto keyCode = min; keyCode < max; keyCode++) {
if (xkb_state_key_get_one_sym(xkbState, keyCode) ==
static_cast<uint32_t>(key.rawKey().sym())) {
Expand All @@ -405,8 +434,7 @@ class XIMInputContext final : public InputContext {
}
xcbEvent.root = server_->root();
xcbEvent.event = xcb_im_input_context_get_focus_window(xic_);
if ((xcbEvent.event = xcb_im_input_context_get_focus_window(xic_)) ==
XCB_WINDOW_NONE) {
if (xcbEvent.event == XCB_WINDOW_NONE) {
xcbEvent.event = xcb_im_input_context_get_client_window(xic_);
}
xcbEvent.child = XCB_WINDOW_NONE;
Expand Down Expand Up @@ -532,6 +560,8 @@ void XIMServer::callback(xcb_im_client_t *client, xcb_im_input_context_t *xic,
XIM_DEBUG() << "Client disconnect: " << client;
clientEncodingMapping_.erase(client);
return;
default:
break;
}

if (!xic) {
Expand All @@ -551,7 +581,7 @@ void XIMServer::callback(xcb_im_client_t *client, xcb_im_input_context_t *xic,
switch (hdr->major_opcode) {
case XCB_XIM_CREATE_IC: {
bool useUtf8 = false;
if (auto entry = findValue(clientEncodingMapping_, client);
if (auto *entry = findValue(clientEncodingMapping_, client);
entry && *entry) {
useUtf8 = true;
}
Expand All @@ -576,14 +606,22 @@ void XIMServer::callback(xcb_im_client_t *client, xcb_im_input_context_t *xic,
xkb_state_get_keymap(state)) {
localState_.reset(xkb_state_new(keymap));
}
xcb_key_press_event_t *xevent =
static_cast<xcb_key_press_event_t *>(arg);
auto *xevent = static_cast<xcb_key_press_event_t *>(arg);
auto layout =
xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE);
// Always use the state that is forwarded by client.
// For xkb_state_key_get_one_sym, no need to distinguish
// depressed/latched/locked.
xkb_state_update_mask(localState_.get(), xevent->state, 0, 0, 0, 0,

// Remove all button mask before send to XKB.
// XKB May have internal virtual state bit, which collides with this
// bits. See: https://github.com/fcitx/fcitx5/issues/1106
constexpr uint16_t button_mask = XCB_BUTTON_MASK_1 | XCB_BUTTON_MASK_2 |
XCB_BUTTON_MASK_3 | XCB_BUTTON_MASK_4 |
XCB_BUTTON_MASK_5;

xkb_state_update_mask(localState_.get(),
(xevent->state & (~button_mask)), 0, 0, 0, 0,
layout);
KeyEvent event(ic,
Key(static_cast<KeySym>(xkb_state_key_get_one_sym(
Expand All @@ -594,6 +632,8 @@ void XIMServer::callback(xcb_im_client_t *client, xcb_im_input_context_t *xic,
XIM_KEY_DEBUG() << "XIM Key Event: "
<< static_cast<int>(xevent->response_type) << " "
<< event.rawKey().toString() << " time:" << xevent->time
<< " detail: " << static_cast<int>(xevent->detail)
<< " state: " << xevent->state
<< " sequence:" << xevent->sequence;
if (!ic->hasFocus()) {
ic->focusIn();
Expand All @@ -620,6 +660,8 @@ void XIMServer::callback(xcb_im_client_t *client, xcb_im_input_context_t *xic,
ic->resetAutoRepeatState();
ic->focusOut();
break;
default:
break;
}
}

Expand All @@ -642,10 +684,10 @@ XIMModule::XIMModule(Instance *instance) : instance_(instance) {
EventType::InputContextFlushUI, EventWatcherPhase::PreInputMethod,
[](Event &event) {
auto &uiEvent = static_cast<InputContextFlushUIEvent &>(event);
auto ic = uiEvent.inputContext();
auto *ic = uiEvent.inputContext();
if (uiEvent.component() == UserInterfaceComponent::InputPanel &&
ic->frontendName() == "xim") {
auto xic = static_cast<XIMInputContext *>(ic);
auto *xic = static_cast<XIMInputContext *>(ic);
xic->maybeUpdateCursorLocationForRootStyle();
}
});
Expand Down

0 comments on commit 6af78b6

Please sign in to comment.