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::all_of(addonNames.begin(), addonNames.end(),
1589 [d](
const std::string &name) {
1590 auto *addon = d->addonManager_.lookupAddon(name);
1594 return addon->canRestart();
1598 InstancePrivate *Instance::privateData() {
1605 return d->eventLoop_;
1610 return d->eventDispatcher_;
1615 return d->icManager_;
1620 return d->addonManager_;
1625 return d->imManager_;
1630 return d->imManager_;
1635 return *d->tempModeManager_;
1640 return d->uiManager_;
1645 return d->globalConfig_;
1648 bool Instance::postEvent(
Event &event) {
1649 return std::as_const(*this).postEvent(event);
1652 bool Instance::postEvent(
Event &event)
const {
1657 auto iter = d->eventHandlers_.find(event.
type());
1658 if (iter != d->eventHandlers_.end()) {
1659 const auto &handlers = iter->second;
1660 EventWatcherPhase phaseOrder[] = {
1661 EventWatcherPhase::ReservedFirst, EventWatcherPhase::PreInputMethod,
1662 EventWatcherPhase::InputMethod, EventWatcherPhase::PostInputMethod,
1663 EventWatcherPhase::ReservedLast};
1665 for (
auto phase : phaseOrder) {
1666 if (
auto iter2 = handlers.find(phase); iter2 != handlers.end()) {
1667 for (
auto &handler : iter2->second.view()) {
1682 auto &keyEvent =
static_cast<KeyEvent &
>(event);
1683 auto *ic = keyEvent.inputContext();
1684 #ifdef ENABLE_KEYBOARD 1686 if (!keyEvent.forward() && !keyEvent.origKey().code()) {
1689 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1690 auto *xkbState = inputState->customXkbState();
1697 xkb_state_update_key(xkbState, keyEvent.origKey().code(),
1698 keyEvent.isRelease() ? XKB_KEY_UP
1702 if (ic->capabilityFlags().test(CapabilityFlag::KeyEventOrderFix) &&
1703 !keyEvent.accepted() && ic->hasPendingEventsStrictOrder()) {
1706 keyEvent.filterAndAccept();
1707 ic->forwardKey(keyEvent.origKey(), keyEvent.isRelease(),
1710 d_ptr->uiManager_.flush();
1713 return event.accepted();
1716 std::unique_ptr<HandlerTableEntry<EventHandler>>
1718 EventHandler callback) {
1720 if (phase == EventWatcherPhase::ReservedFirst ||
1721 phase == EventWatcherPhase::ReservedLast) {
1722 throw std::invalid_argument(
"Reserved Phase is only for internal use");
1724 return d->watchEvent(type, phase, std::move(callback));
1727 bool groupContains(
const InputMethodGroup &group,
const std::string &name) {
1728 const auto &list = group.inputMethodList();
1729 auto iter = std::find_if(list.begin(), list.end(),
1731 return item.name() == name;
1733 return iter != list.end();
1738 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1741 if (!inputState->overrideDeactivateIM_.empty()) {
1742 return inputState->overrideDeactivateIM_;
1745 const auto &group = d->imManager_.currentGroup();
1748 !d->globalConfig_.allowInputMethodForPassword())) {
1749 auto defaultLayoutIM =
1750 stringutils::concat(
"keyboard-", group.defaultLayout());
1751 const auto *entry = d->imManager_.entry(defaultLayoutIM);
1753 entry = d->imManager_.entry(
"keyboard-us");
1755 return entry ? entry->uniqueName() :
"";
1758 if (group.inputMethodList().empty()) {
1761 if (inputState->isActive()) {
1762 if (!inputState->localIM_.empty() &&
1763 groupContains(group, inputState->localIM_)) {
1764 return inputState->localIM_;
1766 return group.defaultInputMethod();
1769 return group.inputMethodList()[0].name();
1774 auto imName = inputMethod(ic);
1775 if (imName.empty()) {
1778 return d->imManager_.entry(imName);
1783 const auto *entry = inputMethodEntry(ic);
1788 d->addonManager_.addon(entry->addon(),
true));
1793 const auto *entry = d->imManager_.entry(name);
1798 d->addonManager_.addon(entry->addon(),
true));
1803 const auto *entry = inputMethodEntry(ic);
1805 auto *engine = inputMethodEngine(ic);
1807 icon = engine->subModeIcon(*entry, *ic);
1810 icon = entry->icon();
1813 icon =
"input-keyboard";
1821 const auto *entry = inputMethodEntry(ic);
1822 auto *engine = inputMethodEngine(ic);
1824 if (engine && entry) {
1825 label = engine->subModeLabel(*entry, *ic);
1827 if (label.empty() && entry) {
1828 label = entry->label();
1834 #ifdef ENABLE_KEYBOARD 1836 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1838 auto *xkbComposeState = state->xkbComposeState();
1839 if (!xkbComposeState) {
1843 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1845 enum xkb_compose_feed_result result =
1846 xkb_compose_state_feed(xkbComposeState, keyval);
1847 if (result == XKB_COMPOSE_FEED_IGNORED) {
1851 enum xkb_compose_status status =
1852 xkb_compose_state_get_status(xkbComposeState);
1853 if (status == XKB_COMPOSE_NOTHING) {
1856 if (status == XKB_COMPOSE_COMPOSED) {
1857 char buffer[FCITX_UTF8_MAX_LENGTH + 1] = {
'\0',
'\0',
'\0',
'\0',
1860 xkb_compose_state_get_utf8(xkbComposeState, buffer,
sizeof(buffer));
1861 xkb_compose_state_reset(xkbComposeState);
1863 return FCITX_INVALID_COMPOSE_RESULT;
1869 if (status == XKB_COMPOSE_CANCELLED) {
1870 xkb_compose_state_reset(xkbComposeState);
1873 return FCITX_INVALID_COMPOSE_RESULT;
1876 FCITX_UNUSED(keysym);
1883 #ifdef ENABLE_KEYBOARD 1885 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1887 auto *xkbComposeState = state->xkbComposeState();
1888 if (!xkbComposeState) {
1889 return std::string();
1892 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1893 enum xkb_compose_feed_result result =
1894 xkb_compose_state_feed(xkbComposeState, keyval);
1896 if (result == XKB_COMPOSE_FEED_IGNORED) {
1897 return std::string();
1900 enum xkb_compose_status status =
1901 xkb_compose_state_get_status(xkbComposeState);
1902 if (status == XKB_COMPOSE_NOTHING) {
1903 return std::string();
1905 if (status == XKB_COMPOSE_COMPOSED) {
1907 std::array<char, 256> buffer;
1908 auto length = xkb_compose_state_get_utf8(xkbComposeState, buffer.data(),
1910 xkb_compose_state_reset(xkbComposeState);
1912 return std::nullopt;
1915 auto bufferBegin = buffer.begin();
1916 auto bufferEnd = std::next(bufferBegin,
length);
1918 return std::string(bufferBegin, bufferEnd);
1920 return std::nullopt;
1922 if (status == XKB_COMPOSE_CANCELLED) {
1923 xkb_compose_state_reset(xkbComposeState);
1925 return std::nullopt;
1928 FCITX_UNUSED(keysym);
1929 return std::string();
1934 #ifdef ENABLE_KEYBOARD 1936 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1938 auto *xkbComposeState = state->xkbComposeState();
1939 if (!xkbComposeState) {
1943 return xkb_compose_state_get_status(xkbComposeState) ==
1944 XKB_COMPOSE_COMPOSING;
1946 FCITX_UNUSED(inputContext);
1952 #ifdef ENABLE_KEYBOARD 1954 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1955 auto *xkbComposeState = state->xkbComposeState();
1956 if (!xkbComposeState) {
1959 xkb_compose_state_reset(xkbComposeState);
1961 FCITX_UNUSED(inputContext);
1968 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
1969 d->imManager_.save();
1970 d->addonManager_.saveAll();
1975 if (
auto *ic = mostRecentInputContext()) {
1976 CheckInputMethodChanged imChangedRAII(ic, d);
1983 if (
const auto *entry = inputMethodManager().entry(imName)) {
1984 return entry->uniqueName();
1994 void Instance::configureAddon(
const std::string & ) {}
1996 void Instance::configureInputMethod(
const std::string & ) {}
1999 if (
auto *ic = mostRecentInputContext()) {
2000 if (
const auto *entry = inputMethodEntry(ic)) {
2001 return entry->uniqueName();
2009 return d->uiManager_.currentUI();
2014 if (
auto *ic = mostRecentInputContext()) {
2015 CheckInputMethodChanged imChangedRAII(ic, d);
2025 d->exitCode_ = exitCode;
2027 d->eventLoop_.exit();
2032 auto *addon = addonManager().addon(addonName);
2034 addon->reloadConfig();
2040 auto [enabled, disabled] = d->overrideAddons();
2041 d->addonManager_.load(enabled, disabled);
2042 d->imManager_.refresh();
2047 readAsIni(d->globalConfig_.config(), StandardPathsType::PkgConfig,
2049 FCITX_DEBUG() <<
"Trigger Key: " 2051 d->icManager_.setPropertyPropagatePolicy(
2052 d->globalConfig_.shareInputState());
2053 if (d->globalConfig_.preeditEnabledByDefault() !=
2054 d->icManager_.isPreeditEnabledByDefault()) {
2055 d->icManager_.setPreeditEnabledByDefault(
2056 d->globalConfig_.preeditEnabledByDefault());
2062 #ifdef ENABLE_KEYBOARD 2063 d->keymapCache_.clear();
2064 if (d->inputStateFactory_.registered()) {
2066 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2067 inputState->resetXkbState();
2076 if (d->globalConfig_.autoSavePeriod() <= 0) {
2077 d->periodicalSave_->setEnabled(
false);
2079 d->periodicalSave_->setNextInterval(AutoSaveMinInUsecs *
2080 d->globalConfig_.autoSavePeriod());
2081 d->periodicalSave_->setOneShot();
2092 if (!canRestart()) {
2100 setCurrentInputMethod(mostRecentInputContext(), name,
false);
2106 if (!canTrigger()) {
2110 auto &imManager = inputMethodManager();
2111 const auto &imList = imManager.currentGroup().inputMethodList();
2112 auto iter = std::find_if(imList.begin(), imList.end(),
2114 return item.name() == name;
2116 if (iter == imList.end()) {
2120 auto setGlobalDefaultInputMethod = [d](
const std::string &name) {
2121 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2122 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2124 groupRAIICheck.push_back(
2125 std::make_unique<CheckInputMethodChanged>(ic, d));
2128 d->imManager_.setDefaultInputMethod(name);
2131 auto idx = std::distance(imList.begin(), iter);
2133 CheckInputMethodChanged imChangedRAII(ic, d);
2134 auto currentIM = inputMethod(ic);
2135 if (currentIM == name) {
2138 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2142 inputState->setLocalIM(name);
2144 inputState->setLocalIM({});
2146 setGlobalDefaultInputMethod(name);
2148 inputState->setActive(
true);
2150 inputState->setActive(
false);
2152 if (inputState->imChanged_) {
2162 setGlobalDefaultInputMethod(name);
2170 if (
auto *ic = mostRecentInputContext()) {
2171 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
2172 return inputState->isActive() ? 2 : 1;
2179 if (
auto *ic = mostRecentInputContext()) {
2180 CheckInputMethodChanged imChangedRAII(ic, d);
2187 if (
auto *ic = mostRecentInputContext()) {
2188 CheckInputMethodChanged imChangedRAII(ic, d);
2189 enumerate(ic, forward);
2193 bool Instance::canTrigger()
const {
2194 const auto &imManager = inputMethodManager();
2195 return (imManager.currentGroup().inputMethodList().size() > 1);
2199 if (!canTrigger()) {
2203 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2204 if (inputState->isActive()) {
2207 return inputState->lastIMChangeIsAltTrigger_;
2212 if (!canTrigger()) {
2216 if (d->globalConfig_.enumerateSkipFirst()) {
2217 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2218 if (!inputState->isActive()) {
2221 return d->imManager_.currentGroup().inputMethodList().size() > 2;
2227 bool Instance::canChangeGroup()
const {
2228 const auto &imManager = inputMethodManager();
2229 return (imManager.groupCount() > 1);
2234 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2235 if (!canTrigger()) {
2238 inputState->setActive(!inputState->isActive());
2239 if (inputState->imChanged_) {
2240 inputState->imChanged_->setReason(reason);
2245 bool Instance::trigger(
InputContext *ic,
bool totallyReleased) {
2247 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2248 if (!canTrigger()) {
2253 if (totallyReleased) {
2255 inputState->firstTrigger_ =
true;
2257 if (!d->globalConfig_.enumerateWithTriggerKeys() ||
2258 (inputState->firstTrigger_ && inputState->isActive()) ||
2259 (d->globalConfig_.enumerateSkipFirst() &&
2260 d->imManager_.currentGroup().inputMethodList().size() <= 2)) {
2263 enumerate(ic,
true);
2265 inputState->firstTrigger_ =
false;
2271 if (!canAltTrigger(ic)) {
2281 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2282 if (!canTrigger()) {
2285 if (inputState->isActive()) {
2288 inputState->setActive(
true);
2289 if (inputState->imChanged_) {
2297 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2298 if (!canTrigger()) {
2301 if (!inputState->isActive()) {
2304 inputState->setActive(
false);
2305 if (inputState->imChanged_) {
2306 inputState->imChanged_->setReason(
2314 auto &imManager = inputMethodManager();
2315 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2316 const auto &imList = imManager.currentGroup().inputMethodList();
2317 if (!canTrigger()) {
2321 if (d->globalConfig_.enumerateSkipFirst() && imList.size() <= 2) {
2325 auto currentIM = inputMethod(ic);
2327 auto iter = std::ranges::find_if(
2329 return item.name() == currentIM;
2331 if (iter == imList.end()) {
2334 int idx = std::distance(imList.begin(), iter);
2335 auto nextIdx = [forward, &imList](
int idx) {
2337 return (idx + (forward ? 1 : (imList.size() - 1))) % imList.size();
2341 if (d->globalConfig_.enumerateSkipFirst() && idx == 0) {
2345 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2346 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2348 groupRAIICheck.push_back(
2349 std::make_unique<CheckInputMethodChanged>(ic, d));
2352 imManager.setDefaultInputMethod(imList[idx].name());
2353 inputState->setActive(
true);
2354 inputState->setLocalIM({});
2356 inputState->setActive(
false);
2358 if (inputState->imChanged_) {
2366 const std::string &orig) {
2367 std::string result = orig;
2368 emit<Instance::CommitFilter>(inputContext, result);
2374 emit<Instance::OutputFilter>(inputContext, result);
2375 if ((&orig == &inputContext->inputPanel().clientPreedit() ||
2376 &orig == &inputContext->inputPanel().preedit()) &&
2377 !globalConfig().showPreeditForPassword() &&
2378 inputContext->capabilityFlags().test(CapabilityFlag::Password)) {
2380 for (
int i = 0, e = result.size(); i < e; i++) {
2385 dot +=
"\xe2\x80\xa2";
2388 newText.append(std::move(dot),
2389 result.formatAt(i) | TextFormatFlag::DontCommit);
2391 result = std::move(newText);
2398 return d->icManager_.lastFocusedInputContext();
2403 return d->icManager_.mostRecentInputContext();
2408 d->uiManager_.flush();
2411 int scoreForGroup(
FocusGroup *group,
const std::string &displayHint) {
2413 if (displayHint.empty()) {
2414 if (group->display() ==
"x11:") {
2417 if (group->display().starts_with(
"x11:")) {
2420 if (group->display() ==
"wayland:") {
2423 if (group->display().starts_with(
"wayland:")) {
2427 if (group->display() == displayHint) {
2430 if (group->display().starts_with(displayHint)) {
2442 d->icManager_.foreachGroup(
2443 [&score, &displayHint, &defaultFocusGroup](
FocusGroup *group) {
2444 auto newScore = scoreForGroup(group, displayHint);
2445 if (newScore > score) {
2446 defaultFocusGroup = group;
2452 return defaultFocusGroup;
2457 FCITX_DEBUG() <<
"Instance::activateInputMethod";
2459 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2460 const auto *entry = inputMethodEntry(ic);
2462 FCITX_DEBUG() <<
"Activate: " 2463 <<
"[Last]:" << inputState->lastIM_
2464 <<
" [Activating]:" << entry->uniqueName();
2465 assert(inputState->lastIM_.empty());
2466 inputState->lastIM_ = entry->uniqueName();
2468 auto *engine = inputMethodEngine(ic);
2469 if (!engine || !entry) {
2472 #ifdef ENABLE_KEYBOARD 2473 if (
auto *xkbState = inputState->customXkbState(
true)) {
2474 if (
auto *mods = findValue(d->stateMask_, ic->
display())) {
2475 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
2476 auto depressed = std::get<0>(*mods);
2477 auto latched = std::get<1>(*mods);
2478 auto locked = std::get<2>(*mods);
2483 FCITX_KEYTRACE() << depressed <<
" " << latched <<
" " << locked;
2484 if (depressed == 0) {
2485 inputState->setModsAllReleased();
2487 xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0,
2493 engine->activate(*entry, event);
2499 FCITX_DEBUG() <<
"Instance::deactivateInputMethod event_type=" 2500 <<
static_cast<uint32_t
>(
event.type());
2502 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2509 FCITX_DEBUG() <<
"Switch reason: " 2510 <<
static_cast<int>(icEvent.reason());
2511 FCITX_DEBUG() <<
"Old Input method: " << icEvent.oldInputMethod();
2512 entry = d->imManager_.entry(icEvent.oldInputMethod());
2514 entry = inputMethodEntry(ic);
2517 FCITX_DEBUG() <<
"Deactivate: " 2518 <<
"[Last]:" << inputState->lastIM_
2519 <<
" [Deactivating]:" << entry->uniqueName();
2520 assert(entry->uniqueName() == inputState->lastIM_);
2522 d->addonManager_.addon(entry->addon()));
2524 inputState->lastIM_.clear();
2525 if (!engine || !entry) {
2528 inputState->overrideDeactivateIM_ = entry->uniqueName();
2530 inputState->overrideDeactivateIM_.clear();
2534 bool Instance::enumerateGroup(
bool forward) {
2535 auto &imManager = inputMethodManager();
2536 auto groups = imManager.groups();
2537 if (groups.size() <= 1) {
2541 imManager.setCurrentGroup(groups[1]);
2543 imManager.setCurrentGroup(groups.back());
2549 FCITX_DEBUG() <<
"Input method switched";
2551 if (!d->globalConfig_.showInputMethodInformation()) {
2554 d->showInputMethodInformation(ic);
2558 const std::string &message) {
2559 FCITX_DEBUG() <<
"Input method switched";
2561 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2562 inputState->showInputMethodInformation(message);
2567 return (isInFlatpak() &&
2568 std::filesystem::is_regular_file(
"/app/.updated")) ||
2569 d->addonManager_.checkUpdate() || d->imManager_.checkUpdate() ||
2574 const std::string &rule,
2575 const std::string &model,
2576 const std::string &options) {
2577 #ifdef ENABLE_KEYBOARD 2579 bool resetState =
false;
2580 if (
auto *param = findValue(d->xkbParams_, display)) {
2581 if (std::get<0>(*param) != rule || std::get<1>(*param) != model ||
2582 std::get<2>(*param) != options) {
2583 std::get<0>(*param) = rule;
2584 std::get<1>(*param) = model;
2585 std::get<2>(*param) = options;
2589 d->xkbParams_.emplace(display, std::make_tuple(rule, model, options));
2593 d->keymapCache_[display].clear();
2594 d->icManager_.foreach([d, &display](
InputContext *ic) {
2595 if (ic->
display() == display ||
2596 !d->xkbParams_.contains(ic->
display())) {
2597 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2598 inputState->resetXkbState();
2604 FCITX_UNUSED(display);
2606 FCITX_UNUSED(model);
2607 FCITX_UNUSED(options);
2612 uint32_t depressed_mods,
2613 uint32_t latched_mods, uint32_t locked_mods) {
2615 d->stateMask_[display] =
2616 std::make_tuple(depressed_mods, latched_mods, locked_mods);
2621 d->stateMask_.erase(display);
void updateXkbStateMask(const std::string &display, uint32_t depressed_mods, uint32_t latched_mods, uint32_t locked_mods)
Update xkb state mask for given display.
void restart()
Restart fcitx instance, this should only be used within a regular Fcitx server, not within embedded m...
void reloadAddonConfig(const std::string &addonName)
Reload certain addon config.
CapabilityFlags capabilityFlags() const
Returns the current capability flags.
FCITXCORE_DEPRECATED uint32_t processCompose(InputContext *ic, KeySym keysym)
Handle current XCompose state.
std::string inputMethodIcon(InputContext *ic)
Return the input method icon for input context.
void setXkbParameters(const std::string &display, const std::string &rule, const std::string &model, const std::string &options)
Set xkb RLVMO tuple for given display.
void activate()
Activate last focused input context. (Switch to the active input method)
EventType
Type of input method events.
Switched by alternative trigger key.
void resetCompose(InputContext *inputContext)
Reset the compose state.
T::PropertyType * propertyFor(const T *factory)
Helper function to return the input context property in specific type by given factory.
std::string UCS4ToUTF8(uint32_t code)
Convert UCS4 to UTF8 string.
FocusInEvent is generated when client gets focused.
Formatted string commonly used in user interface.
Whether client request input method to be disabled.
FocusGroup * defaultFocusGroup(const std::string &displayHint={})
Get the default focus group with given display hint.
static uint32_t keySymToUnicode(KeySym sym)
Convert keysym to a unicode.
Switched by activate key.
void flushUI()
All user interface update is batched internally.
This is generated when input method group changed.
std::string commitFilter(InputContext *inputContext, const std::string &orig)
Update the commit string to frontend.
AddonManager & addonManager()
Get the addon manager.
std::string currentInputMethod()
Return the current input method of last focused input context.
Manage registered TempMode objects for an Instance.
Simple file system related API for checking file status.
size_t length(Iter start, Iter end)
Return the number UTF-8 characters in the string iterator range.
bool validate(Iter start, Iter end)
Check if the string iterator range is valid utf8 string.
when user switch to a different input method by hand such as ctrl+shift by default, or by ui, default behavior is reset IM.
InputMethodSwitchedReason
The reason why input method is switched to another.
void deactivate()
Deactivate last focused input context.
int state()
Return a fcitx5-remote compatible value for the state.
InputMethodEngine * inputMethodEngine(InputContext *ic)
Return the input method engine object for given input context.
void setSignalPipe(int fd)
Set the pipe forwarding unix signal information.
InputMethodMode inputMethodMode() const
The current global input method mode.
void initialize()
Initialize fcitx.
EventLoop & eventLoop()
Get the fcitx event loop.
std::string currentUI()
Return the name of current user interface addon.
bool exitWhenMainDisplayDisconnected() const
Check whether command line specify whether to keep fcitx running.
C++ Utility functions for handling utf8 strings.
InputContext * mostRecentInputContext()
Return the most recent focused input context.
FCITX_NODISCARD std::unique_ptr< HandlerTableEntry< EventHandler > > watchEvent(EventType type, EventWatcherPhase phase, EventHandler callback)
Add a callback to for certain event type.
InputContextManager & inputContextManager()
Get the input context manager.
void setEnablePreedit(bool enable)
Override the preedit hint from client.
std::vector< std::string > split(std::string_view str, std::string_view delim, SplitBehavior behavior)
Split the string by delim.
virtual bool filtered() const
Whether a event is filtered by handler.
void clearGroup(StatusGroup group)
Clear only given status group.
bool hasFocus() const
Returns whether the input context holds the input focus.
bool isRunning() const
Whether event loop is started and still running.
A class represents a formatted string.
bool willTryReplace() const
Check whether command line specify if it will replace an existing fcitx server.
Switched by group change.
bool isRestartRequested() const
Whether restart is requested.
Manager class for user interface.
Instance(int argc, char *argv[])
A main function like construct to be used to create Fcitx Instance.
Base class for fcitx event.
bool isValidChar(uint32_t c)
Check the chr value is not two invalid value above.
std::string inputMethodLabel(InputContext *ic)
Return the input method label for input context.
void save()
Save everything including input method profile and addon data.
Enum type for input context capability.
Class for status area in UI.
void resetInputMethodList()
Reset the input method configuration and recreate based on system language.
Switched by capability change (e.g. password field)
Base class for User Interface addon.
A thread safe class to post event to a certain EventLoop.
void clearXkbStateMask(const std::string &display)
Clear xkb state mask for given display.
Enum flag for text formatting.
void configure()
Launch configtool.
bool checkUpdate() const
Check if need to invoke Instance::refresh.
New Utility classes to handle application specific path.
uint32_t getChar(Iter iter, Iter end)
Get next UCS4 char from iter, do not cross end.
InvokeAction event is generated when client click on the preedit.
InputMethodManager & inputMethodManager()
Get the input method manager.
void reloadConfig()
Reload global config.
int exec()
Start the event loop of Fcitx.
C-style utf8 utility functions.
TempModeManager & tempModeManager()
Get the temporary mode manager.
void setBinaryMode()
Set if this instance is running as fcitx5 binary.
bool isModifier() const
Check if the key is a modifier press.
InputContext * lastFocusedInputContext()
Return a focused input context.
std::string display() const
Returns the display server of the client.
void toggle()
Toggle between the first input method and active input method.
void setCurrentInputMethod(const std::string &imName)
Set the input method of last focused input context.
void setRunning(bool running)
Let other know that event loop is already running.
bool canRestart() const
Check if fcitx 5 can safely restart by itself.
void showCustomInputMethodInformation(InputContext *ic, const std::string &message)
Show a small popup with input popup window with current input method information. ...
std::optional< std::string > processComposeString(InputContext *ic, KeySym keysym)
Handle current XCompose state.
void refresh()
Load newly installed input methods and addons.
Input method mode changed.
std::string inputMethod(InputContext *ic)
Return the unique name of input method for given input context.
UserInterfaceManager & userInterfaceManager()
Get the user interface manager.
void enumerate(bool forward)
Enumerate input method with in current group.
bool exiting() const
Check whether fcitx is in exiting process.
void showInputMethodInformation(InputContext *ic)
Show a small popup with input popup window with current input method information. ...
StatusArea & statusArea()
Returns the associated StatusArea.
EventType type() const
Type of event, can be used to decide event class.
bool empty() const
Whether input panel is totally empty.
void setInputMethodMode(InputMethodMode mode)
Set the current global input method mode.
FCITXCORE_DEPRECATED void reset(ResetReason reason)
Called when input context state need to be reset.
ssize_t safeRead(int fd, void *data, size_t maxlen)
a simple wrapper around read(), ignore EINTR.
std::string addonForInputMethod(const std::string &imName)
Return the addon name of given input method.
Input Context Property for Fcitx.
static std::filesystem::path fcitxPath(const char *path, const std::filesystem::path &subPath={})
Return fcitx specific path defined at compile time.
An input context represents a client of Fcitx.
GlobalConfig & globalConfig()
Get the global config.
void exit()
Exit the fcitx event loop.
EventDispatcher & eventDispatcher()
Return a shared event dispatcher that is already attached to instance's event loop.
Key event is generated when client press or release a key.
const InputMethodEntry * inputMethodEntry(InputContext *ic)
Return the input method entry for given input context.
Class to represent a key.
bool isComposing(InputContext *inputContext)
Check whether input context is composing or not.
Switched by deactivate key.
static std::string keyListToString(const Container &container, KeyStringFormat format=KeyStringFormat::Portable)
Convert a key list to string.
Notify the global config is reloaded.
when using lost focus this might be variance case to case.
Switched by enumerate key.
static const char * version()
Return the version string of Fcitx.
Text outputFilter(InputContext *inputContext, const Text &orig)
Update the string that will be displayed in user interface.