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().setOverlayMessage(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.overlayMessage().size() == 1 &&
619 panel.overlayMessage().stringAt(0) == lastInfo_) {
620 panel.setOverlayMessage(Text());
625 #ifdef ENABLE_KEYBOARD 626 void InputState::resetXkbState() {
627 lastXkbLayout_.clear();
632 CheckInputMethodChanged::CheckInputMethodChanged(InputContext *ic,
633 InstancePrivate *instance)
634 : instance_(instance->q_func()), instancePrivate_(instance),
635 ic_(ic->watch()), inputMethod_(instance_->inputMethod(ic)),
637 auto *inputState = ic->propertyFor(&instance->inputStateFactory_);
638 if (!inputState->imChanged_) {
639 inputState->imChanged_ =
this;
645 CheckInputMethodChanged::~CheckInputMethodChanged() {
646 if (!ic_.isValid()) {
649 auto *ic = ic_.get();
650 auto *inputState = ic->propertyFor(&instancePrivate_->inputStateFactory_);
651 inputState->imChanged_ =
nullptr;
652 if (inputMethod_ != instance_->inputMethod(ic) && !ignore_) {
653 instance_->postEvent(
654 InputContextSwitchInputMethodEvent(reason_, inputMethod_, ic));
659 InstanceArgument arg;
660 arg.parseOption(argc, argv);
668 FCITX_LOG_IF(Info, isInFlatpak()) <<
"Running inside flatpak.";
670 if (arg.runAsDaemon) {
674 if (arg.overrideDelay > 0) {
675 sleep(arg.overrideDelay);
679 d_ptr = std::make_unique<InstancePrivate>(
this);
682 d->eventDispatcher_.attach(&d->eventLoop_);
683 d->addonManager_.setInstance(
this);
684 d->addonManager_.setAddonOptions(arg.addonOptions_);
685 d->icManager_.setInstance(
this);
686 d->tempModeManager_ = std::make_unique<TempModeManager>(
this);
687 d->connections_.emplace_back(
688 d->imManager_.connect<InputMethodManager::CurrentGroupAboutToChange>(
689 [
this, d](
const std::string &lastGroup) {
690 d->icManager_.foreachFocused([this](InputContext *ic) {
691 assert(ic->hasFocus());
692 InputContextSwitchInputMethodEvent event(
693 InputMethodSwitchedReason::GroupChange, inputMethod(ic),
695 deactivateInputMethod(event);
698 d->lastGroup_ = lastGroup;
701 d->connections_.emplace_back(
702 d->imManager_.connect<InputMethodManager::CurrentGroupChanged>(
703 [
this, d](
const std::string &newGroup) {
704 d->icManager_.foreachFocused([this](InputContext *ic) {
705 assert(ic->hasFocus());
706 InputContextSwitchInputMethodEvent event(
707 InputMethodSwitchedReason::GroupChange,
"", ic);
708 activateInputMethod(event);
712 if (!d->lastGroup_.empty() && !newGroup.empty() &&
713 d->lastGroup_ != newGroup && d->notifications_ &&
714 d->imManager_.groupCount() > 1) {
715 d->notifications_->call<INotifications::showTip>(
716 "enumerate-group", _(
"Input Method"),
"input-keyboard",
718 _(
"Switched group to {0}",
719 d->imManager_.currentGroup().name()),
722 d->lastGroup_ = newGroup;
725 d->eventWatchers_.emplace_back(d->watchEvent(
726 EventType::InputContextCapabilityAboutToChange,
727 EventWatcherPhase::ReservedFirst, [
this, d](
Event &event) {
729 static_cast<CapabilityAboutToChangeEvent &>(event);
730 if (!capChanged.inputContext()->hasFocus()) {
735 capChanged.oldFlags(), capChanged.newFlags(),
736 d->globalConfig_.allowInputMethodForPassword())) {
742 inputMethod(capChanged.inputContext()),
743 capChanged.inputContext());
744 deactivateInputMethod(switchIM);
746 d->eventWatchers_.emplace_back(d->watchEvent(
747 EventType::InputContextCapabilityChanged,
748 EventWatcherPhase::ReservedFirst, [
this, d](
Event &event) {
749 auto &capChanged = static_cast<CapabilityChangedEvent &>(event);
750 if (!capChanged.inputContext()->hasFocus()) {
755 capChanged.oldFlags(), capChanged.newFlags(),
756 d->globalConfig_.allowInputMethodForPassword())) {
762 capChanged.inputContext());
763 activateInputMethod(switchIM);
766 d->eventWatchers_.emplace_back(watchEvent(
768 [
this, d](
Event &event) {
769 auto &keyEvent =
static_cast<KeyEvent &
>(event);
770 auto *ic = keyEvent.inputContext();
771 CheckInputMethodChanged imChangedRAII(ic, d);
772 auto origKey = keyEvent.origKey().normalize();
776 std::function<bool()> check;
777 std::function<void(bool)> trigger;
779 {.list = d->globalConfig_.triggerKeys(),
780 .check = [
this]() {
return canTrigger(); },
782 [
this, ic](
bool totallyReleased) {
783 return trigger(ic, totallyReleased);
785 {.list = d->globalConfig_.altTriggerKeys(),
786 .check = [
this, ic]() {
return canAltTrigger(ic); },
787 .trigger = [
this, ic](bool) {
return altTrigger(ic); }},
788 {.list = d->globalConfig_.activateKeys(),
789 .check = [ic, d]() {
return d->canActivate(ic); },
790 .trigger = [
this, ic](bool) {
return activate(ic); }},
791 {.list = d->globalConfig_.deactivateKeys(),
792 .check = [ic, d]() {
return d->canDeactivate(ic); },
793 .trigger = [
this, ic](bool) {
return deactivate(ic); }},
794 {.list = d->globalConfig_.enumerateForwardKeys(),
795 .check = [
this, ic]() {
return canEnumerate(ic); },
796 .trigger = [
this, ic](bool) {
return enumerate(ic,
true); }},
797 {.list = d->globalConfig_.enumerateBackwardKeys(),
798 .check = [
this, ic]() {
return canEnumerate(ic); },
799 .trigger = [
this, ic](bool) {
return enumerate(ic,
false); }},
800 {.list = d->globalConfig_.enumerateGroupForwardKeys(),
801 .check = [
this]() {
return canChangeGroup(); },
802 .trigger = [ic, d, origKey](
803 bool) { d->navigateGroup(ic, origKey,
true); }},
804 {.list = d->globalConfig_.enumerateGroupBackwardKeys(),
805 .check = [
this]() {
return canChangeGroup(); },
807 [ic, d, origKey](bool) {
808 d->navigateGroup(ic, origKey,
false);
812 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
813 int keyReleased = inputState->keyReleased_;
814 Key lastKeyPressed = inputState->lastKeyPressed_;
816 inputState->keyReleased_ = -1;
818 if (keyEvent.isRelease()) {
820 for (
auto &keyHandler : keyHandlers) {
821 if (keyReleased == idx &&
822 origKey.isReleaseOfModifier(lastKeyPressed) &&
823 keyHandler.check()) {
825 if (d->globalConfig_.checkModifierOnlyKeyTimeout(
826 inputState->lastKeyPressedTime_)) {
828 inputState->totallyReleased_);
830 inputState->lastKeyPressedTime_ = 0;
831 if (origKey.hasModifier()) {
832 inputState->totallyReleased_ =
false;
840 if (isSingleModifier(origKey)) {
841 inputState->totallyReleased_ =
true;
845 if (inputState->pendingGroupIndex_ &&
846 inputState->totallyReleased_) {
847 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
848 if (inputState->imChanged_) {
849 inputState->imChanged_->ignore();
851 d->acceptGroupChange(lastKeyPressed, ic);
852 inputState->lastKeyPressed_ =
Key();
855 if (!keyEvent.filtered() && !keyEvent.isRelease()) {
857 for (
auto &keyHandler : keyHandlers) {
858 auto keyIdx = origKey.keyListIndex(keyHandler.list);
859 if (keyIdx >= 0 && keyHandler.check()) {
860 inputState->keyReleased_ = idx;
861 inputState->lastKeyPressed_ = origKey;
863 inputState->lastKeyPressedTime_ =
864 now(CLOCK_MONOTONIC);
870 keyHandler.trigger(inputState->totallyReleased_);
871 if (origKey.hasModifier()) {
872 inputState->totallyReleased_ =
false;
874 keyEvent.filterAndAccept();
881 d->eventWatchers_.emplace_back(watchEvent(
884 auto &keyEvent =
static_cast<KeyEvent &
>(event);
885 auto *ic = keyEvent.inputContext();
886 if (!keyEvent.isRelease() &&
887 keyEvent.key().checkKeyList(
888 d->globalConfig_.togglePreeditKeys())) {
891 ic->setEnablePreedit(!ic->isPreeditEnabled());
892 if (d->notifications_) {
893 d->notifications_->call<INotifications::showTip>(
894 "toggle-preedit", _(
"Input Method"),
"", _(
"Preedit"),
895 ic->isPreeditEnabled() ? _(
"Preedit enabled")
896 : _(
"Preedit disabled"),
899 keyEvent.filterAndAccept();
902 d->eventWatchers_.emplace_back(d->watchEvent(
906 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
907 auto &keyEvent = static_cast<KeyEvent &>(event);
908 auto *ic = keyEvent.inputContext();
909 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
910 #ifdef ENABLE_KEYBOARD
911 auto *xkbState = inputState->customXkbState();
913 if (auto *mods = findValue(d->stateMask_, ic->display())) {
914 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
918 if (inputState->isModsAllReleased()) {
919 depressed = xkb_state_serialize_mods(
920 xkbState, XKB_STATE_MODS_DEPRESSED);
922 depressed = std::get<0>(*mods);
924 if (std::get<0>(*mods) == 0) {
925 inputState->setModsAllReleased();
927 auto latched = xkb_state_serialize_mods(
928 xkbState, XKB_STATE_MODS_LATCHED);
929 auto locked = std::get<2>(*mods);
935 << depressed <<
" " << latched <<
" " << locked;
936 xkb_state_update_mask(xkbState, depressed, latched, locked,
939 const uint32_t effective = xkb_state_serialize_mods(
940 xkbState, XKB_STATE_MODS_EFFECTIVE);
941 auto newSym = xkb_state_key_get_one_sym(
942 xkbState, keyEvent.rawKey().code());
943 auto newModifier = KeyStates(effective);
944 auto *keymap = xkb_state_get_keymap(xkbState);
945 if (keyEvent.rawKey().states().test(KeyState::Repeat) &&
946 xkb_keymap_key_repeats(keymap, keyEvent.rawKey().code())) {
947 newModifier |= KeyState::Repeat;
950 const uint32_t modsDepressed = xkb_state_serialize_mods(
951 xkbState, XKB_STATE_MODS_DEPRESSED);
952 const uint32_t modsLatched =
953 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
954 const uint32_t modsLocked =
955 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
956 FCITX_KEYTRACE() <<
"Current mods: " << modsDepressed <<
" " 957 << modsLatched <<
" " << modsLocked;
958 auto newCode = keyEvent.rawKey().code();
959 Key key(static_cast<KeySym>(newSym), newModifier, newCode);
961 <<
"Custom Xkb translated Key: " << key.toString();
962 keyEvent.setRawKey(key);
965 FCITX_KEYTRACE() <<
"KeyEvent: " << keyEvent.key()
966 <<
" rawKey: " << keyEvent.rawKey()
967 <<
" origKey: " << keyEvent.origKey()
968 <<
" Release:" << keyEvent.isRelease()
969 <<
" keycode: " << keyEvent.origKey().code()
970 <<
" program: " << ic->program();
972 if (keyEvent.isRelease()) {
975 inputState->hideInputMethodInfo();
977 d->eventWatchers_.emplace_back(
979 EventWatcherPhase::InputMethod, [
this](
Event &event) {
980 auto &keyEvent =
static_cast<KeyEvent &
>(event);
981 auto *ic = keyEvent.inputContext();
982 auto *engine = inputMethodEngine(ic);
983 const auto *entry = inputMethodEntry(ic);
984 if (!engine || !entry) {
987 engine->keyEvent(*entry, keyEvent);
989 d->eventWatchers_.emplace_back(watchEvent(
990 EventType::InputContextVirtualKeyboardEvent,
991 EventWatcherPhase::InputMethod, [
this](
Event &event) {
993 auto *ic = keyEvent.inputContext();
994 auto *engine = inputMethodEngine(ic);
995 const auto *entry = inputMethodEntry(ic);
996 if (!engine || !entry) {
999 engine->virtualKeyboardEvent(*entry, keyEvent);
1001 d->eventWatchers_.emplace_back(watchEvent(
1003 [
this](
Event &event) {
1005 auto *ic = invokeActionEvent.inputContext();
1006 auto *engine = inputMethodEngine(ic);
1007 const auto *entry = inputMethodEntry(ic);
1008 if (!engine || !entry) {
1011 engine->invokeAction(*entry, invokeActionEvent);
1013 d->eventWatchers_.emplace_back(d->watchEvent(
1015 [
this](
Event &event) {
1016 auto &keyEvent = static_cast<KeyEvent &>(event);
1017 auto *ic = keyEvent.inputContext();
1018 auto *engine = inputMethodEngine(ic);
1019 const auto *entry = inputMethodEntry(ic);
1020 if (!engine || !entry) {
1023 engine->filterKey(*entry, keyEvent);
1024 emit<Instance::KeyEventResult>(keyEvent);
1025 #ifdef ENABLE_KEYBOARD 1026 if (keyEvent.forward()) {
1031 if (keyEvent.isRelease()) {
1035 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1036 if (
auto *xkbState = inputState->customXkbState()) {
1037 if (
auto utf32 = xkb_state_key_get_utf32(
1038 xkbState, keyEvent.key().code())) {
1040 if (utf32 ==
'\n' || utf32 ==
'\b' || utf32 ==
'\r' ||
1041 utf32 ==
'\t' || utf32 ==
'\033' ||
1045 if (keyEvent.key().states().testAny(
1046 KeyStates{KeyState::Ctrl, KeyState::Alt}) ||
1047 keyEvent.rawKey().sym() ==
1048 keyEvent.origKey().sym()) {
1051 FCITX_KEYTRACE() <<
"Will commit char: " << utf32;
1053 keyEvent.filterAndAccept();
1054 }
else if (!keyEvent.key().states().testAny(
1055 KeyStates{KeyState::Ctrl, KeyState::Alt}) &&
1056 keyEvent.rawKey().sym() !=
1057 keyEvent.origKey().sym() &&
1062 keyEvent.filterAndAccept();
1068 d->eventWatchers_.emplace_back(d->watchEvent(
1070 [
this, d](
Event &event) {
1071 auto &icEvent = static_cast<InputContextEvent &>(event);
1072 auto isSameProgram = [&icEvent, d]() {
1074 return (icEvent.inputContext() == d->lastUnFocusedIc_.get()) ||
1075 (!icEvent.inputContext()->program().empty() &&
1076 (icEvent.inputContext()->program() ==
1077 d->lastUnFocusedProgram_));
1080 if (d->globalConfig_.resetStateWhenFocusIn() ==
1081 PropertyPropagatePolicy::All ||
1082 (d->globalConfig_.resetStateWhenFocusIn() ==
1083 PropertyPropagatePolicy::Program &&
1084 !isSameProgram())) {
1085 if (d->globalConfig_.activeByDefault()) {
1086 activate(icEvent.inputContext());
1088 deactivate(icEvent.inputContext());
1092 activateInputMethod(icEvent);
1094 auto *inputContext = icEvent.inputContext();
1095 if (!inputContext->clientControlVirtualkeyboardShow()) {
1096 inputContext->showVirtualKeyboard();
1099 if (!d->globalConfig_.showInputMethodInformationWhenFocusIn()) {
1110 d->focusInImInfoTimer_ = d->eventLoop_.addTimeEvent(
1111 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1116 if (
auto *ic = icRef.get();
1117 ic && ic->hasFocus() &&
1119 d->showInputMethodInformation(ic);
1124 d->eventWatchers_.emplace_back(d->watchEvent(
1127 auto &icEvent = static_cast<InputContextEvent &>(event);
1128 auto *ic = icEvent.inputContext();
1129 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1130 inputState->reset();
1131 if (!ic->capabilityFlags().test(
1132 CapabilityFlag::ClientUnfocusCommit)) {
1135 ic->inputPanel().clientPreedit().toStringForCommit();
1136 if (!commit.empty()) {
1137 ic->commitString(commit);
1141 d->eventWatchers_.emplace_back(d->watchEvent(
1143 [
this, d](
Event &event) {
1144 auto &icEvent = static_cast<InputContextEvent &>(event);
1145 d->lastUnFocusedProgram_ = icEvent.inputContext()->program();
1146 d->lastUnFocusedIc_ = icEvent.inputContext()->watch();
1147 deactivateInputMethod(icEvent);
1149 auto *inputContext = icEvent.inputContext();
1150 if (!inputContext->clientControlVirtualkeyboardHide()) {
1151 inputContext->hideVirtualKeyboard();
1154 d->eventWatchers_.emplace_back(d->watchEvent(
1157 auto &icEvent = static_cast<InputContextEvent &>(event);
1158 auto *ic = icEvent.inputContext();
1159 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1160 inputState->reset();
1162 d->eventWatchers_.emplace_back(
1164 [
this](
Event &event) {
1166 auto *ic = icEvent.inputContext();
1167 if (!ic->hasFocus()) {
1170 auto *engine = inputMethodEngine(ic);
1171 const auto *entry = inputMethodEntry(ic);
1172 if (!engine || !entry) {
1175 engine->reset(*entry, icEvent);
1177 d->eventWatchers_.emplace_back(d->watchEvent(
1179 EventWatcherPhase::ReservedFirst, [
this](
Event &event) {
1181 static_cast<InputContextSwitchInputMethodEvent &>(event);
1182 auto *ic = icEvent.inputContext();
1183 if (!ic->hasFocus()) {
1186 deactivateInputMethod(icEvent);
1187 activateInputMethod(icEvent);
1189 d->eventWatchers_.emplace_back(d->watchEvent(
1191 EventWatcherPhase::ReservedLast, [
this, d](
Event &event) {
1193 static_cast<InputContextSwitchInputMethodEvent &>(event);
1194 auto *ic = icEvent.inputContext();
1195 if (!ic->hasFocus()) {
1199 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1200 inputState->lastIMChangeIsAltTrigger_ =
1212 showInputMethodInformation(ic);
1214 d->eventWatchers_.emplace_back(
1216 EventWatcherPhase::ReservedLast, [
this, d](
Event &) {
1219 d->imGroupInfoTimer_ = d->eventLoop_.addTimeEvent(
1220 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1221 [this](EventSourceTime *, uint64_t) {
1222 inputContextManager().foreachFocused(
1223 [this](InputContext *ic) {
1224 showInputMethodInformation(ic);
1231 d->eventWatchers_.emplace_back(d->watchEvent(
1232 EventType::InputContextUpdateUI, EventWatcherPhase::ReservedFirst,
1234 auto &icEvent = static_cast<InputContextUpdateUIEvent &>(event);
1235 if (icEvent.immediate()) {
1236 d->uiManager_.update(icEvent.component(),
1237 icEvent.inputContext());
1238 d->uiManager_.flush();
1240 d->uiManager_.update(icEvent.component(),
1241 icEvent.inputContext());
1242 d->uiUpdateEvent_->setOneShot();
1245 d->eventWatchers_.emplace_back(d->watchEvent(
1246 EventType::InputContextDestroyed, EventWatcherPhase::ReservedFirst,
1248 auto &icEvent = static_cast<InputContextEvent &>(event);
1249 d->uiManager_.expire(icEvent.inputContext());
1251 d->eventWatchers_.emplace_back(d->watchEvent(
1253 [d](
Event &) { d->uiManager_.updateAvailability(); }));
1254 d->uiUpdateEvent_ = d->eventLoop_.addDeferEvent([d](
EventSource *) {
1255 d->uiManager_.flush();
1258 d->uiUpdateEvent_->setEnabled(
false);
1259 d->periodicalSave_ = d->eventLoop_.addTimeEvent(
1260 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, AutoSaveIdleTime,
1267 auto currentTime = now(CLOCK_MONOTONIC);
1268 if (currentTime <= d->idleStartTimestamp_ ||
1269 currentTime - d->idleStartTimestamp_ < AutoSaveIdleTime) {
1271 time->setNextInterval(2 * AutoSaveIdleTime);
1276 FCITX_INFO() <<
"Running autosave...";
1278 FCITX_INFO() <<
"End autosave";
1279 if (d->globalConfig_.autoSavePeriod() > 0) {
1280 time->setNextInterval(d->globalConfig_.autoSavePeriod() *
1281 AutoSaveMinInUsecs);
1286 d->periodicalSave_->setEnabled(
false);
1289 Instance::~Instance() {
1291 d->tempModeManager_.reset();
1292 d->icManager_.finalize();
1293 d->addonManager_.unload();
1294 d->notifications_ =
nullptr;
1295 d->icManager_.setInstance(
nullptr);
1298 void InstanceArgument::parseOption(
int argc,
char **argv) {
1304 struct option longOptions[] = {{
"enable", required_argument,
nullptr, 0},
1305 {
"disable", required_argument,
nullptr, 0},
1306 {
"verbose", required_argument,
nullptr, 0},
1307 {
"keep", no_argument,
nullptr,
'k'},
1308 {
"ui", required_argument,
nullptr,
'u'},
1309 {
"replace", no_argument,
nullptr,
'r'},
1310 {
"version", no_argument,
nullptr,
'v'},
1311 {
"help", no_argument,
nullptr,
'h'},
1312 {
"option", required_argument,
nullptr,
'o'},
1313 {
nullptr, 0, 0, 0}};
1315 int optionIndex = 0;
1317 std::string addonOptionString;
1318 while ((c = getopt_long(argc, argv,
"ru:dDs:hvo:k", longOptions,
1319 &optionIndex)) != EOF) {
1322 switch (optionIndex) {
1330 Log::setLogRule(optarg);
1348 runAsDaemon =
false;
1351 exitWhenMainDisplayDisconnected =
false;
1354 overrideDelay = std::atoi(optarg);
1365 addonOptionString = optarg;
1376 std::unordered_map<std::string, std::vector<std::string>> addonOptions;
1377 for (
const std::string_view item :
1380 if (tokens.size() != 2) {
1385 addonOptions_ = std::move(addonOptions);
1393 d->signalPipe_ = fd;
1394 d->signalPipeEvent_ = d->eventLoop_.addIOEvent(
1404 return d->arg_.tryReplace;
1409 return d->arg_.exitWhenMainDisplayDisconnected;
1417 void Instance::handleSignal() {
1421 while (
fs::safeRead(d->signalPipe_, &signo,
sizeof(signo)) > 0) {
1422 if (signo == SIGINT || signo == SIGTERM || signo == SIGQUIT ||
1425 }
else if (signo == SIGUSR1) {
1427 }
else if (signo == SIGCHLD) {
1428 d->zombieReaper_->setNextInterval(2000000);
1429 d->zombieReaper_->setOneShot();
1437 if (!d->arg_.uiName.empty()) {
1438 d->arg_.enableList.push_back(d->arg_.uiName);
1441 d->icManager_.registerProperty(
"inputState", &d->inputStateFactory_);
1442 std::unordered_set<std::string> enabled;
1443 std::unordered_set<std::string> disabled;
1444 std::tie(enabled, disabled) = d->overrideAddons();
1445 FCITX_INFO() <<
"Override Enabled Addons: " << enabled;
1446 FCITX_INFO() <<
"Override Disabled Addons: " << disabled;
1447 d->addonManager_.load(enabled, disabled);
1452 d->uiManager_.load(d->arg_.uiName);
1454 const auto *entry = d->imManager_.entry(
"keyboard-us");
1455 FCITX_LOG_IF(Error, !entry) <<
"Couldn't find keyboard-us";
1456 d->preloadInputMethodEvent_ = d->eventLoop_.addTimeEvent(
1457 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, 0,
1460 if (d->exit_ || !d->globalConfig_.preloadInputMethod()) {
1464 if (!d->imManager_.currentGroup().inputMethodList().empty()) {
1465 if (
const auto *entry =
1466 d->imManager_.entry(d->imManager_.currentGroup()
1467 .inputMethodList()[0]
1469 d->addonManager_.addon(entry->addon(),
true);
1473 if (!d->imManager_.currentGroup().defaultInputMethod().empty()) {
1474 if (
const auto *entry = d->imManager_.entry(
1475 d->imManager_.currentGroup().defaultInputMethod())) {
1476 d->addonManager_.addon(entry->addon(),
true);
1482 d->zombieReaper_ = d->eventLoop_.addTimeEvent(
1483 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 0,
1486 while ((res = waitpid(-1,
nullptr, WNOHANG)) > 0) {
1490 d->zombieReaper_->setEnabled(
false);
1493 d->exitEvent_ = d->eventLoop_.addExitEvent([
this](
EventSource *) {
1494 FCITX_DEBUG() <<
"Running save...";
1498 d->notifications_ = d->addonManager_.addon(
"notifications",
true);
1503 if (d->arg_.quietQuit) {
1510 return d->exitCode_;
1513 auto r = eventLoop().exec();
1514 d->running_ =
false;
1516 return r ? d->exitCode_ : 1;
1521 d->running_ = running;
1531 return d->inputMethodMode_;
1536 if (d->inputMethodMode_ == mode) {
1539 d->inputMethodMode_ = mode;
1548 bool Instance::virtualKeyboardAutoShow()
const {
1550 return d->virtualKeyboardAutoShow_;
1553 void Instance::setVirtualKeyboardAutoShow(
bool autoShow) {
1555 d->virtualKeyboardAutoShow_ = autoShow;
1558 bool Instance::virtualKeyboardAutoHide()
const {
1560 return d->virtualKeyboardAutoHide_;
1563 void Instance::setVirtualKeyboardAutoHide(
bool autoHide) {
1565 d->virtualKeyboardAutoHide_ = autoHide;
1568 VirtualKeyboardFunctionMode Instance::virtualKeyboardFunctionMode()
const {
1570 return d->virtualKeyboardFunctionMode_;
1573 void Instance::setVirtualKeyboardFunctionMode(
1574 VirtualKeyboardFunctionMode mode) {
1576 d->virtualKeyboardFunctionMode_ = mode;
1581 d->binaryMode_ =
true;
1586 const auto &addonNames = d->addonManager_.loadedAddonNames();
1587 return d->binaryMode_ &&
1588 std::ranges::all_of(addonNames, [d](
const std::string &name) {
1589 auto *addon = d->addonManager_.lookupAddon(name);
1593 return addon->canRestart();
1597 InstancePrivate *Instance::privateData() {
1604 return d->eventLoop_;
1609 return d->eventDispatcher_;
1614 return d->icManager_;
1619 return d->addonManager_;
1624 return d->imManager_;
1629 return d->imManager_;
1634 return *d->tempModeManager_;
1639 return d->uiManager_;
1644 return d->globalConfig_;
1647 bool Instance::postEvent(
Event &event) {
1648 return std::as_const(*this).postEvent(event);
1651 bool Instance::postEvent(
Event &event)
const {
1656 auto iter = d->eventHandlers_.find(event.
type());
1657 if (iter != d->eventHandlers_.end()) {
1658 const auto &handlers = iter->second;
1659 EventWatcherPhase phaseOrder[] = {
1660 EventWatcherPhase::ReservedFirst, EventWatcherPhase::PreInputMethod,
1661 EventWatcherPhase::InputMethod, EventWatcherPhase::PostInputMethod,
1662 EventWatcherPhase::ReservedLast};
1664 for (
auto phase : phaseOrder) {
1665 if (
auto iter2 = handlers.find(phase); iter2 != handlers.end()) {
1666 for (
auto &handler : iter2->second.view()) {
1681 auto &keyEvent =
static_cast<KeyEvent &
>(event);
1682 auto *ic = keyEvent.inputContext();
1683 #ifdef ENABLE_KEYBOARD 1685 if (!keyEvent.forward() && !keyEvent.origKey().code()) {
1688 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1689 auto *xkbState = inputState->customXkbState();
1696 xkb_state_update_key(xkbState, keyEvent.origKey().code(),
1697 keyEvent.isRelease() ? XKB_KEY_UP
1701 if (ic->capabilityFlags().test(CapabilityFlag::KeyEventOrderFix) &&
1702 !keyEvent.accepted() && ic->hasPendingEventsStrictOrder()) {
1705 keyEvent.filterAndAccept();
1706 ic->forwardKey(keyEvent.origKey(), keyEvent.isRelease(),
1709 d_ptr->uiManager_.flush();
1712 return event.accepted();
1715 std::unique_ptr<HandlerTableEntry<EventHandler>>
1717 EventHandler callback) {
1719 if (phase == EventWatcherPhase::ReservedFirst ||
1720 phase == EventWatcherPhase::ReservedLast) {
1721 throw std::invalid_argument(
"Reserved Phase is only for internal use");
1723 return d->watchEvent(type, phase, std::move(callback));
1726 bool groupContains(
const InputMethodGroup &group,
const std::string &name) {
1727 const auto &list = group.inputMethodList();
1730 return item.name() == name;
1732 return iter != std::ranges::end(list);
1737 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1740 if (!inputState->overrideDeactivateIM_.empty()) {
1741 return inputState->overrideDeactivateIM_;
1744 const auto &group = d->imManager_.currentGroup();
1747 !d->globalConfig_.allowInputMethodForPassword())) {
1748 auto defaultLayoutIM =
1749 stringutils::concat(
"keyboard-", group.defaultLayout());
1750 const auto *entry = d->imManager_.entry(defaultLayoutIM);
1752 entry = d->imManager_.entry(
"keyboard-us");
1754 return entry ? entry->uniqueName() :
"";
1757 if (group.inputMethodList().empty()) {
1760 if (inputState->isActive()) {
1761 if (!inputState->localIM_.empty() &&
1762 groupContains(group, inputState->localIM_)) {
1763 return inputState->localIM_;
1765 return group.defaultInputMethod();
1768 return group.inputMethodList()[0].name();
1773 auto imName = inputMethod(ic);
1774 if (imName.empty()) {
1777 return d->imManager_.entry(imName);
1782 const auto *entry = inputMethodEntry(ic);
1787 d->addonManager_.addon(entry->addon(),
true));
1792 const auto *entry = d->imManager_.entry(name);
1797 d->addonManager_.addon(entry->addon(),
true));
1802 const auto *entry = inputMethodEntry(ic);
1804 auto *engine = inputMethodEngine(ic);
1806 icon = engine->subModeIcon(*entry, *ic);
1809 icon = entry->icon();
1812 icon =
"input-keyboard";
1820 const auto *entry = inputMethodEntry(ic);
1821 auto *engine = inputMethodEngine(ic);
1823 if (engine && entry) {
1824 label = engine->subModeLabel(*entry, *ic);
1826 if (label.empty() && entry) {
1827 label = entry->label();
1833 #ifdef ENABLE_KEYBOARD 1835 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1837 auto *xkbComposeState = state->xkbComposeState();
1838 if (!xkbComposeState) {
1842 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1844 enum xkb_compose_feed_result result =
1845 xkb_compose_state_feed(xkbComposeState, keyval);
1846 if (result == XKB_COMPOSE_FEED_IGNORED) {
1850 enum xkb_compose_status status =
1851 xkb_compose_state_get_status(xkbComposeState);
1852 if (status == XKB_COMPOSE_NOTHING) {
1855 if (status == XKB_COMPOSE_COMPOSED) {
1856 char buffer[FCITX_UTF8_MAX_LENGTH + 1] = {
'\0',
'\0',
'\0',
'\0',
1859 xkb_compose_state_get_utf8(xkbComposeState, buffer,
sizeof(buffer));
1860 xkb_compose_state_reset(xkbComposeState);
1862 return FCITX_INVALID_COMPOSE_RESULT;
1868 if (status == XKB_COMPOSE_CANCELLED) {
1869 xkb_compose_state_reset(xkbComposeState);
1872 return FCITX_INVALID_COMPOSE_RESULT;
1875 FCITX_UNUSED(keysym);
1882 #ifdef ENABLE_KEYBOARD 1884 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1886 auto *xkbComposeState = state->xkbComposeState();
1887 if (!xkbComposeState) {
1888 return std::string();
1891 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1892 enum xkb_compose_feed_result result =
1893 xkb_compose_state_feed(xkbComposeState, keyval);
1895 if (result == XKB_COMPOSE_FEED_IGNORED) {
1896 return std::string();
1899 enum xkb_compose_status status =
1900 xkb_compose_state_get_status(xkbComposeState);
1901 if (status == XKB_COMPOSE_NOTHING) {
1902 return std::string();
1904 if (status == XKB_COMPOSE_COMPOSED) {
1906 std::array<char, 256> buffer;
1907 auto length = xkb_compose_state_get_utf8(xkbComposeState, buffer.data(),
1909 xkb_compose_state_reset(xkbComposeState);
1911 return std::nullopt;
1914 auto bufferBegin = buffer.begin();
1915 auto bufferEnd = std::next(bufferBegin,
length);
1917 return std::string(bufferBegin, bufferEnd);
1919 return std::nullopt;
1921 if (status == XKB_COMPOSE_CANCELLED) {
1922 xkb_compose_state_reset(xkbComposeState);
1924 return std::nullopt;
1927 FCITX_UNUSED(keysym);
1928 return std::string();
1933 #ifdef ENABLE_KEYBOARD 1935 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1937 auto *xkbComposeState = state->xkbComposeState();
1938 if (!xkbComposeState) {
1942 return xkb_compose_state_get_status(xkbComposeState) ==
1943 XKB_COMPOSE_COMPOSING;
1945 FCITX_UNUSED(inputContext);
1951 #ifdef ENABLE_KEYBOARD 1953 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1954 auto *xkbComposeState = state->xkbComposeState();
1955 if (!xkbComposeState) {
1958 xkb_compose_state_reset(xkbComposeState);
1960 FCITX_UNUSED(inputContext);
1967 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
1968 d->imManager_.save();
1969 d->addonManager_.saveAll();
1974 if (
auto *ic = mostRecentInputContext()) {
1975 CheckInputMethodChanged imChangedRAII(ic, d);
1982 if (
const auto *entry = inputMethodManager().entry(imName)) {
1983 return entry->uniqueName();
1993 void Instance::configureAddon(
const std::string & ) {}
1995 void Instance::configureInputMethod(
const std::string & ) {}
1998 if (
auto *ic = mostRecentInputContext()) {
1999 if (
const auto *entry = inputMethodEntry(ic)) {
2000 return entry->uniqueName();
2008 return d->uiManager_.currentUI();
2013 if (
auto *ic = mostRecentInputContext()) {
2014 CheckInputMethodChanged imChangedRAII(ic, d);
2024 d->exitCode_ = exitCode;
2026 d->eventLoop_.exit();
2031 auto *addon = addonManager().addon(addonName);
2033 addon->reloadConfig();
2039 auto [enabled, disabled] = d->overrideAddons();
2040 d->addonManager_.load(enabled, disabled);
2041 d->imManager_.refresh();
2046 readAsIni(d->globalConfig_.config(), StandardPathsType::PkgConfig,
2048 FCITX_DEBUG() <<
"Trigger Key: " 2050 d->icManager_.setPropertyPropagatePolicy(
2051 d->globalConfig_.shareInputState());
2052 if (d->globalConfig_.preeditEnabledByDefault() !=
2053 d->icManager_.isPreeditEnabledByDefault()) {
2054 d->icManager_.setPreeditEnabledByDefault(
2055 d->globalConfig_.preeditEnabledByDefault());
2061 #ifdef ENABLE_KEYBOARD 2062 d->keymapCache_.clear();
2063 if (d->inputStateFactory_.registered()) {
2065 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2066 inputState->resetXkbState();
2075 if (d->globalConfig_.autoSavePeriod() <= 0) {
2076 d->periodicalSave_->setEnabled(
false);
2078 d->periodicalSave_->setNextInterval(AutoSaveMinInUsecs *
2079 d->globalConfig_.autoSavePeriod());
2080 d->periodicalSave_->setOneShot();
2091 if (!canRestart()) {
2099 setCurrentInputMethod(mostRecentInputContext(), name,
false);
2105 if (!canTrigger()) {
2109 auto &imManager = inputMethodManager();
2110 const auto &imList = imManager.currentGroup().inputMethodList();
2113 return item.name() == name;
2115 if (iter == std::ranges::end(imList)) {
2119 auto setGlobalDefaultInputMethod = [d](
const std::string &name) {
2120 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2121 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2123 groupRAIICheck.push_back(
2124 std::make_unique<CheckInputMethodChanged>(ic, d));
2127 d->imManager_.setDefaultInputMethod(name);
2130 auto idx = std::distance(imList.begin(), iter);
2132 CheckInputMethodChanged imChangedRAII(ic, d);
2133 auto currentIM = inputMethod(ic);
2134 if (currentIM == name) {
2137 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2141 inputState->setLocalIM(name);
2143 inputState->setLocalIM({});
2145 setGlobalDefaultInputMethod(name);
2147 inputState->setActive(
true);
2149 inputState->setActive(
false);
2151 if (inputState->imChanged_) {
2161 setGlobalDefaultInputMethod(name);
2169 if (
auto *ic = mostRecentInputContext()) {
2170 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
2171 return inputState->isActive() ? 2 : 1;
2178 if (
auto *ic = mostRecentInputContext()) {
2179 CheckInputMethodChanged imChangedRAII(ic, d);
2186 if (
auto *ic = mostRecentInputContext()) {
2187 CheckInputMethodChanged imChangedRAII(ic, d);
2188 enumerate(ic, forward);
2192 bool Instance::canTrigger()
const {
2193 const auto &imManager = inputMethodManager();
2194 return (imManager.currentGroup().inputMethodList().size() > 1);
2198 if (!canTrigger()) {
2202 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2203 if (inputState->isActive()) {
2206 return inputState->lastIMChangeIsAltTrigger_;
2211 if (!canTrigger()) {
2215 if (d->globalConfig_.enumerateSkipFirst()) {
2216 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2217 if (!inputState->isActive()) {
2220 return d->imManager_.currentGroup().inputMethodList().size() > 2;
2226 bool Instance::canChangeGroup()
const {
2227 const auto &imManager = inputMethodManager();
2228 return (imManager.groupCount() > 1);
2233 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2234 if (!canTrigger()) {
2237 inputState->setActive(!inputState->isActive());
2238 if (inputState->imChanged_) {
2239 inputState->imChanged_->setReason(reason);
2244 bool Instance::trigger(
InputContext *ic,
bool totallyReleased) {
2246 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2247 if (!canTrigger()) {
2252 if (totallyReleased) {
2254 inputState->firstTrigger_ =
true;
2256 if (!d->globalConfig_.enumerateWithTriggerKeys() ||
2257 (inputState->firstTrigger_ && inputState->isActive()) ||
2258 (d->globalConfig_.enumerateSkipFirst() &&
2259 d->imManager_.currentGroup().inputMethodList().size() <= 2)) {
2262 enumerate(ic,
true);
2264 inputState->firstTrigger_ =
false;
2270 if (!canAltTrigger(ic)) {
2280 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2281 if (!canTrigger()) {
2284 if (inputState->isActive()) {
2287 inputState->setActive(
true);
2288 if (inputState->imChanged_) {
2296 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2297 if (!canTrigger()) {
2300 if (!inputState->isActive()) {
2303 inputState->setActive(
false);
2304 if (inputState->imChanged_) {
2305 inputState->imChanged_->setReason(
2313 auto &imManager = inputMethodManager();
2314 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2315 const auto &imList = imManager.currentGroup().inputMethodList();
2316 if (!canTrigger()) {
2320 if (d->globalConfig_.enumerateSkipFirst() && imList.size() <= 2) {
2324 auto currentIM = inputMethod(ic);
2326 auto iter = std::ranges::find_if(
2328 return item.name() == currentIM;
2330 if (iter == imList.end()) {
2333 int idx = std::distance(imList.begin(), iter);
2334 auto nextIdx = [forward, &imList](
int idx) {
2336 return (idx + (forward ? 1 : (imList.size() - 1))) % imList.size();
2340 if (d->globalConfig_.enumerateSkipFirst() && idx == 0) {
2344 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2345 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2347 groupRAIICheck.push_back(
2348 std::make_unique<CheckInputMethodChanged>(ic, d));
2351 imManager.setDefaultInputMethod(imList[idx].name());
2352 inputState->setActive(
true);
2353 inputState->setLocalIM({});
2355 inputState->setActive(
false);
2357 if (inputState->imChanged_) {
2365 const std::string &orig) {
2366 std::string result = orig;
2367 emit<Instance::CommitFilter>(inputContext, result);
2373 emit<Instance::OutputFilter>(inputContext, result);
2374 if ((&orig == &inputContext->inputPanel().clientPreedit() ||
2375 &orig == &inputContext->inputPanel().preedit()) &&
2376 !globalConfig().showPreeditForPassword() &&
2377 inputContext->capabilityFlags().test(CapabilityFlag::Password)) {
2379 for (
int i = 0, e = result.size(); i < e; i++) {
2384 dot +=
"\xe2\x80\xa2";
2387 newText.append(std::move(dot),
2388 result.formatAt(i) | TextFormatFlag::DontCommit);
2390 result = std::move(newText);
2397 return d->icManager_.lastFocusedInputContext();
2402 return d->icManager_.mostRecentInputContext();
2407 d->uiManager_.flush();
2410 int scoreForGroup(
FocusGroup *group,
const std::string &displayHint) {
2412 if (displayHint.empty()) {
2413 if (group->display() ==
"x11:") {
2416 if (group->display().starts_with(
"x11:")) {
2419 if (group->display() ==
"wayland:") {
2422 if (group->display().starts_with(
"wayland:")) {
2426 if (group->display() == displayHint) {
2429 if (group->display().starts_with(displayHint)) {
2441 d->icManager_.foreachGroup(
2442 [&score, &displayHint, &defaultFocusGroup](
FocusGroup *group) {
2443 auto newScore = scoreForGroup(group, displayHint);
2444 if (newScore > score) {
2445 defaultFocusGroup = group;
2451 return defaultFocusGroup;
2456 FCITX_DEBUG() <<
"Instance::activateInputMethod";
2458 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2459 const auto *entry = inputMethodEntry(ic);
2461 FCITX_DEBUG() <<
"Activate: " 2462 <<
"[Last]:" << inputState->lastIM_
2463 <<
" [Activating]:" << entry->uniqueName();
2464 assert(inputState->lastIM_.empty());
2465 inputState->lastIM_ = entry->uniqueName();
2467 auto *engine = inputMethodEngine(ic);
2468 if (!engine || !entry) {
2471 #ifdef ENABLE_KEYBOARD 2472 if (
auto *xkbState = inputState->customXkbState(
true)) {
2473 if (
auto *mods = findValue(d->stateMask_, ic->
display())) {
2474 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
2475 auto depressed = std::get<0>(*mods);
2476 auto latched = std::get<1>(*mods);
2477 auto locked = std::get<2>(*mods);
2482 FCITX_KEYTRACE() << depressed <<
" " << latched <<
" " << locked;
2483 if (depressed == 0) {
2484 inputState->setModsAllReleased();
2486 xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0,
2492 engine->activate(*entry, event);
2498 FCITX_DEBUG() <<
"Instance::deactivateInputMethod event_type=" 2499 <<
static_cast<uint32_t
>(
event.type());
2501 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2508 FCITX_DEBUG() <<
"Switch reason: " 2509 <<
static_cast<int>(icEvent.reason());
2510 FCITX_DEBUG() <<
"Old Input method: " << icEvent.oldInputMethod();
2511 entry = d->imManager_.entry(icEvent.oldInputMethod());
2513 entry = inputMethodEntry(ic);
2516 FCITX_DEBUG() <<
"Deactivate: " 2517 <<
"[Last]:" << inputState->lastIM_
2518 <<
" [Deactivating]:" << entry->uniqueName();
2519 assert(entry->uniqueName() == inputState->lastIM_);
2521 d->addonManager_.addon(entry->addon()));
2523 inputState->lastIM_.clear();
2524 if (!engine || !entry) {
2527 inputState->overrideDeactivateIM_ = entry->uniqueName();
2529 inputState->overrideDeactivateIM_.clear();
2533 bool Instance::enumerateGroup(
bool forward) {
2534 auto &imManager = inputMethodManager();
2535 auto groups = imManager.groups();
2536 if (groups.size() <= 1) {
2540 imManager.setCurrentGroup(groups[1]);
2542 imManager.setCurrentGroup(groups.back());
2548 FCITX_DEBUG() <<
"Input method switched";
2550 if (!d->globalConfig_.showInputMethodInformation()) {
2553 d->showInputMethodInformation(ic);
2557 const std::string &message) {
2558 FCITX_DEBUG() <<
"Input method switched";
2560 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2561 inputState->showInputMethodInformation(message);
2566 return (isInFlatpak() &&
2567 std::filesystem::is_regular_file(
"/app/.updated")) ||
2568 d->addonManager_.checkUpdate() || d->imManager_.checkUpdate() ||
2573 const std::string &rule,
2574 const std::string &model,
2575 const std::string &options) {
2576 #ifdef ENABLE_KEYBOARD 2578 bool resetState =
false;
2579 if (
auto *param = findValue(d->xkbParams_, display)) {
2580 if (std::get<0>(*param) != rule || std::get<1>(*param) != model ||
2581 std::get<2>(*param) != options) {
2582 std::get<0>(*param) = rule;
2583 std::get<1>(*param) = model;
2584 std::get<2>(*param) = options;
2588 d->xkbParams_.emplace(display, std::make_tuple(rule, model, options));
2592 d->keymapCache_[display].clear();
2593 d->icManager_.foreach([d, &display](
InputContext *ic) {
2594 if (ic->
display() == display ||
2595 !d->xkbParams_.contains(ic->
display())) {
2596 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2597 inputState->resetXkbState();
2603 FCITX_UNUSED(display);
2605 FCITX_UNUSED(model);
2606 FCITX_UNUSED(options);
2611 uint32_t depressed_mods,
2612 uint32_t latched_mods, uint32_t locked_mods) {
2614 auto oldMask = xkbStateMask(display);
2615 auto &newMask = d->stateMask_[display];
2616 newMask = std::make_tuple(depressed_mods, latched_mods, locked_mods);
2617 if (oldMask == newMask) {
2620 emit<Instance::XkbStateMaskChanged>(display, oldMask, newMask);
2625 auto oldMask = xkbStateMask(display);
2626 if (!oldMask.has_value()) {
2629 bool changed = d->stateMask_.erase(display) > 0;
2631 emit<XkbStateMaskChanged>(display, oldMask, std::nullopt);
2635 std::optional<std::tuple<uint32_t, uint32_t, uint32_t>>
2638 if (
const auto *mask = findValue(d->stateMask_, display)) {
2641 return std::nullopt;
void updateXkbStateMask(const std::string &display, uint32_t depressed_mods, uint32_t latched_mods, uint32_t locked_mods)
Update xkb state mask for given display.
void restart()
Restart fcitx instance, this should only be used within a regular Fcitx server, not within embedded m...
void reloadAddonConfig(const std::string &addonName)
Reload certain addon config.
CapabilityFlags capabilityFlags() const
Returns the current capability flags.
FCITXCORE_DEPRECATED uint32_t processCompose(InputContext *ic, KeySym keysym)
Handle current XCompose state.
std::string inputMethodIcon(InputContext *ic)
Return the input method icon for input context.
void setXkbParameters(const std::string &display, const std::string &rule, const std::string &model, const std::string &options)
Set xkb RLVMO tuple for given display.
void activate()
Activate last focused input context. (Switch to the active input method)
EventType
Type of input method events.
Switched by alternative trigger key.
void resetCompose(InputContext *inputContext)
Reset the compose state.
T::PropertyType * propertyFor(const T *factory)
Helper function to return the input context property in specific type by given factory.
std::string UCS4ToUTF8(uint32_t code)
Convert UCS4 to UTF8 string.
FocusInEvent is generated when client gets focused.
Formatted string commonly used in user interface.
Whether client request input method to be disabled.
FocusGroup * defaultFocusGroup(const std::string &displayHint={})
Get the default focus group with given display hint.
static uint32_t keySymToUnicode(KeySym sym)
Convert keysym to a unicode.
Switched by activate key.
void flushUI()
All user interface update is batched internally.
This is generated when input method group changed.
std::string commitFilter(InputContext *inputContext, const std::string &orig)
Update the commit string to frontend.
AddonManager & addonManager()
Get the addon manager.
std::string currentInputMethod()
Return the current input method of last focused input context.
Manage registered TempMode objects for an Instance.
Simple file system related API for checking file status.
size_t length(Iter start, Iter end)
Return the number UTF-8 characters in the string iterator range.
bool validate(Iter start, Iter end)
Check if the string iterator range is valid utf8 string.
when user switch to a different input method by hand such as ctrl+shift by default, or by ui, default behavior is reset IM.
InputMethodSwitchedReason
The reason why input method is switched to another.
void deactivate()
Deactivate last focused input context.
int state()
Return a fcitx5-remote compatible value for the state.
InputMethodEngine * inputMethodEngine(InputContext *ic)
Return the input method engine object for given input context.
void setSignalPipe(int fd)
Set the pipe forwarding unix signal information.
InputMethodMode inputMethodMode() const
The current global input method mode.
void initialize()
Initialize fcitx.
EventLoop & eventLoop()
Get the fcitx event loop.
std::string currentUI()
Return the name of current user interface addon.
bool exitWhenMainDisplayDisconnected() const
Check whether command line specify whether to keep fcitx running.
C++ Utility functions for handling utf8 strings.
std::optional< std::tuple< uint32_t, uint32_t, uint32_t > > xkbStateMask(const std::string &display) const
Return xkb state mask for given display.
InputContext * mostRecentInputContext()
Return the most recent focused input context.
FCITX_NODISCARD std::unique_ptr< HandlerTableEntry< EventHandler > > watchEvent(EventType type, EventWatcherPhase phase, EventHandler callback)
Add a callback to for certain event type.
InputContextManager & inputContextManager()
Get the input context manager.
void setEnablePreedit(bool enable)
Override the preedit hint from client.
std::vector< std::string > split(std::string_view str, std::string_view delim, SplitBehavior behavior)
Split the string by delim.
virtual bool filtered() const
Whether a event is filtered by handler.
void clearGroup(StatusGroup group)
Clear only given status group.
bool hasFocus() const
Returns whether the input context holds the input focus.
bool isRunning() const
Whether event loop is started and still running.
A class represents a formatted string.
bool willTryReplace() const
Check whether command line specify if it will replace an existing fcitx server.
Switched by group change.
bool isRestartRequested() const
Whether restart is requested.
Manager class for user interface.
Instance(int argc, char *argv[])
A main function like construct to be used to create Fcitx Instance.
Base class for fcitx event.
bool isValidChar(uint32_t c)
Check the chr value is not two invalid value above.
std::string inputMethodLabel(InputContext *ic)
Return the input method label for input context.
void save()
Save everything including input method profile and addon data.
Enum type for input context capability.
Class for status area in UI.
void resetInputMethodList()
Reset the input method configuration and recreate based on system language.
Switched by capability change (e.g. password field)
Base class for User Interface addon.
A thread safe class to post event to a certain EventLoop.
void clearXkbStateMask(const std::string &display)
Clear xkb state mask for given display.
Enum flag for text formatting.
void configure()
Launch configtool.
bool checkUpdate() const
Check if need to invoke Instance::refresh.
New Utility classes to handle application specific path.
uint32_t getChar(Iter iter, Iter end)
Get next UCS4 char from iter, do not cross end.
InvokeAction event is generated when client click on the preedit.
InputMethodManager & inputMethodManager()
Get the input method manager.
void reloadConfig()
Reload global config.
int exec()
Start the event loop of Fcitx.
C-style utf8 utility functions.
TempModeManager & tempModeManager()
Get the temporary mode manager.
void setBinaryMode()
Set if this instance is running as fcitx5 binary.
bool isModifier() const
Check if the key is a modifier press.
InputContext * lastFocusedInputContext()
Return a focused input context.
std::string display() const
Returns the display server of the client.
void toggle()
Toggle between the first input method and active input method.
void setCurrentInputMethod(const std::string &imName)
Set the input method of last focused input context.
void setRunning(bool running)
Let other know that event loop is already running.
bool canRestart() const
Check if fcitx 5 can safely restart by itself.
void showCustomInputMethodInformation(InputContext *ic, const std::string &message)
Show a small popup with input popup window with current input method information. ...
std::optional< std::string > processComposeString(InputContext *ic, KeySym keysym)
Handle current XCompose state.
void refresh()
Load newly installed input methods and addons.
Input method mode changed.
std::string inputMethod(InputContext *ic)
Return the unique name of input method for given input context.
UserInterfaceManager & userInterfaceManager()
Get the user interface manager.
void enumerate(bool forward)
Enumerate input method with in current group.
bool exiting() const
Check whether fcitx is in exiting process.
void showInputMethodInformation(InputContext *ic)
Show a small popup with input popup window with current input method information. ...
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.