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->tempModeManager_ = std::make_unique<TempModeManager>(
this);
684 d->connections_.emplace_back(
685 d->imManager_.connect<InputMethodManager::CurrentGroupAboutToChange>(
686 [
this, d](
const std::string &lastGroup) {
687 d->icManager_.foreachFocused([this](InputContext *ic) {
688 assert(ic->hasFocus());
689 InputContextSwitchInputMethodEvent event(
690 InputMethodSwitchedReason::GroupChange, inputMethod(ic),
692 deactivateInputMethod(event);
695 d->lastGroup_ = lastGroup;
698 d->connections_.emplace_back(
699 d->imManager_.connect<InputMethodManager::CurrentGroupChanged>(
700 [
this, d](
const std::string &newGroup) {
701 d->icManager_.foreachFocused([this](InputContext *ic) {
702 assert(ic->hasFocus());
703 InputContextSwitchInputMethodEvent event(
704 InputMethodSwitchedReason::GroupChange,
"", ic);
705 activateInputMethod(event);
709 if (!d->lastGroup_.empty() && !newGroup.empty() &&
710 d->lastGroup_ != newGroup && d->notifications_ &&
711 d->imManager_.groupCount() > 1) {
712 d->notifications_->call<INotifications::showTip>(
713 "enumerate-group", _(
"Input Method"),
"input-keyboard",
715 _(
"Switched group to {0}",
716 d->imManager_.currentGroup().name()),
719 d->lastGroup_ = newGroup;
722 d->eventWatchers_.emplace_back(d->watchEvent(
723 EventType::InputContextCapabilityAboutToChange,
724 EventWatcherPhase::ReservedFirst, [
this, d](
Event &event) {
726 static_cast<CapabilityAboutToChangeEvent &>(event);
727 if (!capChanged.inputContext()->hasFocus()) {
732 capChanged.oldFlags(), capChanged.newFlags(),
733 d->globalConfig_.allowInputMethodForPassword())) {
739 inputMethod(capChanged.inputContext()),
740 capChanged.inputContext());
741 deactivateInputMethod(switchIM);
743 d->eventWatchers_.emplace_back(d->watchEvent(
744 EventType::InputContextCapabilityChanged,
745 EventWatcherPhase::ReservedFirst, [
this, d](
Event &event) {
746 auto &capChanged = static_cast<CapabilityChangedEvent &>(event);
747 if (!capChanged.inputContext()->hasFocus()) {
752 capChanged.oldFlags(), capChanged.newFlags(),
753 d->globalConfig_.allowInputMethodForPassword())) {
759 capChanged.inputContext());
760 activateInputMethod(switchIM);
763 d->eventWatchers_.emplace_back(watchEvent(
765 [
this, d](
Event &event) {
766 auto &keyEvent =
static_cast<KeyEvent &
>(event);
767 auto *ic = keyEvent.inputContext();
768 CheckInputMethodChanged imChangedRAII(ic, d);
769 auto origKey = keyEvent.origKey().normalize();
773 std::function<bool()> check;
774 std::function<void(bool)> trigger;
776 {.list = d->globalConfig_.triggerKeys(),
777 .check = [
this]() {
return canTrigger(); },
779 [
this, ic](
bool totallyReleased) {
780 return trigger(ic, totallyReleased);
782 {.list = d->globalConfig_.altTriggerKeys(),
783 .check = [
this, ic]() {
return canAltTrigger(ic); },
784 .trigger = [
this, ic](bool) {
return altTrigger(ic); }},
785 {.list = d->globalConfig_.activateKeys(),
786 .check = [ic, d]() {
return d->canActivate(ic); },
787 .trigger = [
this, ic](bool) {
return activate(ic); }},
788 {.list = d->globalConfig_.deactivateKeys(),
789 .check = [ic, d]() {
return d->canDeactivate(ic); },
790 .trigger = [
this, ic](bool) {
return deactivate(ic); }},
791 {.list = d->globalConfig_.enumerateForwardKeys(),
792 .check = [
this, ic]() {
return canEnumerate(ic); },
793 .trigger = [
this, ic](bool) {
return enumerate(ic,
true); }},
794 {.list = d->globalConfig_.enumerateBackwardKeys(),
795 .check = [
this, ic]() {
return canEnumerate(ic); },
796 .trigger = [
this, ic](bool) {
return enumerate(ic,
false); }},
797 {.list = d->globalConfig_.enumerateGroupForwardKeys(),
798 .check = [
this]() {
return canChangeGroup(); },
799 .trigger = [ic, d, origKey](
800 bool) { d->navigateGroup(ic, origKey,
true); }},
801 {.list = d->globalConfig_.enumerateGroupBackwardKeys(),
802 .check = [
this]() {
return canChangeGroup(); },
804 [ic, d, origKey](bool) {
805 d->navigateGroup(ic, origKey,
false);
809 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
810 int keyReleased = inputState->keyReleased_;
811 Key lastKeyPressed = inputState->lastKeyPressed_;
813 inputState->keyReleased_ = -1;
815 if (keyEvent.isRelease()) {
817 for (
auto &keyHandler : keyHandlers) {
818 if (keyReleased == idx &&
819 origKey.isReleaseOfModifier(lastKeyPressed) &&
820 keyHandler.check()) {
822 if (d->globalConfig_.checkModifierOnlyKeyTimeout(
823 inputState->lastKeyPressedTime_)) {
825 inputState->totallyReleased_);
827 inputState->lastKeyPressedTime_ = 0;
828 if (origKey.hasModifier()) {
829 inputState->totallyReleased_ =
false;
837 if (isSingleModifier(origKey)) {
838 inputState->totallyReleased_ =
true;
842 if (inputState->pendingGroupIndex_ &&
843 inputState->totallyReleased_) {
844 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
845 if (inputState->imChanged_) {
846 inputState->imChanged_->ignore();
848 d->acceptGroupChange(lastKeyPressed, ic);
849 inputState->lastKeyPressed_ =
Key();
852 if (!keyEvent.filtered() && !keyEvent.isRelease()) {
854 for (
auto &keyHandler : keyHandlers) {
855 auto keyIdx = origKey.keyListIndex(keyHandler.list);
856 if (keyIdx >= 0 && keyHandler.check()) {
857 inputState->keyReleased_ = idx;
858 inputState->lastKeyPressed_ = origKey;
860 inputState->lastKeyPressedTime_ =
861 now(CLOCK_MONOTONIC);
867 keyHandler.trigger(inputState->totallyReleased_);
868 if (origKey.hasModifier()) {
869 inputState->totallyReleased_ =
false;
871 keyEvent.filterAndAccept();
878 d->eventWatchers_.emplace_back(watchEvent(
881 auto &keyEvent =
static_cast<KeyEvent &
>(event);
882 auto *ic = keyEvent.inputContext();
883 if (!keyEvent.isRelease() &&
884 keyEvent.key().checkKeyList(
885 d->globalConfig_.togglePreeditKeys())) {
888 ic->setEnablePreedit(!ic->isPreeditEnabled());
889 if (d->notifications_) {
890 d->notifications_->call<INotifications::showTip>(
891 "toggle-preedit", _(
"Input Method"),
"", _(
"Preedit"),
892 ic->isPreeditEnabled() ? _(
"Preedit enabled")
893 : _(
"Preedit disabled"),
896 keyEvent.filterAndAccept();
899 d->eventWatchers_.emplace_back(d->watchEvent(
903 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
904 auto &keyEvent = static_cast<KeyEvent &>(event);
905 auto *ic = keyEvent.inputContext();
906 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
907 #ifdef ENABLE_KEYBOARD
908 auto *xkbState = inputState->customXkbState();
910 if (auto *mods = findValue(d->stateMask_, ic->display())) {
911 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
915 if (inputState->isModsAllReleased()) {
916 depressed = xkb_state_serialize_mods(
917 xkbState, XKB_STATE_MODS_DEPRESSED);
919 depressed = std::get<0>(*mods);
921 if (std::get<0>(*mods) == 0) {
922 inputState->setModsAllReleased();
924 auto latched = xkb_state_serialize_mods(
925 xkbState, XKB_STATE_MODS_LATCHED);
926 auto locked = std::get<2>(*mods);
932 << depressed <<
" " << latched <<
" " << locked;
933 xkb_state_update_mask(xkbState, depressed, latched, locked,
936 const uint32_t effective = xkb_state_serialize_mods(
937 xkbState, XKB_STATE_MODS_EFFECTIVE);
938 auto newSym = xkb_state_key_get_one_sym(
939 xkbState, keyEvent.rawKey().code());
940 auto newModifier = KeyStates(effective);
941 auto *keymap = xkb_state_get_keymap(xkbState);
942 if (keyEvent.rawKey().states().test(KeyState::Repeat) &&
943 xkb_keymap_key_repeats(keymap, keyEvent.rawKey().code())) {
944 newModifier |= KeyState::Repeat;
947 const uint32_t modsDepressed = xkb_state_serialize_mods(
948 xkbState, XKB_STATE_MODS_DEPRESSED);
949 const uint32_t modsLatched =
950 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
951 const uint32_t modsLocked =
952 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
953 FCITX_KEYTRACE() <<
"Current mods: " << modsDepressed <<
" " 954 << modsLatched <<
" " << modsLocked;
955 auto newCode = keyEvent.rawKey().code();
956 Key key(static_cast<KeySym>(newSym), newModifier, newCode);
958 <<
"Custom Xkb translated Key: " << key.toString();
959 keyEvent.setRawKey(key);
962 FCITX_KEYTRACE() <<
"KeyEvent: " << keyEvent.key()
963 <<
" rawKey: " << keyEvent.rawKey()
964 <<
" origKey: " << keyEvent.origKey()
965 <<
" Release:" << keyEvent.isRelease()
966 <<
" keycode: " << keyEvent.origKey().code()
967 <<
" program: " << ic->program();
969 if (keyEvent.isRelease()) {
972 inputState->hideInputMethodInfo();
974 d->eventWatchers_.emplace_back(
976 EventWatcherPhase::InputMethod, [
this](
Event &event) {
977 auto &keyEvent =
static_cast<KeyEvent &
>(event);
978 auto *ic = keyEvent.inputContext();
979 auto *engine = inputMethodEngine(ic);
980 const auto *entry = inputMethodEntry(ic);
981 if (!engine || !entry) {
984 engine->keyEvent(*entry, keyEvent);
986 d->eventWatchers_.emplace_back(watchEvent(
987 EventType::InputContextVirtualKeyboardEvent,
988 EventWatcherPhase::InputMethod, [
this](
Event &event) {
990 auto *ic = keyEvent.inputContext();
991 auto *engine = inputMethodEngine(ic);
992 const auto *entry = inputMethodEntry(ic);
993 if (!engine || !entry) {
996 engine->virtualKeyboardEvent(*entry, keyEvent);
998 d->eventWatchers_.emplace_back(watchEvent(
1000 [
this](
Event &event) {
1002 auto *ic = invokeActionEvent.inputContext();
1003 auto *engine = inputMethodEngine(ic);
1004 const auto *entry = inputMethodEntry(ic);
1005 if (!engine || !entry) {
1008 engine->invokeAction(*entry, invokeActionEvent);
1010 d->eventWatchers_.emplace_back(d->watchEvent(
1012 [
this](
Event &event) {
1013 auto &keyEvent = static_cast<KeyEvent &>(event);
1014 auto *ic = keyEvent.inputContext();
1015 auto *engine = inputMethodEngine(ic);
1016 const auto *entry = inputMethodEntry(ic);
1017 if (!engine || !entry) {
1020 engine->filterKey(*entry, keyEvent);
1021 emit<Instance::KeyEventResult>(keyEvent);
1022 #ifdef ENABLE_KEYBOARD 1023 if (keyEvent.forward()) {
1028 if (keyEvent.isRelease()) {
1032 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1033 if (
auto *xkbState = inputState->customXkbState()) {
1034 if (
auto utf32 = xkb_state_key_get_utf32(
1035 xkbState, keyEvent.key().code())) {
1037 if (utf32 ==
'\n' || utf32 ==
'\b' || utf32 ==
'\r' ||
1038 utf32 ==
'\t' || utf32 ==
'\033' ||
1042 if (keyEvent.key().states().testAny(
1043 KeyStates{KeyState::Ctrl, KeyState::Alt}) ||
1044 keyEvent.rawKey().sym() ==
1045 keyEvent.origKey().sym()) {
1048 FCITX_KEYTRACE() <<
"Will commit char: " << utf32;
1050 keyEvent.filterAndAccept();
1051 }
else if (!keyEvent.key().states().testAny(
1052 KeyStates{KeyState::Ctrl, KeyState::Alt}) &&
1053 keyEvent.rawKey().sym() !=
1054 keyEvent.origKey().sym() &&
1059 keyEvent.filterAndAccept();
1065 d->eventWatchers_.emplace_back(d->watchEvent(
1067 [
this, d](
Event &event) {
1068 auto &icEvent = static_cast<InputContextEvent &>(event);
1069 auto isSameProgram = [&icEvent, d]() {
1071 return (icEvent.inputContext() == d->lastUnFocusedIc_.get()) ||
1072 (!icEvent.inputContext()->program().empty() &&
1073 (icEvent.inputContext()->program() ==
1074 d->lastUnFocusedProgram_));
1077 if (d->globalConfig_.resetStateWhenFocusIn() ==
1078 PropertyPropagatePolicy::All ||
1079 (d->globalConfig_.resetStateWhenFocusIn() ==
1080 PropertyPropagatePolicy::Program &&
1081 !isSameProgram())) {
1082 if (d->globalConfig_.activeByDefault()) {
1083 activate(icEvent.inputContext());
1085 deactivate(icEvent.inputContext());
1089 activateInputMethod(icEvent);
1091 auto *inputContext = icEvent.inputContext();
1092 if (!inputContext->clientControlVirtualkeyboardShow()) {
1093 inputContext->showVirtualKeyboard();
1096 if (!d->globalConfig_.showInputMethodInformationWhenFocusIn()) {
1107 d->focusInImInfoTimer_ = d->eventLoop_.addTimeEvent(
1108 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1113 if (
auto *ic = icRef.get();
1114 ic && ic->hasFocus() &&
1116 d->showInputMethodInformation(ic);
1121 d->eventWatchers_.emplace_back(d->watchEvent(
1124 auto &icEvent = static_cast<InputContextEvent &>(event);
1125 auto *ic = icEvent.inputContext();
1126 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1127 inputState->reset();
1128 if (!ic->capabilityFlags().test(
1129 CapabilityFlag::ClientUnfocusCommit)) {
1132 ic->inputPanel().clientPreedit().toStringForCommit();
1133 if (!commit.empty()) {
1134 ic->commitString(commit);
1138 d->eventWatchers_.emplace_back(d->watchEvent(
1140 [
this, d](
Event &event) {
1141 auto &icEvent = static_cast<InputContextEvent &>(event);
1142 d->lastUnFocusedProgram_ = icEvent.inputContext()->program();
1143 d->lastUnFocusedIc_ = icEvent.inputContext()->watch();
1144 deactivateInputMethod(icEvent);
1146 auto *inputContext = icEvent.inputContext();
1147 if (!inputContext->clientControlVirtualkeyboardHide()) {
1148 inputContext->hideVirtualKeyboard();
1151 d->eventWatchers_.emplace_back(d->watchEvent(
1154 auto &icEvent = static_cast<InputContextEvent &>(event);
1155 auto *ic = icEvent.inputContext();
1156 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1157 inputState->reset();
1159 d->eventWatchers_.emplace_back(
1161 [
this](
Event &event) {
1163 auto *ic = icEvent.inputContext();
1164 if (!ic->hasFocus()) {
1167 auto *engine = inputMethodEngine(ic);
1168 const auto *entry = inputMethodEntry(ic);
1169 if (!engine || !entry) {
1172 engine->reset(*entry, icEvent);
1174 d->eventWatchers_.emplace_back(d->watchEvent(
1176 EventWatcherPhase::ReservedFirst, [
this](
Event &event) {
1178 static_cast<InputContextSwitchInputMethodEvent &>(event);
1179 auto *ic = icEvent.inputContext();
1180 if (!ic->hasFocus()) {
1183 deactivateInputMethod(icEvent);
1184 activateInputMethod(icEvent);
1186 d->eventWatchers_.emplace_back(d->watchEvent(
1188 EventWatcherPhase::ReservedLast, [
this, d](
Event &event) {
1190 static_cast<InputContextSwitchInputMethodEvent &>(event);
1191 auto *ic = icEvent.inputContext();
1192 if (!ic->hasFocus()) {
1196 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1197 inputState->lastIMChangeIsAltTrigger_ =
1209 showInputMethodInformation(ic);
1211 d->eventWatchers_.emplace_back(
1213 EventWatcherPhase::ReservedLast, [
this, d](
Event &) {
1216 d->imGroupInfoTimer_ = d->eventLoop_.addTimeEvent(
1217 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1218 [this](EventSourceTime *, uint64_t) {
1219 inputContextManager().foreachFocused(
1220 [this](InputContext *ic) {
1221 showInputMethodInformation(ic);
1228 d->eventWatchers_.emplace_back(d->watchEvent(
1229 EventType::InputContextUpdateUI, EventWatcherPhase::ReservedFirst,
1231 auto &icEvent = static_cast<InputContextUpdateUIEvent &>(event);
1232 if (icEvent.immediate()) {
1233 d->uiManager_.update(icEvent.component(),
1234 icEvent.inputContext());
1235 d->uiManager_.flush();
1237 d->uiManager_.update(icEvent.component(),
1238 icEvent.inputContext());
1239 d->uiUpdateEvent_->setOneShot();
1242 d->eventWatchers_.emplace_back(d->watchEvent(
1243 EventType::InputContextDestroyed, EventWatcherPhase::ReservedFirst,
1245 auto &icEvent = static_cast<InputContextEvent &>(event);
1246 d->uiManager_.expire(icEvent.inputContext());
1248 d->eventWatchers_.emplace_back(d->watchEvent(
1250 [d](
Event &) { d->uiManager_.updateAvailability(); }));
1251 d->uiUpdateEvent_ = d->eventLoop_.addDeferEvent([d](
EventSource *) {
1252 d->uiManager_.flush();
1255 d->uiUpdateEvent_->setEnabled(
false);
1256 d->periodicalSave_ = d->eventLoop_.addTimeEvent(
1257 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, AutoSaveIdleTime,
1264 auto currentTime = now(CLOCK_MONOTONIC);
1265 if (currentTime <= d->idleStartTimestamp_ ||
1266 currentTime - d->idleStartTimestamp_ < AutoSaveIdleTime) {
1268 time->setNextInterval(2 * AutoSaveIdleTime);
1273 FCITX_INFO() <<
"Running autosave...";
1275 FCITX_INFO() <<
"End autosave";
1276 if (d->globalConfig_.autoSavePeriod() > 0) {
1277 time->setNextInterval(d->globalConfig_.autoSavePeriod() *
1278 AutoSaveMinInUsecs);
1283 d->periodicalSave_->setEnabled(
false);
1286 Instance::~Instance() {
1288 d->tempModeManager_.reset();
1289 d->icManager_.finalize();
1290 d->addonManager_.unload();
1291 d->notifications_ =
nullptr;
1292 d->icManager_.setInstance(
nullptr);
1295 void InstanceArgument::parseOption(
int argc,
char **argv) {
1301 struct option longOptions[] = {{
"enable", required_argument,
nullptr, 0},
1302 {
"disable", required_argument,
nullptr, 0},
1303 {
"verbose", required_argument,
nullptr, 0},
1304 {
"keep", no_argument,
nullptr,
'k'},
1305 {
"ui", required_argument,
nullptr,
'u'},
1306 {
"replace", no_argument,
nullptr,
'r'},
1307 {
"version", no_argument,
nullptr,
'v'},
1308 {
"help", no_argument,
nullptr,
'h'},
1309 {
"option", required_argument,
nullptr,
'o'},
1310 {
nullptr, 0, 0, 0}};
1312 int optionIndex = 0;
1314 std::string addonOptionString;
1315 while ((c = getopt_long(argc, argv,
"ru:dDs:hvo:k", longOptions,
1316 &optionIndex)) != EOF) {
1319 switch (optionIndex) {
1327 Log::setLogRule(optarg);
1345 runAsDaemon =
false;
1348 exitWhenMainDisplayDisconnected =
false;
1351 overrideDelay = std::atoi(optarg);
1362 addonOptionString = optarg;
1373 std::unordered_map<std::string, std::vector<std::string>> addonOptions;
1374 for (
const std::string_view item :
1377 if (tokens.size() != 2) {
1382 addonOptions_ = std::move(addonOptions);
1390 d->signalPipe_ = fd;
1391 d->signalPipeEvent_ = d->eventLoop_.addIOEvent(
1401 return d->arg_.tryReplace;
1406 return d->arg_.exitWhenMainDisplayDisconnected;
1414 void Instance::handleSignal() {
1418 while (
fs::safeRead(d->signalPipe_, &signo,
sizeof(signo)) > 0) {
1419 if (signo == SIGINT || signo == SIGTERM || signo == SIGQUIT ||
1422 }
else if (signo == SIGUSR1) {
1424 }
else if (signo == SIGCHLD) {
1425 d->zombieReaper_->setNextInterval(2000000);
1426 d->zombieReaper_->setOneShot();
1434 if (!d->arg_.uiName.empty()) {
1435 d->arg_.enableList.push_back(d->arg_.uiName);
1438 d->icManager_.registerProperty(
"inputState", &d->inputStateFactory_);
1439 std::unordered_set<std::string> enabled;
1440 std::unordered_set<std::string> disabled;
1441 std::tie(enabled, disabled) = d->overrideAddons();
1442 FCITX_INFO() <<
"Override Enabled Addons: " << enabled;
1443 FCITX_INFO() <<
"Override Disabled Addons: " << disabled;
1444 d->addonManager_.load(enabled, disabled);
1449 d->uiManager_.load(d->arg_.uiName);
1451 const auto *entry = d->imManager_.entry(
"keyboard-us");
1452 FCITX_LOG_IF(Error, !entry) <<
"Couldn't find keyboard-us";
1453 d->preloadInputMethodEvent_ = d->eventLoop_.addTimeEvent(
1454 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, 0,
1457 if (d->exit_ || !d->globalConfig_.preloadInputMethod()) {
1461 if (!d->imManager_.currentGroup().inputMethodList().empty()) {
1462 if (
const auto *entry =
1463 d->imManager_.entry(d->imManager_.currentGroup()
1464 .inputMethodList()[0]
1466 d->addonManager_.addon(entry->addon(),
true);
1470 if (!d->imManager_.currentGroup().defaultInputMethod().empty()) {
1471 if (
const auto *entry = d->imManager_.entry(
1472 d->imManager_.currentGroup().defaultInputMethod())) {
1473 d->addonManager_.addon(entry->addon(),
true);
1479 d->zombieReaper_ = d->eventLoop_.addTimeEvent(
1480 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 0,
1483 while ((res = waitpid(-1,
nullptr, WNOHANG)) > 0) {
1487 d->zombieReaper_->setEnabled(
false);
1490 d->exitEvent_ = d->eventLoop_.addExitEvent([
this](
EventSource *) {
1491 FCITX_DEBUG() <<
"Running save...";
1495 d->notifications_ = d->addonManager_.addon(
"notifications",
true);
1500 if (d->arg_.quietQuit) {
1507 return d->exitCode_;
1510 auto r = eventLoop().exec();
1511 d->running_ =
false;
1513 return r ? d->exitCode_ : 1;
1518 d->running_ = running;
1528 return d->inputMethodMode_;
1533 if (d->inputMethodMode_ == mode) {
1536 d->inputMethodMode_ = mode;
1545 bool Instance::virtualKeyboardAutoShow()
const {
1547 return d->virtualKeyboardAutoShow_;
1550 void Instance::setVirtualKeyboardAutoShow(
bool autoShow) {
1552 d->virtualKeyboardAutoShow_ = autoShow;
1555 bool Instance::virtualKeyboardAutoHide()
const {
1557 return d->virtualKeyboardAutoHide_;
1560 void Instance::setVirtualKeyboardAutoHide(
bool autoHide) {
1562 d->virtualKeyboardAutoHide_ = autoHide;
1565 VirtualKeyboardFunctionMode Instance::virtualKeyboardFunctionMode()
const {
1567 return d->virtualKeyboardFunctionMode_;
1570 void Instance::setVirtualKeyboardFunctionMode(
1571 VirtualKeyboardFunctionMode mode) {
1573 d->virtualKeyboardFunctionMode_ = mode;
1578 d->binaryMode_ =
true;
1583 const auto &addonNames = d->addonManager_.loadedAddonNames();
1584 return d->binaryMode_ &&
1585 std::all_of(addonNames.begin(), addonNames.end(),
1586 [d](
const std::string &name) {
1587 auto *addon = d->addonManager_.lookupAddon(name);
1591 return addon->canRestart();
1595 InstancePrivate *Instance::privateData() {
1602 return d->eventLoop_;
1607 return d->eventDispatcher_;
1612 return d->icManager_;
1617 return d->addonManager_;
1622 return d->imManager_;
1627 return d->imManager_;
1632 return *d->tempModeManager_;
1637 return d->uiManager_;
1642 return d->globalConfig_;
1645 bool Instance::postEvent(
Event &event) {
1646 return std::as_const(*this).postEvent(event);
1649 bool Instance::postEvent(
Event &event)
const {
1654 auto iter = d->eventHandlers_.find(event.
type());
1655 if (iter != d->eventHandlers_.end()) {
1656 const auto &handlers = iter->second;
1657 EventWatcherPhase phaseOrder[] = {
1658 EventWatcherPhase::ReservedFirst, EventWatcherPhase::PreInputMethod,
1659 EventWatcherPhase::InputMethod, EventWatcherPhase::PostInputMethod,
1660 EventWatcherPhase::ReservedLast};
1662 for (
auto phase : phaseOrder) {
1663 if (
auto iter2 = handlers.find(phase); iter2 != handlers.end()) {
1664 for (
auto &handler : iter2->second.view()) {
1679 auto &keyEvent =
static_cast<KeyEvent &
>(event);
1680 auto *ic = keyEvent.inputContext();
1681 #ifdef ENABLE_KEYBOARD 1683 if (!keyEvent.forward() && !keyEvent.origKey().code()) {
1686 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1687 auto *xkbState = inputState->customXkbState();
1694 xkb_state_update_key(xkbState, keyEvent.origKey().code(),
1695 keyEvent.isRelease() ? XKB_KEY_UP
1699 if (ic->capabilityFlags().test(CapabilityFlag::KeyEventOrderFix) &&
1700 !keyEvent.accepted() && ic->hasPendingEventsStrictOrder()) {
1703 keyEvent.filterAndAccept();
1704 ic->forwardKey(keyEvent.origKey(), keyEvent.isRelease(),
1707 d_ptr->uiManager_.flush();
1710 return event.accepted();
1713 std::unique_ptr<HandlerTableEntry<EventHandler>>
1715 EventHandler callback) {
1717 if (phase == EventWatcherPhase::ReservedFirst ||
1718 phase == EventWatcherPhase::ReservedLast) {
1719 throw std::invalid_argument(
"Reserved Phase is only for internal use");
1721 return d->watchEvent(type, phase, std::move(callback));
1724 bool groupContains(
const InputMethodGroup &group,
const std::string &name) {
1725 const auto &list = group.inputMethodList();
1726 auto iter = std::find_if(list.begin(), list.end(),
1728 return item.name() == name;
1730 return iter != list.end();
1735 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1738 if (!inputState->overrideDeactivateIM_.empty()) {
1739 return inputState->overrideDeactivateIM_;
1742 const auto &group = d->imManager_.currentGroup();
1745 !d->globalConfig_.allowInputMethodForPassword())) {
1746 auto defaultLayoutIM =
1747 stringutils::concat(
"keyboard-", group.defaultLayout());
1748 const auto *entry = d->imManager_.entry(defaultLayoutIM);
1750 entry = d->imManager_.entry(
"keyboard-us");
1752 return entry ? entry->uniqueName() :
"";
1755 if (group.inputMethodList().empty()) {
1758 if (inputState->isActive()) {
1759 if (!inputState->localIM_.empty() &&
1760 groupContains(group, inputState->localIM_)) {
1761 return inputState->localIM_;
1763 return group.defaultInputMethod();
1766 return group.inputMethodList()[0].name();
1771 auto imName = inputMethod(ic);
1772 if (imName.empty()) {
1775 return d->imManager_.entry(imName);
1780 const auto *entry = inputMethodEntry(ic);
1785 d->addonManager_.addon(entry->addon(),
true));
1790 const auto *entry = d->imManager_.entry(name);
1795 d->addonManager_.addon(entry->addon(),
true));
1800 const auto *entry = inputMethodEntry(ic);
1802 auto *engine = inputMethodEngine(ic);
1804 icon = engine->subModeIcon(*entry, *ic);
1807 icon = entry->icon();
1810 icon =
"input-keyboard";
1818 const auto *entry = inputMethodEntry(ic);
1819 auto *engine = inputMethodEngine(ic);
1821 if (engine && entry) {
1822 label = engine->subModeLabel(*entry, *ic);
1824 if (label.empty() && entry) {
1825 label = entry->label();
1831 #ifdef ENABLE_KEYBOARD 1833 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1835 auto *xkbComposeState = state->xkbComposeState();
1836 if (!xkbComposeState) {
1840 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1842 enum xkb_compose_feed_result result =
1843 xkb_compose_state_feed(xkbComposeState, keyval);
1844 if (result == XKB_COMPOSE_FEED_IGNORED) {
1848 enum xkb_compose_status status =
1849 xkb_compose_state_get_status(xkbComposeState);
1850 if (status == XKB_COMPOSE_NOTHING) {
1853 if (status == XKB_COMPOSE_COMPOSED) {
1854 char buffer[FCITX_UTF8_MAX_LENGTH + 1] = {
'\0',
'\0',
'\0',
'\0',
1857 xkb_compose_state_get_utf8(xkbComposeState, buffer,
sizeof(buffer));
1858 xkb_compose_state_reset(xkbComposeState);
1860 return FCITX_INVALID_COMPOSE_RESULT;
1866 if (status == XKB_COMPOSE_CANCELLED) {
1867 xkb_compose_state_reset(xkbComposeState);
1870 return FCITX_INVALID_COMPOSE_RESULT;
1873 FCITX_UNUSED(keysym);
1880 #ifdef ENABLE_KEYBOARD 1882 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1884 auto *xkbComposeState = state->xkbComposeState();
1885 if (!xkbComposeState) {
1886 return std::string();
1889 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1890 enum xkb_compose_feed_result result =
1891 xkb_compose_state_feed(xkbComposeState, keyval);
1893 if (result == XKB_COMPOSE_FEED_IGNORED) {
1894 return std::string();
1897 enum xkb_compose_status status =
1898 xkb_compose_state_get_status(xkbComposeState);
1899 if (status == XKB_COMPOSE_NOTHING) {
1900 return std::string();
1902 if (status == XKB_COMPOSE_COMPOSED) {
1904 std::array<char, 256> buffer;
1905 auto length = xkb_compose_state_get_utf8(xkbComposeState, buffer.data(),
1907 xkb_compose_state_reset(xkbComposeState);
1909 return std::nullopt;
1912 auto bufferBegin = buffer.begin();
1913 auto bufferEnd = std::next(bufferBegin,
length);
1915 return std::string(bufferBegin, bufferEnd);
1917 return std::nullopt;
1919 if (status == XKB_COMPOSE_CANCELLED) {
1920 xkb_compose_state_reset(xkbComposeState);
1922 return std::nullopt;
1925 FCITX_UNUSED(keysym);
1926 return std::string();
1931 #ifdef ENABLE_KEYBOARD 1933 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1935 auto *xkbComposeState = state->xkbComposeState();
1936 if (!xkbComposeState) {
1940 return xkb_compose_state_get_status(xkbComposeState) ==
1941 XKB_COMPOSE_COMPOSING;
1943 FCITX_UNUSED(inputContext);
1949 #ifdef ENABLE_KEYBOARD 1951 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1952 auto *xkbComposeState = state->xkbComposeState();
1953 if (!xkbComposeState) {
1956 xkb_compose_state_reset(xkbComposeState);
1958 FCITX_UNUSED(inputContext);
1965 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
1966 d->imManager_.save();
1967 d->addonManager_.saveAll();
1972 if (
auto *ic = mostRecentInputContext()) {
1973 CheckInputMethodChanged imChangedRAII(ic, d);
1980 if (
const auto *entry = inputMethodManager().entry(imName)) {
1981 return entry->uniqueName();
1991 void Instance::configureAddon(
const std::string & ) {}
1993 void Instance::configureInputMethod(
const std::string & ) {}
1996 if (
auto *ic = mostRecentInputContext()) {
1997 if (
const auto *entry = inputMethodEntry(ic)) {
1998 return entry->uniqueName();
2006 return d->uiManager_.currentUI();
2011 if (
auto *ic = mostRecentInputContext()) {
2012 CheckInputMethodChanged imChangedRAII(ic, d);
2022 d->exitCode_ = exitCode;
2024 d->eventLoop_.exit();
2029 auto *addon = addonManager().addon(addonName);
2031 addon->reloadConfig();
2037 auto [enabled, disabled] = d->overrideAddons();
2038 d->addonManager_.load(enabled, disabled);
2039 d->imManager_.refresh();
2044 readAsIni(d->globalConfig_.config(), StandardPathsType::PkgConfig,
2046 FCITX_DEBUG() <<
"Trigger Key: " 2048 d->icManager_.setPropertyPropagatePolicy(
2049 d->globalConfig_.shareInputState());
2050 if (d->globalConfig_.preeditEnabledByDefault() !=
2051 d->icManager_.isPreeditEnabledByDefault()) {
2052 d->icManager_.setPreeditEnabledByDefault(
2053 d->globalConfig_.preeditEnabledByDefault());
2059 #ifdef ENABLE_KEYBOARD 2060 d->keymapCache_.clear();
2061 if (d->inputStateFactory_.registered()) {
2063 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2064 inputState->resetXkbState();
2073 if (d->globalConfig_.autoSavePeriod() <= 0) {
2074 d->periodicalSave_->setEnabled(
false);
2076 d->periodicalSave_->setNextInterval(AutoSaveMinInUsecs *
2077 d->globalConfig_.autoSavePeriod());
2078 d->periodicalSave_->setOneShot();
2089 if (!canRestart()) {
2097 setCurrentInputMethod(mostRecentInputContext(), name,
false);
2103 if (!canTrigger()) {
2107 auto &imManager = inputMethodManager();
2108 const auto &imList = imManager.currentGroup().inputMethodList();
2109 auto iter = std::find_if(imList.begin(), imList.end(),
2111 return item.name() == name;
2113 if (iter == imList.end()) {
2117 auto setGlobalDefaultInputMethod = [d](
const std::string &name) {
2118 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2119 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2121 groupRAIICheck.push_back(
2122 std::make_unique<CheckInputMethodChanged>(ic, d));
2125 d->imManager_.setDefaultInputMethod(name);
2128 auto idx = std::distance(imList.begin(), iter);
2130 CheckInputMethodChanged imChangedRAII(ic, d);
2131 auto currentIM = inputMethod(ic);
2132 if (currentIM == name) {
2135 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2139 inputState->setLocalIM(name);
2141 inputState->setLocalIM({});
2143 setGlobalDefaultInputMethod(name);
2145 inputState->setActive(
true);
2147 inputState->setActive(
false);
2149 if (inputState->imChanged_) {
2159 setGlobalDefaultInputMethod(name);
2167 if (
auto *ic = mostRecentInputContext()) {
2168 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
2169 return inputState->isActive() ? 2 : 1;
2176 if (
auto *ic = mostRecentInputContext()) {
2177 CheckInputMethodChanged imChangedRAII(ic, d);
2184 if (
auto *ic = mostRecentInputContext()) {
2185 CheckInputMethodChanged imChangedRAII(ic, d);
2186 enumerate(ic, forward);
2190 bool Instance::canTrigger()
const {
2191 const auto &imManager = inputMethodManager();
2192 return (imManager.currentGroup().inputMethodList().size() > 1);
2196 if (!canTrigger()) {
2200 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2201 if (inputState->isActive()) {
2204 return inputState->lastIMChangeIsAltTrigger_;
2209 if (!canTrigger()) {
2213 if (d->globalConfig_.enumerateSkipFirst()) {
2214 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2215 if (!inputState->isActive()) {
2218 return d->imManager_.currentGroup().inputMethodList().size() > 2;
2224 bool Instance::canChangeGroup()
const {
2225 const auto &imManager = inputMethodManager();
2226 return (imManager.groupCount() > 1);
2231 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2232 if (!canTrigger()) {
2235 inputState->setActive(!inputState->isActive());
2236 if (inputState->imChanged_) {
2237 inputState->imChanged_->setReason(reason);
2242 bool Instance::trigger(
InputContext *ic,
bool totallyReleased) {
2244 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2245 if (!canTrigger()) {
2250 if (totallyReleased) {
2252 inputState->firstTrigger_ =
true;
2254 if (!d->globalConfig_.enumerateWithTriggerKeys() ||
2255 (inputState->firstTrigger_ && inputState->isActive()) ||
2256 (d->globalConfig_.enumerateSkipFirst() &&
2257 d->imManager_.currentGroup().inputMethodList().size() <= 2)) {
2260 enumerate(ic,
true);
2262 inputState->firstTrigger_ =
false;
2268 if (!canAltTrigger(ic)) {
2278 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2279 if (!canTrigger()) {
2282 if (inputState->isActive()) {
2285 inputState->setActive(
true);
2286 if (inputState->imChanged_) {
2294 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2295 if (!canTrigger()) {
2298 if (!inputState->isActive()) {
2301 inputState->setActive(
false);
2302 if (inputState->imChanged_) {
2303 inputState->imChanged_->setReason(
2311 auto &imManager = inputMethodManager();
2312 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2313 const auto &imList = imManager.currentGroup().inputMethodList();
2314 if (!canTrigger()) {
2318 if (d->globalConfig_.enumerateSkipFirst() && imList.size() <= 2) {
2322 auto currentIM = inputMethod(ic);
2324 auto iter = std::ranges::find_if(
2326 return item.name() == currentIM;
2328 if (iter == imList.end()) {
2331 int idx = std::distance(imList.begin(), iter);
2332 auto nextIdx = [forward, &imList](
int idx) {
2334 return (idx + (forward ? 1 : (imList.size() - 1))) % imList.size();
2338 if (d->globalConfig_.enumerateSkipFirst() && idx == 0) {
2342 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2343 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2345 groupRAIICheck.push_back(
2346 std::make_unique<CheckInputMethodChanged>(ic, d));
2349 imManager.setDefaultInputMethod(imList[idx].name());
2350 inputState->setActive(
true);
2351 inputState->setLocalIM({});
2353 inputState->setActive(
false);
2355 if (inputState->imChanged_) {
2363 const std::string &orig) {
2364 std::string result = orig;
2365 emit<Instance::CommitFilter>(inputContext, result);
2371 emit<Instance::OutputFilter>(inputContext, result);
2372 if ((&orig == &inputContext->inputPanel().clientPreedit() ||
2373 &orig == &inputContext->inputPanel().preedit()) &&
2374 !globalConfig().showPreeditForPassword() &&
2375 inputContext->capabilityFlags().test(CapabilityFlag::Password)) {
2377 for (
int i = 0, e = result.size(); i < e; i++) {
2382 dot +=
"\xe2\x80\xa2";
2385 newText.append(std::move(dot),
2386 result.formatAt(i) | TextFormatFlag::DontCommit);
2388 result = std::move(newText);
2395 return d->icManager_.lastFocusedInputContext();
2400 return d->icManager_.mostRecentInputContext();
2405 d->uiManager_.flush();
2408 int scoreForGroup(
FocusGroup *group,
const std::string &displayHint) {
2410 if (displayHint.empty()) {
2411 if (group->display() ==
"x11:") {
2414 if (group->display().starts_with(
"x11:")) {
2417 if (group->display() ==
"wayland:") {
2420 if (group->display().starts_with(
"wayland:")) {
2424 if (group->display() == displayHint) {
2427 if (group->display().starts_with(displayHint)) {
2439 d->icManager_.foreachGroup(
2440 [&score, &displayHint, &defaultFocusGroup](
FocusGroup *group) {
2441 auto newScore = scoreForGroup(group, displayHint);
2442 if (newScore > score) {
2443 defaultFocusGroup = group;
2449 return defaultFocusGroup;
2454 FCITX_DEBUG() <<
"Instance::activateInputMethod";
2456 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2457 const auto *entry = inputMethodEntry(ic);
2459 FCITX_DEBUG() <<
"Activate: " 2460 <<
"[Last]:" << inputState->lastIM_
2461 <<
" [Activating]:" << entry->uniqueName();
2462 assert(inputState->lastIM_.empty());
2463 inputState->lastIM_ = entry->uniqueName();
2465 auto *engine = inputMethodEngine(ic);
2466 if (!engine || !entry) {
2469 #ifdef ENABLE_KEYBOARD 2470 if (
auto *xkbState = inputState->customXkbState(
true)) {
2471 if (
auto *mods = findValue(d->stateMask_, ic->
display())) {
2472 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
2473 auto depressed = std::get<0>(*mods);
2474 auto latched = std::get<1>(*mods);
2475 auto locked = std::get<2>(*mods);
2480 FCITX_KEYTRACE() << depressed <<
" " << latched <<
" " << locked;
2481 if (depressed == 0) {
2482 inputState->setModsAllReleased();
2484 xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0,
2490 engine->activate(*entry, event);
2496 FCITX_DEBUG() <<
"Instance::deactivateInputMethod event_type=" 2497 <<
static_cast<uint32_t
>(
event.type());
2499 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2506 FCITX_DEBUG() <<
"Switch reason: " 2507 <<
static_cast<int>(icEvent.reason());
2508 FCITX_DEBUG() <<
"Old Input method: " << icEvent.oldInputMethod();
2509 entry = d->imManager_.entry(icEvent.oldInputMethod());
2511 entry = inputMethodEntry(ic);
2514 FCITX_DEBUG() <<
"Deactivate: " 2515 <<
"[Last]:" << inputState->lastIM_
2516 <<
" [Deactivating]:" << entry->uniqueName();
2517 assert(entry->uniqueName() == inputState->lastIM_);
2519 d->addonManager_.addon(entry->addon()));
2521 inputState->lastIM_.clear();
2522 if (!engine || !entry) {
2525 inputState->overrideDeactivateIM_ = entry->uniqueName();
2527 inputState->overrideDeactivateIM_.clear();
2531 bool Instance::enumerateGroup(
bool forward) {
2532 auto &imManager = inputMethodManager();
2533 auto groups = imManager.groups();
2534 if (groups.size() <= 1) {
2538 imManager.setCurrentGroup(groups[1]);
2540 imManager.setCurrentGroup(groups.back());
2546 FCITX_DEBUG() <<
"Input method switched";
2548 if (!d->globalConfig_.showInputMethodInformation()) {
2551 d->showInputMethodInformation(ic);
2555 const std::string &message) {
2556 FCITX_DEBUG() <<
"Input method switched";
2558 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2559 inputState->showInputMethodInformation(message);
2564 return (isInFlatpak() &&
2565 std::filesystem::is_regular_file(
"/app/.updated")) ||
2566 d->addonManager_.checkUpdate() || d->imManager_.checkUpdate() ||
2571 const std::string &rule,
2572 const std::string &model,
2573 const std::string &options) {
2574 #ifdef ENABLE_KEYBOARD 2576 bool resetState =
false;
2577 if (
auto *param = findValue(d->xkbParams_, display)) {
2578 if (std::get<0>(*param) != rule || std::get<1>(*param) != model ||
2579 std::get<2>(*param) != options) {
2580 std::get<0>(*param) = rule;
2581 std::get<1>(*param) = model;
2582 std::get<2>(*param) = options;
2586 d->xkbParams_.emplace(display, std::make_tuple(rule, model, options));
2590 d->keymapCache_[display].clear();
2591 d->icManager_.foreach([d, &display](
InputContext *ic) {
2592 if (ic->
display() == display ||
2593 !d->xkbParams_.contains(ic->
display())) {
2594 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2595 inputState->resetXkbState();
2601 FCITX_UNUSED(display);
2603 FCITX_UNUSED(model);
2604 FCITX_UNUSED(options);
2609 uint32_t depressed_mods,
2610 uint32_t latched_mods, uint32_t locked_mods) {
2612 d->stateMask_[display] =
2613 std::make_tuple(depressed_mods, latched_mods, locked_mods);
2618 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.
Manage registered TempMode objects for an Instance.
Simple file system related API for checking file status.
size_t length(Iter start, Iter end)
Return the number UTF-8 characters in the string iterator range.
bool validate(Iter start, Iter end)
Check if the string iterator range is valid utf8 string.
when user switch to a different input method by hand such as ctrl+shift by default, or by ui, default behavior is reset IM.
InputMethodSwitchedReason
The reason why input method is switched to another.
void deactivate()
Deactivate last focused input context.
int state()
Return a fcitx5-remote compatible value for the state.
InputMethodEngine * inputMethodEngine(InputContext *ic)
Return the input method engine object for given input context.
void setSignalPipe(int fd)
Set the pipe forwarding unix signal information.
InputMethodMode inputMethodMode() const
The current global input method mode.
void initialize()
Initialize fcitx.
EventLoop & eventLoop()
Get the fcitx event loop.
std::string currentUI()
Return the name of current user interface addon.
bool exitWhenMainDisplayDisconnected() const
Check whether command line specify whether to keep fcitx running.
C++ Utility functions for handling utf8 strings.
InputContext * mostRecentInputContext()
Return the most recent focused input context.
FCITX_NODISCARD std::unique_ptr< HandlerTableEntry< EventHandler > > watchEvent(EventType type, EventWatcherPhase phase, EventHandler callback)
Add a callback to for certain event type.
InputContextManager & inputContextManager()
Get the input context manager.
void setEnablePreedit(bool enable)
Override the preedit hint from client.
std::vector< std::string > split(std::string_view str, std::string_view delim, SplitBehavior behavior)
Split the string by delim.
virtual bool filtered() const
Whether a event is filtered by handler.
void clearGroup(StatusGroup group)
Clear only given status group.
bool hasFocus() const
Returns whether the input context holds the input focus.
bool isRunning() const
Whether event loop is started and still running.
A class represents a formatted string.
bool willTryReplace() const
Check whether command line specify if it will replace an existing fcitx server.
Switched by group change.
bool isRestartRequested() const
Whether restart is requested.
Manager class for user interface.
Instance(int argc, char *argv[])
A main function like construct to be used to create Fcitx Instance.
Base class for fcitx event.
bool isValidChar(uint32_t c)
Check the chr value is not two invalid value above.
std::string inputMethodLabel(InputContext *ic)
Return the input method label for input context.
void save()
Save everything including input method profile and addon data.
Enum type for input context capability.
Class for status area in UI.
void resetInputMethodList()
Reset the input method configuration and recreate based on system language.
Switched by capability change (e.g. password field)
Base class for User Interface addon.
A thread safe class to post event to a certain EventLoop.
void clearXkbStateMask(const std::string &display)
Clear xkb state mask for given display.
Enum flag for text formatting.
void configure()
Launch configtool.
bool checkUpdate() const
Check if need to invoke Instance::refresh.
New Utility classes to handle application specific path.
uint32_t getChar(Iter iter, Iter end)
Get next UCS4 char from iter, do not cross end.
InvokeAction event is generated when client click on the preedit.
InputMethodManager & inputMethodManager()
Get the input method manager.
void reloadConfig()
Reload global config.
int exec()
Start the event loop of Fcitx.
C-style utf8 utility functions.
TempModeManager & tempModeManager()
Get the temporary mode manager.
void setBinaryMode()
Set if this instance is running as fcitx5 binary.
bool isModifier() const
Check if the key is a modifier press.
InputContext * lastFocusedInputContext()
Return a focused input context.
std::string display() const
Returns the display server of the client.
void toggle()
Toggle between the first input method and active input method.
void setCurrentInputMethod(const std::string &imName)
Set the input method of last focused input context.
void setRunning(bool running)
Let other know that event loop is already running.
bool canRestart() const
Check if fcitx 5 can safely restart by itself.
void showCustomInputMethodInformation(InputContext *ic, const std::string &message)
Show a small popup with input popup window with current input method information. ...
std::optional< std::string > processComposeString(InputContext *ic, KeySym keysym)
Handle current XCompose state.
void refresh()
Load newly installed input methods and addons.
Input method mode changed.
std::string inputMethod(InputContext *ic)
Return the unique name of input method for given input context.
UserInterfaceManager & userInterfaceManager()
Get the user interface manager.
void enumerate(bool forward)
Enumerate input method with in current group.
bool exiting() const
Check whether fcitx is in exiting process.
void showInputMethodInformation(InputContext *ic)
Show a small popup with input popup window with current input method information. ...
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.