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/environ.h" 38 #include "fcitx-utils/event.h" 39 #include "fcitx-utils/eventdispatcher.h" 40 #include "fcitx-utils/eventloopinterface.h" 42 #include "fcitx-utils/handlertable.h" 43 #include "fcitx-utils/i18n.h" 47 #include "fcitx-utils/macros.h" 48 #include "fcitx-utils/misc.h" 49 #include "fcitx-utils/misc_p.h" 54 #include "../../modules/notifications/notifications_public.h" 57 #include "focusgroup.h" 58 #include "globalconfig.h" 59 #include "inputcontextmanager.h" 61 #include "inputmethodengine.h" 62 #include "inputmethodentry.h" 63 #include "inputmethodgroup.h" 66 #include "instance_p.h" 73 #ifdef HAVE_SYS_WAIT_H 79 #include <../modules/xcb/xcb_public.h> 82 #ifdef ENABLE_KEYBOARD 83 #include <xkbcommon/xkbcommon-compose.h> 84 #include <xkbcommon/xkbcommon.h> 87 FCITX_DEFINE_LOG_CATEGORY(keyTrace,
"key_trace");
93 constexpr uint64_t AutoSaveMinInUsecs = 60ULL * 1000000ULL;
94 constexpr uint64_t AutoSaveIdleTime = 60ULL * 1000000ULL;
96 FCITX_CONFIGURATION(DefaultInputMethod,
97 Option<std::vector<std::string>> defaultInputMethods{
98 this,
"DefaultInputMethod",
"DefaultInputMethod"};
99 Option<std::vector<std::string>> extraLayouts{
100 this,
"ExtraLayout",
"ExtraLayout"};);
102 void initAsDaemon() {
106 waitpid(pid,
nullptr, 0);
110 auto oldint = signal(SIGINT, SIG_IGN);
111 auto oldhup = signal(SIGHUP, SIG_IGN);
112 auto oldquit = signal(SIGQUIT, SIG_IGN);
113 auto oldpipe = signal(SIGPIPE, SIG_IGN);
114 auto oldttou = signal(SIGTTOU, SIG_IGN);
115 auto oldttin = signal(SIGTTIN, SIG_IGN);
116 auto oldchld = signal(SIGCHLD, SIG_IGN);
122 signal(SIGINT, oldint);
123 signal(SIGHUP, oldhup);
124 signal(SIGQUIT, oldquit);
125 signal(SIGPIPE, oldpipe);
126 signal(SIGTTOU, oldttou);
127 signal(SIGTTIN, oldttin);
128 signal(SIGCHLD, oldchld);
133 bool shouldSwitchIM(
const CapabilityFlags &oldFlags,
134 const CapabilityFlags &newFlags) {
135 const bool oldDisable = oldFlags.testAny(
137 const bool newDisable = newFlags.testAny(
139 return oldDisable != newDisable;
144 void InstanceArgument::printUsage()
const {
146 <<
"Usage: " << argv0 <<
" [Option]\n" 147 <<
" --disable <addon names>\tA comma separated list of addons to " 149 <<
"\t\t\t\t\"all\" can be used to disable all addons.\n" 150 <<
" --enable <addon names>\tA comma separated list of addons to " 152 <<
"\t\t\t\t\"all\" can be used to enable all addons.\n" 153 <<
"\t\t\t\tThis value will override the value in the flag " 155 <<
" --verbose <logging rule>\tSet the logging rule for " 156 "displaying message.\n" 157 <<
"\t\t\t\tSyntax: category1=level1,category2=level2, ...\n" 158 <<
"\t\t\t\tE.g. default=4,key_trace=5\n" 159 <<
"\t\t\t\tLevels are numbers ranging from 0 to 5.\n" 160 <<
"\t\t\t\t\t0 - NoLog\n" 161 <<
"\t\t\t\t\t1 - Fatal\n" 162 <<
"\t\t\t\t\t2 - Error\n" 163 <<
"\t\t\t\t\t3 - Warn\n" 164 <<
"\t\t\t\t\t4 - Info (default)\n" 165 <<
"\t\t\t\t\t5 - Debug\n" 166 <<
"\t\t\t\tSome built-in categories are:\n" 167 <<
"\t\t\t\t\tdefault - miscellaneous category used by fcitx own " 169 <<
"\t\t\t\t\tkey_trace - print the key event received by fcitx.\n" 170 <<
"\t\t\t\t\t\"*\" may be used to represent all logging " 172 <<
" -u, --ui <addon name>\t\tSet the UI addon to be used.\n" 173 <<
" -d\t\t\t\tRun as a daemon.\n" 174 <<
" -D\t\t\t\tDo not run as a daemon (default).\n" 175 <<
" -s <seconds>\t\t\tNumber of seconds to wait before start.\n" 176 <<
" -k, --keep\t\t\tKeep running even the main display is " 178 <<
" -r, --replace\t\t\tReplace the existing instance.\n" 179 <<
" -o --option <option>\t\tPass the option to addons\n" 180 <<
"\t\t\t\t<option> is in format like:\n" 181 <<
"\t\t\t\tname1=opt1a:opt1b,name2=opt2a:opt2b... .\n" 182 <<
" -v, --version\t\t\tShow version and quit.\n" 183 <<
" -h, --help\t\t\tShow this help message and quit.\n";
186 InstancePrivate::InstancePrivate(Instance *q) : QPtrHolder<Instance>(q) {
187 #ifdef ENABLE_KEYBOARD 188 const auto &locale = getCurrentLocale();
189 assert(!locale.empty());
190 xkbContext_.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
192 xkb_context_set_log_level(xkbContext_.get(), XKB_LOG_LEVEL_CRITICAL);
193 xkbComposeTable_.reset(xkb_compose_table_new_from_locale(
194 xkbContext_.get(), locale.data(), XKB_COMPOSE_COMPILE_NO_FLAGS));
195 if (!xkbComposeTable_) {
197 <<
"Trying to fallback to compose table for en_US.UTF-8";
198 xkbComposeTable_.reset(xkb_compose_table_new_from_locale(
199 xkbContext_.get(),
"en_US.UTF-8",
200 XKB_COMPOSE_COMPILE_NO_FLAGS));
202 if (!xkbComposeTable_) {
204 <<
"No compose table is loaded, you may want to check your " 211 std::unique_ptr<HandlerTableEntry<EventHandler>>
212 InstancePrivate::watchEvent(
EventType type, EventWatcherPhase phase,
213 EventHandler callback) {
214 return eventHandlers_[type][phase].add(std::move(callback));
217 #ifdef ENABLE_KEYBOARD 218 xkb_keymap *InstancePrivate::keymap(
const std::string &display,
219 const std::string &layout,
220 const std::string &variant) {
221 auto layoutAndVariant = stringutils::concat(layout,
"-", variant);
222 if (
auto *keymapPtr = findValue(keymapCache_[display], layoutAndVariant)) {
223 return (*keymapPtr).get();
225 struct xkb_rule_names names;
226 names.layout = layout.c_str();
227 names.variant = variant.c_str();
228 std::tuple<std::string, std::string, std::string> xkbParam;
229 if (
auto *param = findValue(xkbParams_, display)) {
232 if (!xkbParams_.empty()) {
233 xkbParam = xkbParams_.begin()->second;
235 xkbParam = std::make_tuple(DEFAULT_XKB_RULES,
"pc101",
"");
238 if (globalConfig_.overrideXkbOption()) {
239 std::get<2>(xkbParam) = globalConfig_.customXkbOption();
241 names.rules = std::get<0>(xkbParam).c_str();
242 names.model = std::get<1>(xkbParam).c_str();
243 names.options = std::get<2>(xkbParam).c_str();
244 UniqueCPtr<xkb_keymap, xkb_keymap_unref> keymap(xkb_keymap_new_from_names(
245 xkbContext_.get(), &names, XKB_KEYMAP_COMPILE_NO_FLAGS));
247 keymapCache_[display].emplace(layoutAndVariant, std::move(keymap));
248 assert(result.second);
249 return result.first->second.get();
253 std::pair<std::unordered_set<std::string>, std::unordered_set<std::string>>
254 InstancePrivate::overrideAddons() {
255 std::unordered_set<std::string> enabled;
256 std::unordered_set<std::string> disabled;
257 for (
const auto &addon : globalConfig_.enabledAddons()) {
258 enabled.insert(addon);
260 for (
const auto &addon : globalConfig_.disabledAddons()) {
261 enabled.erase(addon);
262 disabled.insert(addon);
264 for (
const auto &addon : arg_.enableList) {
265 disabled.erase(addon);
266 enabled.insert(addon);
268 for (
const auto &addon : arg_.disableList) {
269 enabled.erase(addon);
270 disabled.insert(addon);
272 return {enabled, disabled};
275 void InstancePrivate::buildDefaultGroup() {
277 auto *defaultGroup = q_func()->defaultFocusGroup();
278 bool infoFound =
false;
280 std::string variants;
281 auto guessLayout = [
this, &layouts, &variants,
282 &infoFound](FocusGroup *focusGroup) {
288 auto *xcb = addonManager_.addon(
"xcb");
289 auto x11Name = focusGroup->display().substr(4);
291 auto rules = xcb->call<IXCBModule::xkbRulesNames>(x11Name);
292 if (!rules[2].
empty()) {
301 FCITX_UNUSED(layouts);
302 FCITX_UNUSED(variants);
303 FCITX_UNUSED(infoFound);
307 if (!defaultGroup || guessLayout(defaultGroup)) {
308 icManager_.foreachGroup(
309 [defaultGroup, &guessLayout](FocusGroup *focusGroup) {
310 if (defaultGroup == focusGroup) {
313 return guessLayout(focusGroup);
322 constexpr
char imNamePrefix[] =
"keyboard-";
326 variants,
",", stringutils::SplitBehavior::KeepEmpty);
327 auto size = std::max(layoutTokens.size(), variantTokens.size());
329 layoutTokens.resize(size);
330 variantTokens.resize(size);
332 OrderedSet<std::string> imLayouts;
333 for (decltype(size) i = 0; i < size; i++) {
334 if (layoutTokens[i].
empty()) {
337 std::string layoutName = layoutTokens[i];
338 if (!variantTokens[i].
empty()) {
339 layoutName = stringutils::concat(layoutName,
"-", variantTokens[i]);
343 if (!imManager_.entry(stringutils::concat(imNamePrefix, layoutName))) {
347 imLayouts.pushBack(layoutName);
351 auto lang = stripLanguage(getCurrentLanguage());
352 DefaultInputMethod defaultIMConfig;
353 readAsIni(defaultIMConfig, StandardPathsType::PkgData,
354 std::filesystem::path(
"default") / lang);
357 for (
const auto &extraLayout : defaultIMConfig.extraLayouts.value()) {
358 if (!imManager_.entry(stringutils::concat(imNamePrefix, extraLayout))) {
361 imLayouts.pushBack(extraLayout);
365 if (imLayouts.empty()) {
366 imLayouts.pushBack(
"us");
370 std::string defaultIM;
371 for (
const auto &im : defaultIMConfig.defaultInputMethods.value()) {
372 if (imManager_.entry(im)) {
379 std::vector<std::string> groupOrders;
380 for (
const auto &imLayout : imLayouts) {
381 std::string groupName;
382 if (imLayouts.size() == 1) {
383 groupName = _(
"Default");
385 groupName = _(
"Group {}", imManager_.groupCount() + 1);
387 imManager_.addEmptyGroup(groupName);
388 groupOrders.push_back(groupName);
389 InputMethodGroup group(groupName);
390 group.inputMethodList().emplace_back(
391 InputMethodGroupItem(stringutils::concat(imNamePrefix, imLayout)));
392 if (!defaultIM.empty()) {
393 group.inputMethodList().emplace_back(
394 InputMethodGroupItem(defaultIM));
396 FCITX_INFO() <<
"Items in " << groupName <<
": " 397 << group.inputMethodList();
398 group.setDefaultLayout(imLayout);
399 imManager_.setGroup(std::move(group));
401 FCITX_INFO() <<
"Generated groups: " << groupOrders;
402 imManager_.setGroupOrder(groupOrders);
405 void InstancePrivate::showInputMethodInformation(InputContext *ic) {
407 auto *inputState = ic->propertyFor(&inputStateFactory_);
408 auto *engine = q->inputMethodEngine(ic);
409 const auto *entry = q->inputMethodEntry(ic);
410 auto &imManager = q->inputMethodManager();
412 if (!inputState->isActive() &&
413 !globalConfig_.showFirstInputMethodInformation()) {
419 auto subMode = engine->subMode(*entry, *ic);
420 auto subModeLabel = engine->subModeLabel(*entry, *ic);
421 auto name = globalConfig_.compactInputMethodInformation() &&
422 !entry->label().empty()
425 if (globalConfig_.compactInputMethodInformation() &&
426 !subModeLabel.empty()) {
427 display = std::move(subModeLabel);
428 }
else if (subMode.empty()) {
429 display = std::move(name);
431 display = _(
"{0} ({1})", name, subMode);
434 display = _(
"{0} (Not available)", entry->name());
436 display = _(
"(Not available)");
438 if (!globalConfig_.compactInputMethodInformation() &&
439 imManager.groupCount() > 1) {
440 display = _(
"Group {0}: {1}", imManager.currentGroup().name(), display);
442 inputState->showInputMethodInformation(display);
445 bool InstancePrivate::canActivate(InputContext *ic) {
447 if (!q->canTrigger()) {
450 auto *inputState = ic->propertyFor(&inputStateFactory_);
451 return !inputState->isActive();
454 bool InstancePrivate::canDeactivate(InputContext *ic) {
456 if (!q->canTrigger()) {
459 auto *inputState = ic->propertyFor(&inputStateFactory_);
460 return inputState->isActive();
463 void InstancePrivate::navigateGroup(InputContext *ic,
const Key &key,
465 auto *inputState = ic->propertyFor(&inputStateFactory_);
466 inputState->pendingGroupIndex_ =
467 (inputState->pendingGroupIndex_ +
468 (forward ? 1 : imManager_.groupCount() - 1)) %
469 imManager_.groupCount();
470 FCITX_DEBUG() <<
"Switch to group " << inputState->pendingGroupIndex_;
472 if (notifications_ && !isSingleKey(key)) {
473 notifications_->call<INotifications::showTip>(
474 "enumerate-group", _(
"Input Method"),
"input-keyboard",
476 _(
"Switch group to {0}",
477 imManager_.groups()[inputState->pendingGroupIndex_]),
482 void InstancePrivate::acceptGroupChange(
const Key &key, InputContext *ic) {
483 FCITX_DEBUG() <<
"Accept group change, isSingleKey: " << key;
485 auto *inputState = ic->propertyFor(&inputStateFactory_);
486 auto groups = imManager_.groups();
487 if (groups.size() > inputState->pendingGroupIndex_) {
488 if (isSingleKey(key)) {
489 FCITX_DEBUG() <<
"EnumerateGroupTo: " 490 << inputState->pendingGroupIndex_ <<
" " << key;
491 imManager_.enumerateGroupTo(groups[inputState->pendingGroupIndex_]);
493 FCITX_DEBUG() <<
"SetCurrentGroup: " 494 << inputState->pendingGroupIndex_ <<
" " << key;
495 imManager_.setCurrentGroup(groups[inputState->pendingGroupIndex_]);
498 inputState->pendingGroupIndex_ = 0;
501 InputState::InputState(InstancePrivate *d, InputContext *ic)
502 : d_ptr(d), ic_(ic) {
503 active_ = d->globalConfig_.activeByDefault();
504 #ifdef ENABLE_KEYBOARD 505 if (d->xkbComposeTable_) {
506 xkbComposeState_.reset(xkb_compose_state_new(
507 d->xkbComposeTable_.get(), XKB_COMPOSE_STATE_NO_FLAGS));
512 void InputState::showInputMethodInformation(
const std::string &name) {
513 ic_->inputPanel().setAuxUp(Text(name));
516 imInfoTimer_ = d_ptr->eventLoop_.addTimeEvent(
517 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, 0,
518 [
this](EventSourceTime *, uint64_t) {
519 hideInputMethodInfo();
524 #ifdef ENABLE_KEYBOARD 525 xkb_state *InputState::customXkbState(
bool refresh) {
526 auto *instance = d_ptr->q_func();
527 const InputMethodGroup &group = d_ptr->imManager_.currentGroup();
528 const auto im = instance->inputMethod(ic_);
529 auto layout = group.layoutFor(im);
531 layout = im.substr(9);
533 if (layout.empty() || layout == group.defaultLayout()) {
536 modsAllReleased_ =
false;
537 lastXkbLayout_.clear();
541 if (layout == lastXkbLayout_ && !refresh) {
542 return xkbState_.get();
545 lastXkbLayout_ = layout;
546 const auto layoutAndVariant = parseLayout(layout);
547 if (
auto *keymap = d_ptr->keymap(ic_->display(), layoutAndVariant.first,
548 layoutAndVariant.second)) {
549 xkbState_.reset(xkb_state_new(keymap));
553 modsAllReleased_ =
false;
554 return xkbState_.get();
558 void InputState::setActive(
bool active) {
559 if (active_ != active) {
561 ic_->updateProperty(&d_ptr->inputStateFactory_);
565 void InputState::setLocalIM(
const std::string &localIM) {
566 if (localIM_ != localIM) {
568 ic_->updateProperty(&d_ptr->inputStateFactory_);
572 void InputState::copyTo(InputContextProperty *other) {
573 auto *otherState =
static_cast<InputState *
>(other);
574 if (otherState->active_ == active_ && otherState->localIM_ == localIM_) {
578 if (otherState->ic_->hasFocus()) {
579 FCITX_DEBUG() <<
"Sync state to focused ic: " 580 << otherState->ic_->program();
581 CheckInputMethodChanged imChangedRAII(otherState->ic_, d_ptr);
582 otherState->active_ = active_;
583 otherState->localIM_ = localIM_;
585 otherState->active_ = active_;
586 otherState->localIM_ = localIM_;
590 void InputState::reset() {
591 #ifdef ENABLE_KEYBOARD 592 if (xkbComposeState_) {
593 xkb_compose_state_reset(xkbComposeState_.get());
596 pendingGroupIndex_ = 0;
598 lastKeyPressed_ = Key();
599 lastKeyPressedTime_ = 0;
600 totallyReleased_ =
true;
603 void InputState::hideInputMethodInfo() {
607 imInfoTimer_.reset();
608 auto &panel = ic_->inputPanel();
609 if (panel.auxDown().empty() && panel.preedit().empty() &&
610 panel.clientPreedit().empty() &&
611 (!panel.candidateList() || panel.candidateList()->empty()) &&
612 panel.auxUp().size() == 1 && panel.auxUp().stringAt(0) == lastInfo_) {
618 #ifdef ENABLE_KEYBOARD 619 void InputState::resetXkbState() {
620 lastXkbLayout_.clear();
625 CheckInputMethodChanged::CheckInputMethodChanged(InputContext *ic,
626 InstancePrivate *instance)
627 : instance_(instance->q_func()), instancePrivate_(instance),
628 ic_(ic->watch()), inputMethod_(instance_->inputMethod(ic)),
630 auto *inputState = ic->propertyFor(&instance->inputStateFactory_);
631 if (!inputState->imChanged_) {
632 inputState->imChanged_ =
this;
638 CheckInputMethodChanged::~CheckInputMethodChanged() {
639 if (!ic_.isValid()) {
642 auto *ic = ic_.get();
643 auto *inputState = ic->propertyFor(&instancePrivate_->inputStateFactory_);
644 inputState->imChanged_ =
nullptr;
645 if (inputMethod_ != instance_->inputMethod(ic) && !ignore_) {
646 instance_->postEvent(
647 InputContextSwitchInputMethodEvent(reason_, inputMethod_, ic));
652 InstanceArgument arg;
653 arg.parseOption(argc, argv);
658 if (arg.runAsDaemon) {
662 if (arg.overrideDelay > 0) {
663 sleep(arg.overrideDelay);
667 d_ptr = std::make_unique<InstancePrivate>(
this);
670 d->eventDispatcher_.attach(&d->eventLoop_);
671 d->addonManager_.setInstance(
this);
672 d->addonManager_.setAddonOptions(arg.addonOptions_);
673 d->icManager_.setInstance(
this);
674 d->connections_.emplace_back(
675 d->imManager_.connect<InputMethodManager::CurrentGroupAboutToChange>(
676 [
this, d](
const std::string &lastGroup) {
677 d->icManager_.foreachFocused([this](InputContext *ic) {
678 assert(ic->hasFocus());
679 InputContextSwitchInputMethodEvent event(
680 InputMethodSwitchedReason::GroupChange, inputMethod(ic),
682 deactivateInputMethod(event);
685 d->lastGroup_ = lastGroup;
688 d->connections_.emplace_back(
689 d->imManager_.connect<InputMethodManager::CurrentGroupChanged>(
690 [
this, d](
const std::string &newGroup) {
691 d->icManager_.foreachFocused([this](InputContext *ic) {
692 assert(ic->hasFocus());
693 InputContextSwitchInputMethodEvent event(
694 InputMethodSwitchedReason::GroupChange,
"", ic);
695 activateInputMethod(event);
699 if (!d->lastGroup_.empty() && !newGroup.empty() &&
700 d->lastGroup_ != newGroup && d->notifications_ &&
701 d->imManager_.groupCount() > 1) {
702 d->notifications_->call<INotifications::showTip>(
703 "enumerate-group", _(
"Input Method"),
"input-keyboard",
705 _(
"Switched group to {0}",
706 d->imManager_.currentGroup().name()),
709 d->lastGroup_ = newGroup;
712 d->eventWatchers_.emplace_back(d->watchEvent(
713 EventType::InputContextCapabilityAboutToChange,
714 EventWatcherPhase::ReservedFirst, [
this](
Event &event) {
716 static_cast<CapabilityAboutToChangeEvent &>(event);
717 if (!capChanged.inputContext()->hasFocus()) {
721 if (!shouldSwitchIM(capChanged.oldFlags(), capChanged.newFlags())) {
727 inputMethod(capChanged.inputContext()),
728 capChanged.inputContext());
729 deactivateInputMethod(switchIM);
731 d->eventWatchers_.emplace_back(d->watchEvent(
732 EventType::InputContextCapabilityChanged,
733 EventWatcherPhase::ReservedFirst, [
this](
Event &event) {
734 auto &capChanged = static_cast<CapabilityChangedEvent &>(event);
735 if (!capChanged.inputContext()->hasFocus()) {
739 if (!shouldSwitchIM(capChanged.oldFlags(), capChanged.newFlags())) {
745 capChanged.inputContext());
746 activateInputMethod(switchIM);
749 d->eventWatchers_.emplace_back(watchEvent(
751 [
this, d](
Event &event) {
752 auto &keyEvent =
static_cast<KeyEvent &
>(event);
753 auto *ic = keyEvent.inputContext();
754 CheckInputMethodChanged imChangedRAII(ic, d);
755 auto origKey = keyEvent.origKey().normalize();
759 std::function<bool()> check;
760 std::function<void(bool)> trigger;
762 {.list = d->globalConfig_.triggerKeys(),
763 .check = [
this]() {
return canTrigger(); },
765 [
this, ic](
bool totallyReleased) {
766 return trigger(ic, totallyReleased);
768 {.list = d->globalConfig_.altTriggerKeys(),
769 .check = [
this, ic]() {
return canAltTrigger(ic); },
770 .trigger = [
this, ic](bool) {
return altTrigger(ic); }},
771 {.list = d->globalConfig_.activateKeys(),
772 .check = [ic, d]() {
return d->canActivate(ic); },
773 .trigger = [
this, ic](bool) {
return activate(ic); }},
774 {.list = d->globalConfig_.deactivateKeys(),
775 .check = [ic, d]() {
return d->canDeactivate(ic); },
776 .trigger = [
this, ic](bool) {
return deactivate(ic); }},
777 {.list = d->globalConfig_.enumerateForwardKeys(),
778 .check = [
this, ic]() {
return canEnumerate(ic); },
779 .trigger = [
this, ic](bool) {
return enumerate(ic,
true); }},
780 {.list = d->globalConfig_.enumerateBackwardKeys(),
781 .check = [
this, ic]() {
return canEnumerate(ic); },
782 .trigger = [
this, ic](bool) {
return enumerate(ic,
false); }},
783 {.list = d->globalConfig_.enumerateGroupForwardKeys(),
784 .check = [
this]() {
return canChangeGroup(); },
785 .trigger = [ic, d, origKey](
786 bool) { d->navigateGroup(ic, origKey,
true); }},
787 {.list = d->globalConfig_.enumerateGroupBackwardKeys(),
788 .check = [
this]() {
return canChangeGroup(); },
790 [ic, d, origKey](bool) {
791 d->navigateGroup(ic, origKey,
false);
795 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
796 int keyReleased = inputState->keyReleased_;
797 Key lastKeyPressed = inputState->lastKeyPressed_;
799 inputState->keyReleased_ = -1;
801 if (keyEvent.isRelease()) {
803 for (
auto &keyHandler : keyHandlers) {
804 if (keyReleased == idx &&
805 origKey.isReleaseOfModifier(lastKeyPressed) &&
806 keyHandler.check()) {
808 if (d->globalConfig_.checkModifierOnlyKeyTimeout(
809 inputState->lastKeyPressedTime_)) {
811 inputState->totallyReleased_);
813 inputState->lastKeyPressedTime_ = 0;
814 if (origKey.hasModifier()) {
815 inputState->totallyReleased_ =
false;
823 if (isSingleModifier(origKey)) {
824 inputState->totallyReleased_ =
true;
828 if (inputState->pendingGroupIndex_ &&
829 inputState->totallyReleased_) {
830 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
831 if (inputState->imChanged_) {
832 inputState->imChanged_->ignore();
834 d->acceptGroupChange(lastKeyPressed, ic);
835 inputState->lastKeyPressed_ =
Key();
838 if (!keyEvent.filtered() && !keyEvent.isRelease()) {
840 for (
auto &keyHandler : keyHandlers) {
841 auto keyIdx = origKey.keyListIndex(keyHandler.list);
842 if (keyIdx >= 0 && keyHandler.check()) {
843 inputState->keyReleased_ = idx;
844 inputState->lastKeyPressed_ = origKey;
846 inputState->lastKeyPressedTime_ =
847 now(CLOCK_MONOTONIC);
853 keyHandler.trigger(inputState->totallyReleased_);
854 if (origKey.hasModifier()) {
855 inputState->totallyReleased_ =
false;
857 keyEvent.filterAndAccept();
864 d->eventWatchers_.emplace_back(watchEvent(
867 auto &keyEvent =
static_cast<KeyEvent &
>(event);
868 auto *ic = keyEvent.inputContext();
869 if (!keyEvent.isRelease() &&
870 keyEvent.key().checkKeyList(
871 d->globalConfig_.togglePreeditKeys())) {
873 if (d->notifications_) {
874 d->notifications_->call<INotifications::showTip>(
875 "toggle-preedit", _(
"Input Method"),
"", _(
"Preedit"),
876 ic->isPreeditEnabled() ? _(
"Preedit enabled")
877 : _(
"Preedit disabled"),
880 keyEvent.filterAndAccept();
883 d->eventWatchers_.emplace_back(d->watchEvent(
887 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
888 auto &keyEvent = static_cast<KeyEvent &>(event);
889 auto *ic = keyEvent.inputContext();
890 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
891 #ifdef ENABLE_KEYBOARD
892 auto *xkbState = inputState->customXkbState();
894 if (auto *mods = findValue(d->stateMask_, ic->display())) {
895 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
899 if (inputState->isModsAllReleased()) {
900 depressed = xkb_state_serialize_mods(
901 xkbState, XKB_STATE_MODS_DEPRESSED);
903 depressed = std::get<0>(*mods);
905 if (std::get<0>(*mods) == 0) {
906 inputState->setModsAllReleased();
908 auto latched = xkb_state_serialize_mods(
909 xkbState, XKB_STATE_MODS_LATCHED);
910 auto locked = std::get<2>(*mods);
916 << depressed <<
" " << latched <<
" " << locked;
917 xkb_state_update_mask(xkbState, depressed, latched, locked,
920 const uint32_t effective = xkb_state_serialize_mods(
921 xkbState, XKB_STATE_MODS_EFFECTIVE);
922 auto newSym = xkb_state_key_get_one_sym(
923 xkbState, keyEvent.rawKey().code());
924 auto newModifier = KeyStates(effective);
925 auto *keymap = xkb_state_get_keymap(xkbState);
926 if (keyEvent.rawKey().states().test(KeyState::Repeat) &&
927 xkb_keymap_key_repeats(keymap, keyEvent.rawKey().code())) {
928 newModifier |= KeyState::Repeat;
931 const uint32_t modsDepressed = xkb_state_serialize_mods(
932 xkbState, XKB_STATE_MODS_DEPRESSED);
933 const uint32_t modsLatched =
934 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
935 const uint32_t modsLocked =
936 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
937 FCITX_KEYTRACE() <<
"Current mods: " << modsDepressed <<
" " 938 << modsLatched <<
" " << modsLocked;
939 auto newCode = keyEvent.rawKey().code();
940 Key key(static_cast<KeySym>(newSym), newModifier, newCode);
942 <<
"Custom Xkb translated Key: " << key.toString();
943 keyEvent.setRawKey(key);
946 FCITX_KEYTRACE() <<
"KeyEvent: " << keyEvent.key()
947 <<
" rawKey: " << keyEvent.rawKey()
948 <<
" origKey: " << keyEvent.origKey()
949 <<
" Release:" << keyEvent.isRelease()
950 <<
" keycode: " << keyEvent.origKey().code()
951 <<
" program: " << ic->program();
953 if (keyEvent.isRelease()) {
956 inputState->hideInputMethodInfo();
958 d->eventWatchers_.emplace_back(
960 EventWatcherPhase::InputMethod, [
this](
Event &event) {
961 auto &keyEvent =
static_cast<KeyEvent &
>(event);
962 auto *ic = keyEvent.inputContext();
963 auto *engine = inputMethodEngine(ic);
964 const auto *entry = inputMethodEntry(ic);
965 if (!engine || !entry) {
968 engine->keyEvent(*entry, keyEvent);
970 d->eventWatchers_.emplace_back(watchEvent(
971 EventType::InputContextVirtualKeyboardEvent,
972 EventWatcherPhase::InputMethod, [
this](
Event &event) {
974 auto *ic = keyEvent.inputContext();
975 auto *engine = inputMethodEngine(ic);
976 const auto *entry = inputMethodEntry(ic);
977 if (!engine || !entry) {
980 engine->virtualKeyboardEvent(*entry, keyEvent);
982 d->eventWatchers_.emplace_back(watchEvent(
984 [
this](
Event &event) {
986 auto *ic = invokeActionEvent.inputContext();
987 auto *engine = inputMethodEngine(ic);
988 const auto *entry = inputMethodEntry(ic);
989 if (!engine || !entry) {
992 engine->invokeAction(*entry, invokeActionEvent);
994 d->eventWatchers_.emplace_back(d->watchEvent(
996 [
this](
Event &event) {
997 auto &keyEvent = static_cast<KeyEvent &>(event);
998 auto *ic = keyEvent.inputContext();
999 auto *engine = inputMethodEngine(ic);
1000 const auto *entry = inputMethodEntry(ic);
1001 if (!engine || !entry) {
1004 engine->filterKey(*entry, keyEvent);
1005 emit<Instance::KeyEventResult>(keyEvent);
1006 #ifdef ENABLE_KEYBOARD 1007 if (keyEvent.forward()) {
1012 if (keyEvent.isRelease()) {
1016 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1017 if (
auto *xkbState = inputState->customXkbState()) {
1018 if (
auto utf32 = xkb_state_key_get_utf32(
1019 xkbState, keyEvent.key().code())) {
1021 if (utf32 ==
'\n' || utf32 ==
'\b' || utf32 ==
'\r' ||
1022 utf32 ==
'\t' || utf32 ==
'\033' ||
1026 if (keyEvent.key().states().test(KeyState::Ctrl) ||
1027 keyEvent.rawKey().sym() ==
1028 keyEvent.origKey().sym()) {
1031 FCITX_KEYTRACE() <<
"Will commit char: " << utf32;
1033 keyEvent.filterAndAccept();
1034 }
else if (!keyEvent.key().states().test(KeyState::Ctrl) &&
1035 keyEvent.rawKey().sym() !=
1036 keyEvent.origKey().sym() &&
1041 keyEvent.filterAndAccept();
1047 d->eventWatchers_.emplace_back(d->watchEvent(
1049 [
this, d](
Event &event) {
1050 auto &icEvent = static_cast<InputContextEvent &>(event);
1051 auto isSameProgram = [&icEvent, d]() {
1053 return (icEvent.inputContext() == d->lastUnFocusedIc_.get()) ||
1054 (!icEvent.inputContext()->program().empty() &&
1055 (icEvent.inputContext()->program() ==
1056 d->lastUnFocusedProgram_));
1059 if (d->globalConfig_.resetStateWhenFocusIn() ==
1060 PropertyPropagatePolicy::All ||
1061 (d->globalConfig_.resetStateWhenFocusIn() ==
1062 PropertyPropagatePolicy::Program &&
1063 !isSameProgram())) {
1064 if (d->globalConfig_.activeByDefault()) {
1065 activate(icEvent.inputContext());
1067 deactivate(icEvent.inputContext());
1071 activateInputMethod(icEvent);
1073 auto *inputContext = icEvent.inputContext();
1074 if (!inputContext->clientControlVirtualkeyboardShow()) {
1075 inputContext->showVirtualKeyboard();
1078 if (!d->globalConfig_.showInputMethodInformationWhenFocusIn() ||
1079 icEvent.inputContext()->capabilityFlags().test(
1085 d->focusInImInfoTimer_ = d->eventLoop_.addTimeEvent(
1086 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1090 if (
auto *ic = icRef.get(); ic && ic->hasFocus()) {
1091 d->showInputMethodInformation(ic);
1096 d->eventWatchers_.emplace_back(d->watchEvent(
1099 auto &icEvent = static_cast<InputContextEvent &>(event);
1100 auto *ic = icEvent.inputContext();
1101 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1102 inputState->reset();
1103 if (!ic->capabilityFlags().test(
1104 CapabilityFlag::ClientUnfocusCommit)) {
1107 ic->inputPanel().clientPreedit().toStringForCommit();
1108 if (!commit.empty()) {
1109 ic->commitString(commit);
1113 d->eventWatchers_.emplace_back(d->watchEvent(
1115 [
this, d](
Event &event) {
1116 auto &icEvent = static_cast<InputContextEvent &>(event);
1117 d->lastUnFocusedProgram_ = icEvent.inputContext()->program();
1118 d->lastUnFocusedIc_ = icEvent.inputContext()->watch();
1119 deactivateInputMethod(icEvent);
1121 auto *inputContext = icEvent.inputContext();
1122 if (!inputContext->clientControlVirtualkeyboardHide()) {
1123 inputContext->hideVirtualKeyboard();
1126 d->eventWatchers_.emplace_back(d->watchEvent(
1129 auto &icEvent = static_cast<InputContextEvent &>(event);
1130 auto *ic = icEvent.inputContext();
1131 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1132 inputState->reset();
1134 d->eventWatchers_.emplace_back(
1136 [
this](
Event &event) {
1138 auto *ic = icEvent.inputContext();
1139 if (!ic->hasFocus()) {
1142 auto *engine = inputMethodEngine(ic);
1143 const auto *entry = inputMethodEntry(ic);
1144 if (!engine || !entry) {
1147 engine->reset(*entry, icEvent);
1149 d->eventWatchers_.emplace_back(d->watchEvent(
1151 EventWatcherPhase::ReservedFirst, [
this](
Event &event) {
1153 static_cast<InputContextSwitchInputMethodEvent &>(event);
1154 auto *ic = icEvent.inputContext();
1155 if (!ic->hasFocus()) {
1158 deactivateInputMethod(icEvent);
1159 activateInputMethod(icEvent);
1161 d->eventWatchers_.emplace_back(d->watchEvent(
1163 EventWatcherPhase::ReservedLast, [
this, d](
Event &event) {
1165 static_cast<InputContextSwitchInputMethodEvent &>(event);
1166 auto *ic = icEvent.inputContext();
1167 if (!ic->hasFocus()) {
1171 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1172 inputState->lastIMChangeIsAltTrigger_ =
1184 showInputMethodInformation(ic);
1186 d->eventWatchers_.emplace_back(
1188 EventWatcherPhase::ReservedLast, [
this, d](
Event &) {
1191 d->imGroupInfoTimer_ = d->eventLoop_.addTimeEvent(
1192 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1193 [this](EventSourceTime *, uint64_t) {
1194 inputContextManager().foreachFocused(
1195 [this](InputContext *ic) {
1196 showInputMethodInformation(ic);
1203 d->eventWatchers_.emplace_back(d->watchEvent(
1204 EventType::InputContextUpdateUI, EventWatcherPhase::ReservedFirst,
1206 auto &icEvent = static_cast<InputContextUpdateUIEvent &>(event);
1207 if (icEvent.immediate()) {
1208 d->uiManager_.update(icEvent.component(),
1209 icEvent.inputContext());
1210 d->uiManager_.flush();
1212 d->uiManager_.update(icEvent.component(),
1213 icEvent.inputContext());
1214 d->uiUpdateEvent_->setOneShot();
1217 d->eventWatchers_.emplace_back(d->watchEvent(
1218 EventType::InputContextDestroyed, EventWatcherPhase::ReservedFirst,
1220 auto &icEvent = static_cast<InputContextEvent &>(event);
1221 d->uiManager_.expire(icEvent.inputContext());
1223 d->eventWatchers_.emplace_back(d->watchEvent(
1225 [d](
Event &) { d->uiManager_.updateAvailability(); }));
1226 d->uiUpdateEvent_ = d->eventLoop_.addDeferEvent([d](
EventSource *) {
1227 d->uiManager_.flush();
1230 d->uiUpdateEvent_->setEnabled(
false);
1231 d->periodicalSave_ = d->eventLoop_.addTimeEvent(
1232 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, AutoSaveIdleTime,
1239 auto currentTime = now(CLOCK_MONOTONIC);
1240 if (currentTime <= d->idleStartTimestamp_ ||
1241 currentTime - d->idleStartTimestamp_ < AutoSaveIdleTime) {
1243 time->setNextInterval(2 * AutoSaveIdleTime);
1248 FCITX_INFO() <<
"Running autosave...";
1250 FCITX_INFO() <<
"End autosave";
1251 if (d->globalConfig_.autoSavePeriod() > 0) {
1252 time->setNextInterval(d->globalConfig_.autoSavePeriod() *
1253 AutoSaveMinInUsecs);
1258 d->periodicalSave_->setEnabled(
false);
1261 Instance::~Instance() {
1263 d->icManager_.finalize();
1264 d->addonManager_.unload();
1265 d->notifications_ =
nullptr;
1266 d->icManager_.setInstance(
nullptr);
1269 void InstanceArgument::parseOption(
int argc,
char **argv) {
1275 struct option longOptions[] = {{
"enable", required_argument,
nullptr, 0},
1276 {
"disable", required_argument,
nullptr, 0},
1277 {
"verbose", required_argument,
nullptr, 0},
1278 {
"keep", no_argument,
nullptr,
'k'},
1279 {
"ui", required_argument,
nullptr,
'u'},
1280 {
"replace", no_argument,
nullptr,
'r'},
1281 {
"version", no_argument,
nullptr,
'v'},
1282 {
"help", no_argument,
nullptr,
'h'},
1283 {
"option", required_argument,
nullptr,
'o'},
1284 {
nullptr, 0, 0, 0}};
1286 int optionIndex = 0;
1288 std::string addonOptionString;
1289 while ((c = getopt_long(argc, argv,
"ru:dDs:hvo:k", longOptions,
1290 &optionIndex)) != EOF) {
1293 switch (optionIndex) {
1301 Log::setLogRule(optarg);
1319 runAsDaemon =
false;
1322 exitWhenMainDisplayDisconnected =
false;
1325 overrideDelay = std::atoi(optarg);
1336 addonOptionString = optarg;
1347 std::unordered_map<std::string, std::vector<std::string>> addonOptions;
1348 for (
const std::string_view item :
1351 if (tokens.size() != 2) {
1356 addonOptions_ = std::move(addonOptions);
1364 d->signalPipe_ = fd;
1365 d->signalPipeEvent_ = d->eventLoop_.addIOEvent(
1375 return d->arg_.tryReplace;
1380 return d->arg_.exitWhenMainDisplayDisconnected;
1388 void Instance::handleSignal() {
1392 while (
fs::safeRead(d->signalPipe_, &signo,
sizeof(signo)) > 0) {
1393 if (signo == SIGINT || signo == SIGTERM || signo == SIGQUIT ||
1396 }
else if (signo == SIGUSR1) {
1398 }
else if (signo == SIGCHLD) {
1399 d->zombieReaper_->setNextInterval(2000000);
1400 d->zombieReaper_->setOneShot();
1408 if (!d->arg_.uiName.empty()) {
1409 d->arg_.enableList.push_back(d->arg_.uiName);
1412 d->icManager_.registerProperty(
"inputState", &d->inputStateFactory_);
1413 std::unordered_set<std::string> enabled;
1414 std::unordered_set<std::string> disabled;
1415 std::tie(enabled, disabled) = d->overrideAddons();
1416 FCITX_INFO() <<
"Override Enabled Addons: " << enabled;
1417 FCITX_INFO() <<
"Override Disabled Addons: " << disabled;
1418 d->addonManager_.load(enabled, disabled);
1423 d->uiManager_.load(d->arg_.uiName);
1425 const auto *entry = d->imManager_.entry(
"keyboard-us");
1426 FCITX_LOG_IF(Error, !entry) <<
"Couldn't find keyboard-us";
1427 d->preloadInputMethodEvent_ = d->eventLoop_.addTimeEvent(
1428 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, 0,
1431 if (d->exit_ || !d->globalConfig_.preloadInputMethod()) {
1435 if (!d->imManager_.currentGroup().inputMethodList().empty()) {
1436 if (
const auto *entry =
1437 d->imManager_.entry(d->imManager_.currentGroup()
1438 .inputMethodList()[0]
1440 d->addonManager_.addon(entry->addon(),
true);
1444 if (!d->imManager_.currentGroup().defaultInputMethod().empty()) {
1445 if (
const auto *entry = d->imManager_.entry(
1446 d->imManager_.currentGroup().defaultInputMethod())) {
1447 d->addonManager_.addon(entry->addon(),
true);
1453 d->zombieReaper_ = d->eventLoop_.addTimeEvent(
1454 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 0,
1457 while ((res = waitpid(-1,
nullptr, WNOHANG)) > 0) {
1461 d->zombieReaper_->setEnabled(
false);
1464 d->exitEvent_ = d->eventLoop_.addExitEvent([
this](
EventSource *) {
1465 FCITX_DEBUG() <<
"Running save...";
1469 d->notifications_ = d->addonManager_.addon(
"notifications",
true);
1474 if (d->arg_.quietQuit) {
1481 return d->exitCode_;
1484 auto r = eventLoop().exec();
1485 d->running_ =
false;
1487 return r ? d->exitCode_ : 1;
1492 d->running_ = running;
1502 return d->inputMethodMode_;
1507 if (d->inputMethodMode_ == mode) {
1510 d->inputMethodMode_ = mode;
1519 bool Instance::virtualKeyboardAutoShow()
const {
1521 return d->virtualKeyboardAutoShow_;
1524 void Instance::setVirtualKeyboardAutoShow(
bool autoShow) {
1526 d->virtualKeyboardAutoShow_ = autoShow;
1529 bool Instance::virtualKeyboardAutoHide()
const {
1531 return d->virtualKeyboardAutoHide_;
1534 void Instance::setVirtualKeyboardAutoHide(
bool autoHide) {
1536 d->virtualKeyboardAutoHide_ = autoHide;
1539 VirtualKeyboardFunctionMode Instance::virtualKeyboardFunctionMode()
const {
1541 return d->virtualKeyboardFunctionMode_;
1544 void Instance::setVirtualKeyboardFunctionMode(
1545 VirtualKeyboardFunctionMode mode) {
1547 d->virtualKeyboardFunctionMode_ = mode;
1552 d->binaryMode_ =
true;
1557 const auto &addonNames = d->addonManager_.loadedAddonNames();
1558 return d->binaryMode_ &&
1559 std::all_of(addonNames.begin(), addonNames.end(),
1560 [d](
const std::string &name) {
1561 auto *addon = d->addonManager_.lookupAddon(name);
1565 return addon->canRestart();
1569 InstancePrivate *Instance::privateData() {
1576 return d->eventLoop_;
1581 return d->eventDispatcher_;
1586 return d->icManager_;
1591 return d->addonManager_;
1596 return d->imManager_;
1601 return d->imManager_;
1606 return d->uiManager_;
1611 return d->globalConfig_;
1614 bool Instance::postEvent(
Event &event) {
1615 return std::as_const(*this).postEvent(event);
1618 bool Instance::postEvent(
Event &event)
const {
1623 auto iter = d->eventHandlers_.find(event.
type());
1624 if (iter != d->eventHandlers_.end()) {
1625 const auto &handlers = iter->second;
1626 EventWatcherPhase phaseOrder[] = {
1627 EventWatcherPhase::ReservedFirst, EventWatcherPhase::PreInputMethod,
1628 EventWatcherPhase::InputMethod, EventWatcherPhase::PostInputMethod,
1629 EventWatcherPhase::ReservedLast};
1631 for (
auto phase : phaseOrder) {
1632 if (
auto iter2 = handlers.find(phase); iter2 != handlers.end()) {
1633 for (
auto &handler : iter2->second.view()) {
1648 auto &keyEvent =
static_cast<KeyEvent &
>(event);
1649 auto *ic = keyEvent.inputContext();
1650 #ifdef ENABLE_KEYBOARD 1652 if (!keyEvent.forward() && !keyEvent.origKey().code()) {
1655 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1656 auto *xkbState = inputState->customXkbState();
1663 xkb_state_update_key(xkbState, keyEvent.origKey().code(),
1664 keyEvent.isRelease() ? XKB_KEY_UP
1668 if (ic->capabilityFlags().test(CapabilityFlag::KeyEventOrderFix) &&
1669 !keyEvent.accepted() && ic->hasPendingEventsStrictOrder()) {
1672 keyEvent.filterAndAccept();
1673 ic->forwardKey(keyEvent.origKey(), keyEvent.isRelease(),
1676 d_ptr->uiManager_.flush();
1679 return event.accepted();
1682 std::unique_ptr<HandlerTableEntry<EventHandler>>
1684 EventHandler callback) {
1686 if (phase == EventWatcherPhase::ReservedFirst ||
1687 phase == EventWatcherPhase::ReservedLast) {
1688 throw std::invalid_argument(
"Reserved Phase is only for internal use");
1690 return d->watchEvent(type, phase, std::move(callback));
1693 bool groupContains(
const InputMethodGroup &group,
const std::string &name) {
1694 const auto &list = group.inputMethodList();
1695 auto iter = std::find_if(list.begin(), list.end(),
1697 return item.name() == name;
1699 return iter != list.end();
1704 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1707 if (!inputState->overrideDeactivateIM_.empty()) {
1708 return inputState->overrideDeactivateIM_;
1711 const auto &group = d->imManager_.currentGroup();
1714 !d->globalConfig_.allowInputMethodForPassword())) {
1715 auto defaultLayoutIM =
1716 stringutils::concat(
"keyboard-", group.defaultLayout());
1717 const auto *entry = d->imManager_.entry(defaultLayoutIM);
1719 entry = d->imManager_.entry(
"keyboard-us");
1721 return entry ? entry->uniqueName() :
"";
1724 if (group.inputMethodList().empty()) {
1727 if (inputState->isActive()) {
1728 if (!inputState->localIM_.empty() &&
1729 groupContains(group, inputState->localIM_)) {
1730 return inputState->localIM_;
1732 return group.defaultInputMethod();
1735 return group.inputMethodList()[0].name();
1740 auto imName = inputMethod(ic);
1741 if (imName.empty()) {
1744 return d->imManager_.entry(imName);
1749 const auto *entry = inputMethodEntry(ic);
1754 d->addonManager_.addon(entry->addon(),
true));
1759 const auto *entry = d->imManager_.entry(name);
1764 d->addonManager_.addon(entry->addon(),
true));
1769 const auto *entry = inputMethodEntry(ic);
1771 auto *engine = inputMethodEngine(ic);
1773 icon = engine->subModeIcon(*entry, *ic);
1776 icon = entry->icon();
1779 icon =
"input-keyboard";
1787 const auto *entry = inputMethodEntry(ic);
1788 auto *engine = inputMethodEngine(ic);
1790 if (engine && entry) {
1791 label = engine->subModeLabel(*entry, *ic);
1793 if (label.empty() && entry) {
1794 label = entry->label();
1800 #ifdef ENABLE_KEYBOARD 1802 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1804 auto *xkbComposeState = state->xkbComposeState();
1805 if (!xkbComposeState) {
1809 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1811 enum xkb_compose_feed_result result =
1812 xkb_compose_state_feed(xkbComposeState, keyval);
1813 if (result == XKB_COMPOSE_FEED_IGNORED) {
1817 enum xkb_compose_status status =
1818 xkb_compose_state_get_status(xkbComposeState);
1819 if (status == XKB_COMPOSE_NOTHING) {
1822 if (status == XKB_COMPOSE_COMPOSED) {
1823 char buffer[FCITX_UTF8_MAX_LENGTH + 1] = {
'\0',
'\0',
'\0',
'\0',
1826 xkb_compose_state_get_utf8(xkbComposeState, buffer,
sizeof(buffer));
1827 xkb_compose_state_reset(xkbComposeState);
1829 return FCITX_INVALID_COMPOSE_RESULT;
1835 if (status == XKB_COMPOSE_CANCELLED) {
1836 xkb_compose_state_reset(xkbComposeState);
1839 return FCITX_INVALID_COMPOSE_RESULT;
1842 FCITX_UNUSED(keysym);
1849 #ifdef ENABLE_KEYBOARD 1851 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1853 auto *xkbComposeState = state->xkbComposeState();
1854 if (!xkbComposeState) {
1855 return std::string();
1858 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1859 enum xkb_compose_feed_result result =
1860 xkb_compose_state_feed(xkbComposeState, keyval);
1862 if (result == XKB_COMPOSE_FEED_IGNORED) {
1863 return std::string();
1866 enum xkb_compose_status status =
1867 xkb_compose_state_get_status(xkbComposeState);
1868 if (status == XKB_COMPOSE_NOTHING) {
1869 return std::string();
1871 if (status == XKB_COMPOSE_COMPOSED) {
1873 std::array<char, 256> buffer;
1874 auto length = xkb_compose_state_get_utf8(xkbComposeState, buffer.data(),
1876 xkb_compose_state_reset(xkbComposeState);
1878 return std::nullopt;
1881 auto bufferBegin = buffer.begin();
1882 auto bufferEnd = std::next(bufferBegin,
length);
1884 return std::string(bufferBegin, bufferEnd);
1886 return std::nullopt;
1888 if (status == XKB_COMPOSE_CANCELLED) {
1889 xkb_compose_state_reset(xkbComposeState);
1891 return std::nullopt;
1894 FCITX_UNUSED(keysym);
1895 return std::string();
1900 #ifdef ENABLE_KEYBOARD 1902 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1904 auto *xkbComposeState = state->xkbComposeState();
1905 if (!xkbComposeState) {
1909 return xkb_compose_state_get_status(xkbComposeState) ==
1910 XKB_COMPOSE_COMPOSING;
1912 FCITX_UNUSED(inputContext);
1918 #ifdef ENABLE_KEYBOARD 1920 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1921 auto *xkbComposeState = state->xkbComposeState();
1922 if (!xkbComposeState) {
1925 xkb_compose_state_reset(xkbComposeState);
1927 FCITX_UNUSED(inputContext);
1934 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
1935 d->imManager_.save();
1936 d->addonManager_.saveAll();
1941 if (
auto *ic = mostRecentInputContext()) {
1942 CheckInputMethodChanged imChangedRAII(ic, d);
1949 if (
const auto *entry = inputMethodManager().entry(imName)) {
1950 return entry->uniqueName();
1960 void Instance::configureAddon(
const std::string & ) {}
1962 void Instance::configureInputMethod(
const std::string & ) {}
1965 if (
auto *ic = mostRecentInputContext()) {
1966 if (
const auto *entry = inputMethodEntry(ic)) {
1967 return entry->uniqueName();
1975 return d->uiManager_.currentUI();
1980 if (
auto *ic = mostRecentInputContext()) {
1981 CheckInputMethodChanged imChangedRAII(ic, d);
1991 d->exitCode_ = exitCode;
1993 d->eventLoop_.exit();
1998 auto *addon = addonManager().addon(addonName);
2000 addon->reloadConfig();
2006 auto [enabled, disabled] = d->overrideAddons();
2007 d->addonManager_.load(enabled, disabled);
2008 d->imManager_.refresh();
2013 readAsIni(d->globalConfig_.config(), StandardPathsType::PkgConfig,
2015 FCITX_DEBUG() <<
"Trigger Key: " 2017 d->icManager_.setPropertyPropagatePolicy(
2018 d->globalConfig_.shareInputState());
2019 if (d->globalConfig_.preeditEnabledByDefault() !=
2020 d->icManager_.isPreeditEnabledByDefault()) {
2021 d->icManager_.setPreeditEnabledByDefault(
2022 d->globalConfig_.preeditEnabledByDefault());
2028 #ifdef ENABLE_KEYBOARD 2029 d->keymapCache_.clear();
2030 if (d->inputStateFactory_.registered()) {
2032 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2033 inputState->resetXkbState();
2042 if (d->globalConfig_.autoSavePeriod() <= 0) {
2043 d->periodicalSave_->setEnabled(
false);
2045 d->periodicalSave_->setNextInterval(AutoSaveMinInUsecs *
2046 d->globalConfig_.autoSavePeriod());
2047 d->periodicalSave_->setOneShot();
2058 if (!canRestart()) {
2066 setCurrentInputMethod(mostRecentInputContext(), name,
false);
2072 if (!canTrigger()) {
2076 auto &imManager = inputMethodManager();
2077 const auto &imList = imManager.currentGroup().inputMethodList();
2078 auto iter = std::find_if(imList.begin(), imList.end(),
2080 return item.name() == name;
2082 if (iter == imList.end()) {
2086 auto setGlobalDefaultInputMethod = [d](
const std::string &name) {
2087 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2088 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2090 groupRAIICheck.push_back(
2091 std::make_unique<CheckInputMethodChanged>(ic, d));
2094 d->imManager_.setDefaultInputMethod(name);
2097 auto idx = std::distance(imList.begin(), iter);
2099 CheckInputMethodChanged imChangedRAII(ic, d);
2100 auto currentIM = inputMethod(ic);
2101 if (currentIM == name) {
2104 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2108 inputState->setLocalIM(name);
2110 inputState->setLocalIM({});
2112 setGlobalDefaultInputMethod(name);
2114 inputState->setActive(
true);
2116 inputState->setActive(
false);
2118 if (inputState->imChanged_) {
2128 setGlobalDefaultInputMethod(name);
2136 if (
auto *ic = mostRecentInputContext()) {
2137 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
2138 return inputState->isActive() ? 2 : 1;
2145 if (
auto *ic = mostRecentInputContext()) {
2146 CheckInputMethodChanged imChangedRAII(ic, d);
2153 if (
auto *ic = mostRecentInputContext()) {
2154 CheckInputMethodChanged imChangedRAII(ic, d);
2155 enumerate(ic, forward);
2159 bool Instance::canTrigger()
const {
2160 const auto &imManager = inputMethodManager();
2161 return (imManager.currentGroup().inputMethodList().size() > 1);
2165 if (!canTrigger()) {
2169 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2170 if (inputState->isActive()) {
2173 return inputState->lastIMChangeIsAltTrigger_;
2178 if (!canTrigger()) {
2182 if (d->globalConfig_.enumerateSkipFirst()) {
2183 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2184 if (!inputState->isActive()) {
2187 return d->imManager_.currentGroup().inputMethodList().size() > 2;
2193 bool Instance::canChangeGroup()
const {
2194 const auto &imManager = inputMethodManager();
2195 return (imManager.groupCount() > 1);
2200 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2201 if (!canTrigger()) {
2204 inputState->setActive(!inputState->isActive());
2205 if (inputState->imChanged_) {
2206 inputState->imChanged_->setReason(reason);
2211 bool Instance::trigger(
InputContext *ic,
bool totallyReleased) {
2213 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2214 if (!canTrigger()) {
2219 if (totallyReleased) {
2221 inputState->firstTrigger_ =
true;
2223 if (!d->globalConfig_.enumerateWithTriggerKeys() ||
2224 (inputState->firstTrigger_ && inputState->isActive()) ||
2225 (d->globalConfig_.enumerateSkipFirst() &&
2226 d->imManager_.currentGroup().inputMethodList().size() <= 2)) {
2229 enumerate(ic,
true);
2231 inputState->firstTrigger_ =
false;
2237 if (!canAltTrigger(ic)) {
2247 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2248 if (!canTrigger()) {
2251 if (inputState->isActive()) {
2254 inputState->setActive(
true);
2255 if (inputState->imChanged_) {
2263 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2264 if (!canTrigger()) {
2267 if (!inputState->isActive()) {
2270 inputState->setActive(
false);
2271 if (inputState->imChanged_) {
2272 inputState->imChanged_->setReason(
2280 auto &imManager = inputMethodManager();
2281 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2282 const auto &imList = imManager.currentGroup().inputMethodList();
2283 if (!canTrigger()) {
2287 if (d->globalConfig_.enumerateSkipFirst() && imList.size() <= 2) {
2291 auto currentIM = inputMethod(ic);
2293 auto iter = std::ranges::find_if(
2295 return item.name() == currentIM;
2297 if (iter == imList.end()) {
2300 int idx = std::distance(imList.begin(), iter);
2301 auto nextIdx = [forward, &imList](
int idx) {
2303 return (idx + (forward ? 1 : (imList.size() - 1))) % imList.size();
2307 if (d->globalConfig_.enumerateSkipFirst() && idx == 0) {
2311 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2312 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2314 groupRAIICheck.push_back(
2315 std::make_unique<CheckInputMethodChanged>(ic, d));
2318 imManager.setDefaultInputMethod(imList[idx].name());
2319 inputState->setActive(
true);
2320 inputState->setLocalIM({});
2322 inputState->setActive(
false);
2324 if (inputState->imChanged_) {
2332 const std::string &orig) {
2333 std::string result = orig;
2334 emit<Instance::CommitFilter>(inputContext, result);
2340 emit<Instance::OutputFilter>(inputContext, result);
2341 if ((&orig == &inputContext->inputPanel().clientPreedit() ||
2342 &orig == &inputContext->inputPanel().preedit()) &&
2343 !globalConfig().showPreeditForPassword() &&
2344 inputContext->capabilityFlags().test(CapabilityFlag::Password)) {
2346 for (
int i = 0, e = result.size(); i < e; i++) {
2351 dot +=
"\xe2\x80\xa2";
2354 newText.append(std::move(dot),
2355 result.formatAt(i) | TextFormatFlag::DontCommit);
2357 result = std::move(newText);
2364 return d->icManager_.lastFocusedInputContext();
2369 return d->icManager_.mostRecentInputContext();
2374 d->uiManager_.flush();
2377 int scoreForGroup(
FocusGroup *group,
const std::string &displayHint) {
2379 if (displayHint.empty()) {
2380 if (group->display() ==
"x11:") {
2386 if (group->display() ==
"wayland:") {
2393 if (group->display() == displayHint) {
2408 d->icManager_.foreachGroup(
2409 [&score, &displayHint, &defaultFocusGroup](
FocusGroup *group) {
2410 auto newScore = scoreForGroup(group, displayHint);
2411 if (newScore > score) {
2412 defaultFocusGroup = group;
2418 return defaultFocusGroup;
2423 FCITX_DEBUG() <<
"Instance::activateInputMethod";
2425 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2426 const auto *entry = inputMethodEntry(ic);
2428 FCITX_DEBUG() <<
"Activate: " 2429 <<
"[Last]:" << inputState->lastIM_
2430 <<
" [Activating]:" << entry->uniqueName();
2431 assert(inputState->lastIM_.empty());
2432 inputState->lastIM_ = entry->uniqueName();
2434 auto *engine = inputMethodEngine(ic);
2435 if (!engine || !entry) {
2438 #ifdef ENABLE_KEYBOARD 2439 if (
auto *xkbState = inputState->customXkbState(
true)) {
2440 if (
auto *mods = findValue(d->stateMask_, ic->
display())) {
2441 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
2442 auto depressed = std::get<0>(*mods);
2443 auto latched = std::get<1>(*mods);
2444 auto locked = std::get<2>(*mods);
2449 FCITX_KEYTRACE() << depressed <<
" " << latched <<
" " << locked;
2450 if (depressed == 0) {
2451 inputState->setModsAllReleased();
2453 xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0,
2459 engine->activate(*entry, event);
2465 FCITX_DEBUG() <<
"Instance::deactivateInputMethod event_type=" 2466 <<
static_cast<uint32_t
>(
event.type());
2468 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2475 FCITX_DEBUG() <<
"Switch reason: " 2476 <<
static_cast<int>(icEvent.reason());
2477 FCITX_DEBUG() <<
"Old Input method: " << icEvent.oldInputMethod();
2478 entry = d->imManager_.entry(icEvent.oldInputMethod());
2480 entry = inputMethodEntry(ic);
2483 FCITX_DEBUG() <<
"Deactivate: " 2484 <<
"[Last]:" << inputState->lastIM_
2485 <<
" [Deactivating]:" << entry->uniqueName();
2486 assert(entry->uniqueName() == inputState->lastIM_);
2488 d->addonManager_.addon(entry->addon()));
2490 inputState->lastIM_.clear();
2491 if (!engine || !entry) {
2494 inputState->overrideDeactivateIM_ = entry->uniqueName();
2496 inputState->overrideDeactivateIM_.clear();
2500 bool Instance::enumerateGroup(
bool forward) {
2501 auto &imManager = inputMethodManager();
2502 auto groups = imManager.groups();
2503 if (groups.size() <= 1) {
2507 imManager.setCurrentGroup(groups[1]);
2509 imManager.setCurrentGroup(groups.back());
2515 FCITX_DEBUG() <<
"Input method switched";
2517 if (!d->globalConfig_.showInputMethodInformation()) {
2520 d->showInputMethodInformation(ic);
2524 const std::string &message) {
2525 FCITX_DEBUG() <<
"Input method switched";
2527 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2528 inputState->showInputMethodInformation(message);
2533 return (isInFlatpak() &&
2534 std::filesystem::is_regular_file(
"/app/.updated")) ||
2535 d->addonManager_.checkUpdate() || d->imManager_.checkUpdate() ||
2540 const std::string &rule,
2541 const std::string &model,
2542 const std::string &options) {
2543 #ifdef ENABLE_KEYBOARD 2545 bool resetState =
false;
2546 if (
auto *param = findValue(d->xkbParams_, display)) {
2547 if (std::get<0>(*param) != rule || std::get<1>(*param) != model ||
2548 std::get<2>(*param) != options) {
2549 std::get<0>(*param) = rule;
2550 std::get<1>(*param) = model;
2551 std::get<2>(*param) = options;
2555 d->xkbParams_.emplace(display, std::make_tuple(rule, model, options));
2559 d->keymapCache_[display].clear();
2560 d->icManager_.foreach([d, &display](
InputContext *ic) {
2561 if (ic->
display() == display ||
2562 !d->xkbParams_.contains(ic->
display())) {
2563 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2564 inputState->resetXkbState();
2570 FCITX_UNUSED(display);
2572 FCITX_UNUSED(model);
2573 FCITX_UNUSED(options);
2578 uint32_t depressed_mods,
2579 uint32_t latched_mods, uint32_t locked_mods) {
2581 d->stateMask_[display] =
2582 std::make_tuple(depressed_mods, latched_mods, locked_mods);
2587 d->stateMask_.erase(display);
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.
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.
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.
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.
bool startsWith(std::string_view str, std::string_view prefix)
Check if a string starts with a prefix.
void showInputMethodInformation(InputContext *ic)
Show a small popup with input popup window with current input method information. ...
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.
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.