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 emit<Instance::AboutToExit>();
1495 FCITX_INFO() <<
"Save before exiting...";
1497 emit<Instance::Exit>();
1500 d->notifications_ = d->addonManager_.addon(
"notifications",
true);
1505 if (d->arg_.quietQuit) {
1512 return d->exitCode_;
1515 auto r = eventLoop().exec();
1516 d->running_ =
false;
1518 return r ? d->exitCode_ : 1;
1523 d->running_ = running;
1533 return d->inputMethodMode_;
1538 if (d->inputMethodMode_ == mode) {
1541 d->inputMethodMode_ = mode;
1550 bool Instance::virtualKeyboardAutoShow()
const {
1552 return d->virtualKeyboardAutoShow_;
1555 void Instance::setVirtualKeyboardAutoShow(
bool autoShow) {
1557 d->virtualKeyboardAutoShow_ = autoShow;
1560 bool Instance::virtualKeyboardAutoHide()
const {
1562 return d->virtualKeyboardAutoHide_;
1565 void Instance::setVirtualKeyboardAutoHide(
bool autoHide) {
1567 d->virtualKeyboardAutoHide_ = autoHide;
1570 VirtualKeyboardFunctionMode Instance::virtualKeyboardFunctionMode()
const {
1572 return d->virtualKeyboardFunctionMode_;
1575 void Instance::setVirtualKeyboardFunctionMode(
1576 VirtualKeyboardFunctionMode mode) {
1578 d->virtualKeyboardFunctionMode_ = mode;
1583 d->binaryMode_ =
true;
1588 const auto &addonNames = d->addonManager_.loadedAddonNames();
1589 return d->binaryMode_ &&
1590 std::ranges::all_of(addonNames, [d](
const std::string &name) {
1591 auto *addon = d->addonManager_.lookupAddon(name);
1595 return addon->canRestart();
1599 InstancePrivate *Instance::privateData() {
1606 return d->eventLoop_;
1611 return d->eventDispatcher_;
1616 return d->icManager_;
1621 return d->addonManager_;
1626 return d->imManager_;
1631 return d->imManager_;
1636 return *d->tempModeManager_;
1641 return d->uiManager_;
1646 return d->globalConfig_;
1649 bool Instance::postEvent(
Event &event) {
1650 return std::as_const(*this).postEvent(event);
1653 bool Instance::postEvent(
Event &event)
const {
1658 auto iter = d->eventHandlers_.find(event.
type());
1659 if (iter != d->eventHandlers_.end()) {
1660 const auto &handlers = iter->second;
1661 EventWatcherPhase phaseOrder[] = {
1662 EventWatcherPhase::ReservedFirst, EventWatcherPhase::PreInputMethod,
1663 EventWatcherPhase::InputMethod, EventWatcherPhase::PostInputMethod,
1664 EventWatcherPhase::ReservedLast};
1666 for (
auto phase : phaseOrder) {
1667 if (
auto iter2 = handlers.find(phase); iter2 != handlers.end()) {
1668 for (
auto &handler : iter2->second.view()) {
1683 auto &keyEvent =
static_cast<KeyEvent &
>(event);
1684 auto *ic = keyEvent.inputContext();
1685 #ifdef ENABLE_KEYBOARD 1687 if (!keyEvent.forward() && !keyEvent.origKey().code()) {
1690 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1691 auto *xkbState = inputState->customXkbState();
1698 xkb_state_update_key(xkbState, keyEvent.origKey().code(),
1699 keyEvent.isRelease() ? XKB_KEY_UP
1703 if (ic->capabilityFlags().test(CapabilityFlag::KeyEventOrderFix) &&
1704 !keyEvent.accepted() && ic->hasPendingEventsStrictOrder()) {
1707 keyEvent.filterAndAccept();
1708 ic->forwardKey(keyEvent.origKey(), keyEvent.isRelease(),
1711 d_ptr->uiManager_.flush();
1714 return event.accepted();
1717 std::unique_ptr<HandlerTableEntry<EventHandler>>
1719 EventHandler callback) {
1721 if (phase == EventWatcherPhase::ReservedFirst ||
1722 phase == EventWatcherPhase::ReservedLast) {
1723 throw std::invalid_argument(
"Reserved Phase is only for internal use");
1725 return d->watchEvent(type, phase, std::move(callback));
1728 bool groupContains(
const InputMethodGroup &group,
const std::string &name) {
1729 const auto &list = group.inputMethodList();
1732 return item.name() == name;
1734 return iter != std::ranges::end(list);
1739 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1742 if (!inputState->overrideDeactivateIM_.empty()) {
1743 return inputState->overrideDeactivateIM_;
1746 const auto &group = d->imManager_.currentGroup();
1749 !d->globalConfig_.allowInputMethodForPassword())) {
1750 auto defaultLayoutIM =
1751 stringutils::concat(
"keyboard-", group.defaultLayout());
1752 const auto *entry = d->imManager_.entry(defaultLayoutIM);
1754 entry = d->imManager_.entry(
"keyboard-us");
1756 return entry ? entry->uniqueName() :
"";
1759 if (group.inputMethodList().empty()) {
1762 if (inputState->isActive()) {
1763 if (!inputState->localIM_.empty() &&
1764 groupContains(group, inputState->localIM_)) {
1765 return inputState->localIM_;
1767 return group.defaultInputMethod();
1770 return group.inputMethodList()[0].name();
1775 auto imName = inputMethod(ic);
1776 if (imName.empty()) {
1779 return d->imManager_.entry(imName);
1784 const auto *entry = inputMethodEntry(ic);
1789 d->addonManager_.addon(entry->addon(),
true));
1794 const auto *entry = d->imManager_.entry(name);
1799 d->addonManager_.addon(entry->addon(),
true));
1804 const auto *entry = inputMethodEntry(ic);
1806 auto *engine = inputMethodEngine(ic);
1808 icon = engine->subModeIcon(*entry, *ic);
1811 icon = entry->icon();
1814 icon =
"input-keyboard";
1822 const auto *entry = inputMethodEntry(ic);
1823 auto *engine = inputMethodEngine(ic);
1825 if (engine && entry) {
1826 label = engine->subModeLabel(*entry, *ic);
1828 if (label.empty() && entry) {
1829 label = entry->label();
1835 #ifdef ENABLE_KEYBOARD 1837 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1839 auto *xkbComposeState = state->xkbComposeState();
1840 if (!xkbComposeState) {
1844 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1846 enum xkb_compose_feed_result result =
1847 xkb_compose_state_feed(xkbComposeState, keyval);
1848 if (result == XKB_COMPOSE_FEED_IGNORED) {
1852 enum xkb_compose_status status =
1853 xkb_compose_state_get_status(xkbComposeState);
1854 if (status == XKB_COMPOSE_NOTHING) {
1857 if (status == XKB_COMPOSE_COMPOSED) {
1858 char buffer[FCITX_UTF8_MAX_LENGTH + 1] = {
'\0',
'\0',
'\0',
'\0',
1861 xkb_compose_state_get_utf8(xkbComposeState, buffer,
sizeof(buffer));
1862 xkb_compose_state_reset(xkbComposeState);
1864 return FCITX_INVALID_COMPOSE_RESULT;
1870 if (status == XKB_COMPOSE_CANCELLED) {
1871 xkb_compose_state_reset(xkbComposeState);
1874 return FCITX_INVALID_COMPOSE_RESULT;
1877 FCITX_UNUSED(keysym);
1884 #ifdef ENABLE_KEYBOARD 1886 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1888 auto *xkbComposeState = state->xkbComposeState();
1889 if (!xkbComposeState) {
1890 return std::string();
1893 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1894 enum xkb_compose_feed_result result =
1895 xkb_compose_state_feed(xkbComposeState, keyval);
1897 if (result == XKB_COMPOSE_FEED_IGNORED) {
1898 return std::string();
1901 enum xkb_compose_status status =
1902 xkb_compose_state_get_status(xkbComposeState);
1903 if (status == XKB_COMPOSE_NOTHING) {
1904 return std::string();
1906 if (status == XKB_COMPOSE_COMPOSED) {
1908 std::array<char, 256> buffer;
1909 auto length = xkb_compose_state_get_utf8(xkbComposeState, buffer.data(),
1911 xkb_compose_state_reset(xkbComposeState);
1913 return std::nullopt;
1916 auto bufferBegin = buffer.begin();
1917 auto bufferEnd = std::next(bufferBegin,
length);
1919 return std::string(bufferBegin, bufferEnd);
1921 return std::nullopt;
1923 if (status == XKB_COMPOSE_CANCELLED) {
1924 xkb_compose_state_reset(xkbComposeState);
1926 return std::nullopt;
1929 FCITX_UNUSED(keysym);
1930 return std::string();
1935 #ifdef ENABLE_KEYBOARD 1937 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1939 auto *xkbComposeState = state->xkbComposeState();
1940 if (!xkbComposeState) {
1944 return xkb_compose_state_get_status(xkbComposeState) ==
1945 XKB_COMPOSE_COMPOSING;
1947 FCITX_UNUSED(inputContext);
1953 #ifdef ENABLE_KEYBOARD 1955 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1956 auto *xkbComposeState = state->xkbComposeState();
1957 if (!xkbComposeState) {
1960 xkb_compose_state_reset(xkbComposeState);
1962 FCITX_UNUSED(inputContext);
1969 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
1970 d->imManager_.save();
1971 d->addonManager_.saveAll();
1976 if (
auto *ic = mostRecentInputContext()) {
1977 CheckInputMethodChanged imChangedRAII(ic, d);
1984 if (
const auto *entry = inputMethodManager().entry(imName)) {
1985 return entry->uniqueName();
1995 void Instance::configureAddon(
const std::string & ) {}
1997 void Instance::configureInputMethod(
const std::string & ) {}
2000 if (
auto *ic = mostRecentInputContext()) {
2001 if (
const auto *entry = inputMethodEntry(ic)) {
2002 return entry->uniqueName();
2010 return d->uiManager_.currentUI();
2015 if (
auto *ic = mostRecentInputContext()) {
2016 CheckInputMethodChanged imChangedRAII(ic, d);
2026 d->exitCode_ = exitCode;
2028 d->eventLoop_.exit();
2033 auto *addon = addonManager().addon(addonName);
2035 addon->reloadConfig();
2041 auto [enabled, disabled] = d->overrideAddons();
2042 d->addonManager_.load(enabled, disabled);
2043 d->imManager_.refresh();
2048 readAsIni(d->globalConfig_.config(), StandardPathsType::PkgConfig,
2050 FCITX_DEBUG() <<
"Trigger Key: " 2052 d->icManager_.setPropertyPropagatePolicy(
2053 d->globalConfig_.shareInputState());
2054 if (d->globalConfig_.preeditEnabledByDefault() !=
2055 d->icManager_.isPreeditEnabledByDefault()) {
2056 d->icManager_.setPreeditEnabledByDefault(
2057 d->globalConfig_.preeditEnabledByDefault());
2063 #ifdef ENABLE_KEYBOARD 2064 d->keymapCache_.clear();
2065 if (d->inputStateFactory_.registered()) {
2067 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2068 inputState->resetXkbState();
2077 if (d->globalConfig_.autoSavePeriod() <= 0) {
2078 d->periodicalSave_->setEnabled(
false);
2080 d->periodicalSave_->setNextInterval(AutoSaveMinInUsecs *
2081 d->globalConfig_.autoSavePeriod());
2082 d->periodicalSave_->setOneShot();
2093 if (!canRestart()) {
2101 setCurrentInputMethod(mostRecentInputContext(), name,
false);
2107 if (!canTrigger()) {
2111 auto &imManager = inputMethodManager();
2112 const auto &imList = imManager.currentGroup().inputMethodList();
2115 return item.name() == name;
2117 if (iter == std::ranges::end(imList)) {
2121 auto setGlobalDefaultInputMethod = [d](
const std::string &name) {
2122 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2123 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2125 groupRAIICheck.push_back(
2126 std::make_unique<CheckInputMethodChanged>(ic, d));
2129 d->imManager_.setDefaultInputMethod(name);
2132 auto idx = std::distance(imList.begin(), iter);
2134 CheckInputMethodChanged imChangedRAII(ic, d);
2135 auto currentIM = inputMethod(ic);
2136 if (currentIM == name) {
2139 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2143 inputState->setLocalIM(name);
2145 inputState->setLocalIM({});
2147 setGlobalDefaultInputMethod(name);
2149 inputState->setActive(
true);
2151 inputState->setActive(
false);
2153 if (inputState->imChanged_) {
2163 setGlobalDefaultInputMethod(name);
2171 if (
auto *ic = mostRecentInputContext()) {
2172 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
2173 return inputState->isActive() ? 2 : 1;
2180 if (
auto *ic = mostRecentInputContext()) {
2181 CheckInputMethodChanged imChangedRAII(ic, d);
2188 if (
auto *ic = mostRecentInputContext()) {
2189 CheckInputMethodChanged imChangedRAII(ic, d);
2190 enumerate(ic, forward);
2194 bool Instance::canTrigger()
const {
2195 const auto &imManager = inputMethodManager();
2196 return (imManager.currentGroup().inputMethodList().size() > 1);
2200 if (!canTrigger()) {
2204 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2205 if (inputState->isActive()) {
2208 return inputState->lastIMChangeIsAltTrigger_;
2213 if (!canTrigger()) {
2217 if (d->globalConfig_.enumerateSkipFirst()) {
2218 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2219 if (!inputState->isActive()) {
2222 return d->imManager_.currentGroup().inputMethodList().size() > 2;
2228 bool Instance::canChangeGroup()
const {
2229 const auto &imManager = inputMethodManager();
2230 return (imManager.groupCount() > 1);
2235 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2236 if (!canTrigger()) {
2239 inputState->setActive(!inputState->isActive());
2240 if (inputState->imChanged_) {
2241 inputState->imChanged_->setReason(reason);
2246 bool Instance::trigger(
InputContext *ic,
bool totallyReleased) {
2248 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2249 if (!canTrigger()) {
2254 if (totallyReleased) {
2256 inputState->firstTrigger_ =
true;
2258 if (!d->globalConfig_.enumerateWithTriggerKeys() ||
2259 (inputState->firstTrigger_ && inputState->isActive()) ||
2260 (d->globalConfig_.enumerateSkipFirst() &&
2261 d->imManager_.currentGroup().inputMethodList().size() <= 2)) {
2264 enumerate(ic,
true);
2266 inputState->firstTrigger_ =
false;
2272 if (!canAltTrigger(ic)) {
2282 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2283 if (!canTrigger()) {
2286 if (inputState->isActive()) {
2289 inputState->setActive(
true);
2290 if (inputState->imChanged_) {
2298 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2299 if (!canTrigger()) {
2302 if (!inputState->isActive()) {
2305 inputState->setActive(
false);
2306 if (inputState->imChanged_) {
2307 inputState->imChanged_->setReason(
2315 auto &imManager = inputMethodManager();
2316 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2317 const auto &imList = imManager.currentGroup().inputMethodList();
2318 if (!canTrigger()) {
2322 if (d->globalConfig_.enumerateSkipFirst() && imList.size() <= 2) {
2326 auto currentIM = inputMethod(ic);
2328 auto iter = std::ranges::find_if(
2330 return item.name() == currentIM;
2332 if (iter == imList.end()) {
2335 int idx = std::distance(imList.begin(), iter);
2336 auto nextIdx = [forward, &imList](
int idx) {
2338 return (idx + (forward ? 1 : (imList.size() - 1))) % imList.size();
2342 if (d->globalConfig_.enumerateSkipFirst() && idx == 0) {
2346 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2347 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2349 groupRAIICheck.push_back(
2350 std::make_unique<CheckInputMethodChanged>(ic, d));
2353 imManager.setDefaultInputMethod(imList[idx].name());
2354 inputState->setActive(
true);
2355 inputState->setLocalIM({});
2357 inputState->setActive(
false);
2359 if (inputState->imChanged_) {
2367 const std::string &orig) {
2368 std::string result = orig;
2369 emit<Instance::CommitFilter>(inputContext, result);
2375 emit<Instance::OutputFilter>(inputContext, result);
2376 if ((&orig == &inputContext->inputPanel().clientPreedit() ||
2377 &orig == &inputContext->inputPanel().preedit()) &&
2378 !globalConfig().showPreeditForPassword() &&
2379 inputContext->capabilityFlags().test(CapabilityFlag::Password)) {
2381 for (
int i = 0, e = result.size(); i < e; i++) {
2386 dot +=
"\xe2\x80\xa2";
2389 newText.append(std::move(dot),
2390 result.formatAt(i) | TextFormatFlag::DontCommit);
2392 result = std::move(newText);
2399 return d->icManager_.lastFocusedInputContext();
2404 return d->icManager_.mostRecentInputContext();
2409 d->uiManager_.flush();
2412 int scoreForGroup(
FocusGroup *group,
const std::string &displayHint) {
2414 if (displayHint.empty()) {
2415 if (group->display() ==
"x11:") {
2418 if (group->display().starts_with(
"x11:")) {
2421 if (group->display() ==
"wayland:") {
2424 if (group->display().starts_with(
"wayland:")) {
2428 if (group->display() == displayHint) {
2431 if (group->display().starts_with(displayHint)) {
2443 d->icManager_.foreachGroup(
2444 [&score, &displayHint, &defaultFocusGroup](
FocusGroup *group) {
2445 auto newScore = scoreForGroup(group, displayHint);
2446 if (newScore > score) {
2447 defaultFocusGroup = group;
2453 return defaultFocusGroup;
2458 FCITX_DEBUG() <<
"Instance::activateInputMethod";
2460 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2461 const auto *entry = inputMethodEntry(ic);
2463 FCITX_DEBUG() <<
"Activate: " 2464 <<
"[Last]:" << inputState->lastIM_
2465 <<
" [Activating]:" << entry->uniqueName();
2466 assert(inputState->lastIM_.empty());
2467 inputState->lastIM_ = entry->uniqueName();
2469 auto *engine = inputMethodEngine(ic);
2470 if (!engine || !entry) {
2473 #ifdef ENABLE_KEYBOARD 2474 if (
auto *xkbState = inputState->customXkbState(
true)) {
2475 if (
auto *mods = findValue(d->stateMask_, ic->
display())) {
2476 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
2477 auto depressed = std::get<0>(*mods);
2478 auto latched = std::get<1>(*mods);
2479 auto locked = std::get<2>(*mods);
2484 FCITX_KEYTRACE() << depressed <<
" " << latched <<
" " << locked;
2485 if (depressed == 0) {
2486 inputState->setModsAllReleased();
2488 xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0,
2494 engine->activate(*entry, event);
2500 FCITX_DEBUG() <<
"Instance::deactivateInputMethod event_type=" 2501 <<
static_cast<uint32_t
>(
event.type());
2503 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2510 FCITX_DEBUG() <<
"Switch reason: " 2511 <<
static_cast<int>(icEvent.reason());
2512 FCITX_DEBUG() <<
"Old Input method: " << icEvent.oldInputMethod();
2513 entry = d->imManager_.entry(icEvent.oldInputMethod());
2515 entry = inputMethodEntry(ic);
2518 FCITX_DEBUG() <<
"Deactivate: " 2519 <<
"[Last]:" << inputState->lastIM_
2520 <<
" [Deactivating]:" << entry->uniqueName();
2521 assert(entry->uniqueName() == inputState->lastIM_);
2523 d->addonManager_.addon(entry->addon()));
2525 inputState->lastIM_.clear();
2526 if (!engine || !entry) {
2529 inputState->overrideDeactivateIM_ = entry->uniqueName();
2531 inputState->overrideDeactivateIM_.clear();
2535 bool Instance::enumerateGroup(
bool forward) {
2536 auto &imManager = inputMethodManager();
2537 auto groups = imManager.groups();
2538 if (groups.size() <= 1) {
2542 imManager.setCurrentGroup(groups[1]);
2544 imManager.setCurrentGroup(groups.back());
2550 FCITX_DEBUG() <<
"Input method switched";
2552 if (!d->globalConfig_.showInputMethodInformation()) {
2555 d->showInputMethodInformation(ic);
2559 const std::string &message) {
2560 FCITX_DEBUG() <<
"Input method switched";
2562 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2563 inputState->showInputMethodInformation(message);
2568 return (isInFlatpak() &&
2569 std::filesystem::is_regular_file(
"/app/.updated")) ||
2570 d->addonManager_.checkUpdate() || d->imManager_.checkUpdate() ||
2575 const std::string &rule,
2576 const std::string &model,
2577 const std::string &options) {
2578 #ifdef ENABLE_KEYBOARD 2580 bool resetState =
false;
2581 if (
auto *param = findValue(d->xkbParams_, display)) {
2582 if (std::get<0>(*param) != rule || std::get<1>(*param) != model ||
2583 std::get<2>(*param) != options) {
2584 std::get<0>(*param) = rule;
2585 std::get<1>(*param) = model;
2586 std::get<2>(*param) = options;
2590 d->xkbParams_.emplace(display, std::make_tuple(rule, model, options));
2594 d->keymapCache_[display].clear();
2595 d->icManager_.foreach([d, &display](
InputContext *ic) {
2596 if (ic->
display() == display ||
2597 !d->xkbParams_.contains(ic->
display())) {
2598 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2599 inputState->resetXkbState();
2605 FCITX_UNUSED(display);
2607 FCITX_UNUSED(model);
2608 FCITX_UNUSED(options);
2613 uint32_t depressed_mods,
2614 uint32_t latched_mods, uint32_t locked_mods) {
2616 auto oldMask = xkbStateMask(display);
2617 auto &newMask = d->stateMask_[display];
2618 newMask = std::make_tuple(depressed_mods, latched_mods, locked_mods);
2619 if (oldMask == newMask) {
2622 emit<Instance::XkbStateMaskChanged>(display, oldMask, newMask);
2627 auto oldMask = xkbStateMask(display);
2628 if (!oldMask.has_value()) {
2631 bool changed = d->stateMask_.erase(display) > 0;
2633 emit<XkbStateMaskChanged>(display, oldMask, std::nullopt);
2637 std::optional<std::tuple<uint32_t, uint32_t, uint32_t>>
2640 if (
const auto *mask = findValue(d->stateMask_, display)) {
2643 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.