25 #include <string_view> 27 #include <unordered_map> 28 #include <unordered_set> 32 #include "fcitx-config/configuration.h" 33 #include "fcitx-config/iniparser.h" 34 #include "fcitx-config/option.h" 37 #include "fcitx-utils/event.h" 38 #include "fcitx-utils/eventdispatcher.h" 39 #include "fcitx-utils/eventloopinterface.h" 41 #include "fcitx-utils/handlertable.h" 42 #include "fcitx-utils/i18n.h" 46 #include "fcitx-utils/macros.h" 47 #include "fcitx-utils/misc.h" 48 #include "fcitx-utils/misc_p.h" 53 #include "../../modules/notifications/notifications_public.h" 56 #include "focusgroup.h" 57 #include "globalconfig.h" 58 #include "inputcontextmanager.h" 60 #include "inputmethodengine.h" 61 #include "inputmethodentry.h" 62 #include "inputmethodgroup.h" 65 #include "instance_p.h" 72 #ifdef HAVE_SYS_WAIT_H 78 #include <../modules/xcb/xcb_public.h> 81 #ifdef ENABLE_KEYBOARD 82 #include <xkbcommon/xkbcommon-compose.h> 83 #include <xkbcommon/xkbcommon.h> 86 FCITX_DEFINE_LOG_CATEGORY(keyTrace,
"key_trace");
92 constexpr uint64_t AutoSaveMinInUsecs = 60ULL * 1000000ULL;
93 constexpr uint64_t AutoSaveIdleTime = 60ULL * 1000000ULL;
95 FCITX_CONFIGURATION(DefaultInputMethod,
96 Option<std::vector<std::string>> defaultInputMethods{
97 this,
"DefaultInputMethod",
"DefaultInputMethod"};
98 Option<std::vector<std::string>> extraLayouts{
99 this,
"ExtraLayout",
"ExtraLayout"};);
101 void initAsDaemon() {
105 waitpid(pid,
nullptr, 0);
109 auto oldint = signal(SIGINT, SIG_IGN);
110 auto oldhup = signal(SIGHUP, SIG_IGN);
111 auto oldquit = signal(SIGQUIT, SIG_IGN);
112 auto oldpipe = signal(SIGPIPE, SIG_IGN);
113 auto oldttou = signal(SIGTTOU, SIG_IGN);
114 auto oldttin = signal(SIGTTIN, SIG_IGN);
115 auto oldchld = signal(SIGCHLD, SIG_IGN);
121 signal(SIGINT, oldint);
122 signal(SIGHUP, oldhup);
123 signal(SIGQUIT, oldquit);
124 signal(SIGPIPE, oldpipe);
125 signal(SIGTTOU, oldttou);
126 signal(SIGTTIN, oldttin);
127 signal(SIGCHLD, oldchld);
135 bool isInputMethodDisabled(
const CapabilityFlags &flags,
136 bool allowInputMethodForPassword) {
138 (flags.test(CapabilityFlag::Password) &&
139 !allowInputMethodForPassword);
143 bool shouldSwitchIM(
const CapabilityFlags &oldFlags,
144 const CapabilityFlags &newFlags,
145 bool allowInputMethodForPassword) {
146 return isInputMethodDisabled(oldFlags, allowInputMethodForPassword) !=
147 isInputMethodDisabled(newFlags, allowInputMethodForPassword);
152 uint32_t keyStatesToXkbMask(KeyStates states) {
155 states = states.unset(KeyState::Virtual);
157 states = states.unset(KeyState::HandledMask);
158 states = states.unset(KeyState::IgnoredMask);
160 if (states.test(KeyState::Super2)) {
161 states = states | KeyState::Super;
162 states = states.unset(KeyState::Super2);
164 if (states.test(KeyState::Hyper2)) {
165 states = states | KeyState::Hyper;
166 states = states.unset(KeyState::Hyper2);
169 states = states.unset(KeyStates(0x1F00U));
170 return static_cast<uint32_t
>(states);
175 void InstanceArgument::printUsage()
const {
177 <<
"Usage: " << argv0 <<
" [Option]\n" 178 <<
" --disable <addon names>\tA comma separated list of addons to " 180 <<
"\t\t\t\t\"all\" can be used to disable all addons.\n" 181 <<
" --enable <addon names>\tA comma separated list of addons to " 183 <<
"\t\t\t\t\"all\" can be used to enable all addons.\n" 184 <<
"\t\t\t\tThis value will override the value in the flag " 186 <<
" --verbose <logging rule>\tSet the logging rule for " 187 "displaying message.\n" 188 <<
"\t\t\t\tSyntax: category1=level1,category2=level2, ...\n" 189 <<
"\t\t\t\tE.g. default=4,key_trace=5\n" 190 <<
"\t\t\t\tLevels are numbers ranging from 0 to 5.\n" 191 <<
"\t\t\t\t\t0 - NoLog\n" 192 <<
"\t\t\t\t\t1 - Fatal\n" 193 <<
"\t\t\t\t\t2 - Error\n" 194 <<
"\t\t\t\t\t3 - Warn\n" 195 <<
"\t\t\t\t\t4 - Info (default)\n" 196 <<
"\t\t\t\t\t5 - Debug\n" 197 <<
"\t\t\t\tSome built-in categories are:\n" 198 <<
"\t\t\t\t\tdefault - miscellaneous category used by fcitx own " 200 <<
"\t\t\t\t\tkey_trace - print the key event received by fcitx.\n" 201 <<
"\t\t\t\t\t\"*\" may be used to represent all logging " 203 <<
" -u, --ui <addon name>\t\tSet the UI addon to be used.\n" 204 <<
" -d\t\t\t\tRun as a daemon.\n" 205 <<
" -D\t\t\t\tDo not run as a daemon (default).\n" 206 <<
" -s <seconds>\t\t\tNumber of seconds to wait before start.\n" 207 <<
" -k, --keep\t\t\tKeep running even the main display is " 209 <<
" -r, --replace\t\t\tReplace the existing instance.\n" 210 <<
" -o --option <option>\t\tPass the option to addons\n" 211 <<
"\t\t\t\t<option> is in format like:\n" 212 <<
"\t\t\t\tname1=opt1a:opt1b,name2=opt2a:opt2b... .\n" 213 <<
" -v, --version\t\t\tShow version and quit.\n" 214 <<
" -h, --help\t\t\tShow this help message and quit.\n";
217 InstancePrivate::InstancePrivate(Instance *q) : QPtrHolder<Instance>(q) {
218 #ifdef ENABLE_KEYBOARD 219 const auto &locale = getCurrentLocale();
220 assert(!locale.empty());
221 xkbContext_.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
223 xkb_context_set_log_level(xkbContext_.get(), XKB_LOG_LEVEL_CRITICAL);
224 xkbComposeTable_.reset(xkb_compose_table_new_from_locale(
225 xkbContext_.get(), locale.data(), XKB_COMPOSE_COMPILE_NO_FLAGS));
226 if (!xkbComposeTable_) {
228 <<
"Trying to fallback to compose table for en_US.UTF-8";
229 xkbComposeTable_.reset(xkb_compose_table_new_from_locale(
230 xkbContext_.get(),
"en_US.UTF-8",
231 XKB_COMPOSE_COMPILE_NO_FLAGS));
233 if (!xkbComposeTable_) {
235 <<
"No compose table is loaded, you may want to check your " 242 std::unique_ptr<HandlerTableEntry<EventHandler>>
243 InstancePrivate::watchEvent(
EventType type, EventWatcherPhase phase,
244 EventHandler callback) {
245 return eventHandlers_[type][phase].add(std::move(callback));
248 #ifdef ENABLE_KEYBOARD 249 xkb_keymap *InstancePrivate::keymap(
const std::string &display,
250 const std::string &layout,
251 const std::string &variant) {
252 auto layoutAndVariant = stringutils::concat(layout,
"-", variant);
253 if (
auto *keymapPtr = findValue(keymapCache_[display], layoutAndVariant)) {
254 return (*keymapPtr).get();
256 struct xkb_rule_names names;
257 names.layout = layout.c_str();
258 names.variant = variant.c_str();
259 std::tuple<std::string, std::string, std::string> xkbParam;
260 if (
auto *param = findValue(xkbParams_, display)) {
263 if (!xkbParams_.empty()) {
264 xkbParam = xkbParams_.begin()->second;
266 xkbParam = std::make_tuple(DEFAULT_XKB_RULES,
"pc101",
"");
269 if (globalConfig_.overrideXkbOption()) {
270 std::get<2>(xkbParam) = globalConfig_.customXkbOption();
272 names.rules = std::get<0>(xkbParam).c_str();
273 names.model = std::get<1>(xkbParam).c_str();
274 names.options = std::get<2>(xkbParam).c_str();
275 UniqueCPtr<xkb_keymap, xkb_keymap_unref> keymap(xkb_keymap_new_from_names(
276 xkbContext_.get(), &names, XKB_KEYMAP_COMPILE_NO_FLAGS));
278 keymapCache_[display].emplace(layoutAndVariant, std::move(keymap));
279 assert(result.second);
280 return result.first->second.get();
284 std::pair<std::unordered_set<std::string>, std::unordered_set<std::string>>
285 InstancePrivate::overrideAddons() {
286 std::unordered_set<std::string> enabled;
287 std::unordered_set<std::string> disabled;
288 for (
const auto &addon : globalConfig_.enabledAddons()) {
289 enabled.insert(addon);
291 for (
const auto &addon : globalConfig_.disabledAddons()) {
292 enabled.erase(addon);
293 disabled.insert(addon);
295 for (
const auto &addon : arg_.enableList) {
296 disabled.erase(addon);
297 enabled.insert(addon);
299 for (
const auto &addon : arg_.disableList) {
300 enabled.erase(addon);
301 disabled.insert(addon);
303 return {enabled, disabled};
306 void InstancePrivate::buildDefaultGroup() {
308 auto *defaultGroup = q_func()->defaultFocusGroup();
309 bool infoFound =
false;
311 std::string variants;
312 auto guessLayout = [
this, &layouts, &variants,
313 &infoFound](FocusGroup *focusGroup) {
315 if (!focusGroup->display().starts_with(
"x11:")) {
319 auto *xcb = addonManager_.addon(
"xcb");
320 auto x11Name = focusGroup->display().substr(4);
322 auto rules = xcb->call<IXCBModule::xkbRulesNames>(x11Name);
323 if (!rules[2].
empty()) {
332 FCITX_UNUSED(layouts);
333 FCITX_UNUSED(variants);
334 FCITX_UNUSED(infoFound);
338 if (!defaultGroup || guessLayout(defaultGroup)) {
339 icManager_.foreachGroup(
340 [defaultGroup, &guessLayout](FocusGroup *focusGroup) {
341 if (defaultGroup == focusGroup) {
344 return guessLayout(focusGroup);
353 constexpr
char imNamePrefix[] =
"keyboard-";
357 variants,
",", stringutils::SplitBehavior::KeepEmpty);
358 auto size = std::max(layoutTokens.size(), variantTokens.size());
360 layoutTokens.resize(size);
361 variantTokens.resize(size);
363 OrderedSet<std::string> imLayouts;
364 for (decltype(size) i = 0; i < size; i++) {
365 if (layoutTokens[i].
empty()) {
368 std::string layoutName = layoutTokens[i];
369 if (!variantTokens[i].
empty()) {
370 layoutName = stringutils::concat(layoutName,
"-", variantTokens[i]);
374 if (!imManager_.entry(stringutils::concat(imNamePrefix, layoutName))) {
378 imLayouts.pushBack(layoutName);
382 auto lang = stripLanguage(getCurrentLanguage());
383 DefaultInputMethod defaultIMConfig;
384 readAsIni(defaultIMConfig, StandardPathsType::PkgData,
385 std::filesystem::path(
"default") / lang);
388 for (
const auto &extraLayout : defaultIMConfig.extraLayouts.value()) {
389 if (!imManager_.entry(stringutils::concat(imNamePrefix, extraLayout))) {
392 imLayouts.pushBack(extraLayout);
396 if (imLayouts.empty()) {
397 imLayouts.pushBack(
"us");
401 std::string defaultIM;
402 for (
const auto &im : defaultIMConfig.defaultInputMethods.value()) {
403 if (imManager_.entry(im)) {
410 std::vector<std::string> groupOrders;
411 for (
const auto &imLayout : imLayouts) {
412 std::string groupName;
413 if (imLayouts.size() == 1) {
414 groupName = _(
"Default");
416 groupName = _(
"Group {}", imManager_.groupCount() + 1);
418 imManager_.addEmptyGroup(groupName);
419 groupOrders.push_back(groupName);
420 InputMethodGroup group(groupName);
421 group.inputMethodList().emplace_back(
422 InputMethodGroupItem(stringutils::concat(imNamePrefix, imLayout)));
423 if (!defaultIM.empty()) {
424 group.inputMethodList().emplace_back(
425 InputMethodGroupItem(defaultIM));
427 FCITX_INFO() <<
"Items in " << groupName <<
": " 428 << group.inputMethodList();
429 group.setDefaultLayout(imLayout);
430 imManager_.setGroup(std::move(group));
432 FCITX_INFO() <<
"Generated groups: " << groupOrders;
433 imManager_.setGroupOrder(groupOrders);
436 void InstancePrivate::showInputMethodInformation(InputContext *ic) {
438 auto *inputState = ic->propertyFor(&inputStateFactory_);
439 auto *engine = q->inputMethodEngine(ic);
440 const auto *entry = q->inputMethodEntry(ic);
441 auto &imManager = q->inputMethodManager();
443 if (!inputState->isActive() &&
444 !globalConfig_.showFirstInputMethodInformation()) {
450 auto subMode = engine->subMode(*entry, *ic);
451 auto subModeLabel = engine->subModeLabel(*entry, *ic);
452 auto name = globalConfig_.compactInputMethodInformation() &&
453 !entry->label().empty()
456 if (globalConfig_.compactInputMethodInformation() &&
457 !subModeLabel.empty()) {
458 display = std::move(subModeLabel);
459 }
else if (subMode.empty()) {
460 display = std::move(name);
462 display = _(
"{0} ({1})", name, subMode);
465 display = _(
"{0} (Not available)", entry->name());
467 display = _(
"(Not available)");
469 if (!globalConfig_.compactInputMethodInformation() &&
470 imManager.groupCount() > 1) {
471 display = _(
"Group {0}: {1}", imManager.currentGroup().name(), display);
473 inputState->showInputMethodInformation(display);
476 bool InstancePrivate::canActivate(InputContext *ic) {
478 if (!q->canTrigger()) {
481 auto *inputState = ic->propertyFor(&inputStateFactory_);
482 return (!inputState->isActive()) ||
483 globalConfig_.consumeRedundantActivateKeys();
486 bool InstancePrivate::canDeactivate(InputContext *ic) {
488 if (!q->canTrigger()) {
491 auto *inputState = ic->propertyFor(&inputStateFactory_);
492 return inputState->isActive() ||
493 globalConfig_.consumeRedundantActivateKeys();
496 void InstancePrivate::navigateGroup(InputContext *ic,
const Key &key,
498 auto *inputState = ic->propertyFor(&inputStateFactory_);
499 inputState->pendingGroupIndex_ =
500 (inputState->pendingGroupIndex_ +
501 (forward ? 1 : imManager_.groupCount() - 1)) %
502 imManager_.groupCount();
503 FCITX_DEBUG() <<
"Switch to group " << inputState->pendingGroupIndex_;
505 if (notifications_ && !isSingleKey(key)) {
506 notifications_->call<INotifications::showTip>(
507 "enumerate-group", _(
"Input Method"),
"input-keyboard",
509 _(
"Switch group to {0}",
510 imManager_.groups()[inputState->pendingGroupIndex_]),
515 void InstancePrivate::acceptGroupChange(
const Key &key, InputContext *ic) {
516 FCITX_DEBUG() <<
"Accept group change, isSingleKey: " << key;
518 auto *inputState = ic->propertyFor(&inputStateFactory_);
519 auto groups = imManager_.groups();
520 if (groups.size() > inputState->pendingGroupIndex_) {
521 if (isSingleKey(key)) {
522 FCITX_DEBUG() <<
"EnumerateGroupTo: " 523 << inputState->pendingGroupIndex_ <<
" " << key;
524 imManager_.enumerateGroupTo(groups[inputState->pendingGroupIndex_]);
526 FCITX_DEBUG() <<
"SetCurrentGroup: " 527 << inputState->pendingGroupIndex_ <<
" " << key;
528 imManager_.setCurrentGroup(groups[inputState->pendingGroupIndex_]);
531 inputState->pendingGroupIndex_ = 0;
534 InputState::InputState(InstancePrivate *d, InputContext *ic)
535 : d_ptr(d), ic_(ic) {
536 active_ = d->globalConfig_.activeByDefault();
537 #ifdef ENABLE_KEYBOARD 538 if (d->xkbComposeTable_) {
539 xkbComposeState_.reset(xkb_compose_state_new(
540 d->xkbComposeTable_.get(), XKB_COMPOSE_STATE_NO_FLAGS));
545 void InputState::showInputMethodInformation(
const std::string &name) {
546 ic_->inputPanel().setOverlayMessage(Text(name));
549 imInfoTimer_ = d_ptr->eventLoop_.addTimeEvent(
550 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, 0,
551 [
this](EventSourceTime *, uint64_t) {
552 hideInputMethodInfo();
557 #ifdef ENABLE_KEYBOARD 558 xkb_state *InputState::customXkbState(
bool refresh) {
559 auto *instance = d_ptr->q_func();
560 const InputMethodGroup &group = d_ptr->imManager_.currentGroup();
561 const auto im = instance->inputMethod(ic_);
562 auto layout = group.layoutFor(im);
563 if (layout.empty() && im.starts_with(
"keyboard-")) {
564 layout = im.substr(9);
566 if (layout.empty() || layout == group.defaultLayout()) {
569 modsAllReleased_ =
false;
570 lastXkbLayout_.clear();
574 if (layout == lastXkbLayout_ && !refresh) {
575 return xkbState_.get();
578 lastXkbLayout_ = layout;
579 const auto layoutAndVariant = parseLayout(layout);
580 if (
auto *keymap = d_ptr->keymap(ic_->display(), layoutAndVariant.first,
581 layoutAndVariant.second)) {
582 xkbState_.reset(xkb_state_new(keymap));
586 modsAllReleased_ =
false;
587 return xkbState_.get();
591 void InputState::setActive(
bool active) {
592 if (active_ != active) {
594 ic_->updateProperty(&d_ptr->inputStateFactory_);
598 void InputState::setLocalIM(
const std::string &localIM) {
599 if (localIM_ != localIM) {
601 ic_->updateProperty(&d_ptr->inputStateFactory_);
605 void InputState::copyTo(InputContextProperty *other) {
606 auto *otherState =
static_cast<InputState *
>(other);
607 if (otherState->active_ == active_ && otherState->localIM_ == localIM_) {
611 if (otherState->ic_->hasFocus()) {
612 FCITX_DEBUG() <<
"Sync state to focused ic: " 613 << otherState->ic_->program();
614 CheckInputMethodChanged imChangedRAII(otherState->ic_, d_ptr);
615 otherState->active_ = active_;
616 otherState->localIM_ = localIM_;
618 otherState->active_ = active_;
619 otherState->localIM_ = localIM_;
623 void InputState::reset() {
624 #ifdef ENABLE_KEYBOARD 625 if (xkbComposeState_) {
626 xkb_compose_state_reset(xkbComposeState_.get());
629 pendingGroupIndex_ = 0;
631 lastKeyPressed_ = Key();
632 lastKeyPressedTime_ = 0;
633 totallyReleased_ =
true;
636 void InputState::hideInputMethodInfo() {
640 imInfoTimer_.reset();
641 auto &panel = ic_->inputPanel();
642 if (panel.overlayMessage().size() == 1 &&
643 panel.overlayMessage().stringAt(0) == lastInfo_) {
644 panel.setOverlayMessage(Text());
649 #ifdef ENABLE_KEYBOARD 650 void InputState::resetXkbState() {
651 lastXkbLayout_.clear();
656 CheckInputMethodChanged::CheckInputMethodChanged(InputContext *ic,
657 InstancePrivate *instance)
658 : instance_(instance->q_func()), instancePrivate_(instance),
659 ic_(ic->watch()), inputMethod_(instance_->inputMethod(ic)),
661 auto *inputState = ic->propertyFor(&instance->inputStateFactory_);
662 if (!inputState->imChanged_) {
663 inputState->imChanged_ =
this;
669 CheckInputMethodChanged::~CheckInputMethodChanged() {
670 if (!ic_.isValid()) {
673 auto *ic = ic_.get();
674 auto *inputState = ic->propertyFor(&instancePrivate_->inputStateFactory_);
675 inputState->imChanged_ =
nullptr;
676 if (inputMethod_ != instance_->inputMethod(ic) && !ignore_) {
677 instance_->postEvent(
678 InputContextSwitchInputMethodEvent(reason_, inputMethod_, ic));
683 InstanceArgument arg;
684 arg.parseOption(argc, argv);
692 FCITX_LOG_IF(Info, isInFlatpak()) <<
"Running inside flatpak.";
694 if (arg.runAsDaemon) {
698 if (arg.overrideDelay > 0) {
699 sleep(arg.overrideDelay);
703 d_ptr = std::make_unique<InstancePrivate>(
this);
706 d->eventDispatcher_.attach(&d->eventLoop_);
707 d->addonManager_.setInstance(
this);
708 d->addonManager_.setAddonOptions(arg.addonOptions_);
709 d->icManager_.setInstance(
this);
710 d->tempModeManager_ = std::make_unique<TempModeManager>(
this);
711 d->connections_.emplace_back(
712 d->imManager_.connect<InputMethodManager::CurrentGroupAboutToChange>(
713 [
this, d](
const std::string &lastGroup) {
714 d->icManager_.foreachFocused([this](InputContext *ic) {
715 assert(ic->hasFocus());
716 InputContextSwitchInputMethodEvent event(
717 InputMethodSwitchedReason::GroupChange, inputMethod(ic),
719 deactivateInputMethod(event);
722 d->lastGroup_ = lastGroup;
725 d->connections_.emplace_back(
726 d->imManager_.connect<InputMethodManager::CurrentGroupChanged>(
727 [
this, d](
const std::string &newGroup) {
728 d->icManager_.foreachFocused([this](InputContext *ic) {
729 assert(ic->hasFocus());
730 InputContextSwitchInputMethodEvent event(
731 InputMethodSwitchedReason::GroupChange,
"", ic);
732 activateInputMethod(event);
736 if (!d->lastGroup_.empty() && !newGroup.empty() &&
737 d->lastGroup_ != newGroup && d->notifications_ &&
738 d->imManager_.groupCount() > 1) {
739 d->notifications_->call<INotifications::showTip>(
740 "enumerate-group", _(
"Input Method"),
"input-keyboard",
742 _(
"Switched group to {0}",
743 d->imManager_.currentGroup().name()),
746 d->lastGroup_ = newGroup;
749 d->eventWatchers_.emplace_back(d->watchEvent(
750 EventType::InputContextCapabilityAboutToChange,
751 EventWatcherPhase::ReservedFirst, [
this, d](
Event &event) {
753 static_cast<CapabilityAboutToChangeEvent &>(event);
754 if (!capChanged.inputContext()->hasFocus()) {
759 capChanged.oldFlags(), capChanged.newFlags(),
760 d->globalConfig_.allowInputMethodForPassword())) {
766 inputMethod(capChanged.inputContext()),
767 capChanged.inputContext());
768 deactivateInputMethod(switchIM);
770 d->eventWatchers_.emplace_back(d->watchEvent(
771 EventType::InputContextCapabilityChanged,
772 EventWatcherPhase::ReservedFirst, [
this, d](
Event &event) {
773 auto &capChanged = static_cast<CapabilityChangedEvent &>(event);
774 if (!capChanged.inputContext()->hasFocus()) {
779 capChanged.oldFlags(), capChanged.newFlags(),
780 d->globalConfig_.allowInputMethodForPassword())) {
786 capChanged.inputContext());
787 activateInputMethod(switchIM);
790 d->eventWatchers_.emplace_back(watchEvent(
792 [
this, d](
Event &event) {
793 auto &keyEvent =
static_cast<KeyEvent &
>(event);
794 auto *ic = keyEvent.inputContext();
795 CheckInputMethodChanged imChangedRAII(ic, d);
796 auto origKey = keyEvent.origKey().normalize();
800 std::function<bool()> check;
801 std::function<void(bool)> trigger;
803 {.list = d->globalConfig_.triggerKeys(),
804 .check = [
this]() {
return canTrigger(); },
806 [
this, ic](
bool totallyReleased) {
807 return trigger(ic, totallyReleased);
809 {.list = d->globalConfig_.altTriggerKeys(),
810 .check = [
this, ic]() {
return canAltTrigger(ic); },
811 .trigger = [
this, ic](bool) {
return altTrigger(ic); }},
812 {.list = d->globalConfig_.activateKeys(),
813 .check = [ic, d]() {
return d->canActivate(ic); },
814 .trigger = [
this, ic](bool) {
return activate(ic); }},
815 {.list = d->globalConfig_.deactivateKeys(),
816 .check = [ic, d]() {
return d->canDeactivate(ic); },
817 .trigger = [
this, ic](bool) {
return deactivate(ic); }},
818 {.list = d->globalConfig_.enumerateForwardKeys(),
819 .check = [
this, ic]() {
return canEnumerate(ic); },
820 .trigger = [
this, ic](bool) {
return enumerate(ic,
true); }},
821 {.list = d->globalConfig_.enumerateBackwardKeys(),
822 .check = [
this, ic]() {
return canEnumerate(ic); },
823 .trigger = [
this, ic](bool) {
return enumerate(ic,
false); }},
824 {.list = d->globalConfig_.enumerateGroupForwardKeys(),
825 .check = [
this]() {
return canChangeGroup(); },
826 .trigger = [ic, d, origKey](
827 bool) { d->navigateGroup(ic, origKey,
true); }},
828 {.list = d->globalConfig_.enumerateGroupBackwardKeys(),
829 .check = [
this]() {
return canChangeGroup(); },
831 [ic, d, origKey](bool) {
832 d->navigateGroup(ic, origKey,
false);
836 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
837 int keyReleased = inputState->keyReleased_;
838 Key lastKeyPressed = inputState->lastKeyPressed_;
840 inputState->keyReleased_ = -1;
842 if (keyEvent.isRelease()) {
844 for (
auto &keyHandler : keyHandlers) {
845 if (keyReleased == idx &&
846 origKey.isReleaseOfModifier(lastKeyPressed) &&
847 keyHandler.check()) {
849 if (d->globalConfig_.checkModifierOnlyKeyTimeout(
850 inputState->lastKeyPressedTime_)) {
852 inputState->totallyReleased_);
854 inputState->lastKeyPressedTime_ = 0;
855 if (origKey.hasModifier()) {
856 inputState->totallyReleased_ =
false;
864 if (isSingleModifier(origKey)) {
865 inputState->totallyReleased_ =
true;
869 if (inputState->pendingGroupIndex_ &&
870 inputState->totallyReleased_) {
871 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
872 if (inputState->imChanged_) {
873 inputState->imChanged_->ignore();
875 d->acceptGroupChange(lastKeyPressed, ic);
876 inputState->lastKeyPressed_ =
Key();
879 if (!keyEvent.filtered() && !keyEvent.isRelease()) {
881 for (
auto &keyHandler : keyHandlers) {
882 auto keyIdx = origKey.keyListIndex(keyHandler.list);
883 if (keyIdx >= 0 && keyHandler.check()) {
884 inputState->keyReleased_ = idx;
885 inputState->lastKeyPressed_ = origKey;
887 inputState->lastKeyPressedTime_ =
888 now(CLOCK_MONOTONIC);
894 keyHandler.trigger(inputState->totallyReleased_);
895 if (origKey.hasModifier()) {
896 inputState->totallyReleased_ =
false;
898 keyEvent.filterAndAccept();
905 d->eventWatchers_.emplace_back(watchEvent(
908 auto &keyEvent =
static_cast<KeyEvent &
>(event);
909 auto *ic = keyEvent.inputContext();
910 if (!keyEvent.isRelease() &&
911 keyEvent.checkKeyList(
912 d->globalConfig_.togglePreeditKeys(),
913 KeyEventMatchingMode::MatchAllNormalizedKeys)) {
916 ic->setEnablePreedit(!ic->isPreeditEnabled());
917 if (d->notifications_) {
918 d->notifications_->call<INotifications::showTip>(
919 "toggle-preedit", _(
"Input Method"),
"", _(
"Preedit"),
920 ic->isPreeditEnabled() ? _(
"Preedit enabled")
921 : _(
"Preedit disabled"),
924 keyEvent.filterAndAccept();
927 d->eventWatchers_.emplace_back(d->watchEvent(
931 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
932 auto &keyEvent = static_cast<KeyEvent &>(event);
933 auto *ic = keyEvent.inputContext();
934 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
935 #ifdef ENABLE_KEYBOARD
936 auto *xkbState = inputState->customXkbState();
938 if (auto *mods = findValue(d->stateMask_, ic->display())) {
939 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
943 if (inputState->isModsAllReleased()) {
944 depressed = xkb_state_serialize_mods(
945 xkbState, XKB_STATE_MODS_DEPRESSED);
947 depressed = std::get<0>(*mods);
949 if (std::get<0>(*mods) == 0) {
950 inputState->setModsAllReleased();
952 auto latched = xkb_state_serialize_mods(
953 xkbState, XKB_STATE_MODS_LATCHED);
954 auto locked = std::get<2>(*mods);
960 << depressed <<
" " << latched <<
" " << locked;
961 xkb_state_update_mask(xkbState, depressed, latched, locked,
964 auto latched = xkb_state_serialize_mods(
965 xkbState, XKB_STATE_MODS_LATCHED);
968 keyStatesToXkbMask(keyEvent.origKey().states());
973 .unset(KeyState::CapsLock)
974 .unset(KeyState::NumLock) == 0) {
975 inputState->setModsAllReleased();
977 KeyStates inferredLock(mask);
979 KeyStates{KeyState::CapsLock, KeyState::NumLock};
981 if (inputState->isModsAllReleased()) {
982 depressed = xkb_state_serialize_mods(
983 xkbState, XKB_STATE_MODS_DEPRESSED) |
984 static_cast<uint32_t>(inferredLock);
989 <<
"Update mask to customXkbState from key orig mask: " 990 << static_cast<uint32_t>(keyEvent.origKey().states())
991 <<
" xkb mask: " << mask;
992 xkb_state_update_mask(xkbState, depressed, latched, 0, 0, 0,
995 const uint32_t effective = xkb_state_serialize_mods(
996 xkbState, XKB_STATE_MODS_EFFECTIVE);
997 auto newSym = xkb_state_key_get_one_sym(
998 xkbState, keyEvent.rawKey().code());
999 auto newModifier = KeyStates(effective);
1000 auto *keymap = xkb_state_get_keymap(xkbState);
1001 if (keyEvent.rawKey().states().test(KeyState::Repeat) &&
1002 xkb_keymap_key_repeats(keymap, keyEvent.rawKey().code())) {
1003 newModifier |= KeyState::Repeat;
1006 const uint32_t modsDepressed = xkb_state_serialize_mods(
1007 xkbState, XKB_STATE_MODS_DEPRESSED);
1008 const uint32_t modsLatched =
1009 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
1010 const uint32_t modsLocked =
1011 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
1012 FCITX_KEYTRACE() <<
"Current mods: " << modsDepressed <<
" " 1013 << modsLatched <<
" " << modsLocked;
1014 auto newCode = keyEvent.rawKey().code();
1015 Key key(static_cast<KeySym>(newSym), newModifier, newCode);
1017 <<
"Custom Xkb translated Key: " << key.toString();
1018 keyEvent.setRawKey(key);
1021 FCITX_KEYTRACE() <<
"KeyEvent: " << keyEvent.key()
1022 <<
" rawKey: " << keyEvent.rawKey()
1023 <<
" origKey: " << keyEvent.origKey()
1024 <<
" Release:" << keyEvent.isRelease()
1025 <<
" keycode: " << keyEvent.origKey().code()
1026 <<
" program: " << ic->program();
1028 if (keyEvent.isRelease()) {
1031 inputState->hideInputMethodInfo();
1033 d->eventWatchers_.emplace_back(
1035 EventWatcherPhase::InputMethod, [
this](
Event &event) {
1036 auto &keyEvent =
static_cast<KeyEvent &
>(event);
1037 auto *ic = keyEvent.inputContext();
1038 auto *engine = inputMethodEngine(ic);
1039 const auto *entry = inputMethodEntry(ic);
1040 if (!engine || !entry) {
1043 engine->keyEvent(*entry, keyEvent);
1045 d->eventWatchers_.emplace_back(watchEvent(
1046 EventType::InputContextVirtualKeyboardEvent,
1047 EventWatcherPhase::InputMethod, [
this](
Event &event) {
1049 auto *ic = keyEvent.inputContext();
1050 auto *engine = inputMethodEngine(ic);
1051 const auto *entry = inputMethodEntry(ic);
1052 if (!engine || !entry) {
1055 engine->virtualKeyboardEvent(*entry, keyEvent);
1057 d->eventWatchers_.emplace_back(watchEvent(
1059 [
this](
Event &event) {
1061 auto *ic = invokeActionEvent.inputContext();
1062 auto *engine = inputMethodEngine(ic);
1063 const auto *entry = inputMethodEntry(ic);
1064 if (!engine || !entry) {
1067 engine->invokeAction(*entry, invokeActionEvent);
1069 d->eventWatchers_.emplace_back(d->watchEvent(
1071 [
this](
Event &event) {
1072 auto &keyEvent = static_cast<KeyEvent &>(event);
1073 auto *ic = keyEvent.inputContext();
1074 auto *engine = inputMethodEngine(ic);
1075 const auto *entry = inputMethodEntry(ic);
1076 if (!engine || !entry) {
1079 engine->filterKey(*entry, keyEvent);
1080 emit<Instance::KeyEventResult>(keyEvent);
1081 #ifdef ENABLE_KEYBOARD 1082 if (keyEvent.forward()) {
1087 if (keyEvent.isRelease()) {
1091 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1092 if (
auto *xkbState = inputState->customXkbState()) {
1093 if (
auto utf32 = xkb_state_key_get_utf32(
1094 xkbState, keyEvent.key().code())) {
1096 if (utf32 ==
'\n' || utf32 ==
'\b' || utf32 ==
'\r' ||
1097 utf32 ==
'\t' || utf32 ==
'\033' ||
1101 if (keyEvent.key().states().testAny(
1102 KeyStates{KeyState::Ctrl, KeyState::Alt}) ||
1103 keyEvent.rawKey().sym() ==
1104 keyEvent.origKey().sym()) {
1107 FCITX_KEYTRACE() <<
"Will commit char: " << utf32;
1109 keyEvent.filterAndAccept();
1110 }
else if (!keyEvent.key().states().testAny(
1111 KeyStates{KeyState::Ctrl, KeyState::Alt}) &&
1112 keyEvent.rawKey().sym() !=
1113 keyEvent.origKey().sym() &&
1118 keyEvent.filterAndAccept();
1124 d->eventWatchers_.emplace_back(d->watchEvent(
1126 [
this, d](
Event &event) {
1127 auto &icEvent = static_cast<InputContextEvent &>(event);
1128 auto isSameProgram = [&icEvent, d]() {
1130 return (icEvent.inputContext() == d->lastUnFocusedIc_.get()) ||
1131 (!icEvent.inputContext()->program().empty() &&
1132 (icEvent.inputContext()->program() ==
1133 d->lastUnFocusedProgram_));
1136 if (d->globalConfig_.resetStateWhenFocusIn() ==
1137 PropertyPropagatePolicy::All ||
1138 (d->globalConfig_.resetStateWhenFocusIn() ==
1139 PropertyPropagatePolicy::Program &&
1140 !isSameProgram())) {
1141 if (d->globalConfig_.activeByDefault()) {
1142 activate(icEvent.inputContext());
1144 deactivate(icEvent.inputContext());
1148 activateInputMethod(icEvent);
1150 auto *inputContext = icEvent.inputContext();
1151 if (!inputContext->clientControlVirtualkeyboardShow()) {
1152 inputContext->showVirtualKeyboard();
1155 if (!d->globalConfig_.showInputMethodInformationWhenFocusIn()) {
1166 d->focusInImInfoTimer_ = d->eventLoop_.addTimeEvent(
1167 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1172 if (
auto *ic = icRef.get();
1173 ic && ic->hasFocus() &&
1175 d->showInputMethodInformation(ic);
1180 d->eventWatchers_.emplace_back(d->watchEvent(
1183 auto &icEvent = static_cast<InputContextEvent &>(event);
1184 auto *ic = icEvent.inputContext();
1185 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1186 inputState->reset();
1187 if (!ic->capabilityFlags().test(
1188 CapabilityFlag::ClientUnfocusCommit)) {
1191 ic->inputPanel().clientPreedit().toStringForCommit();
1192 if (!commit.empty()) {
1193 ic->commitString(commit);
1197 d->eventWatchers_.emplace_back(d->watchEvent(
1199 [
this, d](
Event &event) {
1200 auto &icEvent = static_cast<InputContextEvent &>(event);
1201 d->lastUnFocusedProgram_ = icEvent.inputContext()->program();
1202 d->lastUnFocusedIc_ = icEvent.inputContext()->watch();
1203 deactivateInputMethod(icEvent);
1205 auto *inputContext = icEvent.inputContext();
1206 if (!inputContext->clientControlVirtualkeyboardHide()) {
1207 inputContext->hideVirtualKeyboard();
1210 d->eventWatchers_.emplace_back(d->watchEvent(
1213 auto &icEvent = static_cast<InputContextEvent &>(event);
1214 auto *ic = icEvent.inputContext();
1215 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1216 inputState->reset();
1218 d->eventWatchers_.emplace_back(
1220 [
this](
Event &event) {
1222 auto *ic = icEvent.inputContext();
1223 if (!ic->hasFocus()) {
1226 auto *engine = inputMethodEngine(ic);
1227 const auto *entry = inputMethodEntry(ic);
1228 if (!engine || !entry) {
1231 engine->reset(*entry, icEvent);
1233 d->eventWatchers_.emplace_back(d->watchEvent(
1235 EventWatcherPhase::ReservedFirst, [
this](
Event &event) {
1237 static_cast<InputContextSwitchInputMethodEvent &>(event);
1238 auto *ic = icEvent.inputContext();
1239 if (!ic->hasFocus()) {
1242 deactivateInputMethod(icEvent);
1243 activateInputMethod(icEvent);
1245 d->eventWatchers_.emplace_back(d->watchEvent(
1247 EventWatcherPhase::ReservedLast, [
this, d](
Event &event) {
1249 static_cast<InputContextSwitchInputMethodEvent &>(event);
1250 auto *ic = icEvent.inputContext();
1251 if (!ic->hasFocus()) {
1255 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1256 inputState->lastIMChangeIsAltTrigger_ =
1268 showInputMethodInformation(ic);
1270 d->eventWatchers_.emplace_back(
1272 EventWatcherPhase::ReservedLast, [
this, d](
Event &) {
1275 d->imGroupInfoTimer_ = d->eventLoop_.addTimeEvent(
1276 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1277 [this](EventSourceTime *, uint64_t) {
1278 inputContextManager().foreachFocused(
1279 [this](InputContext *ic) {
1280 showInputMethodInformation(ic);
1287 d->eventWatchers_.emplace_back(d->watchEvent(
1288 EventType::InputContextUpdateUI, EventWatcherPhase::ReservedFirst,
1290 auto &icEvent = static_cast<InputContextUpdateUIEvent &>(event);
1291 if (icEvent.immediate()) {
1292 d->uiManager_.update(icEvent.component(),
1293 icEvent.inputContext());
1294 d->uiManager_.flush();
1296 d->uiManager_.update(icEvent.component(),
1297 icEvent.inputContext());
1298 d->uiUpdateEvent_->setOneShot();
1301 d->eventWatchers_.emplace_back(d->watchEvent(
1302 EventType::InputContextDestroyed, EventWatcherPhase::ReservedFirst,
1304 auto &icEvent = static_cast<InputContextEvent &>(event);
1305 d->uiManager_.expire(icEvent.inputContext());
1307 d->eventWatchers_.emplace_back(d->watchEvent(
1309 [d](
Event &) { d->uiManager_.updateAvailability(); }));
1310 d->uiUpdateEvent_ = d->eventLoop_.addDeferEvent([d](
EventSource *) {
1311 d->uiManager_.flush();
1314 d->uiUpdateEvent_->setEnabled(
false);
1315 d->periodicalSave_ = d->eventLoop_.addTimeEvent(
1316 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, AutoSaveIdleTime,
1323 auto currentTime = now(CLOCK_MONOTONIC);
1324 if (currentTime <= d->idleStartTimestamp_ ||
1325 currentTime - d->idleStartTimestamp_ < AutoSaveIdleTime) {
1327 time->setNextInterval(2 * AutoSaveIdleTime);
1332 FCITX_INFO() <<
"Running autosave...";
1334 FCITX_INFO() <<
"End autosave";
1335 if (d->globalConfig_.autoSavePeriod() > 0) {
1336 time->setNextInterval(d->globalConfig_.autoSavePeriod() *
1337 AutoSaveMinInUsecs);
1342 d->periodicalSave_->setEnabled(
false);
1345 Instance::~Instance() {
1347 d->tempModeManager_.reset();
1348 d->icManager_.finalize();
1349 d->addonManager_.unload();
1350 d->notifications_ =
nullptr;
1351 d->icManager_.setInstance(
nullptr);
1354 void InstanceArgument::parseOption(
int argc,
char **argv) {
1360 struct option longOptions[] = {{
"enable", required_argument,
nullptr, 0},
1361 {
"disable", required_argument,
nullptr, 0},
1362 {
"verbose", required_argument,
nullptr, 0},
1363 {
"keep", no_argument,
nullptr,
'k'},
1364 {
"ui", required_argument,
nullptr,
'u'},
1365 {
"replace", no_argument,
nullptr,
'r'},
1366 {
"version", no_argument,
nullptr,
'v'},
1367 {
"help", no_argument,
nullptr,
'h'},
1368 {
"option", required_argument,
nullptr,
'o'},
1369 {
nullptr, 0, 0, 0}};
1371 int optionIndex = 0;
1373 std::string addonOptionString;
1374 while ((c = getopt_long(argc, argv,
"ru:dDs:hvo:k", longOptions,
1375 &optionIndex)) != EOF) {
1378 switch (optionIndex) {
1386 Log::setLogRule(optarg);
1404 runAsDaemon =
false;
1407 exitWhenMainDisplayDisconnected =
false;
1410 overrideDelay = std::atoi(optarg);
1421 addonOptionString = optarg;
1432 std::unordered_map<std::string, std::vector<std::string>> addonOptions;
1433 for (
const std::string_view item :
1436 if (tokens.size() != 2) {
1441 addonOptions_ = std::move(addonOptions);
1449 d->signalPipe_ = fd;
1450 d->signalPipeEvent_ = d->eventLoop_.addIOEvent(
1460 return d->arg_.tryReplace;
1465 return d->arg_.exitWhenMainDisplayDisconnected;
1473 void Instance::handleSignal() {
1477 while (
fs::safeRead(d->signalPipe_, &signo,
sizeof(signo)) > 0) {
1478 if (signo == SIGINT || signo == SIGTERM || signo == SIGQUIT ||
1481 }
else if (signo == SIGUSR1) {
1483 }
else if (signo == SIGCHLD) {
1484 d->zombieReaper_->setNextInterval(2000000);
1485 d->zombieReaper_->setOneShot();
1493 if (!d->arg_.uiName.empty()) {
1494 d->arg_.enableList.push_back(d->arg_.uiName);
1497 d->icManager_.registerProperty(
"inputState", &d->inputStateFactory_);
1498 std::unordered_set<std::string> enabled;
1499 std::unordered_set<std::string> disabled;
1500 std::tie(enabled, disabled) = d->overrideAddons();
1501 FCITX_INFO() <<
"Override Enabled Addons: " << enabled;
1502 FCITX_INFO() <<
"Override Disabled Addons: " << disabled;
1503 d->addonManager_.load(enabled, disabled);
1508 d->uiManager_.load(d->arg_.uiName);
1510 const auto *entry = d->imManager_.entry(
"keyboard-us");
1511 FCITX_LOG_IF(Error, !entry) <<
"Couldn't find keyboard-us";
1512 d->preloadInputMethodEvent_ = d->eventLoop_.addTimeEvent(
1513 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, 0,
1516 if (d->exit_ || !d->globalConfig_.preloadInputMethod()) {
1520 if (!d->imManager_.currentGroup().inputMethodList().empty()) {
1521 if (
const auto *entry =
1522 d->imManager_.entry(d->imManager_.currentGroup()
1523 .inputMethodList()[0]
1525 d->addonManager_.addon(entry->addon(),
true);
1529 if (!d->imManager_.currentGroup().defaultInputMethod().empty()) {
1530 if (
const auto *entry = d->imManager_.entry(
1531 d->imManager_.currentGroup().defaultInputMethod())) {
1532 d->addonManager_.addon(entry->addon(),
true);
1538 d->zombieReaper_ = d->eventLoop_.addTimeEvent(
1539 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 0,
1542 while ((res = waitpid(-1,
nullptr, WNOHANG)) > 0) {
1546 d->zombieReaper_->setEnabled(
false);
1549 d->exitEvent_ = d->eventLoop_.addExitEvent([
this](
EventSource *) {
1550 emit<Instance::AboutToExit>();
1551 FCITX_INFO() <<
"Save before exiting...";
1553 emit<Instance::Exit>();
1556 d->notifications_ = d->addonManager_.addon(
"notifications",
true);
1561 if (d->arg_.quietQuit) {
1568 return d->exitCode_;
1571 auto r = eventLoop().exec();
1572 d->running_ =
false;
1574 return r ? d->exitCode_ : 1;
1579 d->running_ = running;
1589 return d->inputMethodMode_;
1594 if (d->inputMethodMode_ == mode) {
1597 d->inputMethodMode_ = mode;
1606 bool Instance::virtualKeyboardAutoShow()
const {
1608 return d->virtualKeyboardAutoShow_;
1611 void Instance::setVirtualKeyboardAutoShow(
bool autoShow) {
1613 d->virtualKeyboardAutoShow_ = autoShow;
1616 bool Instance::virtualKeyboardAutoHide()
const {
1618 return d->virtualKeyboardAutoHide_;
1621 void Instance::setVirtualKeyboardAutoHide(
bool autoHide) {
1623 d->virtualKeyboardAutoHide_ = autoHide;
1626 VirtualKeyboardFunctionMode Instance::virtualKeyboardFunctionMode()
const {
1628 return d->virtualKeyboardFunctionMode_;
1631 void Instance::setVirtualKeyboardFunctionMode(
1632 VirtualKeyboardFunctionMode mode) {
1634 d->virtualKeyboardFunctionMode_ = mode;
1639 d->binaryMode_ =
true;
1644 const auto &addonNames = d->addonManager_.loadedAddonNames();
1645 return d->binaryMode_ &&
1646 std::ranges::all_of(addonNames, [d](
const std::string &name) {
1647 auto *addon = d->addonManager_.lookupAddon(name);
1651 return addon->canRestart();
1655 InstancePrivate *Instance::privateData() {
1662 return d->eventLoop_;
1667 return d->eventDispatcher_;
1672 return d->icManager_;
1677 return d->addonManager_;
1682 return d->imManager_;
1687 return d->imManager_;
1692 return *d->tempModeManager_;
1697 return d->uiManager_;
1702 return d->globalConfig_;
1705 bool Instance::postEvent(
Event &event) {
1706 return std::as_const(*this).postEvent(event);
1709 bool Instance::postEvent(
Event &event)
const {
1714 auto iter = d->eventHandlers_.find(event.
type());
1715 if (iter != d->eventHandlers_.end()) {
1716 const auto &handlers = iter->second;
1717 EventWatcherPhase phaseOrder[] = {
1718 EventWatcherPhase::ReservedFirst, EventWatcherPhase::PreInputMethod,
1719 EventWatcherPhase::InputMethod, EventWatcherPhase::PostInputMethod,
1720 EventWatcherPhase::ReservedLast};
1722 for (
auto phase : phaseOrder) {
1723 if (
auto iter2 = handlers.find(phase); iter2 != handlers.end()) {
1724 for (
auto &handler : iter2->second.view()) {
1739 auto &keyEvent =
static_cast<KeyEvent &
>(event);
1740 auto *ic = keyEvent.inputContext();
1741 #ifdef ENABLE_KEYBOARD 1743 if (!keyEvent.forward() && !keyEvent.origKey().code()) {
1746 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1747 auto *xkbState = inputState->customXkbState();
1754 xkb_state_update_key(xkbState, keyEvent.origKey().code(),
1755 keyEvent.isRelease() ? XKB_KEY_UP
1759 if (ic->capabilityFlags().test(CapabilityFlag::KeyEventOrderFix) &&
1760 !keyEvent.accepted() && ic->hasPendingEventsStrictOrder()) {
1763 keyEvent.filterAndAccept();
1764 ic->forwardKey(keyEvent.origKey(), keyEvent.isRelease(),
1767 d_ptr->uiManager_.flush();
1770 return event.accepted();
1773 std::unique_ptr<HandlerTableEntry<EventHandler>>
1775 EventHandler callback) {
1777 if (phase == EventWatcherPhase::ReservedFirst ||
1778 phase == EventWatcherPhase::ReservedLast) {
1779 throw std::invalid_argument(
"Reserved Phase is only for internal use");
1781 return d->watchEvent(type, phase, std::move(callback));
1784 bool groupContains(
const InputMethodGroup &group,
const std::string &name) {
1785 const auto &list = group.inputMethodList();
1788 return item.name() == name;
1790 return iter != std::ranges::end(list);
1795 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1798 if (!inputState->overrideDeactivateIM_.empty()) {
1799 return inputState->overrideDeactivateIM_;
1802 const auto &group = d->imManager_.currentGroup();
1805 !d->globalConfig_.allowInputMethodForPassword())) {
1806 auto defaultLayoutIM =
1807 stringutils::concat(
"keyboard-", group.defaultLayout());
1808 const auto *entry = d->imManager_.entry(defaultLayoutIM);
1810 entry = d->imManager_.entry(
"keyboard-us");
1812 return entry ? entry->uniqueName() :
"";
1815 if (group.inputMethodList().empty()) {
1818 if (inputState->isActive()) {
1819 if (!inputState->localIM_.empty() &&
1820 groupContains(group, inputState->localIM_)) {
1821 return inputState->localIM_;
1823 return group.defaultInputMethod();
1826 return group.inputMethodList()[0].name();
1831 auto imName = inputMethod(ic);
1832 if (imName.empty()) {
1835 return d->imManager_.entry(imName);
1840 const auto *entry = inputMethodEntry(ic);
1845 d->addonManager_.addon(entry->addon(),
true));
1850 const auto *entry = d->imManager_.entry(name);
1855 d->addonManager_.addon(entry->addon(),
true));
1860 const auto *entry = inputMethodEntry(ic);
1862 auto *engine = inputMethodEngine(ic);
1864 icon = engine->subModeIcon(*entry, *ic);
1867 icon = entry->icon();
1870 icon =
"input-keyboard";
1878 const auto *entry = inputMethodEntry(ic);
1879 auto *engine = inputMethodEngine(ic);
1881 if (engine && entry) {
1882 label = engine->subModeLabel(*entry, *ic);
1884 if (label.empty() && entry) {
1885 label = entry->label();
1891 #ifdef ENABLE_KEYBOARD 1893 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1895 auto *xkbComposeState = state->xkbComposeState();
1896 if (!xkbComposeState) {
1900 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1902 enum xkb_compose_feed_result result =
1903 xkb_compose_state_feed(xkbComposeState, keyval);
1904 if (result == XKB_COMPOSE_FEED_IGNORED) {
1908 enum xkb_compose_status status =
1909 xkb_compose_state_get_status(xkbComposeState);
1910 if (status == XKB_COMPOSE_NOTHING) {
1913 if (status == XKB_COMPOSE_COMPOSED) {
1914 char buffer[FCITX_UTF8_MAX_LENGTH + 1] = {
'\0',
'\0',
'\0',
'\0',
1917 xkb_compose_state_get_utf8(xkbComposeState, buffer,
sizeof(buffer));
1918 xkb_compose_state_reset(xkbComposeState);
1920 return FCITX_INVALID_COMPOSE_RESULT;
1926 if (status == XKB_COMPOSE_CANCELLED) {
1927 xkb_compose_state_reset(xkbComposeState);
1930 return FCITX_INVALID_COMPOSE_RESULT;
1933 FCITX_UNUSED(keysym);
1940 #ifdef ENABLE_KEYBOARD 1942 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1944 auto *xkbComposeState = state->xkbComposeState();
1945 if (!xkbComposeState) {
1946 return std::string();
1949 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1950 enum xkb_compose_feed_result result =
1951 xkb_compose_state_feed(xkbComposeState, keyval);
1953 if (result == XKB_COMPOSE_FEED_IGNORED) {
1954 return std::string();
1957 enum xkb_compose_status status =
1958 xkb_compose_state_get_status(xkbComposeState);
1959 if (status == XKB_COMPOSE_NOTHING) {
1960 return std::string();
1962 if (status == XKB_COMPOSE_COMPOSED) {
1964 std::array<char, 256> buffer;
1965 auto length = xkb_compose_state_get_utf8(xkbComposeState, buffer.data(),
1967 xkb_compose_state_reset(xkbComposeState);
1969 return std::nullopt;
1972 auto bufferBegin = buffer.begin();
1973 auto bufferEnd = std::next(bufferBegin,
length);
1975 return std::string(bufferBegin, bufferEnd);
1977 return std::nullopt;
1979 if (status == XKB_COMPOSE_CANCELLED) {
1980 xkb_compose_state_reset(xkbComposeState);
1982 return std::nullopt;
1985 FCITX_UNUSED(keysym);
1986 return std::string();
1991 #ifdef ENABLE_KEYBOARD 1993 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1995 auto *xkbComposeState = state->xkbComposeState();
1996 if (!xkbComposeState) {
2000 return xkb_compose_state_get_status(xkbComposeState) ==
2001 XKB_COMPOSE_COMPOSING;
2003 FCITX_UNUSED(inputContext);
2009 #ifdef ENABLE_KEYBOARD 2011 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
2012 auto *xkbComposeState = state->xkbComposeState();
2013 if (!xkbComposeState) {
2016 xkb_compose_state_reset(xkbComposeState);
2018 FCITX_UNUSED(inputContext);
2025 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
2026 d->imManager_.save();
2027 d->addonManager_.saveAll();
2032 if (
auto *ic = mostRecentInputContext()) {
2033 CheckInputMethodChanged imChangedRAII(ic, d);
2040 if (
const auto *entry = inputMethodManager().entry(imName)) {
2041 return entry->uniqueName();
2051 void Instance::configureAddon(
const std::string & ) {}
2053 void Instance::configureInputMethod(
const std::string & ) {}
2056 if (
auto *ic = mostRecentInputContext()) {
2057 if (
const auto *entry = inputMethodEntry(ic)) {
2058 return entry->uniqueName();
2066 return d->uiManager_.currentUI();
2071 if (
auto *ic = mostRecentInputContext()) {
2072 CheckInputMethodChanged imChangedRAII(ic, d);
2082 d->exitCode_ = exitCode;
2084 d->eventLoop_.exit();
2089 auto *addon = addonManager().addon(addonName);
2091 addon->reloadConfig();
2097 auto [enabled, disabled] = d->overrideAddons();
2098 d->addonManager_.load(enabled, disabled);
2099 d->imManager_.refresh();
2104 readAsIni(d->globalConfig_.config(), StandardPathsType::PkgConfig,
2106 FCITX_DEBUG() <<
"Trigger Key: " 2108 d->icManager_.setPropertyPropagatePolicy(
2109 d->globalConfig_.shareInputState());
2110 if (d->globalConfig_.preeditEnabledByDefault() !=
2111 d->icManager_.isPreeditEnabledByDefault()) {
2112 d->icManager_.setPreeditEnabledByDefault(
2113 d->globalConfig_.preeditEnabledByDefault());
2119 #ifdef ENABLE_KEYBOARD 2120 d->keymapCache_.clear();
2121 if (d->inputStateFactory_.registered()) {
2123 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2124 inputState->resetXkbState();
2133 if (d->globalConfig_.autoSavePeriod() <= 0) {
2134 d->periodicalSave_->setEnabled(
false);
2136 d->periodicalSave_->setNextInterval(AutoSaveMinInUsecs *
2137 d->globalConfig_.autoSavePeriod());
2138 d->periodicalSave_->setOneShot();
2149 if (!canRestart()) {
2157 setCurrentInputMethod(mostRecentInputContext(), name,
false);
2163 if (!canTrigger()) {
2167 auto &imManager = inputMethodManager();
2168 const auto &imList = imManager.currentGroup().inputMethodList();
2171 return item.name() == name;
2173 if (iter == std::ranges::end(imList)) {
2177 auto setGlobalDefaultInputMethod = [d](
const std::string &name) {
2178 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2179 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2181 groupRAIICheck.push_back(
2182 std::make_unique<CheckInputMethodChanged>(ic, d));
2185 d->imManager_.setDefaultInputMethod(name);
2188 auto idx = std::distance(imList.begin(), iter);
2190 CheckInputMethodChanged imChangedRAII(ic, d);
2191 auto currentIM = inputMethod(ic);
2192 if (currentIM == name) {
2195 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2199 inputState->setLocalIM(name);
2201 inputState->setLocalIM({});
2203 setGlobalDefaultInputMethod(name);
2205 inputState->setActive(
true);
2207 inputState->setActive(
false);
2209 if (inputState->imChanged_) {
2219 setGlobalDefaultInputMethod(name);
2227 if (
auto *ic = mostRecentInputContext()) {
2228 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
2229 return inputState->isActive() ? 2 : 1;
2236 if (
auto *ic = mostRecentInputContext()) {
2237 CheckInputMethodChanged imChangedRAII(ic, d);
2244 if (
auto *ic = mostRecentInputContext()) {
2245 CheckInputMethodChanged imChangedRAII(ic, d);
2246 enumerate(ic, forward);
2250 bool Instance::canTrigger()
const {
2251 const auto &imManager = inputMethodManager();
2252 return (imManager.currentGroup().inputMethodList().size() > 1);
2256 if (!canTrigger()) {
2260 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2261 if (inputState->isActive()) {
2264 return inputState->lastIMChangeIsAltTrigger_;
2269 if (!canTrigger()) {
2273 if (d->globalConfig_.enumerateSkipFirst()) {
2274 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2275 if (!inputState->isActive()) {
2278 return d->imManager_.currentGroup().inputMethodList().size() > 2;
2284 bool Instance::canChangeGroup()
const {
2285 const auto &imManager = inputMethodManager();
2286 return (imManager.groupCount() > 1);
2291 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2292 if (!canTrigger()) {
2295 inputState->setActive(!inputState->isActive());
2296 if (inputState->imChanged_) {
2297 inputState->imChanged_->setReason(reason);
2302 bool Instance::trigger(
InputContext *ic,
bool totallyReleased) {
2304 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2305 if (!canTrigger()) {
2310 if (totallyReleased) {
2312 inputState->firstTrigger_ =
true;
2314 if (!d->globalConfig_.enumerateWithTriggerKeys() ||
2315 (inputState->firstTrigger_ && inputState->isActive()) ||
2316 (d->globalConfig_.enumerateSkipFirst() &&
2317 d->imManager_.currentGroup().inputMethodList().size() <= 2)) {
2320 enumerate(ic,
true);
2322 inputState->firstTrigger_ =
false;
2328 if (!canAltTrigger(ic)) {
2338 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2339 if (!canTrigger()) {
2342 if (inputState->isActive()) {
2345 inputState->setActive(
true);
2346 if (inputState->imChanged_) {
2354 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2355 if (!canTrigger()) {
2358 if (!inputState->isActive()) {
2361 inputState->setActive(
false);
2362 if (inputState->imChanged_) {
2363 inputState->imChanged_->setReason(
2371 auto &imManager = inputMethodManager();
2372 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2373 const auto &imList = imManager.currentGroup().inputMethodList();
2374 if (!canTrigger()) {
2378 if (d->globalConfig_.enumerateSkipFirst() && imList.size() <= 2) {
2382 auto currentIM = inputMethod(ic);
2384 auto iter = std::ranges::find_if(
2386 return item.name() == currentIM;
2388 if (iter == imList.end()) {
2391 int idx = std::distance(imList.begin(), iter);
2392 auto nextIdx = [forward, &imList](
int idx) {
2394 return (idx + (forward ? 1 : (imList.size() - 1))) % imList.size();
2398 if (d->globalConfig_.enumerateSkipFirst() && idx == 0) {
2402 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2403 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2405 groupRAIICheck.push_back(
2406 std::make_unique<CheckInputMethodChanged>(ic, d));
2409 imManager.setDefaultInputMethod(imList[idx].name());
2410 inputState->setActive(
true);
2411 inputState->setLocalIM({});
2413 inputState->setActive(
false);
2415 if (inputState->imChanged_) {
2423 const std::string &orig) {
2424 std::string result = orig;
2425 emit<Instance::CommitFilter>(inputContext, result);
2431 emit<Instance::OutputFilter>(inputContext, result);
2432 if ((&orig == &inputContext->inputPanel().clientPreedit() ||
2433 &orig == &inputContext->inputPanel().preedit()) &&
2434 !globalConfig().showPreeditForPassword() &&
2435 inputContext->capabilityFlags().test(CapabilityFlag::Password)) {
2437 for (
int i = 0, e = result.size(); i < e; i++) {
2442 dot +=
"\xe2\x80\xa2";
2445 newText.append(std::move(dot),
2446 result.formatAt(i) | TextFormatFlag::DontCommit);
2448 result = std::move(newText);
2455 return d->icManager_.lastFocusedInputContext();
2460 return d->icManager_.mostRecentInputContext();
2465 d->uiManager_.flush();
2468 int scoreForGroup(
FocusGroup *group,
const std::string &displayHint) {
2470 if (displayHint.empty()) {
2471 if (group->display() ==
"x11:") {
2474 if (group->display().starts_with(
"x11:")) {
2477 if (group->display() ==
"wayland:") {
2480 if (group->display().starts_with(
"wayland:")) {
2484 if (group->display() == displayHint) {
2487 if (group->display().starts_with(displayHint)) {
2499 d->icManager_.foreachGroup(
2500 [&score, &displayHint, &defaultFocusGroup](
FocusGroup *group) {
2501 auto newScore = scoreForGroup(group, displayHint);
2502 if (newScore > score) {
2503 defaultFocusGroup = group;
2509 return defaultFocusGroup;
2514 FCITX_DEBUG() <<
"Instance::activateInputMethod";
2516 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2517 const auto *entry = inputMethodEntry(ic);
2519 FCITX_DEBUG() <<
"Activate: " 2520 <<
"[Last]:" << inputState->lastIM_
2521 <<
" [Activating]:" << entry->uniqueName();
2522 assert(inputState->lastIM_.empty());
2523 inputState->lastIM_ = entry->uniqueName();
2525 auto *engine = inputMethodEngine(ic);
2526 if (!engine || !entry) {
2529 #ifdef ENABLE_KEYBOARD 2530 if (
auto *xkbState = inputState->customXkbState(
true)) {
2531 if (
auto *mods = findValue(d->stateMask_, ic->
display())) {
2532 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
2533 auto depressed = std::get<0>(*mods);
2534 auto latched = std::get<1>(*mods);
2535 auto locked = std::get<2>(*mods);
2540 FCITX_KEYTRACE() << depressed <<
" " << latched <<
" " << locked;
2541 if (depressed == 0) {
2542 inputState->setModsAllReleased();
2544 xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0,
2550 engine->activate(*entry, event);
2556 FCITX_DEBUG() <<
"Instance::deactivateInputMethod event_type=" 2557 <<
static_cast<uint32_t
>(
event.type());
2559 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2566 FCITX_DEBUG() <<
"Switch reason: " 2567 <<
static_cast<int>(icEvent.reason());
2568 FCITX_DEBUG() <<
"Old Input method: " << icEvent.oldInputMethod();
2569 entry = d->imManager_.entry(icEvent.oldInputMethod());
2571 entry = inputMethodEntry(ic);
2574 FCITX_DEBUG() <<
"Deactivate: " 2575 <<
"[Last]:" << inputState->lastIM_
2576 <<
" [Deactivating]:" << entry->uniqueName();
2577 assert(entry->uniqueName() == inputState->lastIM_);
2579 d->addonManager_.addon(entry->addon()));
2581 inputState->lastIM_.clear();
2582 if (!engine || !entry) {
2585 inputState->overrideDeactivateIM_ = entry->uniqueName();
2587 inputState->overrideDeactivateIM_.clear();
2591 bool Instance::enumerateGroup(
bool forward) {
2592 auto &imManager = inputMethodManager();
2593 auto groups = imManager.groups();
2594 if (groups.size() <= 1) {
2598 imManager.setCurrentGroup(groups[1]);
2600 imManager.setCurrentGroup(groups.back());
2606 FCITX_DEBUG() <<
"Input method switched";
2608 if (!d->globalConfig_.showInputMethodInformation()) {
2611 d->showInputMethodInformation(ic);
2615 const std::string &message) {
2616 FCITX_DEBUG() <<
"Input method switched";
2618 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2619 inputState->showInputMethodInformation(message);
2624 return (isInFlatpak() &&
2625 std::filesystem::is_regular_file(
"/app/.updated")) ||
2626 d->addonManager_.checkUpdate() || d->imManager_.checkUpdate() ||
2631 const std::string &rule,
2632 const std::string &model,
2633 const std::string &options) {
2634 #ifdef ENABLE_KEYBOARD 2636 bool resetState =
false;
2637 if (
auto *param = findValue(d->xkbParams_, display)) {
2638 if (std::get<0>(*param) != rule || std::get<1>(*param) != model ||
2639 std::get<2>(*param) != options) {
2640 std::get<0>(*param) = rule;
2641 std::get<1>(*param) = model;
2642 std::get<2>(*param) = options;
2646 d->xkbParams_.emplace(display, std::make_tuple(rule, model, options));
2650 d->keymapCache_[display].clear();
2651 d->icManager_.foreach([d, &display](
InputContext *ic) {
2652 if (ic->
display() == display ||
2653 !d->xkbParams_.contains(ic->
display())) {
2654 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2655 inputState->resetXkbState();
2661 FCITX_UNUSED(display);
2663 FCITX_UNUSED(model);
2664 FCITX_UNUSED(options);
2669 uint32_t depressed_mods,
2670 uint32_t latched_mods, uint32_t locked_mods) {
2672 auto oldMask = xkbStateMask(display);
2673 auto &newMask = d->stateMask_[display];
2674 newMask = std::make_tuple(depressed_mods, latched_mods, locked_mods);
2675 if (oldMask == newMask) {
2678 emit<Instance::XkbStateMaskChanged>(display, oldMask, newMask);
2683 auto oldMask = xkbStateMask(display);
2684 if (!oldMask.has_value()) {
2687 bool changed = d->stateMask_.erase(display) > 0;
2689 emit<XkbStateMaskChanged>(display, oldMask, std::nullopt);
2693 std::optional<std::tuple<uint32_t, uint32_t, uint32_t>>
2696 if (
const auto *mask = findValue(d->stateMask_, display)) {
2699 return std::nullopt;
void updateXkbStateMask(const std::string &display, uint32_t depressed_mods, uint32_t latched_mods, uint32_t locked_mods)
Update xkb state mask for given display.
void restart()
Restart fcitx instance, this should only be used within a regular Fcitx server, not within embedded m...
void reloadAddonConfig(const std::string &addonName)
Reload certain addon config.
CapabilityFlags capabilityFlags() const
Returns the current capability flags.
FCITXCORE_DEPRECATED uint32_t processCompose(InputContext *ic, KeySym keysym)
Handle current XCompose state.
std::string inputMethodIcon(InputContext *ic)
Return the input method icon for input context.
void setXkbParameters(const std::string &display, const std::string &rule, const std::string &model, const std::string &options)
Set xkb RLVMO tuple for given display.
void activate()
Activate last focused input context. (Switch to the active input method)
EventType
Type of input method events.
Switched by alternative trigger key.
void resetCompose(InputContext *inputContext)
Reset the compose state.
T::PropertyType * propertyFor(const T *factory)
Helper function to return the input context property in specific type by given factory.
std::string UCS4ToUTF8(uint32_t code)
Convert UCS4 to UTF8 string.
FocusInEvent is generated when client gets focused.
Formatted string commonly used in user interface.
Whether client request input method to be disabled.
FocusGroup * defaultFocusGroup(const std::string &displayHint={})
Get the default focus group with given display hint.
static uint32_t keySymToUnicode(KeySym sym)
Convert keysym to a unicode.
Switched by activate key.
void flushUI()
All user interface update is batched internally.
This is generated when input method group changed.
std::string commitFilter(InputContext *inputContext, const std::string &orig)
Update the commit string to frontend.
AddonManager & addonManager()
Get the addon manager.
std::string currentInputMethod()
Return the current input method of last focused input context.
Manage registered TempMode objects for an Instance.
Simple file system related API for checking file status.
size_t length(Iter start, Iter end)
Return the number UTF-8 characters in the string iterator range.
bool validate(Iter start, Iter end)
Check if the string iterator range is valid utf8 string.
when user switch to a different input method by hand such as ctrl+shift by default, or by ui, default behavior is reset IM.
InputMethodSwitchedReason
The reason why input method is switched to another.
void deactivate()
Deactivate last focused input context.
int state()
Return a fcitx5-remote compatible value for the state.
InputMethodEngine * inputMethodEngine(InputContext *ic)
Return the input method engine object for given input context.
void setSignalPipe(int fd)
Set the pipe forwarding unix signal information.
InputMethodMode inputMethodMode() const
The current global input method mode.
void initialize()
Initialize fcitx.
EventLoop & eventLoop()
Get the fcitx event loop.
std::string currentUI()
Return the name of current user interface addon.
bool exitWhenMainDisplayDisconnected() const
Check whether command line specify whether to keep fcitx running.
C++ Utility functions for handling utf8 strings.
std::optional< std::tuple< uint32_t, uint32_t, uint32_t > > xkbStateMask(const std::string &display) const
Return xkb state mask for given display.
InputContext * mostRecentInputContext()
Return the most recent focused input context.
FCITX_NODISCARD std::unique_ptr< HandlerTableEntry< EventHandler > > watchEvent(EventType type, EventWatcherPhase phase, EventHandler callback)
Add a callback to for certain event type.
InputContextManager & inputContextManager()
Get the input context manager.
void setEnablePreedit(bool enable)
Override the preedit hint from client.
std::vector< std::string > split(std::string_view str, std::string_view delim, SplitBehavior behavior)
Split the string by delim.
virtual bool filtered() const
Whether a event is filtered by handler.
void clearGroup(StatusGroup group)
Clear only given status group.
bool hasFocus() const
Returns whether the input context holds the input focus.
bool isRunning() const
Whether event loop is started and still running.
A class represents a formatted string.
bool willTryReplace() const
Check whether command line specify if it will replace an existing fcitx server.
Switched by group change.
bool isRestartRequested() const
Whether restart is requested.
Manager class for user interface.
Instance(int argc, char *argv[])
A main function like construct to be used to create Fcitx Instance.
Base class for fcitx event.
bool isValidChar(uint32_t c)
Check the chr value is not two invalid value above.
std::string inputMethodLabel(InputContext *ic)
Return the input method label for input context.
void save()
Save everything including input method profile and addon data.
Enum type for input context capability.
Class for status area in UI.
void resetInputMethodList()
Reset the input method configuration and recreate based on system language.
Switched by capability change (e.g. password field)
Base class for User Interface addon.
A thread safe class to post event to a certain EventLoop.
void clearXkbStateMask(const std::string &display)
Clear xkb state mask for given display.
Enum flag for text formatting.
void configure()
Launch configtool.
bool checkUpdate() const
Check if need to invoke Instance::refresh.
New Utility classes to handle application specific path.
uint32_t getChar(Iter iter, Iter end)
Get next UCS4 char from iter, do not cross end.
InvokeAction event is generated when client click on the preedit.
InputMethodManager & inputMethodManager()
Get the input method manager.
void reloadConfig()
Reload global config.
int exec()
Start the event loop of Fcitx.
C-style utf8 utility functions.
TempModeManager & tempModeManager()
Get the temporary mode manager.
void setBinaryMode()
Set if this instance is running as fcitx5 binary.
bool isModifier() const
Check if the key is a modifier press.
InputContext * lastFocusedInputContext()
Return a focused input context.
std::string display() const
Returns the display server of the client.
void toggle()
Toggle between the first input method and active input method.
void setCurrentInputMethod(const std::string &imName)
Set the input method of last focused input context.
void setRunning(bool running)
Let other know that event loop is already running.
bool canRestart() const
Check if fcitx 5 can safely restart by itself.
void showCustomInputMethodInformation(InputContext *ic, const std::string &message)
Show a small popup with input popup window with current input method information. ...
std::optional< std::string > processComposeString(InputContext *ic, KeySym keysym)
Handle current XCompose state.
void refresh()
Load newly installed input methods and addons.
Input method mode changed.
std::string inputMethod(InputContext *ic)
Return the unique name of input method for given input context.
UserInterfaceManager & userInterfaceManager()
Get the user interface manager.
void enumerate(bool forward)
Enumerate input method with in current group.
bool exiting() const
Check whether fcitx is in exiting process.
void showInputMethodInformation(InputContext *ic)
Show a small popup with input popup window with current input method information. ...
Whether a Key Press is from key repetition.
StatusArea & statusArea()
Returns the associated StatusArea.
EventType type() const
Type of event, can be used to decide event class.
bool empty() const
Whether input panel is totally empty.
void setInputMethodMode(InputMethodMode mode)
Set the current global input method mode.
FCITXCORE_DEPRECATED void reset(ResetReason reason)
Called when input context state need to be reset.
ssize_t safeRead(int fd, void *data, size_t maxlen)
a simple wrapper around read(), ignore EINTR.
std::string addonForInputMethod(const std::string &imName)
Return the addon name of given input method.
Input Context Property for Fcitx.
static std::filesystem::path fcitxPath(const char *path, const std::filesystem::path &subPath={})
Return fcitx specific path defined at compile time.
An input context represents a client of Fcitx.
GlobalConfig & globalConfig()
Get the global config.
void exit()
Exit the fcitx event loop.
EventDispatcher & eventDispatcher()
Return a shared event dispatcher that is already attached to instance's event loop.
Key event is generated when client press or release a key.
const InputMethodEntry * inputMethodEntry(InputContext *ic)
Return the input method entry for given input context.
Class to represent a key.
bool isComposing(InputContext *inputContext)
Check whether input context is composing or not.
Switched by deactivate key.
static std::string keyListToString(const Container &container, KeyStringFormat format=KeyStringFormat::Portable)
Convert a key list to string.
Notify the global config is reloaded.
when using lost focus this might be variance case to case.
Switched by enumerate key.
static const char * version()
Return the version string of Fcitx.
Text outputFilter(InputContext *inputContext, const Text &orig)
Update the string that will be displayed in user interface.