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);
136 bool isInputMethodDisabled(
const CapabilityFlags &flags,
137 bool allowInputMethodForPassword) {
139 (flags.test(CapabilityFlag::Password) &&
140 !allowInputMethodForPassword);
144 bool shouldSwitchIM(
const CapabilityFlags &oldFlags,
145 const CapabilityFlags &newFlags,
146 bool allowInputMethodForPassword) {
147 return isInputMethodDisabled(oldFlags, allowInputMethodForPassword) !=
148 isInputMethodDisabled(newFlags, allowInputMethodForPassword);
153 void InstanceArgument::printUsage()
const {
155 <<
"Usage: " << argv0 <<
" [Option]\n" 156 <<
" --disable <addon names>\tA comma separated list of addons to " 158 <<
"\t\t\t\t\"all\" can be used to disable all addons.\n" 159 <<
" --enable <addon names>\tA comma separated list of addons to " 161 <<
"\t\t\t\t\"all\" can be used to enable all addons.\n" 162 <<
"\t\t\t\tThis value will override the value in the flag " 164 <<
" --verbose <logging rule>\tSet the logging rule for " 165 "displaying message.\n" 166 <<
"\t\t\t\tSyntax: category1=level1,category2=level2, ...\n" 167 <<
"\t\t\t\tE.g. default=4,key_trace=5\n" 168 <<
"\t\t\t\tLevels are numbers ranging from 0 to 5.\n" 169 <<
"\t\t\t\t\t0 - NoLog\n" 170 <<
"\t\t\t\t\t1 - Fatal\n" 171 <<
"\t\t\t\t\t2 - Error\n" 172 <<
"\t\t\t\t\t3 - Warn\n" 173 <<
"\t\t\t\t\t4 - Info (default)\n" 174 <<
"\t\t\t\t\t5 - Debug\n" 175 <<
"\t\t\t\tSome built-in categories are:\n" 176 <<
"\t\t\t\t\tdefault - miscellaneous category used by fcitx own " 178 <<
"\t\t\t\t\tkey_trace - print the key event received by fcitx.\n" 179 <<
"\t\t\t\t\t\"*\" may be used to represent all logging " 181 <<
" -u, --ui <addon name>\t\tSet the UI addon to be used.\n" 182 <<
" -d\t\t\t\tRun as a daemon.\n" 183 <<
" -D\t\t\t\tDo not run as a daemon (default).\n" 184 <<
" -s <seconds>\t\t\tNumber of seconds to wait before start.\n" 185 <<
" -k, --keep\t\t\tKeep running even the main display is " 187 <<
" -r, --replace\t\t\tReplace the existing instance.\n" 188 <<
" -o --option <option>\t\tPass the option to addons\n" 189 <<
"\t\t\t\t<option> is in format like:\n" 190 <<
"\t\t\t\tname1=opt1a:opt1b,name2=opt2a:opt2b... .\n" 191 <<
" -v, --version\t\t\tShow version and quit.\n" 192 <<
" -h, --help\t\t\tShow this help message and quit.\n";
195 InstancePrivate::InstancePrivate(Instance *q) : QPtrHolder<Instance>(q) {
196 #ifdef ENABLE_KEYBOARD 197 const auto &locale = getCurrentLocale();
198 assert(!locale.empty());
199 xkbContext_.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
201 xkb_context_set_log_level(xkbContext_.get(), XKB_LOG_LEVEL_CRITICAL);
202 xkbComposeTable_.reset(xkb_compose_table_new_from_locale(
203 xkbContext_.get(), locale.data(), XKB_COMPOSE_COMPILE_NO_FLAGS));
204 if (!xkbComposeTable_) {
206 <<
"Trying to fallback to compose table for en_US.UTF-8";
207 xkbComposeTable_.reset(xkb_compose_table_new_from_locale(
208 xkbContext_.get(),
"en_US.UTF-8",
209 XKB_COMPOSE_COMPILE_NO_FLAGS));
211 if (!xkbComposeTable_) {
213 <<
"No compose table is loaded, you may want to check your " 220 std::unique_ptr<HandlerTableEntry<EventHandler>>
221 InstancePrivate::watchEvent(
EventType type, EventWatcherPhase phase,
222 EventHandler callback) {
223 return eventHandlers_[type][phase].add(std::move(callback));
226 #ifdef ENABLE_KEYBOARD 227 xkb_keymap *InstancePrivate::keymap(
const std::string &display,
228 const std::string &layout,
229 const std::string &variant) {
230 auto layoutAndVariant = stringutils::concat(layout,
"-", variant);
231 if (
auto *keymapPtr = findValue(keymapCache_[display], layoutAndVariant)) {
232 return (*keymapPtr).get();
234 struct xkb_rule_names names;
235 names.layout = layout.c_str();
236 names.variant = variant.c_str();
237 std::tuple<std::string, std::string, std::string> xkbParam;
238 if (
auto *param = findValue(xkbParams_, display)) {
241 if (!xkbParams_.empty()) {
242 xkbParam = xkbParams_.begin()->second;
244 xkbParam = std::make_tuple(DEFAULT_XKB_RULES,
"pc101",
"");
247 if (globalConfig_.overrideXkbOption()) {
248 std::get<2>(xkbParam) = globalConfig_.customXkbOption();
250 names.rules = std::get<0>(xkbParam).c_str();
251 names.model = std::get<1>(xkbParam).c_str();
252 names.options = std::get<2>(xkbParam).c_str();
253 UniqueCPtr<xkb_keymap, xkb_keymap_unref> keymap(xkb_keymap_new_from_names(
254 xkbContext_.get(), &names, XKB_KEYMAP_COMPILE_NO_FLAGS));
256 keymapCache_[display].emplace(layoutAndVariant, std::move(keymap));
257 assert(result.second);
258 return result.first->second.get();
262 std::pair<std::unordered_set<std::string>, std::unordered_set<std::string>>
263 InstancePrivate::overrideAddons() {
264 std::unordered_set<std::string> enabled;
265 std::unordered_set<std::string> disabled;
266 for (
const auto &addon : globalConfig_.enabledAddons()) {
267 enabled.insert(addon);
269 for (
const auto &addon : globalConfig_.disabledAddons()) {
270 enabled.erase(addon);
271 disabled.insert(addon);
273 for (
const auto &addon : arg_.enableList) {
274 disabled.erase(addon);
275 enabled.insert(addon);
277 for (
const auto &addon : arg_.disableList) {
278 enabled.erase(addon);
279 disabled.insert(addon);
281 return {enabled, disabled};
284 void InstancePrivate::buildDefaultGroup() {
286 auto *defaultGroup = q_func()->defaultFocusGroup();
287 bool infoFound =
false;
289 std::string variants;
290 auto guessLayout = [
this, &layouts, &variants,
291 &infoFound](FocusGroup *focusGroup) {
293 if (!focusGroup->display().starts_with(
"x11:")) {
297 auto *xcb = addonManager_.addon(
"xcb");
298 auto x11Name = focusGroup->display().substr(4);
300 auto rules = xcb->call<IXCBModule::xkbRulesNames>(x11Name);
301 if (!rules[2].
empty()) {
310 FCITX_UNUSED(layouts);
311 FCITX_UNUSED(variants);
312 FCITX_UNUSED(infoFound);
316 if (!defaultGroup || guessLayout(defaultGroup)) {
317 icManager_.foreachGroup(
318 [defaultGroup, &guessLayout](FocusGroup *focusGroup) {
319 if (defaultGroup == focusGroup) {
322 return guessLayout(focusGroup);
331 constexpr
char imNamePrefix[] =
"keyboard-";
335 variants,
",", stringutils::SplitBehavior::KeepEmpty);
336 auto size = std::max(layoutTokens.size(), variantTokens.size());
338 layoutTokens.resize(size);
339 variantTokens.resize(size);
341 OrderedSet<std::string> imLayouts;
342 for (decltype(size) i = 0; i < size; i++) {
343 if (layoutTokens[i].
empty()) {
346 std::string layoutName = layoutTokens[i];
347 if (!variantTokens[i].
empty()) {
348 layoutName = stringutils::concat(layoutName,
"-", variantTokens[i]);
352 if (!imManager_.entry(stringutils::concat(imNamePrefix, layoutName))) {
356 imLayouts.pushBack(layoutName);
360 auto lang = stripLanguage(getCurrentLanguage());
361 DefaultInputMethod defaultIMConfig;
362 readAsIni(defaultIMConfig, StandardPathsType::PkgData,
363 std::filesystem::path(
"default") / lang);
366 for (
const auto &extraLayout : defaultIMConfig.extraLayouts.value()) {
367 if (!imManager_.entry(stringutils::concat(imNamePrefix, extraLayout))) {
370 imLayouts.pushBack(extraLayout);
374 if (imLayouts.empty()) {
375 imLayouts.pushBack(
"us");
379 std::string defaultIM;
380 for (
const auto &im : defaultIMConfig.defaultInputMethods.value()) {
381 if (imManager_.entry(im)) {
388 std::vector<std::string> groupOrders;
389 for (
const auto &imLayout : imLayouts) {
390 std::string groupName;
391 if (imLayouts.size() == 1) {
392 groupName = _(
"Default");
394 groupName = _(
"Group {}", imManager_.groupCount() + 1);
396 imManager_.addEmptyGroup(groupName);
397 groupOrders.push_back(groupName);
398 InputMethodGroup group(groupName);
399 group.inputMethodList().emplace_back(
400 InputMethodGroupItem(stringutils::concat(imNamePrefix, imLayout)));
401 if (!defaultIM.empty()) {
402 group.inputMethodList().emplace_back(
403 InputMethodGroupItem(defaultIM));
405 FCITX_INFO() <<
"Items in " << groupName <<
": " 406 << group.inputMethodList();
407 group.setDefaultLayout(imLayout);
408 imManager_.setGroup(std::move(group));
410 FCITX_INFO() <<
"Generated groups: " << groupOrders;
411 imManager_.setGroupOrder(groupOrders);
414 void InstancePrivate::showInputMethodInformation(InputContext *ic) {
416 auto *inputState = ic->propertyFor(&inputStateFactory_);
417 auto *engine = q->inputMethodEngine(ic);
418 const auto *entry = q->inputMethodEntry(ic);
419 auto &imManager = q->inputMethodManager();
421 if (!inputState->isActive() &&
422 !globalConfig_.showFirstInputMethodInformation()) {
428 auto subMode = engine->subMode(*entry, *ic);
429 auto subModeLabel = engine->subModeLabel(*entry, *ic);
430 auto name = globalConfig_.compactInputMethodInformation() &&
431 !entry->label().empty()
434 if (globalConfig_.compactInputMethodInformation() &&
435 !subModeLabel.empty()) {
436 display = std::move(subModeLabel);
437 }
else if (subMode.empty()) {
438 display = std::move(name);
440 display = _(
"{0} ({1})", name, subMode);
443 display = _(
"{0} (Not available)", entry->name());
445 display = _(
"(Not available)");
447 if (!globalConfig_.compactInputMethodInformation() &&
448 imManager.groupCount() > 1) {
449 display = _(
"Group {0}: {1}", imManager.currentGroup().name(), display);
451 inputState->showInputMethodInformation(display);
454 bool InstancePrivate::canActivate(InputContext *ic) {
456 if (!q->canTrigger()) {
459 auto *inputState = ic->propertyFor(&inputStateFactory_);
460 return !inputState->isActive();
463 bool InstancePrivate::canDeactivate(InputContext *ic) {
465 if (!q->canTrigger()) {
468 auto *inputState = ic->propertyFor(&inputStateFactory_);
469 return inputState->isActive();
472 void InstancePrivate::navigateGroup(InputContext *ic,
const Key &key,
474 auto *inputState = ic->propertyFor(&inputStateFactory_);
475 inputState->pendingGroupIndex_ =
476 (inputState->pendingGroupIndex_ +
477 (forward ? 1 : imManager_.groupCount() - 1)) %
478 imManager_.groupCount();
479 FCITX_DEBUG() <<
"Switch to group " << inputState->pendingGroupIndex_;
481 if (notifications_ && !isSingleKey(key)) {
482 notifications_->call<INotifications::showTip>(
483 "enumerate-group", _(
"Input Method"),
"input-keyboard",
485 _(
"Switch group to {0}",
486 imManager_.groups()[inputState->pendingGroupIndex_]),
491 void InstancePrivate::acceptGroupChange(
const Key &key, InputContext *ic) {
492 FCITX_DEBUG() <<
"Accept group change, isSingleKey: " << key;
494 auto *inputState = ic->propertyFor(&inputStateFactory_);
495 auto groups = imManager_.groups();
496 if (groups.size() > inputState->pendingGroupIndex_) {
497 if (isSingleKey(key)) {
498 FCITX_DEBUG() <<
"EnumerateGroupTo: " 499 << inputState->pendingGroupIndex_ <<
" " << key;
500 imManager_.enumerateGroupTo(groups[inputState->pendingGroupIndex_]);
502 FCITX_DEBUG() <<
"SetCurrentGroup: " 503 << inputState->pendingGroupIndex_ <<
" " << key;
504 imManager_.setCurrentGroup(groups[inputState->pendingGroupIndex_]);
507 inputState->pendingGroupIndex_ = 0;
510 InputState::InputState(InstancePrivate *d, InputContext *ic)
511 : d_ptr(d), ic_(ic) {
512 active_ = d->globalConfig_.activeByDefault();
513 #ifdef ENABLE_KEYBOARD 514 if (d->xkbComposeTable_) {
515 xkbComposeState_.reset(xkb_compose_state_new(
516 d->xkbComposeTable_.get(), XKB_COMPOSE_STATE_NO_FLAGS));
521 void InputState::showInputMethodInformation(
const std::string &name) {
522 ic_->inputPanel().setAuxUp(Text(name));
525 imInfoTimer_ = d_ptr->eventLoop_.addTimeEvent(
526 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, 0,
527 [
this](EventSourceTime *, uint64_t) {
528 hideInputMethodInfo();
533 #ifdef ENABLE_KEYBOARD 534 xkb_state *InputState::customXkbState(
bool refresh) {
535 auto *instance = d_ptr->q_func();
536 const InputMethodGroup &group = d_ptr->imManager_.currentGroup();
537 const auto im = instance->inputMethod(ic_);
538 auto layout = group.layoutFor(im);
539 if (layout.empty() && im.starts_with(
"keyboard-")) {
540 layout = im.substr(9);
542 if (layout.empty() || layout == group.defaultLayout()) {
545 modsAllReleased_ =
false;
546 lastXkbLayout_.clear();
550 if (layout == lastXkbLayout_ && !refresh) {
551 return xkbState_.get();
554 lastXkbLayout_ = layout;
555 const auto layoutAndVariant = parseLayout(layout);
556 if (
auto *keymap = d_ptr->keymap(ic_->display(), layoutAndVariant.first,
557 layoutAndVariant.second)) {
558 xkbState_.reset(xkb_state_new(keymap));
562 modsAllReleased_ =
false;
563 return xkbState_.get();
567 void InputState::setActive(
bool active) {
568 if (active_ != active) {
570 ic_->updateProperty(&d_ptr->inputStateFactory_);
574 void InputState::setLocalIM(
const std::string &localIM) {
575 if (localIM_ != localIM) {
577 ic_->updateProperty(&d_ptr->inputStateFactory_);
581 void InputState::copyTo(InputContextProperty *other) {
582 auto *otherState =
static_cast<InputState *
>(other);
583 if (otherState->active_ == active_ && otherState->localIM_ == localIM_) {
587 if (otherState->ic_->hasFocus()) {
588 FCITX_DEBUG() <<
"Sync state to focused ic: " 589 << otherState->ic_->program();
590 CheckInputMethodChanged imChangedRAII(otherState->ic_, d_ptr);
591 otherState->active_ = active_;
592 otherState->localIM_ = localIM_;
594 otherState->active_ = active_;
595 otherState->localIM_ = localIM_;
599 void InputState::reset() {
600 #ifdef ENABLE_KEYBOARD 601 if (xkbComposeState_) {
602 xkb_compose_state_reset(xkbComposeState_.get());
605 pendingGroupIndex_ = 0;
607 lastKeyPressed_ = Key();
608 lastKeyPressedTime_ = 0;
609 totallyReleased_ =
true;
612 void InputState::hideInputMethodInfo() {
616 imInfoTimer_.reset();
617 auto &panel = ic_->inputPanel();
618 if (panel.auxDown().empty() && panel.preedit().empty() &&
619 panel.clientPreedit().empty() &&
620 (!panel.candidateList() || panel.candidateList()->empty()) &&
621 panel.auxUp().size() == 1 && panel.auxUp().stringAt(0) == lastInfo_) {
627 #ifdef ENABLE_KEYBOARD 628 void InputState::resetXkbState() {
629 lastXkbLayout_.clear();
634 CheckInputMethodChanged::CheckInputMethodChanged(InputContext *ic,
635 InstancePrivate *instance)
636 : instance_(instance->q_func()), instancePrivate_(instance),
637 ic_(ic->watch()), inputMethod_(instance_->inputMethod(ic)),
639 auto *inputState = ic->propertyFor(&instance->inputStateFactory_);
640 if (!inputState->imChanged_) {
641 inputState->imChanged_ =
this;
647 CheckInputMethodChanged::~CheckInputMethodChanged() {
648 if (!ic_.isValid()) {
651 auto *ic = ic_.get();
652 auto *inputState = ic->propertyFor(&instancePrivate_->inputStateFactory_);
653 inputState->imChanged_ =
nullptr;
654 if (inputMethod_ != instance_->inputMethod(ic) && !ignore_) {
655 instance_->postEvent(
656 InputContextSwitchInputMethodEvent(reason_, inputMethod_, ic));
661 InstanceArgument arg;
662 arg.parseOption(argc, argv);
667 if (arg.runAsDaemon) {
671 if (arg.overrideDelay > 0) {
672 sleep(arg.overrideDelay);
676 d_ptr = std::make_unique<InstancePrivate>(
this);
679 d->eventDispatcher_.attach(&d->eventLoop_);
680 d->addonManager_.setInstance(
this);
681 d->addonManager_.setAddonOptions(arg.addonOptions_);
682 d->icManager_.setInstance(
this);
683 d->connections_.emplace_back(
684 d->imManager_.connect<InputMethodManager::CurrentGroupAboutToChange>(
685 [
this, d](
const std::string &lastGroup) {
686 d->icManager_.foreachFocused([this](InputContext *ic) {
687 assert(ic->hasFocus());
688 InputContextSwitchInputMethodEvent event(
689 InputMethodSwitchedReason::GroupChange, inputMethod(ic),
691 deactivateInputMethod(event);
694 d->lastGroup_ = lastGroup;
697 d->connections_.emplace_back(
698 d->imManager_.connect<InputMethodManager::CurrentGroupChanged>(
699 [
this, d](
const std::string &newGroup) {
700 d->icManager_.foreachFocused([this](InputContext *ic) {
701 assert(ic->hasFocus());
702 InputContextSwitchInputMethodEvent event(
703 InputMethodSwitchedReason::GroupChange,
"", ic);
704 activateInputMethod(event);
708 if (!d->lastGroup_.empty() && !newGroup.empty() &&
709 d->lastGroup_ != newGroup && d->notifications_ &&
710 d->imManager_.groupCount() > 1) {
711 d->notifications_->call<INotifications::showTip>(
712 "enumerate-group", _(
"Input Method"),
"input-keyboard",
714 _(
"Switched group to {0}",
715 d->imManager_.currentGroup().name()),
718 d->lastGroup_ = newGroup;
721 d->eventWatchers_.emplace_back(d->watchEvent(
722 EventType::InputContextCapabilityAboutToChange,
723 EventWatcherPhase::ReservedFirst, [
this, d](
Event &event) {
725 static_cast<CapabilityAboutToChangeEvent &>(event);
726 if (!capChanged.inputContext()->hasFocus()) {
731 capChanged.oldFlags(), capChanged.newFlags(),
732 d->globalConfig_.allowInputMethodForPassword())) {
738 inputMethod(capChanged.inputContext()),
739 capChanged.inputContext());
740 deactivateInputMethod(switchIM);
742 d->eventWatchers_.emplace_back(d->watchEvent(
743 EventType::InputContextCapabilityChanged,
744 EventWatcherPhase::ReservedFirst, [
this, d](
Event &event) {
745 auto &capChanged = static_cast<CapabilityChangedEvent &>(event);
746 if (!capChanged.inputContext()->hasFocus()) {
751 capChanged.oldFlags(), capChanged.newFlags(),
752 d->globalConfig_.allowInputMethodForPassword())) {
758 capChanged.inputContext());
759 activateInputMethod(switchIM);
762 d->eventWatchers_.emplace_back(watchEvent(
764 [
this, d](
Event &event) {
765 auto &keyEvent =
static_cast<KeyEvent &
>(event);
766 auto *ic = keyEvent.inputContext();
767 CheckInputMethodChanged imChangedRAII(ic, d);
768 auto origKey = keyEvent.origKey().normalize();
772 std::function<bool()> check;
773 std::function<void(bool)> trigger;
775 {.list = d->globalConfig_.triggerKeys(),
776 .check = [
this]() {
return canTrigger(); },
778 [
this, ic](
bool totallyReleased) {
779 return trigger(ic, totallyReleased);
781 {.list = d->globalConfig_.altTriggerKeys(),
782 .check = [
this, ic]() {
return canAltTrigger(ic); },
783 .trigger = [
this, ic](bool) {
return altTrigger(ic); }},
784 {.list = d->globalConfig_.activateKeys(),
785 .check = [ic, d]() {
return d->canActivate(ic); },
786 .trigger = [
this, ic](bool) {
return activate(ic); }},
787 {.list = d->globalConfig_.deactivateKeys(),
788 .check = [ic, d]() {
return d->canDeactivate(ic); },
789 .trigger = [
this, ic](bool) {
return deactivate(ic); }},
790 {.list = d->globalConfig_.enumerateForwardKeys(),
791 .check = [
this, ic]() {
return canEnumerate(ic); },
792 .trigger = [
this, ic](bool) {
return enumerate(ic,
true); }},
793 {.list = d->globalConfig_.enumerateBackwardKeys(),
794 .check = [
this, ic]() {
return canEnumerate(ic); },
795 .trigger = [
this, ic](bool) {
return enumerate(ic,
false); }},
796 {.list = d->globalConfig_.enumerateGroupForwardKeys(),
797 .check = [
this]() {
return canChangeGroup(); },
798 .trigger = [ic, d, origKey](
799 bool) { d->navigateGroup(ic, origKey,
true); }},
800 {.list = d->globalConfig_.enumerateGroupBackwardKeys(),
801 .check = [
this]() {
return canChangeGroup(); },
803 [ic, d, origKey](bool) {
804 d->navigateGroup(ic, origKey,
false);
808 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
809 int keyReleased = inputState->keyReleased_;
810 Key lastKeyPressed = inputState->lastKeyPressed_;
812 inputState->keyReleased_ = -1;
814 if (keyEvent.isRelease()) {
816 for (
auto &keyHandler : keyHandlers) {
817 if (keyReleased == idx &&
818 origKey.isReleaseOfModifier(lastKeyPressed) &&
819 keyHandler.check()) {
821 if (d->globalConfig_.checkModifierOnlyKeyTimeout(
822 inputState->lastKeyPressedTime_)) {
824 inputState->totallyReleased_);
826 inputState->lastKeyPressedTime_ = 0;
827 if (origKey.hasModifier()) {
828 inputState->totallyReleased_ =
false;
836 if (isSingleModifier(origKey)) {
837 inputState->totallyReleased_ =
true;
841 if (inputState->pendingGroupIndex_ &&
842 inputState->totallyReleased_) {
843 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
844 if (inputState->imChanged_) {
845 inputState->imChanged_->ignore();
847 d->acceptGroupChange(lastKeyPressed, ic);
848 inputState->lastKeyPressed_ =
Key();
851 if (!keyEvent.filtered() && !keyEvent.isRelease()) {
853 for (
auto &keyHandler : keyHandlers) {
854 auto keyIdx = origKey.keyListIndex(keyHandler.list);
855 if (keyIdx >= 0 && keyHandler.check()) {
856 inputState->keyReleased_ = idx;
857 inputState->lastKeyPressed_ = origKey;
859 inputState->lastKeyPressedTime_ =
860 now(CLOCK_MONOTONIC);
866 keyHandler.trigger(inputState->totallyReleased_);
867 if (origKey.hasModifier()) {
868 inputState->totallyReleased_ =
false;
870 keyEvent.filterAndAccept();
877 d->eventWatchers_.emplace_back(watchEvent(
880 auto &keyEvent =
static_cast<KeyEvent &
>(event);
881 auto *ic = keyEvent.inputContext();
882 if (!keyEvent.isRelease() &&
883 keyEvent.key().checkKeyList(
884 d->globalConfig_.togglePreeditKeys())) {
887 ic->setEnablePreedit(!ic->isPreeditEnabled());
888 if (d->notifications_) {
889 d->notifications_->call<INotifications::showTip>(
890 "toggle-preedit", _(
"Input Method"),
"", _(
"Preedit"),
891 ic->isPreeditEnabled() ? _(
"Preedit enabled")
892 : _(
"Preedit disabled"),
895 keyEvent.filterAndAccept();
898 d->eventWatchers_.emplace_back(d->watchEvent(
902 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
903 auto &keyEvent = static_cast<KeyEvent &>(event);
904 auto *ic = keyEvent.inputContext();
905 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
906 #ifdef ENABLE_KEYBOARD
907 auto *xkbState = inputState->customXkbState();
909 if (auto *mods = findValue(d->stateMask_, ic->display())) {
910 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
914 if (inputState->isModsAllReleased()) {
915 depressed = xkb_state_serialize_mods(
916 xkbState, XKB_STATE_MODS_DEPRESSED);
918 depressed = std::get<0>(*mods);
920 if (std::get<0>(*mods) == 0) {
921 inputState->setModsAllReleased();
923 auto latched = xkb_state_serialize_mods(
924 xkbState, XKB_STATE_MODS_LATCHED);
925 auto locked = std::get<2>(*mods);
931 << depressed <<
" " << latched <<
" " << locked;
932 xkb_state_update_mask(xkbState, depressed, latched, locked,
935 const uint32_t effective = xkb_state_serialize_mods(
936 xkbState, XKB_STATE_MODS_EFFECTIVE);
937 auto newSym = xkb_state_key_get_one_sym(
938 xkbState, keyEvent.rawKey().code());
939 auto newModifier = KeyStates(effective);
940 auto *keymap = xkb_state_get_keymap(xkbState);
941 if (keyEvent.rawKey().states().test(KeyState::Repeat) &&
942 xkb_keymap_key_repeats(keymap, keyEvent.rawKey().code())) {
943 newModifier |= KeyState::Repeat;
946 const uint32_t modsDepressed = xkb_state_serialize_mods(
947 xkbState, XKB_STATE_MODS_DEPRESSED);
948 const uint32_t modsLatched =
949 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
950 const uint32_t modsLocked =
951 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
952 FCITX_KEYTRACE() <<
"Current mods: " << modsDepressed <<
" " 953 << modsLatched <<
" " << modsLocked;
954 auto newCode = keyEvent.rawKey().code();
955 Key key(static_cast<KeySym>(newSym), newModifier, newCode);
957 <<
"Custom Xkb translated Key: " << key.toString();
958 keyEvent.setRawKey(key);
961 FCITX_KEYTRACE() <<
"KeyEvent: " << keyEvent.key()
962 <<
" rawKey: " << keyEvent.rawKey()
963 <<
" origKey: " << keyEvent.origKey()
964 <<
" Release:" << keyEvent.isRelease()
965 <<
" keycode: " << keyEvent.origKey().code()
966 <<
" program: " << ic->program();
968 if (keyEvent.isRelease()) {
971 inputState->hideInputMethodInfo();
973 d->eventWatchers_.emplace_back(
975 EventWatcherPhase::InputMethod, [
this](
Event &event) {
976 auto &keyEvent =
static_cast<KeyEvent &
>(event);
977 auto *ic = keyEvent.inputContext();
978 auto *engine = inputMethodEngine(ic);
979 const auto *entry = inputMethodEntry(ic);
980 if (!engine || !entry) {
983 engine->keyEvent(*entry, keyEvent);
985 d->eventWatchers_.emplace_back(watchEvent(
986 EventType::InputContextVirtualKeyboardEvent,
987 EventWatcherPhase::InputMethod, [
this](
Event &event) {
989 auto *ic = keyEvent.inputContext();
990 auto *engine = inputMethodEngine(ic);
991 const auto *entry = inputMethodEntry(ic);
992 if (!engine || !entry) {
995 engine->virtualKeyboardEvent(*entry, keyEvent);
997 d->eventWatchers_.emplace_back(watchEvent(
999 [
this](
Event &event) {
1001 auto *ic = invokeActionEvent.inputContext();
1002 auto *engine = inputMethodEngine(ic);
1003 const auto *entry = inputMethodEntry(ic);
1004 if (!engine || !entry) {
1007 engine->invokeAction(*entry, invokeActionEvent);
1009 d->eventWatchers_.emplace_back(d->watchEvent(
1011 [
this](
Event &event) {
1012 auto &keyEvent = static_cast<KeyEvent &>(event);
1013 auto *ic = keyEvent.inputContext();
1014 auto *engine = inputMethodEngine(ic);
1015 const auto *entry = inputMethodEntry(ic);
1016 if (!engine || !entry) {
1019 engine->filterKey(*entry, keyEvent);
1020 emit<Instance::KeyEventResult>(keyEvent);
1021 #ifdef ENABLE_KEYBOARD 1022 if (keyEvent.forward()) {
1027 if (keyEvent.isRelease()) {
1031 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1032 if (
auto *xkbState = inputState->customXkbState()) {
1033 if (
auto utf32 = xkb_state_key_get_utf32(
1034 xkbState, keyEvent.key().code())) {
1036 if (utf32 ==
'\n' || utf32 ==
'\b' || utf32 ==
'\r' ||
1037 utf32 ==
'\t' || utf32 ==
'\033' ||
1041 if (keyEvent.key().states().testAny(
1042 KeyStates{KeyState::Ctrl, KeyState::Alt}) ||
1043 keyEvent.rawKey().sym() ==
1044 keyEvent.origKey().sym()) {
1047 FCITX_KEYTRACE() <<
"Will commit char: " << utf32;
1049 keyEvent.filterAndAccept();
1050 }
else if (!keyEvent.key().states().testAny(
1051 KeyStates{KeyState::Ctrl, KeyState::Alt}) &&
1052 keyEvent.rawKey().sym() !=
1053 keyEvent.origKey().sym() &&
1058 keyEvent.filterAndAccept();
1064 d->eventWatchers_.emplace_back(d->watchEvent(
1066 [
this, d](
Event &event) {
1067 auto &icEvent = static_cast<InputContextEvent &>(event);
1068 auto isSameProgram = [&icEvent, d]() {
1070 return (icEvent.inputContext() == d->lastUnFocusedIc_.get()) ||
1071 (!icEvent.inputContext()->program().empty() &&
1072 (icEvent.inputContext()->program() ==
1073 d->lastUnFocusedProgram_));
1076 if (d->globalConfig_.resetStateWhenFocusIn() ==
1077 PropertyPropagatePolicy::All ||
1078 (d->globalConfig_.resetStateWhenFocusIn() ==
1079 PropertyPropagatePolicy::Program &&
1080 !isSameProgram())) {
1081 if (d->globalConfig_.activeByDefault()) {
1082 activate(icEvent.inputContext());
1084 deactivate(icEvent.inputContext());
1088 activateInputMethod(icEvent);
1090 auto *inputContext = icEvent.inputContext();
1091 if (!inputContext->clientControlVirtualkeyboardShow()) {
1092 inputContext->showVirtualKeyboard();
1095 if (!d->globalConfig_.showInputMethodInformationWhenFocusIn()) {
1106 d->focusInImInfoTimer_ = d->eventLoop_.addTimeEvent(
1107 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1112 if (
auto *ic = icRef.get();
1113 ic && ic->hasFocus() &&
1115 d->showInputMethodInformation(ic);
1120 d->eventWatchers_.emplace_back(d->watchEvent(
1123 auto &icEvent = static_cast<InputContextEvent &>(event);
1124 auto *ic = icEvent.inputContext();
1125 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1126 inputState->reset();
1127 if (!ic->capabilityFlags().test(
1128 CapabilityFlag::ClientUnfocusCommit)) {
1131 ic->inputPanel().clientPreedit().toStringForCommit();
1132 if (!commit.empty()) {
1133 ic->commitString(commit);
1137 d->eventWatchers_.emplace_back(d->watchEvent(
1139 [
this, d](
Event &event) {
1140 auto &icEvent = static_cast<InputContextEvent &>(event);
1141 d->lastUnFocusedProgram_ = icEvent.inputContext()->program();
1142 d->lastUnFocusedIc_ = icEvent.inputContext()->watch();
1143 deactivateInputMethod(icEvent);
1145 auto *inputContext = icEvent.inputContext();
1146 if (!inputContext->clientControlVirtualkeyboardHide()) {
1147 inputContext->hideVirtualKeyboard();
1150 d->eventWatchers_.emplace_back(d->watchEvent(
1153 auto &icEvent = static_cast<InputContextEvent &>(event);
1154 auto *ic = icEvent.inputContext();
1155 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1156 inputState->reset();
1158 d->eventWatchers_.emplace_back(
1160 [
this](
Event &event) {
1162 auto *ic = icEvent.inputContext();
1163 if (!ic->hasFocus()) {
1166 auto *engine = inputMethodEngine(ic);
1167 const auto *entry = inputMethodEntry(ic);
1168 if (!engine || !entry) {
1171 engine->reset(*entry, icEvent);
1173 d->eventWatchers_.emplace_back(d->watchEvent(
1175 EventWatcherPhase::ReservedFirst, [
this](
Event &event) {
1177 static_cast<InputContextSwitchInputMethodEvent &>(event);
1178 auto *ic = icEvent.inputContext();
1179 if (!ic->hasFocus()) {
1182 deactivateInputMethod(icEvent);
1183 activateInputMethod(icEvent);
1185 d->eventWatchers_.emplace_back(d->watchEvent(
1187 EventWatcherPhase::ReservedLast, [
this, d](
Event &event) {
1189 static_cast<InputContextSwitchInputMethodEvent &>(event);
1190 auto *ic = icEvent.inputContext();
1191 if (!ic->hasFocus()) {
1195 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1196 inputState->lastIMChangeIsAltTrigger_ =
1208 showInputMethodInformation(ic);
1210 d->eventWatchers_.emplace_back(
1212 EventWatcherPhase::ReservedLast, [
this, d](
Event &) {
1215 d->imGroupInfoTimer_ = d->eventLoop_.addTimeEvent(
1216 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1217 [this](EventSourceTime *, uint64_t) {
1218 inputContextManager().foreachFocused(
1219 [this](InputContext *ic) {
1220 showInputMethodInformation(ic);
1227 d->eventWatchers_.emplace_back(d->watchEvent(
1228 EventType::InputContextUpdateUI, EventWatcherPhase::ReservedFirst,
1230 auto &icEvent = static_cast<InputContextUpdateUIEvent &>(event);
1231 if (icEvent.immediate()) {
1232 d->uiManager_.update(icEvent.component(),
1233 icEvent.inputContext());
1234 d->uiManager_.flush();
1236 d->uiManager_.update(icEvent.component(),
1237 icEvent.inputContext());
1238 d->uiUpdateEvent_->setOneShot();
1241 d->eventWatchers_.emplace_back(d->watchEvent(
1242 EventType::InputContextDestroyed, EventWatcherPhase::ReservedFirst,
1244 auto &icEvent = static_cast<InputContextEvent &>(event);
1245 d->uiManager_.expire(icEvent.inputContext());
1247 d->eventWatchers_.emplace_back(d->watchEvent(
1249 [d](
Event &) { d->uiManager_.updateAvailability(); }));
1250 d->uiUpdateEvent_ = d->eventLoop_.addDeferEvent([d](
EventSource *) {
1251 d->uiManager_.flush();
1254 d->uiUpdateEvent_->setEnabled(
false);
1255 d->periodicalSave_ = d->eventLoop_.addTimeEvent(
1256 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, AutoSaveIdleTime,
1263 auto currentTime = now(CLOCK_MONOTONIC);
1264 if (currentTime <= d->idleStartTimestamp_ ||
1265 currentTime - d->idleStartTimestamp_ < AutoSaveIdleTime) {
1267 time->setNextInterval(2 * AutoSaveIdleTime);
1272 FCITX_INFO() <<
"Running autosave...";
1274 FCITX_INFO() <<
"End autosave";
1275 if (d->globalConfig_.autoSavePeriod() > 0) {
1276 time->setNextInterval(d->globalConfig_.autoSavePeriod() *
1277 AutoSaveMinInUsecs);
1282 d->periodicalSave_->setEnabled(
false);
1285 Instance::~Instance() {
1287 d->icManager_.finalize();
1288 d->addonManager_.unload();
1289 d->notifications_ =
nullptr;
1290 d->icManager_.setInstance(
nullptr);
1293 void InstanceArgument::parseOption(
int argc,
char **argv) {
1299 struct option longOptions[] = {{
"enable", required_argument,
nullptr, 0},
1300 {
"disable", required_argument,
nullptr, 0},
1301 {
"verbose", required_argument,
nullptr, 0},
1302 {
"keep", no_argument,
nullptr,
'k'},
1303 {
"ui", required_argument,
nullptr,
'u'},
1304 {
"replace", no_argument,
nullptr,
'r'},
1305 {
"version", no_argument,
nullptr,
'v'},
1306 {
"help", no_argument,
nullptr,
'h'},
1307 {
"option", required_argument,
nullptr,
'o'},
1308 {
nullptr, 0, 0, 0}};
1310 int optionIndex = 0;
1312 std::string addonOptionString;
1313 while ((c = getopt_long(argc, argv,
"ru:dDs:hvo:k", longOptions,
1314 &optionIndex)) != EOF) {
1317 switch (optionIndex) {
1325 Log::setLogRule(optarg);
1343 runAsDaemon =
false;
1346 exitWhenMainDisplayDisconnected =
false;
1349 overrideDelay = std::atoi(optarg);
1360 addonOptionString = optarg;
1371 std::unordered_map<std::string, std::vector<std::string>> addonOptions;
1372 for (
const std::string_view item :
1375 if (tokens.size() != 2) {
1380 addonOptions_ = std::move(addonOptions);
1388 d->signalPipe_ = fd;
1389 d->signalPipeEvent_ = d->eventLoop_.addIOEvent(
1399 return d->arg_.tryReplace;
1404 return d->arg_.exitWhenMainDisplayDisconnected;
1412 void Instance::handleSignal() {
1416 while (
fs::safeRead(d->signalPipe_, &signo,
sizeof(signo)) > 0) {
1417 if (signo == SIGINT || signo == SIGTERM || signo == SIGQUIT ||
1420 }
else if (signo == SIGUSR1) {
1422 }
else if (signo == SIGCHLD) {
1423 d->zombieReaper_->setNextInterval(2000000);
1424 d->zombieReaper_->setOneShot();
1432 if (!d->arg_.uiName.empty()) {
1433 d->arg_.enableList.push_back(d->arg_.uiName);
1436 d->icManager_.registerProperty(
"inputState", &d->inputStateFactory_);
1437 std::unordered_set<std::string> enabled;
1438 std::unordered_set<std::string> disabled;
1439 std::tie(enabled, disabled) = d->overrideAddons();
1440 FCITX_INFO() <<
"Override Enabled Addons: " << enabled;
1441 FCITX_INFO() <<
"Override Disabled Addons: " << disabled;
1442 d->addonManager_.load(enabled, disabled);
1447 d->uiManager_.load(d->arg_.uiName);
1449 const auto *entry = d->imManager_.entry(
"keyboard-us");
1450 FCITX_LOG_IF(Error, !entry) <<
"Couldn't find keyboard-us";
1451 d->preloadInputMethodEvent_ = d->eventLoop_.addTimeEvent(
1452 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, 0,
1455 if (d->exit_ || !d->globalConfig_.preloadInputMethod()) {
1459 if (!d->imManager_.currentGroup().inputMethodList().empty()) {
1460 if (
const auto *entry =
1461 d->imManager_.entry(d->imManager_.currentGroup()
1462 .inputMethodList()[0]
1464 d->addonManager_.addon(entry->addon(),
true);
1468 if (!d->imManager_.currentGroup().defaultInputMethod().empty()) {
1469 if (
const auto *entry = d->imManager_.entry(
1470 d->imManager_.currentGroup().defaultInputMethod())) {
1471 d->addonManager_.addon(entry->addon(),
true);
1477 d->zombieReaper_ = d->eventLoop_.addTimeEvent(
1478 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 0,
1481 while ((res = waitpid(-1,
nullptr, WNOHANG)) > 0) {
1485 d->zombieReaper_->setEnabled(
false);
1488 d->exitEvent_ = d->eventLoop_.addExitEvent([
this](
EventSource *) {
1489 FCITX_DEBUG() <<
"Running save...";
1493 d->notifications_ = d->addonManager_.addon(
"notifications",
true);
1498 if (d->arg_.quietQuit) {
1505 return d->exitCode_;
1508 auto r = eventLoop().exec();
1509 d->running_ =
false;
1511 return r ? d->exitCode_ : 1;
1516 d->running_ = running;
1526 return d->inputMethodMode_;
1531 if (d->inputMethodMode_ == mode) {
1534 d->inputMethodMode_ = mode;
1543 bool Instance::virtualKeyboardAutoShow()
const {
1545 return d->virtualKeyboardAutoShow_;
1548 void Instance::setVirtualKeyboardAutoShow(
bool autoShow) {
1550 d->virtualKeyboardAutoShow_ = autoShow;
1553 bool Instance::virtualKeyboardAutoHide()
const {
1555 return d->virtualKeyboardAutoHide_;
1558 void Instance::setVirtualKeyboardAutoHide(
bool autoHide) {
1560 d->virtualKeyboardAutoHide_ = autoHide;
1563 VirtualKeyboardFunctionMode Instance::virtualKeyboardFunctionMode()
const {
1565 return d->virtualKeyboardFunctionMode_;
1568 void Instance::setVirtualKeyboardFunctionMode(
1569 VirtualKeyboardFunctionMode mode) {
1571 d->virtualKeyboardFunctionMode_ = mode;
1576 d->binaryMode_ =
true;
1581 const auto &addonNames = d->addonManager_.loadedAddonNames();
1582 return d->binaryMode_ &&
1583 std::all_of(addonNames.begin(), addonNames.end(),
1584 [d](
const std::string &name) {
1585 auto *addon = d->addonManager_.lookupAddon(name);
1589 return addon->canRestart();
1593 InstancePrivate *Instance::privateData() {
1600 return d->eventLoop_;
1605 return d->eventDispatcher_;
1610 return d->icManager_;
1615 return d->addonManager_;
1620 return d->imManager_;
1625 return d->imManager_;
1630 return d->uiManager_;
1635 return d->globalConfig_;
1638 bool Instance::postEvent(
Event &event) {
1639 return std::as_const(*this).postEvent(event);
1642 bool Instance::postEvent(
Event &event)
const {
1647 auto iter = d->eventHandlers_.find(event.
type());
1648 if (iter != d->eventHandlers_.end()) {
1649 const auto &handlers = iter->second;
1650 EventWatcherPhase phaseOrder[] = {
1651 EventWatcherPhase::ReservedFirst, EventWatcherPhase::PreInputMethod,
1652 EventWatcherPhase::InputMethod, EventWatcherPhase::PostInputMethod,
1653 EventWatcherPhase::ReservedLast};
1655 for (
auto phase : phaseOrder) {
1656 if (
auto iter2 = handlers.find(phase); iter2 != handlers.end()) {
1657 for (
auto &handler : iter2->second.view()) {
1672 auto &keyEvent =
static_cast<KeyEvent &
>(event);
1673 auto *ic = keyEvent.inputContext();
1674 #ifdef ENABLE_KEYBOARD 1676 if (!keyEvent.forward() && !keyEvent.origKey().code()) {
1679 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1680 auto *xkbState = inputState->customXkbState();
1687 xkb_state_update_key(xkbState, keyEvent.origKey().code(),
1688 keyEvent.isRelease() ? XKB_KEY_UP
1692 if (ic->capabilityFlags().test(CapabilityFlag::KeyEventOrderFix) &&
1693 !keyEvent.accepted() && ic->hasPendingEventsStrictOrder()) {
1696 keyEvent.filterAndAccept();
1697 ic->forwardKey(keyEvent.origKey(), keyEvent.isRelease(),
1700 d_ptr->uiManager_.flush();
1703 return event.accepted();
1706 std::unique_ptr<HandlerTableEntry<EventHandler>>
1708 EventHandler callback) {
1710 if (phase == EventWatcherPhase::ReservedFirst ||
1711 phase == EventWatcherPhase::ReservedLast) {
1712 throw std::invalid_argument(
"Reserved Phase is only for internal use");
1714 return d->watchEvent(type, phase, std::move(callback));
1717 bool groupContains(
const InputMethodGroup &group,
const std::string &name) {
1718 const auto &list = group.inputMethodList();
1719 auto iter = std::find_if(list.begin(), list.end(),
1721 return item.name() == name;
1723 return iter != list.end();
1728 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1731 if (!inputState->overrideDeactivateIM_.empty()) {
1732 return inputState->overrideDeactivateIM_;
1735 const auto &group = d->imManager_.currentGroup();
1738 !d->globalConfig_.allowInputMethodForPassword())) {
1739 auto defaultLayoutIM =
1740 stringutils::concat(
"keyboard-", group.defaultLayout());
1741 const auto *entry = d->imManager_.entry(defaultLayoutIM);
1743 entry = d->imManager_.entry(
"keyboard-us");
1745 return entry ? entry->uniqueName() :
"";
1748 if (group.inputMethodList().empty()) {
1751 if (inputState->isActive()) {
1752 if (!inputState->localIM_.empty() &&
1753 groupContains(group, inputState->localIM_)) {
1754 return inputState->localIM_;
1756 return group.defaultInputMethod();
1759 return group.inputMethodList()[0].name();
1764 auto imName = inputMethod(ic);
1765 if (imName.empty()) {
1768 return d->imManager_.entry(imName);
1773 const auto *entry = inputMethodEntry(ic);
1778 d->addonManager_.addon(entry->addon(),
true));
1783 const auto *entry = d->imManager_.entry(name);
1788 d->addonManager_.addon(entry->addon(),
true));
1793 const auto *entry = inputMethodEntry(ic);
1795 auto *engine = inputMethodEngine(ic);
1797 icon = engine->subModeIcon(*entry, *ic);
1800 icon = entry->icon();
1803 icon =
"input-keyboard";
1811 const auto *entry = inputMethodEntry(ic);
1812 auto *engine = inputMethodEngine(ic);
1814 if (engine && entry) {
1815 label = engine->subModeLabel(*entry, *ic);
1817 if (label.empty() && entry) {
1818 label = entry->label();
1824 #ifdef ENABLE_KEYBOARD 1826 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1828 auto *xkbComposeState = state->xkbComposeState();
1829 if (!xkbComposeState) {
1833 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1835 enum xkb_compose_feed_result result =
1836 xkb_compose_state_feed(xkbComposeState, keyval);
1837 if (result == XKB_COMPOSE_FEED_IGNORED) {
1841 enum xkb_compose_status status =
1842 xkb_compose_state_get_status(xkbComposeState);
1843 if (status == XKB_COMPOSE_NOTHING) {
1846 if (status == XKB_COMPOSE_COMPOSED) {
1847 char buffer[FCITX_UTF8_MAX_LENGTH + 1] = {
'\0',
'\0',
'\0',
'\0',
1850 xkb_compose_state_get_utf8(xkbComposeState, buffer,
sizeof(buffer));
1851 xkb_compose_state_reset(xkbComposeState);
1853 return FCITX_INVALID_COMPOSE_RESULT;
1859 if (status == XKB_COMPOSE_CANCELLED) {
1860 xkb_compose_state_reset(xkbComposeState);
1863 return FCITX_INVALID_COMPOSE_RESULT;
1866 FCITX_UNUSED(keysym);
1873 #ifdef ENABLE_KEYBOARD 1875 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1877 auto *xkbComposeState = state->xkbComposeState();
1878 if (!xkbComposeState) {
1879 return std::string();
1882 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1883 enum xkb_compose_feed_result result =
1884 xkb_compose_state_feed(xkbComposeState, keyval);
1886 if (result == XKB_COMPOSE_FEED_IGNORED) {
1887 return std::string();
1890 enum xkb_compose_status status =
1891 xkb_compose_state_get_status(xkbComposeState);
1892 if (status == XKB_COMPOSE_NOTHING) {
1893 return std::string();
1895 if (status == XKB_COMPOSE_COMPOSED) {
1897 std::array<char, 256> buffer;
1898 auto length = xkb_compose_state_get_utf8(xkbComposeState, buffer.data(),
1900 xkb_compose_state_reset(xkbComposeState);
1902 return std::nullopt;
1905 auto bufferBegin = buffer.begin();
1906 auto bufferEnd = std::next(bufferBegin,
length);
1908 return std::string(bufferBegin, bufferEnd);
1910 return std::nullopt;
1912 if (status == XKB_COMPOSE_CANCELLED) {
1913 xkb_compose_state_reset(xkbComposeState);
1915 return std::nullopt;
1918 FCITX_UNUSED(keysym);
1919 return std::string();
1924 #ifdef ENABLE_KEYBOARD 1926 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1928 auto *xkbComposeState = state->xkbComposeState();
1929 if (!xkbComposeState) {
1933 return xkb_compose_state_get_status(xkbComposeState) ==
1934 XKB_COMPOSE_COMPOSING;
1936 FCITX_UNUSED(inputContext);
1942 #ifdef ENABLE_KEYBOARD 1944 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1945 auto *xkbComposeState = state->xkbComposeState();
1946 if (!xkbComposeState) {
1949 xkb_compose_state_reset(xkbComposeState);
1951 FCITX_UNUSED(inputContext);
1958 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
1959 d->imManager_.save();
1960 d->addonManager_.saveAll();
1965 if (
auto *ic = mostRecentInputContext()) {
1966 CheckInputMethodChanged imChangedRAII(ic, d);
1973 if (
const auto *entry = inputMethodManager().entry(imName)) {
1974 return entry->uniqueName();
1984 void Instance::configureAddon(
const std::string & ) {}
1986 void Instance::configureInputMethod(
const std::string & ) {}
1989 if (
auto *ic = mostRecentInputContext()) {
1990 if (
const auto *entry = inputMethodEntry(ic)) {
1991 return entry->uniqueName();
1999 return d->uiManager_.currentUI();
2004 if (
auto *ic = mostRecentInputContext()) {
2005 CheckInputMethodChanged imChangedRAII(ic, d);
2015 d->exitCode_ = exitCode;
2017 d->eventLoop_.exit();
2022 auto *addon = addonManager().addon(addonName);
2024 addon->reloadConfig();
2030 auto [enabled, disabled] = d->overrideAddons();
2031 d->addonManager_.load(enabled, disabled);
2032 d->imManager_.refresh();
2037 readAsIni(d->globalConfig_.config(), StandardPathsType::PkgConfig,
2039 FCITX_DEBUG() <<
"Trigger Key: " 2041 d->icManager_.setPropertyPropagatePolicy(
2042 d->globalConfig_.shareInputState());
2043 if (d->globalConfig_.preeditEnabledByDefault() !=
2044 d->icManager_.isPreeditEnabledByDefault()) {
2045 d->icManager_.setPreeditEnabledByDefault(
2046 d->globalConfig_.preeditEnabledByDefault());
2052 #ifdef ENABLE_KEYBOARD 2053 d->keymapCache_.clear();
2054 if (d->inputStateFactory_.registered()) {
2056 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2057 inputState->resetXkbState();
2066 if (d->globalConfig_.autoSavePeriod() <= 0) {
2067 d->periodicalSave_->setEnabled(
false);
2069 d->periodicalSave_->setNextInterval(AutoSaveMinInUsecs *
2070 d->globalConfig_.autoSavePeriod());
2071 d->periodicalSave_->setOneShot();
2082 if (!canRestart()) {
2090 setCurrentInputMethod(mostRecentInputContext(), name,
false);
2096 if (!canTrigger()) {
2100 auto &imManager = inputMethodManager();
2101 const auto &imList = imManager.currentGroup().inputMethodList();
2102 auto iter = std::find_if(imList.begin(), imList.end(),
2104 return item.name() == name;
2106 if (iter == imList.end()) {
2110 auto setGlobalDefaultInputMethod = [d](
const std::string &name) {
2111 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2112 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2114 groupRAIICheck.push_back(
2115 std::make_unique<CheckInputMethodChanged>(ic, d));
2118 d->imManager_.setDefaultInputMethod(name);
2121 auto idx = std::distance(imList.begin(), iter);
2123 CheckInputMethodChanged imChangedRAII(ic, d);
2124 auto currentIM = inputMethod(ic);
2125 if (currentIM == name) {
2128 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2132 inputState->setLocalIM(name);
2134 inputState->setLocalIM({});
2136 setGlobalDefaultInputMethod(name);
2138 inputState->setActive(
true);
2140 inputState->setActive(
false);
2142 if (inputState->imChanged_) {
2152 setGlobalDefaultInputMethod(name);
2160 if (
auto *ic = mostRecentInputContext()) {
2161 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
2162 return inputState->isActive() ? 2 : 1;
2169 if (
auto *ic = mostRecentInputContext()) {
2170 CheckInputMethodChanged imChangedRAII(ic, d);
2177 if (
auto *ic = mostRecentInputContext()) {
2178 CheckInputMethodChanged imChangedRAII(ic, d);
2179 enumerate(ic, forward);
2183 bool Instance::canTrigger()
const {
2184 const auto &imManager = inputMethodManager();
2185 return (imManager.currentGroup().inputMethodList().size() > 1);
2189 if (!canTrigger()) {
2193 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2194 if (inputState->isActive()) {
2197 return inputState->lastIMChangeIsAltTrigger_;
2202 if (!canTrigger()) {
2206 if (d->globalConfig_.enumerateSkipFirst()) {
2207 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2208 if (!inputState->isActive()) {
2211 return d->imManager_.currentGroup().inputMethodList().size() > 2;
2217 bool Instance::canChangeGroup()
const {
2218 const auto &imManager = inputMethodManager();
2219 return (imManager.groupCount() > 1);
2224 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2225 if (!canTrigger()) {
2228 inputState->setActive(!inputState->isActive());
2229 if (inputState->imChanged_) {
2230 inputState->imChanged_->setReason(reason);
2235 bool Instance::trigger(
InputContext *ic,
bool totallyReleased) {
2237 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2238 if (!canTrigger()) {
2243 if (totallyReleased) {
2245 inputState->firstTrigger_ =
true;
2247 if (!d->globalConfig_.enumerateWithTriggerKeys() ||
2248 (inputState->firstTrigger_ && inputState->isActive()) ||
2249 (d->globalConfig_.enumerateSkipFirst() &&
2250 d->imManager_.currentGroup().inputMethodList().size() <= 2)) {
2253 enumerate(ic,
true);
2255 inputState->firstTrigger_ =
false;
2261 if (!canAltTrigger(ic)) {
2271 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2272 if (!canTrigger()) {
2275 if (inputState->isActive()) {
2278 inputState->setActive(
true);
2279 if (inputState->imChanged_) {
2287 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2288 if (!canTrigger()) {
2291 if (!inputState->isActive()) {
2294 inputState->setActive(
false);
2295 if (inputState->imChanged_) {
2296 inputState->imChanged_->setReason(
2304 auto &imManager = inputMethodManager();
2305 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2306 const auto &imList = imManager.currentGroup().inputMethodList();
2307 if (!canTrigger()) {
2311 if (d->globalConfig_.enumerateSkipFirst() && imList.size() <= 2) {
2315 auto currentIM = inputMethod(ic);
2317 auto iter = std::ranges::find_if(
2319 return item.name() == currentIM;
2321 if (iter == imList.end()) {
2324 int idx = std::distance(imList.begin(), iter);
2325 auto nextIdx = [forward, &imList](
int idx) {
2327 return (idx + (forward ? 1 : (imList.size() - 1))) % imList.size();
2331 if (d->globalConfig_.enumerateSkipFirst() && idx == 0) {
2335 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2336 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2338 groupRAIICheck.push_back(
2339 std::make_unique<CheckInputMethodChanged>(ic, d));
2342 imManager.setDefaultInputMethod(imList[idx].name());
2343 inputState->setActive(
true);
2344 inputState->setLocalIM({});
2346 inputState->setActive(
false);
2348 if (inputState->imChanged_) {
2356 const std::string &orig) {
2357 std::string result = orig;
2358 emit<Instance::CommitFilter>(inputContext, result);
2364 emit<Instance::OutputFilter>(inputContext, result);
2365 if ((&orig == &inputContext->inputPanel().clientPreedit() ||
2366 &orig == &inputContext->inputPanel().preedit()) &&
2367 !globalConfig().showPreeditForPassword() &&
2368 inputContext->capabilityFlags().test(CapabilityFlag::Password)) {
2370 for (
int i = 0, e = result.size(); i < e; i++) {
2375 dot +=
"\xe2\x80\xa2";
2378 newText.append(std::move(dot),
2379 result.formatAt(i) | TextFormatFlag::DontCommit);
2381 result = std::move(newText);
2388 return d->icManager_.lastFocusedInputContext();
2393 return d->icManager_.mostRecentInputContext();
2398 d->uiManager_.flush();
2401 int scoreForGroup(
FocusGroup *group,
const std::string &displayHint) {
2403 if (displayHint.empty()) {
2404 if (group->display() ==
"x11:") {
2407 if (group->display().starts_with(
"x11:")) {
2410 if (group->display() ==
"wayland:") {
2413 if (group->display().starts_with(
"wayland:")) {
2417 if (group->display() == displayHint) {
2420 if (group->display().starts_with(displayHint)) {
2432 d->icManager_.foreachGroup(
2433 [&score, &displayHint, &defaultFocusGroup](
FocusGroup *group) {
2434 auto newScore = scoreForGroup(group, displayHint);
2435 if (newScore > score) {
2436 defaultFocusGroup = group;
2442 return defaultFocusGroup;
2447 FCITX_DEBUG() <<
"Instance::activateInputMethod";
2449 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2450 const auto *entry = inputMethodEntry(ic);
2452 FCITX_DEBUG() <<
"Activate: " 2453 <<
"[Last]:" << inputState->lastIM_
2454 <<
" [Activating]:" << entry->uniqueName();
2455 assert(inputState->lastIM_.empty());
2456 inputState->lastIM_ = entry->uniqueName();
2458 auto *engine = inputMethodEngine(ic);
2459 if (!engine || !entry) {
2462 #ifdef ENABLE_KEYBOARD 2463 if (
auto *xkbState = inputState->customXkbState(
true)) {
2464 if (
auto *mods = findValue(d->stateMask_, ic->
display())) {
2465 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
2466 auto depressed = std::get<0>(*mods);
2467 auto latched = std::get<1>(*mods);
2468 auto locked = std::get<2>(*mods);
2473 FCITX_KEYTRACE() << depressed <<
" " << latched <<
" " << locked;
2474 if (depressed == 0) {
2475 inputState->setModsAllReleased();
2477 xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0,
2483 engine->activate(*entry, event);
2489 FCITX_DEBUG() <<
"Instance::deactivateInputMethod event_type=" 2490 <<
static_cast<uint32_t
>(
event.type());
2492 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2499 FCITX_DEBUG() <<
"Switch reason: " 2500 <<
static_cast<int>(icEvent.reason());
2501 FCITX_DEBUG() <<
"Old Input method: " << icEvent.oldInputMethod();
2502 entry = d->imManager_.entry(icEvent.oldInputMethod());
2504 entry = inputMethodEntry(ic);
2507 FCITX_DEBUG() <<
"Deactivate: " 2508 <<
"[Last]:" << inputState->lastIM_
2509 <<
" [Deactivating]:" << entry->uniqueName();
2510 assert(entry->uniqueName() == inputState->lastIM_);
2512 d->addonManager_.addon(entry->addon()));
2514 inputState->lastIM_.clear();
2515 if (!engine || !entry) {
2518 inputState->overrideDeactivateIM_ = entry->uniqueName();
2520 inputState->overrideDeactivateIM_.clear();
2524 bool Instance::enumerateGroup(
bool forward) {
2525 auto &imManager = inputMethodManager();
2526 auto groups = imManager.groups();
2527 if (groups.size() <= 1) {
2531 imManager.setCurrentGroup(groups[1]);
2533 imManager.setCurrentGroup(groups.back());
2539 FCITX_DEBUG() <<
"Input method switched";
2541 if (!d->globalConfig_.showInputMethodInformation()) {
2544 d->showInputMethodInformation(ic);
2548 const std::string &message) {
2549 FCITX_DEBUG() <<
"Input method switched";
2551 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2552 inputState->showInputMethodInformation(message);
2557 return (isInFlatpak() &&
2558 std::filesystem::is_regular_file(
"/app/.updated")) ||
2559 d->addonManager_.checkUpdate() || d->imManager_.checkUpdate() ||
2564 const std::string &rule,
2565 const std::string &model,
2566 const std::string &options) {
2567 #ifdef ENABLE_KEYBOARD 2569 bool resetState =
false;
2570 if (
auto *param = findValue(d->xkbParams_, display)) {
2571 if (std::get<0>(*param) != rule || std::get<1>(*param) != model ||
2572 std::get<2>(*param) != options) {
2573 std::get<0>(*param) = rule;
2574 std::get<1>(*param) = model;
2575 std::get<2>(*param) = options;
2579 d->xkbParams_.emplace(display, std::make_tuple(rule, model, options));
2583 d->keymapCache_[display].clear();
2584 d->icManager_.foreach([d, &display](
InputContext *ic) {
2585 if (ic->
display() == display ||
2586 !d->xkbParams_.contains(ic->
display())) {
2587 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2588 inputState->resetXkbState();
2594 FCITX_UNUSED(display);
2596 FCITX_UNUSED(model);
2597 FCITX_UNUSED(options);
2602 uint32_t depressed_mods,
2603 uint32_t latched_mods, uint32_t locked_mods) {
2605 d->stateMask_[display] =
2606 std::make_tuple(depressed_mods, latched_mods, locked_mods);
2611 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.
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.
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.