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);
133 bool shouldSwitchIM(
const CapabilityFlags &oldFlags,
134 const CapabilityFlags &newFlags) {
135 const bool oldDisable = oldFlags.testAny(
137 const bool newDisable = newFlags.testAny(
139 return oldDisable != newDisable;
144 void InstanceArgument::printUsage()
const {
146 <<
"Usage: " << argv0 <<
" [Option]\n" 147 <<
" --disable <addon names>\tA comma separated list of addons to " 149 <<
"\t\t\t\t\"all\" can be used to disable all addons.\n" 150 <<
" --enable <addon names>\tA comma separated list of addons to " 152 <<
"\t\t\t\t\"all\" can be used to enable all addons.\n" 153 <<
"\t\t\t\tThis value will override the value in the flag " 155 <<
" --verbose <logging rule>\tSet the logging rule for " 156 "displaying message.\n" 157 <<
"\t\t\t\tSyntax: category1=level1,category2=level2, ...\n" 158 <<
"\t\t\t\tE.g. default=4,key_trace=5\n" 159 <<
"\t\t\t\tLevels are numbers ranging from 0 to 5.\n" 160 <<
"\t\t\t\t\t0 - NoLog\n" 161 <<
"\t\t\t\t\t1 - Fatal\n" 162 <<
"\t\t\t\t\t2 - Error\n" 163 <<
"\t\t\t\t\t3 - Warn\n" 164 <<
"\t\t\t\t\t4 - Info (default)\n" 165 <<
"\t\t\t\t\t5 - Debug\n" 166 <<
"\t\t\t\tSome built-in categories are:\n" 167 <<
"\t\t\t\t\tdefault - miscellaneous category used by fcitx own " 169 <<
"\t\t\t\t\tkey_trace - print the key event received by fcitx.\n" 170 <<
"\t\t\t\t\t\"*\" may be used to represent all logging " 172 <<
" -u, --ui <addon name>\t\tSet the UI addon to be used.\n" 173 <<
" -d\t\t\t\tRun as a daemon.\n" 174 <<
" -D\t\t\t\tDo not run as a daemon (default).\n" 175 <<
" -s <seconds>\t\t\tNumber of seconds to wait before start.\n" 176 <<
" -k, --keep\t\t\tKeep running even the main display is " 178 <<
" -r, --replace\t\t\tReplace the existing instance.\n" 179 <<
" -o --option <option>\t\tPass the option to addons\n" 180 <<
"\t\t\t\t<option> is in format like:\n" 181 <<
"\t\t\t\tname1=opt1a:opt1b,name2=opt2a:opt2b... .\n" 182 <<
" -v, --version\t\t\tShow version and quit.\n" 183 <<
" -h, --help\t\t\tShow this help message and quit.\n";
186 InstancePrivate::InstancePrivate(Instance *q) : QPtrHolder<Instance>(q) {
187 #ifdef ENABLE_KEYBOARD 188 const auto &locale = getCurrentLocale();
189 assert(!locale.empty());
190 xkbContext_.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
192 xkb_context_set_log_level(xkbContext_.get(), XKB_LOG_LEVEL_CRITICAL);
193 xkbComposeTable_.reset(xkb_compose_table_new_from_locale(
194 xkbContext_.get(), locale.data(), XKB_COMPOSE_COMPILE_NO_FLAGS));
195 if (!xkbComposeTable_) {
197 <<
"Trying to fallback to compose table for en_US.UTF-8";
198 xkbComposeTable_.reset(xkb_compose_table_new_from_locale(
199 xkbContext_.get(),
"en_US.UTF-8",
200 XKB_COMPOSE_COMPILE_NO_FLAGS));
202 if (!xkbComposeTable_) {
204 <<
"No compose table is loaded, you may want to check your " 211 std::unique_ptr<HandlerTableEntry<EventHandler>>
212 InstancePrivate::watchEvent(
EventType type, EventWatcherPhase phase,
213 EventHandler callback) {
214 return eventHandlers_[type][phase].add(std::move(callback));
217 #ifdef ENABLE_KEYBOARD 218 xkb_keymap *InstancePrivate::keymap(
const std::string &display,
219 const std::string &layout,
220 const std::string &variant) {
221 auto layoutAndVariant = stringutils::concat(layout,
"-", variant);
222 if (
auto *keymapPtr = findValue(keymapCache_[display], layoutAndVariant)) {
223 return (*keymapPtr).get();
225 struct xkb_rule_names names;
226 names.layout = layout.c_str();
227 names.variant = variant.c_str();
228 std::tuple<std::string, std::string, std::string> xkbParam;
229 if (
auto *param = findValue(xkbParams_, display)) {
232 if (!xkbParams_.empty()) {
233 xkbParam = xkbParams_.begin()->second;
235 xkbParam = std::make_tuple(DEFAULT_XKB_RULES,
"pc101",
"");
238 if (globalConfig_.overrideXkbOption()) {
239 std::get<2>(xkbParam) = globalConfig_.customXkbOption();
241 names.rules = std::get<0>(xkbParam).c_str();
242 names.model = std::get<1>(xkbParam).c_str();
243 names.options = std::get<2>(xkbParam).c_str();
244 UniqueCPtr<xkb_keymap, xkb_keymap_unref> keymap(xkb_keymap_new_from_names(
245 xkbContext_.get(), &names, XKB_KEYMAP_COMPILE_NO_FLAGS));
247 keymapCache_[display].emplace(layoutAndVariant, std::move(keymap));
248 assert(result.second);
249 return result.first->second.get();
253 std::pair<std::unordered_set<std::string>, std::unordered_set<std::string>>
254 InstancePrivate::overrideAddons() {
255 std::unordered_set<std::string> enabled;
256 std::unordered_set<std::string> disabled;
257 for (
const auto &addon : globalConfig_.enabledAddons()) {
258 enabled.insert(addon);
260 for (
const auto &addon : globalConfig_.disabledAddons()) {
261 enabled.erase(addon);
262 disabled.insert(addon);
264 for (
const auto &addon : arg_.enableList) {
265 disabled.erase(addon);
266 enabled.insert(addon);
268 for (
const auto &addon : arg_.disableList) {
269 enabled.erase(addon);
270 disabled.insert(addon);
272 return {enabled, disabled};
275 void InstancePrivate::buildDefaultGroup() {
277 auto *defaultGroup = q_func()->defaultFocusGroup();
278 bool infoFound =
false;
280 std::string variants;
281 auto guessLayout = [
this, &layouts, &variants,
282 &infoFound](FocusGroup *focusGroup) {
284 if (!focusGroup->display().starts_with(
"x11:")) {
288 auto *xcb = addonManager_.addon(
"xcb");
289 auto x11Name = focusGroup->display().substr(4);
291 auto rules = xcb->call<IXCBModule::xkbRulesNames>(x11Name);
292 if (!rules[2].
empty()) {
301 FCITX_UNUSED(layouts);
302 FCITX_UNUSED(variants);
303 FCITX_UNUSED(infoFound);
307 if (!defaultGroup || guessLayout(defaultGroup)) {
308 icManager_.foreachGroup(
309 [defaultGroup, &guessLayout](FocusGroup *focusGroup) {
310 if (defaultGroup == focusGroup) {
313 return guessLayout(focusGroup);
322 constexpr
char imNamePrefix[] =
"keyboard-";
326 variants,
",", stringutils::SplitBehavior::KeepEmpty);
327 auto size = std::max(layoutTokens.size(), variantTokens.size());
329 layoutTokens.resize(size);
330 variantTokens.resize(size);
332 OrderedSet<std::string> imLayouts;
333 for (decltype(size) i = 0; i < size; i++) {
334 if (layoutTokens[i].
empty()) {
337 std::string layoutName = layoutTokens[i];
338 if (!variantTokens[i].
empty()) {
339 layoutName = stringutils::concat(layoutName,
"-", variantTokens[i]);
343 if (!imManager_.entry(stringutils::concat(imNamePrefix, layoutName))) {
347 imLayouts.pushBack(layoutName);
351 auto lang = stripLanguage(getCurrentLanguage());
352 DefaultInputMethod defaultIMConfig;
353 readAsIni(defaultIMConfig, StandardPathsType::PkgData,
354 std::filesystem::path(
"default") / lang);
357 for (
const auto &extraLayout : defaultIMConfig.extraLayouts.value()) {
358 if (!imManager_.entry(stringutils::concat(imNamePrefix, extraLayout))) {
361 imLayouts.pushBack(extraLayout);
365 if (imLayouts.empty()) {
366 imLayouts.pushBack(
"us");
370 std::string defaultIM;
371 for (
const auto &im : defaultIMConfig.defaultInputMethods.value()) {
372 if (imManager_.entry(im)) {
379 std::vector<std::string> groupOrders;
380 for (
const auto &imLayout : imLayouts) {
381 std::string groupName;
382 if (imLayouts.size() == 1) {
383 groupName = _(
"Default");
385 groupName = _(
"Group {}", imManager_.groupCount() + 1);
387 imManager_.addEmptyGroup(groupName);
388 groupOrders.push_back(groupName);
389 InputMethodGroup group(groupName);
390 group.inputMethodList().emplace_back(
391 InputMethodGroupItem(stringutils::concat(imNamePrefix, imLayout)));
392 if (!defaultIM.empty()) {
393 group.inputMethodList().emplace_back(
394 InputMethodGroupItem(defaultIM));
396 FCITX_INFO() <<
"Items in " << groupName <<
": " 397 << group.inputMethodList();
398 group.setDefaultLayout(imLayout);
399 imManager_.setGroup(std::move(group));
401 FCITX_INFO() <<
"Generated groups: " << groupOrders;
402 imManager_.setGroupOrder(groupOrders);
405 void InstancePrivate::showInputMethodInformation(InputContext *ic) {
407 auto *inputState = ic->propertyFor(&inputStateFactory_);
408 auto *engine = q->inputMethodEngine(ic);
409 const auto *entry = q->inputMethodEntry(ic);
410 auto &imManager = q->inputMethodManager();
412 if (!inputState->isActive() &&
413 !globalConfig_.showFirstInputMethodInformation()) {
419 auto subMode = engine->subMode(*entry, *ic);
420 auto subModeLabel = engine->subModeLabel(*entry, *ic);
421 auto name = globalConfig_.compactInputMethodInformation() &&
422 !entry->label().empty()
425 if (globalConfig_.compactInputMethodInformation() &&
426 !subModeLabel.empty()) {
427 display = std::move(subModeLabel);
428 }
else if (subMode.empty()) {
429 display = std::move(name);
431 display = _(
"{0} ({1})", name, subMode);
434 display = _(
"{0} (Not available)", entry->name());
436 display = _(
"(Not available)");
438 if (!globalConfig_.compactInputMethodInformation() &&
439 imManager.groupCount() > 1) {
440 display = _(
"Group {0}: {1}", imManager.currentGroup().name(), display);
442 inputState->showInputMethodInformation(display);
445 bool InstancePrivate::canActivate(InputContext *ic) {
447 if (!q->canTrigger()) {
450 auto *inputState = ic->propertyFor(&inputStateFactory_);
451 return !inputState->isActive();
454 bool InstancePrivate::canDeactivate(InputContext *ic) {
456 if (!q->canTrigger()) {
459 auto *inputState = ic->propertyFor(&inputStateFactory_);
460 return inputState->isActive();
463 void InstancePrivate::navigateGroup(InputContext *ic,
const Key &key,
465 auto *inputState = ic->propertyFor(&inputStateFactory_);
466 inputState->pendingGroupIndex_ =
467 (inputState->pendingGroupIndex_ +
468 (forward ? 1 : imManager_.groupCount() - 1)) %
469 imManager_.groupCount();
470 FCITX_DEBUG() <<
"Switch to group " << inputState->pendingGroupIndex_;
472 if (notifications_ && !isSingleKey(key)) {
473 notifications_->call<INotifications::showTip>(
474 "enumerate-group", _(
"Input Method"),
"input-keyboard",
476 _(
"Switch group to {0}",
477 imManager_.groups()[inputState->pendingGroupIndex_]),
482 void InstancePrivate::acceptGroupChange(
const Key &key, InputContext *ic) {
483 FCITX_DEBUG() <<
"Accept group change, isSingleKey: " << key;
485 auto *inputState = ic->propertyFor(&inputStateFactory_);
486 auto groups = imManager_.groups();
487 if (groups.size() > inputState->pendingGroupIndex_) {
488 if (isSingleKey(key)) {
489 FCITX_DEBUG() <<
"EnumerateGroupTo: " 490 << inputState->pendingGroupIndex_ <<
" " << key;
491 imManager_.enumerateGroupTo(groups[inputState->pendingGroupIndex_]);
493 FCITX_DEBUG() <<
"SetCurrentGroup: " 494 << inputState->pendingGroupIndex_ <<
" " << key;
495 imManager_.setCurrentGroup(groups[inputState->pendingGroupIndex_]);
498 inputState->pendingGroupIndex_ = 0;
501 InputState::InputState(InstancePrivate *d, InputContext *ic)
502 : d_ptr(d), ic_(ic) {
503 active_ = d->globalConfig_.activeByDefault();
504 #ifdef ENABLE_KEYBOARD 505 if (d->xkbComposeTable_) {
506 xkbComposeState_.reset(xkb_compose_state_new(
507 d->xkbComposeTable_.get(), XKB_COMPOSE_STATE_NO_FLAGS));
512 void InputState::showInputMethodInformation(
const std::string &name) {
513 ic_->inputPanel().setAuxUp(Text(name));
516 imInfoTimer_ = d_ptr->eventLoop_.addTimeEvent(
517 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, 0,
518 [
this](EventSourceTime *, uint64_t) {
519 hideInputMethodInfo();
524 #ifdef ENABLE_KEYBOARD 525 xkb_state *InputState::customXkbState(
bool refresh) {
526 auto *instance = d_ptr->q_func();
527 const InputMethodGroup &group = d_ptr->imManager_.currentGroup();
528 const auto im = instance->inputMethod(ic_);
529 auto layout = group.layoutFor(im);
530 if (layout.empty() && im.starts_with(
"keyboard-")) {
531 layout = im.substr(9);
533 if (layout.empty() || layout == group.defaultLayout()) {
536 modsAllReleased_ =
false;
537 lastXkbLayout_.clear();
541 if (layout == lastXkbLayout_ && !refresh) {
542 return xkbState_.get();
545 lastXkbLayout_ = layout;
546 const auto layoutAndVariant = parseLayout(layout);
547 if (
auto *keymap = d_ptr->keymap(ic_->display(), layoutAndVariant.first,
548 layoutAndVariant.second)) {
549 xkbState_.reset(xkb_state_new(keymap));
553 modsAllReleased_ =
false;
554 return xkbState_.get();
558 void InputState::setActive(
bool active) {
559 if (active_ != active) {
561 ic_->updateProperty(&d_ptr->inputStateFactory_);
565 void InputState::setLocalIM(
const std::string &localIM) {
566 if (localIM_ != localIM) {
568 ic_->updateProperty(&d_ptr->inputStateFactory_);
572 void InputState::copyTo(InputContextProperty *other) {
573 auto *otherState =
static_cast<InputState *
>(other);
574 if (otherState->active_ == active_ && otherState->localIM_ == localIM_) {
578 if (otherState->ic_->hasFocus()) {
579 FCITX_DEBUG() <<
"Sync state to focused ic: " 580 << otherState->ic_->program();
581 CheckInputMethodChanged imChangedRAII(otherState->ic_, d_ptr);
582 otherState->active_ = active_;
583 otherState->localIM_ = localIM_;
585 otherState->active_ = active_;
586 otherState->localIM_ = localIM_;
590 void InputState::reset() {
591 #ifdef ENABLE_KEYBOARD 592 if (xkbComposeState_) {
593 xkb_compose_state_reset(xkbComposeState_.get());
596 pendingGroupIndex_ = 0;
598 lastKeyPressed_ = Key();
599 lastKeyPressedTime_ = 0;
600 totallyReleased_ =
true;
603 void InputState::hideInputMethodInfo() {
607 imInfoTimer_.reset();
608 auto &panel = ic_->inputPanel();
609 if (panel.auxDown().empty() && panel.preedit().empty() &&
610 panel.clientPreedit().empty() &&
611 (!panel.candidateList() || panel.candidateList()->empty()) &&
612 panel.auxUp().size() == 1 && panel.auxUp().stringAt(0) == lastInfo_) {
618 #ifdef ENABLE_KEYBOARD 619 void InputState::resetXkbState() {
620 lastXkbLayout_.clear();
625 CheckInputMethodChanged::CheckInputMethodChanged(InputContext *ic,
626 InstancePrivate *instance)
627 : instance_(instance->q_func()), instancePrivate_(instance),
628 ic_(ic->watch()), inputMethod_(instance_->inputMethod(ic)),
630 auto *inputState = ic->propertyFor(&instance->inputStateFactory_);
631 if (!inputState->imChanged_) {
632 inputState->imChanged_ =
this;
638 CheckInputMethodChanged::~CheckInputMethodChanged() {
639 if (!ic_.isValid()) {
642 auto *ic = ic_.get();
643 auto *inputState = ic->propertyFor(&instancePrivate_->inputStateFactory_);
644 inputState->imChanged_ =
nullptr;
645 if (inputMethod_ != instance_->inputMethod(ic) && !ignore_) {
646 instance_->postEvent(
647 InputContextSwitchInputMethodEvent(reason_, inputMethod_, ic));
652 InstanceArgument arg;
653 arg.parseOption(argc, argv);
658 if (arg.runAsDaemon) {
662 if (arg.overrideDelay > 0) {
663 sleep(arg.overrideDelay);
667 d_ptr = std::make_unique<InstancePrivate>(
this);
670 d->eventDispatcher_.attach(&d->eventLoop_);
671 d->addonManager_.setInstance(
this);
672 d->addonManager_.setAddonOptions(arg.addonOptions_);
673 d->icManager_.setInstance(
this);
674 d->connections_.emplace_back(
675 d->imManager_.connect<InputMethodManager::CurrentGroupAboutToChange>(
676 [
this, d](
const std::string &lastGroup) {
677 d->icManager_.foreachFocused([this](InputContext *ic) {
678 assert(ic->hasFocus());
679 InputContextSwitchInputMethodEvent event(
680 InputMethodSwitchedReason::GroupChange, inputMethod(ic),
682 deactivateInputMethod(event);
685 d->lastGroup_ = lastGroup;
688 d->connections_.emplace_back(
689 d->imManager_.connect<InputMethodManager::CurrentGroupChanged>(
690 [
this, d](
const std::string &newGroup) {
691 d->icManager_.foreachFocused([this](InputContext *ic) {
692 assert(ic->hasFocus());
693 InputContextSwitchInputMethodEvent event(
694 InputMethodSwitchedReason::GroupChange,
"", ic);
695 activateInputMethod(event);
699 if (!d->lastGroup_.empty() && !newGroup.empty() &&
700 d->lastGroup_ != newGroup && d->notifications_ &&
701 d->imManager_.groupCount() > 1) {
702 d->notifications_->call<INotifications::showTip>(
703 "enumerate-group", _(
"Input Method"),
"input-keyboard",
705 _(
"Switched group to {0}",
706 d->imManager_.currentGroup().name()),
709 d->lastGroup_ = newGroup;
712 d->eventWatchers_.emplace_back(d->watchEvent(
713 EventType::InputContextCapabilityAboutToChange,
714 EventWatcherPhase::ReservedFirst, [
this](
Event &event) {
716 static_cast<CapabilityAboutToChangeEvent &>(event);
717 if (!capChanged.inputContext()->hasFocus()) {
721 if (!shouldSwitchIM(capChanged.oldFlags(), capChanged.newFlags())) {
727 inputMethod(capChanged.inputContext()),
728 capChanged.inputContext());
729 deactivateInputMethod(switchIM);
731 d->eventWatchers_.emplace_back(d->watchEvent(
732 EventType::InputContextCapabilityChanged,
733 EventWatcherPhase::ReservedFirst, [
this](
Event &event) {
734 auto &capChanged = static_cast<CapabilityChangedEvent &>(event);
735 if (!capChanged.inputContext()->hasFocus()) {
739 if (!shouldSwitchIM(capChanged.oldFlags(), capChanged.newFlags())) {
745 capChanged.inputContext());
746 activateInputMethod(switchIM);
749 d->eventWatchers_.emplace_back(watchEvent(
751 [
this, d](
Event &event) {
752 auto &keyEvent =
static_cast<KeyEvent &
>(event);
753 auto *ic = keyEvent.inputContext();
754 CheckInputMethodChanged imChangedRAII(ic, d);
755 auto origKey = keyEvent.origKey().normalize();
759 std::function<bool()> check;
760 std::function<void(bool)> trigger;
762 {.list = d->globalConfig_.triggerKeys(),
763 .check = [
this]() {
return canTrigger(); },
765 [
this, ic](
bool totallyReleased) {
766 return trigger(ic, totallyReleased);
768 {.list = d->globalConfig_.altTriggerKeys(),
769 .check = [
this, ic]() {
return canAltTrigger(ic); },
770 .trigger = [
this, ic](bool) {
return altTrigger(ic); }},
771 {.list = d->globalConfig_.activateKeys(),
772 .check = [ic, d]() {
return d->canActivate(ic); },
773 .trigger = [
this, ic](bool) {
return activate(ic); }},
774 {.list = d->globalConfig_.deactivateKeys(),
775 .check = [ic, d]() {
return d->canDeactivate(ic); },
776 .trigger = [
this, ic](bool) {
return deactivate(ic); }},
777 {.list = d->globalConfig_.enumerateForwardKeys(),
778 .check = [
this, ic]() {
return canEnumerate(ic); },
779 .trigger = [
this, ic](bool) {
return enumerate(ic,
true); }},
780 {.list = d->globalConfig_.enumerateBackwardKeys(),
781 .check = [
this, ic]() {
return canEnumerate(ic); },
782 .trigger = [
this, ic](bool) {
return enumerate(ic,
false); }},
783 {.list = d->globalConfig_.enumerateGroupForwardKeys(),
784 .check = [
this]() {
return canChangeGroup(); },
785 .trigger = [ic, d, origKey](
786 bool) { d->navigateGroup(ic, origKey,
true); }},
787 {.list = d->globalConfig_.enumerateGroupBackwardKeys(),
788 .check = [
this]() {
return canChangeGroup(); },
790 [ic, d, origKey](bool) {
791 d->navigateGroup(ic, origKey,
false);
795 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
796 int keyReleased = inputState->keyReleased_;
797 Key lastKeyPressed = inputState->lastKeyPressed_;
799 inputState->keyReleased_ = -1;
801 if (keyEvent.isRelease()) {
803 for (
auto &keyHandler : keyHandlers) {
804 if (keyReleased == idx &&
805 origKey.isReleaseOfModifier(lastKeyPressed) &&
806 keyHandler.check()) {
808 if (d->globalConfig_.checkModifierOnlyKeyTimeout(
809 inputState->lastKeyPressedTime_)) {
811 inputState->totallyReleased_);
813 inputState->lastKeyPressedTime_ = 0;
814 if (origKey.hasModifier()) {
815 inputState->totallyReleased_ =
false;
823 if (isSingleModifier(origKey)) {
824 inputState->totallyReleased_ =
true;
828 if (inputState->pendingGroupIndex_ &&
829 inputState->totallyReleased_) {
830 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
831 if (inputState->imChanged_) {
832 inputState->imChanged_->ignore();
834 d->acceptGroupChange(lastKeyPressed, ic);
835 inputState->lastKeyPressed_ =
Key();
838 if (!keyEvent.filtered() && !keyEvent.isRelease()) {
840 for (
auto &keyHandler : keyHandlers) {
841 auto keyIdx = origKey.keyListIndex(keyHandler.list);
842 if (keyIdx >= 0 && keyHandler.check()) {
843 inputState->keyReleased_ = idx;
844 inputState->lastKeyPressed_ = origKey;
846 inputState->lastKeyPressedTime_ =
847 now(CLOCK_MONOTONIC);
853 keyHandler.trigger(inputState->totallyReleased_);
854 if (origKey.hasModifier()) {
855 inputState->totallyReleased_ =
false;
857 keyEvent.filterAndAccept();
864 d->eventWatchers_.emplace_back(watchEvent(
867 auto &keyEvent =
static_cast<KeyEvent &
>(event);
868 auto *ic = keyEvent.inputContext();
869 if (!keyEvent.isRelease() &&
870 keyEvent.key().checkKeyList(
871 d->globalConfig_.togglePreeditKeys())) {
874 ic->setEnablePreedit(!ic->isPreeditEnabled());
875 if (d->notifications_) {
876 d->notifications_->call<INotifications::showTip>(
877 "toggle-preedit", _(
"Input Method"),
"", _(
"Preedit"),
878 ic->isPreeditEnabled() ? _(
"Preedit enabled")
879 : _(
"Preedit disabled"),
882 keyEvent.filterAndAccept();
885 d->eventWatchers_.emplace_back(d->watchEvent(
889 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
890 auto &keyEvent = static_cast<KeyEvent &>(event);
891 auto *ic = keyEvent.inputContext();
892 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
893 #ifdef ENABLE_KEYBOARD
894 auto *xkbState = inputState->customXkbState();
896 if (auto *mods = findValue(d->stateMask_, ic->display())) {
897 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
901 if (inputState->isModsAllReleased()) {
902 depressed = xkb_state_serialize_mods(
903 xkbState, XKB_STATE_MODS_DEPRESSED);
905 depressed = std::get<0>(*mods);
907 if (std::get<0>(*mods) == 0) {
908 inputState->setModsAllReleased();
910 auto latched = xkb_state_serialize_mods(
911 xkbState, XKB_STATE_MODS_LATCHED);
912 auto locked = std::get<2>(*mods);
918 << depressed <<
" " << latched <<
" " << locked;
919 xkb_state_update_mask(xkbState, depressed, latched, locked,
922 const uint32_t effective = xkb_state_serialize_mods(
923 xkbState, XKB_STATE_MODS_EFFECTIVE);
924 auto newSym = xkb_state_key_get_one_sym(
925 xkbState, keyEvent.rawKey().code());
926 auto newModifier = KeyStates(effective);
927 auto *keymap = xkb_state_get_keymap(xkbState);
928 if (keyEvent.rawKey().states().test(KeyState::Repeat) &&
929 xkb_keymap_key_repeats(keymap, keyEvent.rawKey().code())) {
930 newModifier |= KeyState::Repeat;
933 const uint32_t modsDepressed = xkb_state_serialize_mods(
934 xkbState, XKB_STATE_MODS_DEPRESSED);
935 const uint32_t modsLatched =
936 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
937 const uint32_t modsLocked =
938 xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
939 FCITX_KEYTRACE() <<
"Current mods: " << modsDepressed <<
" " 940 << modsLatched <<
" " << modsLocked;
941 auto newCode = keyEvent.rawKey().code();
942 Key key(static_cast<KeySym>(newSym), newModifier, newCode);
944 <<
"Custom Xkb translated Key: " << key.toString();
945 keyEvent.setRawKey(key);
948 FCITX_KEYTRACE() <<
"KeyEvent: " << keyEvent.key()
949 <<
" rawKey: " << keyEvent.rawKey()
950 <<
" origKey: " << keyEvent.origKey()
951 <<
" Release:" << keyEvent.isRelease()
952 <<
" keycode: " << keyEvent.origKey().code()
953 <<
" program: " << ic->program();
955 if (keyEvent.isRelease()) {
958 inputState->hideInputMethodInfo();
960 d->eventWatchers_.emplace_back(
962 EventWatcherPhase::InputMethod, [
this](
Event &event) {
963 auto &keyEvent =
static_cast<KeyEvent &
>(event);
964 auto *ic = keyEvent.inputContext();
965 auto *engine = inputMethodEngine(ic);
966 const auto *entry = inputMethodEntry(ic);
967 if (!engine || !entry) {
970 engine->keyEvent(*entry, keyEvent);
972 d->eventWatchers_.emplace_back(watchEvent(
973 EventType::InputContextVirtualKeyboardEvent,
974 EventWatcherPhase::InputMethod, [
this](
Event &event) {
976 auto *ic = keyEvent.inputContext();
977 auto *engine = inputMethodEngine(ic);
978 const auto *entry = inputMethodEntry(ic);
979 if (!engine || !entry) {
982 engine->virtualKeyboardEvent(*entry, keyEvent);
984 d->eventWatchers_.emplace_back(watchEvent(
986 [
this](
Event &event) {
988 auto *ic = invokeActionEvent.inputContext();
989 auto *engine = inputMethodEngine(ic);
990 const auto *entry = inputMethodEntry(ic);
991 if (!engine || !entry) {
994 engine->invokeAction(*entry, invokeActionEvent);
996 d->eventWatchers_.emplace_back(d->watchEvent(
998 [
this](
Event &event) {
999 auto &keyEvent = static_cast<KeyEvent &>(event);
1000 auto *ic = keyEvent.inputContext();
1001 auto *engine = inputMethodEngine(ic);
1002 const auto *entry = inputMethodEntry(ic);
1003 if (!engine || !entry) {
1006 engine->filterKey(*entry, keyEvent);
1007 emit<Instance::KeyEventResult>(keyEvent);
1008 #ifdef ENABLE_KEYBOARD 1009 if (keyEvent.forward()) {
1014 if (keyEvent.isRelease()) {
1018 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1019 if (
auto *xkbState = inputState->customXkbState()) {
1020 if (
auto utf32 = xkb_state_key_get_utf32(
1021 xkbState, keyEvent.key().code())) {
1023 if (utf32 ==
'\n' || utf32 ==
'\b' || utf32 ==
'\r' ||
1024 utf32 ==
'\t' || utf32 ==
'\033' ||
1028 if (keyEvent.key().states().testAny(
1029 KeyStates{KeyState::Ctrl, KeyState::Alt}) ||
1030 keyEvent.rawKey().sym() ==
1031 keyEvent.origKey().sym()) {
1034 FCITX_KEYTRACE() <<
"Will commit char: " << utf32;
1036 keyEvent.filterAndAccept();
1037 }
else if (!keyEvent.key().states().testAny(
1038 KeyStates{KeyState::Ctrl, KeyState::Alt}) &&
1039 keyEvent.rawKey().sym() !=
1040 keyEvent.origKey().sym() &&
1045 keyEvent.filterAndAccept();
1051 d->eventWatchers_.emplace_back(d->watchEvent(
1053 [
this, d](
Event &event) {
1054 auto &icEvent = static_cast<InputContextEvent &>(event);
1055 auto isSameProgram = [&icEvent, d]() {
1057 return (icEvent.inputContext() == d->lastUnFocusedIc_.get()) ||
1058 (!icEvent.inputContext()->program().empty() &&
1059 (icEvent.inputContext()->program() ==
1060 d->lastUnFocusedProgram_));
1063 if (d->globalConfig_.resetStateWhenFocusIn() ==
1064 PropertyPropagatePolicy::All ||
1065 (d->globalConfig_.resetStateWhenFocusIn() ==
1066 PropertyPropagatePolicy::Program &&
1067 !isSameProgram())) {
1068 if (d->globalConfig_.activeByDefault()) {
1069 activate(icEvent.inputContext());
1071 deactivate(icEvent.inputContext());
1075 activateInputMethod(icEvent);
1077 auto *inputContext = icEvent.inputContext();
1078 if (!inputContext->clientControlVirtualkeyboardShow()) {
1079 inputContext->showVirtualKeyboard();
1082 if (!d->globalConfig_.showInputMethodInformationWhenFocusIn() ||
1083 icEvent.inputContext()->capabilityFlags().test(
1089 d->focusInImInfoTimer_ = d->eventLoop_.addTimeEvent(
1090 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1094 if (
auto *ic = icRef.get(); ic && ic->hasFocus()) {
1095 d->showInputMethodInformation(ic);
1100 d->eventWatchers_.emplace_back(d->watchEvent(
1103 auto &icEvent = static_cast<InputContextEvent &>(event);
1104 auto *ic = icEvent.inputContext();
1105 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1106 inputState->reset();
1107 if (!ic->capabilityFlags().test(
1108 CapabilityFlag::ClientUnfocusCommit)) {
1111 ic->inputPanel().clientPreedit().toStringForCommit();
1112 if (!commit.empty()) {
1113 ic->commitString(commit);
1117 d->eventWatchers_.emplace_back(d->watchEvent(
1119 [
this, d](
Event &event) {
1120 auto &icEvent = static_cast<InputContextEvent &>(event);
1121 d->lastUnFocusedProgram_ = icEvent.inputContext()->program();
1122 d->lastUnFocusedIc_ = icEvent.inputContext()->watch();
1123 deactivateInputMethod(icEvent);
1125 auto *inputContext = icEvent.inputContext();
1126 if (!inputContext->clientControlVirtualkeyboardHide()) {
1127 inputContext->hideVirtualKeyboard();
1130 d->eventWatchers_.emplace_back(d->watchEvent(
1133 auto &icEvent = static_cast<InputContextEvent &>(event);
1134 auto *ic = icEvent.inputContext();
1135 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1136 inputState->reset();
1138 d->eventWatchers_.emplace_back(
1140 [
this](
Event &event) {
1142 auto *ic = icEvent.inputContext();
1143 if (!ic->hasFocus()) {
1146 auto *engine = inputMethodEngine(ic);
1147 const auto *entry = inputMethodEntry(ic);
1148 if (!engine || !entry) {
1151 engine->reset(*entry, icEvent);
1153 d->eventWatchers_.emplace_back(d->watchEvent(
1155 EventWatcherPhase::ReservedFirst, [
this](
Event &event) {
1157 static_cast<InputContextSwitchInputMethodEvent &>(event);
1158 auto *ic = icEvent.inputContext();
1159 if (!ic->hasFocus()) {
1162 deactivateInputMethod(icEvent);
1163 activateInputMethod(icEvent);
1165 d->eventWatchers_.emplace_back(d->watchEvent(
1167 EventWatcherPhase::ReservedLast, [
this, d](
Event &event) {
1169 static_cast<InputContextSwitchInputMethodEvent &>(event);
1170 auto *ic = icEvent.inputContext();
1171 if (!ic->hasFocus()) {
1175 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
1176 inputState->lastIMChangeIsAltTrigger_ =
1188 showInputMethodInformation(ic);
1190 d->eventWatchers_.emplace_back(
1192 EventWatcherPhase::ReservedLast, [
this, d](
Event &) {
1195 d->imGroupInfoTimer_ = d->eventLoop_.addTimeEvent(
1196 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 30000, 0,
1197 [this](EventSourceTime *, uint64_t) {
1198 inputContextManager().foreachFocused(
1199 [this](InputContext *ic) {
1200 showInputMethodInformation(ic);
1207 d->eventWatchers_.emplace_back(d->watchEvent(
1208 EventType::InputContextUpdateUI, EventWatcherPhase::ReservedFirst,
1210 auto &icEvent = static_cast<InputContextUpdateUIEvent &>(event);
1211 if (icEvent.immediate()) {
1212 d->uiManager_.update(icEvent.component(),
1213 icEvent.inputContext());
1214 d->uiManager_.flush();
1216 d->uiManager_.update(icEvent.component(),
1217 icEvent.inputContext());
1218 d->uiUpdateEvent_->setOneShot();
1221 d->eventWatchers_.emplace_back(d->watchEvent(
1222 EventType::InputContextDestroyed, EventWatcherPhase::ReservedFirst,
1224 auto &icEvent = static_cast<InputContextEvent &>(event);
1225 d->uiManager_.expire(icEvent.inputContext());
1227 d->eventWatchers_.emplace_back(d->watchEvent(
1229 [d](
Event &) { d->uiManager_.updateAvailability(); }));
1230 d->uiUpdateEvent_ = d->eventLoop_.addDeferEvent([d](
EventSource *) {
1231 d->uiManager_.flush();
1234 d->uiUpdateEvent_->setEnabled(
false);
1235 d->periodicalSave_ = d->eventLoop_.addTimeEvent(
1236 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, AutoSaveIdleTime,
1243 auto currentTime = now(CLOCK_MONOTONIC);
1244 if (currentTime <= d->idleStartTimestamp_ ||
1245 currentTime - d->idleStartTimestamp_ < AutoSaveIdleTime) {
1247 time->setNextInterval(2 * AutoSaveIdleTime);
1252 FCITX_INFO() <<
"Running autosave...";
1254 FCITX_INFO() <<
"End autosave";
1255 if (d->globalConfig_.autoSavePeriod() > 0) {
1256 time->setNextInterval(d->globalConfig_.autoSavePeriod() *
1257 AutoSaveMinInUsecs);
1262 d->periodicalSave_->setEnabled(
false);
1265 Instance::~Instance() {
1267 d->icManager_.finalize();
1268 d->addonManager_.unload();
1269 d->notifications_ =
nullptr;
1270 d->icManager_.setInstance(
nullptr);
1273 void InstanceArgument::parseOption(
int argc,
char **argv) {
1279 struct option longOptions[] = {{
"enable", required_argument,
nullptr, 0},
1280 {
"disable", required_argument,
nullptr, 0},
1281 {
"verbose", required_argument,
nullptr, 0},
1282 {
"keep", no_argument,
nullptr,
'k'},
1283 {
"ui", required_argument,
nullptr,
'u'},
1284 {
"replace", no_argument,
nullptr,
'r'},
1285 {
"version", no_argument,
nullptr,
'v'},
1286 {
"help", no_argument,
nullptr,
'h'},
1287 {
"option", required_argument,
nullptr,
'o'},
1288 {
nullptr, 0, 0, 0}};
1290 int optionIndex = 0;
1292 std::string addonOptionString;
1293 while ((c = getopt_long(argc, argv,
"ru:dDs:hvo:k", longOptions,
1294 &optionIndex)) != EOF) {
1297 switch (optionIndex) {
1305 Log::setLogRule(optarg);
1323 runAsDaemon =
false;
1326 exitWhenMainDisplayDisconnected =
false;
1329 overrideDelay = std::atoi(optarg);
1340 addonOptionString = optarg;
1351 std::unordered_map<std::string, std::vector<std::string>> addonOptions;
1352 for (
const std::string_view item :
1355 if (tokens.size() != 2) {
1360 addonOptions_ = std::move(addonOptions);
1368 d->signalPipe_ = fd;
1369 d->signalPipeEvent_ = d->eventLoop_.addIOEvent(
1379 return d->arg_.tryReplace;
1384 return d->arg_.exitWhenMainDisplayDisconnected;
1392 void Instance::handleSignal() {
1396 while (
fs::safeRead(d->signalPipe_, &signo,
sizeof(signo)) > 0) {
1397 if (signo == SIGINT || signo == SIGTERM || signo == SIGQUIT ||
1400 }
else if (signo == SIGUSR1) {
1402 }
else if (signo == SIGCHLD) {
1403 d->zombieReaper_->setNextInterval(2000000);
1404 d->zombieReaper_->setOneShot();
1412 if (!d->arg_.uiName.empty()) {
1413 d->arg_.enableList.push_back(d->arg_.uiName);
1416 d->icManager_.registerProperty(
"inputState", &d->inputStateFactory_);
1417 std::unordered_set<std::string> enabled;
1418 std::unordered_set<std::string> disabled;
1419 std::tie(enabled, disabled) = d->overrideAddons();
1420 FCITX_INFO() <<
"Override Enabled Addons: " << enabled;
1421 FCITX_INFO() <<
"Override Disabled Addons: " << disabled;
1422 d->addonManager_.load(enabled, disabled);
1427 d->uiManager_.load(d->arg_.uiName);
1429 const auto *entry = d->imManager_.entry(
"keyboard-us");
1430 FCITX_LOG_IF(Error, !entry) <<
"Couldn't find keyboard-us";
1431 d->preloadInputMethodEvent_ = d->eventLoop_.addTimeEvent(
1432 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000000, 0,
1435 if (d->exit_ || !d->globalConfig_.preloadInputMethod()) {
1439 if (!d->imManager_.currentGroup().inputMethodList().empty()) {
1440 if (
const auto *entry =
1441 d->imManager_.entry(d->imManager_.currentGroup()
1442 .inputMethodList()[0]
1444 d->addonManager_.addon(entry->addon(),
true);
1448 if (!d->imManager_.currentGroup().defaultInputMethod().empty()) {
1449 if (
const auto *entry = d->imManager_.entry(
1450 d->imManager_.currentGroup().defaultInputMethod())) {
1451 d->addonManager_.addon(entry->addon(),
true);
1457 d->zombieReaper_ = d->eventLoop_.addTimeEvent(
1458 CLOCK_MONOTONIC, now(CLOCK_MONOTONIC), 0,
1461 while ((res = waitpid(-1,
nullptr, WNOHANG)) > 0) {
1465 d->zombieReaper_->setEnabled(
false);
1468 d->exitEvent_ = d->eventLoop_.addExitEvent([
this](
EventSource *) {
1469 FCITX_DEBUG() <<
"Running save...";
1473 d->notifications_ = d->addonManager_.addon(
"notifications",
true);
1478 if (d->arg_.quietQuit) {
1485 return d->exitCode_;
1488 auto r = eventLoop().exec();
1489 d->running_ =
false;
1491 return r ? d->exitCode_ : 1;
1496 d->running_ = running;
1506 return d->inputMethodMode_;
1511 if (d->inputMethodMode_ == mode) {
1514 d->inputMethodMode_ = mode;
1523 bool Instance::virtualKeyboardAutoShow()
const {
1525 return d->virtualKeyboardAutoShow_;
1528 void Instance::setVirtualKeyboardAutoShow(
bool autoShow) {
1530 d->virtualKeyboardAutoShow_ = autoShow;
1533 bool Instance::virtualKeyboardAutoHide()
const {
1535 return d->virtualKeyboardAutoHide_;
1538 void Instance::setVirtualKeyboardAutoHide(
bool autoHide) {
1540 d->virtualKeyboardAutoHide_ = autoHide;
1543 VirtualKeyboardFunctionMode Instance::virtualKeyboardFunctionMode()
const {
1545 return d->virtualKeyboardFunctionMode_;
1548 void Instance::setVirtualKeyboardFunctionMode(
1549 VirtualKeyboardFunctionMode mode) {
1551 d->virtualKeyboardFunctionMode_ = mode;
1556 d->binaryMode_ =
true;
1561 const auto &addonNames = d->addonManager_.loadedAddonNames();
1562 return d->binaryMode_ &&
1563 std::all_of(addonNames.begin(), addonNames.end(),
1564 [d](
const std::string &name) {
1565 auto *addon = d->addonManager_.lookupAddon(name);
1569 return addon->canRestart();
1573 InstancePrivate *Instance::privateData() {
1580 return d->eventLoop_;
1585 return d->eventDispatcher_;
1590 return d->icManager_;
1595 return d->addonManager_;
1600 return d->imManager_;
1605 return d->imManager_;
1610 return d->uiManager_;
1615 return d->globalConfig_;
1618 bool Instance::postEvent(
Event &event) {
1619 return std::as_const(*this).postEvent(event);
1622 bool Instance::postEvent(
Event &event)
const {
1627 auto iter = d->eventHandlers_.find(event.
type());
1628 if (iter != d->eventHandlers_.end()) {
1629 const auto &handlers = iter->second;
1630 EventWatcherPhase phaseOrder[] = {
1631 EventWatcherPhase::ReservedFirst, EventWatcherPhase::PreInputMethod,
1632 EventWatcherPhase::InputMethod, EventWatcherPhase::PostInputMethod,
1633 EventWatcherPhase::ReservedLast};
1635 for (
auto phase : phaseOrder) {
1636 if (
auto iter2 = handlers.find(phase); iter2 != handlers.end()) {
1637 for (
auto &handler : iter2->second.view()) {
1652 auto &keyEvent =
static_cast<KeyEvent &
>(event);
1653 auto *ic = keyEvent.inputContext();
1654 #ifdef ENABLE_KEYBOARD 1656 if (!keyEvent.forward() && !keyEvent.origKey().code()) {
1659 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1660 auto *xkbState = inputState->customXkbState();
1667 xkb_state_update_key(xkbState, keyEvent.origKey().code(),
1668 keyEvent.isRelease() ? XKB_KEY_UP
1672 if (ic->capabilityFlags().test(CapabilityFlag::KeyEventOrderFix) &&
1673 !keyEvent.accepted() && ic->hasPendingEventsStrictOrder()) {
1676 keyEvent.filterAndAccept();
1677 ic->forwardKey(keyEvent.origKey(), keyEvent.isRelease(),
1680 d_ptr->uiManager_.flush();
1683 return event.accepted();
1686 std::unique_ptr<HandlerTableEntry<EventHandler>>
1688 EventHandler callback) {
1690 if (phase == EventWatcherPhase::ReservedFirst ||
1691 phase == EventWatcherPhase::ReservedLast) {
1692 throw std::invalid_argument(
"Reserved Phase is only for internal use");
1694 return d->watchEvent(type, phase, std::move(callback));
1697 bool groupContains(
const InputMethodGroup &group,
const std::string &name) {
1698 const auto &list = group.inputMethodList();
1699 auto iter = std::find_if(list.begin(), list.end(),
1701 return item.name() == name;
1703 return iter != list.end();
1708 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
1711 if (!inputState->overrideDeactivateIM_.empty()) {
1712 return inputState->overrideDeactivateIM_;
1715 const auto &group = d->imManager_.currentGroup();
1718 !d->globalConfig_.allowInputMethodForPassword())) {
1719 auto defaultLayoutIM =
1720 stringutils::concat(
"keyboard-", group.defaultLayout());
1721 const auto *entry = d->imManager_.entry(defaultLayoutIM);
1723 entry = d->imManager_.entry(
"keyboard-us");
1725 return entry ? entry->uniqueName() :
"";
1728 if (group.inputMethodList().empty()) {
1731 if (inputState->isActive()) {
1732 if (!inputState->localIM_.empty() &&
1733 groupContains(group, inputState->localIM_)) {
1734 return inputState->localIM_;
1736 return group.defaultInputMethod();
1739 return group.inputMethodList()[0].name();
1744 auto imName = inputMethod(ic);
1745 if (imName.empty()) {
1748 return d->imManager_.entry(imName);
1753 const auto *entry = inputMethodEntry(ic);
1758 d->addonManager_.addon(entry->addon(),
true));
1763 const auto *entry = d->imManager_.entry(name);
1768 d->addonManager_.addon(entry->addon(),
true));
1773 const auto *entry = inputMethodEntry(ic);
1775 auto *engine = inputMethodEngine(ic);
1777 icon = engine->subModeIcon(*entry, *ic);
1780 icon = entry->icon();
1783 icon =
"input-keyboard";
1791 const auto *entry = inputMethodEntry(ic);
1792 auto *engine = inputMethodEngine(ic);
1794 if (engine && entry) {
1795 label = engine->subModeLabel(*entry, *ic);
1797 if (label.empty() && entry) {
1798 label = entry->label();
1804 #ifdef ENABLE_KEYBOARD 1806 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1808 auto *xkbComposeState = state->xkbComposeState();
1809 if (!xkbComposeState) {
1813 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1815 enum xkb_compose_feed_result result =
1816 xkb_compose_state_feed(xkbComposeState, keyval);
1817 if (result == XKB_COMPOSE_FEED_IGNORED) {
1821 enum xkb_compose_status status =
1822 xkb_compose_state_get_status(xkbComposeState);
1823 if (status == XKB_COMPOSE_NOTHING) {
1826 if (status == XKB_COMPOSE_COMPOSED) {
1827 char buffer[FCITX_UTF8_MAX_LENGTH + 1] = {
'\0',
'\0',
'\0',
'\0',
1830 xkb_compose_state_get_utf8(xkbComposeState, buffer,
sizeof(buffer));
1831 xkb_compose_state_reset(xkbComposeState);
1833 return FCITX_INVALID_COMPOSE_RESULT;
1839 if (status == XKB_COMPOSE_CANCELLED) {
1840 xkb_compose_state_reset(xkbComposeState);
1843 return FCITX_INVALID_COMPOSE_RESULT;
1846 FCITX_UNUSED(keysym);
1853 #ifdef ENABLE_KEYBOARD 1855 auto *state = ic->
propertyFor(&d->inputStateFactory_);
1857 auto *xkbComposeState = state->xkbComposeState();
1858 if (!xkbComposeState) {
1859 return std::string();
1862 auto keyval =
static_cast<xkb_keysym_t
>(keysym);
1863 enum xkb_compose_feed_result result =
1864 xkb_compose_state_feed(xkbComposeState, keyval);
1866 if (result == XKB_COMPOSE_FEED_IGNORED) {
1867 return std::string();
1870 enum xkb_compose_status status =
1871 xkb_compose_state_get_status(xkbComposeState);
1872 if (status == XKB_COMPOSE_NOTHING) {
1873 return std::string();
1875 if (status == XKB_COMPOSE_COMPOSED) {
1877 std::array<char, 256> buffer;
1878 auto length = xkb_compose_state_get_utf8(xkbComposeState, buffer.data(),
1880 xkb_compose_state_reset(xkbComposeState);
1882 return std::nullopt;
1885 auto bufferBegin = buffer.begin();
1886 auto bufferEnd = std::next(bufferBegin,
length);
1888 return std::string(bufferBegin, bufferEnd);
1890 return std::nullopt;
1892 if (status == XKB_COMPOSE_CANCELLED) {
1893 xkb_compose_state_reset(xkbComposeState);
1895 return std::nullopt;
1898 FCITX_UNUSED(keysym);
1899 return std::string();
1904 #ifdef ENABLE_KEYBOARD 1906 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1908 auto *xkbComposeState = state->xkbComposeState();
1909 if (!xkbComposeState) {
1913 return xkb_compose_state_get_status(xkbComposeState) ==
1914 XKB_COMPOSE_COMPOSING;
1916 FCITX_UNUSED(inputContext);
1922 #ifdef ENABLE_KEYBOARD 1924 auto *state = inputContext->
propertyFor(&d->inputStateFactory_);
1925 auto *xkbComposeState = state->xkbComposeState();
1926 if (!xkbComposeState) {
1929 xkb_compose_state_reset(xkbComposeState);
1931 FCITX_UNUSED(inputContext);
1938 d->idleStartTimestamp_ = now(CLOCK_MONOTONIC);
1939 d->imManager_.save();
1940 d->addonManager_.saveAll();
1945 if (
auto *ic = mostRecentInputContext()) {
1946 CheckInputMethodChanged imChangedRAII(ic, d);
1953 if (
const auto *entry = inputMethodManager().entry(imName)) {
1954 return entry->uniqueName();
1964 void Instance::configureAddon(
const std::string & ) {}
1966 void Instance::configureInputMethod(
const std::string & ) {}
1969 if (
auto *ic = mostRecentInputContext()) {
1970 if (
const auto *entry = inputMethodEntry(ic)) {
1971 return entry->uniqueName();
1979 return d->uiManager_.currentUI();
1984 if (
auto *ic = mostRecentInputContext()) {
1985 CheckInputMethodChanged imChangedRAII(ic, d);
1995 d->exitCode_ = exitCode;
1997 d->eventLoop_.exit();
2002 auto *addon = addonManager().addon(addonName);
2004 addon->reloadConfig();
2010 auto [enabled, disabled] = d->overrideAddons();
2011 d->addonManager_.load(enabled, disabled);
2012 d->imManager_.refresh();
2017 readAsIni(d->globalConfig_.config(), StandardPathsType::PkgConfig,
2019 FCITX_DEBUG() <<
"Trigger Key: " 2021 d->icManager_.setPropertyPropagatePolicy(
2022 d->globalConfig_.shareInputState());
2023 if (d->globalConfig_.preeditEnabledByDefault() !=
2024 d->icManager_.isPreeditEnabledByDefault()) {
2025 d->icManager_.setPreeditEnabledByDefault(
2026 d->globalConfig_.preeditEnabledByDefault());
2032 #ifdef ENABLE_KEYBOARD 2033 d->keymapCache_.clear();
2034 if (d->inputStateFactory_.registered()) {
2036 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2037 inputState->resetXkbState();
2046 if (d->globalConfig_.autoSavePeriod() <= 0) {
2047 d->periodicalSave_->setEnabled(
false);
2049 d->periodicalSave_->setNextInterval(AutoSaveMinInUsecs *
2050 d->globalConfig_.autoSavePeriod());
2051 d->periodicalSave_->setOneShot();
2062 if (!canRestart()) {
2070 setCurrentInputMethod(mostRecentInputContext(), name,
false);
2076 if (!canTrigger()) {
2080 auto &imManager = inputMethodManager();
2081 const auto &imList = imManager.currentGroup().inputMethodList();
2082 auto iter = std::find_if(imList.begin(), imList.end(),
2084 return item.name() == name;
2086 if (iter == imList.end()) {
2090 auto setGlobalDefaultInputMethod = [d](
const std::string &name) {
2091 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2092 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2094 groupRAIICheck.push_back(
2095 std::make_unique<CheckInputMethodChanged>(ic, d));
2098 d->imManager_.setDefaultInputMethod(name);
2101 auto idx = std::distance(imList.begin(), iter);
2103 CheckInputMethodChanged imChangedRAII(ic, d);
2104 auto currentIM = inputMethod(ic);
2105 if (currentIM == name) {
2108 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2112 inputState->setLocalIM(name);
2114 inputState->setLocalIM({});
2116 setGlobalDefaultInputMethod(name);
2118 inputState->setActive(
true);
2120 inputState->setActive(
false);
2122 if (inputState->imChanged_) {
2132 setGlobalDefaultInputMethod(name);
2140 if (
auto *ic = mostRecentInputContext()) {
2141 auto *inputState = ic->propertyFor(&d->inputStateFactory_);
2142 return inputState->isActive() ? 2 : 1;
2149 if (
auto *ic = mostRecentInputContext()) {
2150 CheckInputMethodChanged imChangedRAII(ic, d);
2157 if (
auto *ic = mostRecentInputContext()) {
2158 CheckInputMethodChanged imChangedRAII(ic, d);
2159 enumerate(ic, forward);
2163 bool Instance::canTrigger()
const {
2164 const auto &imManager = inputMethodManager();
2165 return (imManager.currentGroup().inputMethodList().size() > 1);
2169 if (!canTrigger()) {
2173 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2174 if (inputState->isActive()) {
2177 return inputState->lastIMChangeIsAltTrigger_;
2182 if (!canTrigger()) {
2186 if (d->globalConfig_.enumerateSkipFirst()) {
2187 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2188 if (!inputState->isActive()) {
2191 return d->imManager_.currentGroup().inputMethodList().size() > 2;
2197 bool Instance::canChangeGroup()
const {
2198 const auto &imManager = inputMethodManager();
2199 return (imManager.groupCount() > 1);
2204 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2205 if (!canTrigger()) {
2208 inputState->setActive(!inputState->isActive());
2209 if (inputState->imChanged_) {
2210 inputState->imChanged_->setReason(reason);
2215 bool Instance::trigger(
InputContext *ic,
bool totallyReleased) {
2217 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2218 if (!canTrigger()) {
2223 if (totallyReleased) {
2225 inputState->firstTrigger_ =
true;
2227 if (!d->globalConfig_.enumerateWithTriggerKeys() ||
2228 (inputState->firstTrigger_ && inputState->isActive()) ||
2229 (d->globalConfig_.enumerateSkipFirst() &&
2230 d->imManager_.currentGroup().inputMethodList().size() <= 2)) {
2233 enumerate(ic,
true);
2235 inputState->firstTrigger_ =
false;
2241 if (!canAltTrigger(ic)) {
2251 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2252 if (!canTrigger()) {
2255 if (inputState->isActive()) {
2258 inputState->setActive(
true);
2259 if (inputState->imChanged_) {
2267 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2268 if (!canTrigger()) {
2271 if (!inputState->isActive()) {
2274 inputState->setActive(
false);
2275 if (inputState->imChanged_) {
2276 inputState->imChanged_->setReason(
2284 auto &imManager = inputMethodManager();
2285 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2286 const auto &imList = imManager.currentGroup().inputMethodList();
2287 if (!canTrigger()) {
2291 if (d->globalConfig_.enumerateSkipFirst() && imList.size() <= 2) {
2295 auto currentIM = inputMethod(ic);
2297 auto iter = std::ranges::find_if(
2299 return item.name() == currentIM;
2301 if (iter == imList.end()) {
2304 int idx = std::distance(imList.begin(), iter);
2305 auto nextIdx = [forward, &imList](
int idx) {
2307 return (idx + (forward ? 1 : (imList.size() - 1))) % imList.size();
2311 if (d->globalConfig_.enumerateSkipFirst() && idx == 0) {
2315 std::vector<std::unique_ptr<CheckInputMethodChanged>> groupRAIICheck;
2316 d->icManager_.foreachFocused([d, &groupRAIICheck](
InputContext *ic) {
2318 groupRAIICheck.push_back(
2319 std::make_unique<CheckInputMethodChanged>(ic, d));
2322 imManager.setDefaultInputMethod(imList[idx].name());
2323 inputState->setActive(
true);
2324 inputState->setLocalIM({});
2326 inputState->setActive(
false);
2328 if (inputState->imChanged_) {
2336 const std::string &orig) {
2337 std::string result = orig;
2338 emit<Instance::CommitFilter>(inputContext, result);
2344 emit<Instance::OutputFilter>(inputContext, result);
2345 if ((&orig == &inputContext->inputPanel().clientPreedit() ||
2346 &orig == &inputContext->inputPanel().preedit()) &&
2347 !globalConfig().showPreeditForPassword() &&
2348 inputContext->capabilityFlags().test(CapabilityFlag::Password)) {
2350 for (
int i = 0, e = result.size(); i < e; i++) {
2355 dot +=
"\xe2\x80\xa2";
2358 newText.append(std::move(dot),
2359 result.formatAt(i) | TextFormatFlag::DontCommit);
2361 result = std::move(newText);
2368 return d->icManager_.lastFocusedInputContext();
2373 return d->icManager_.mostRecentInputContext();
2378 d->uiManager_.flush();
2381 int scoreForGroup(
FocusGroup *group,
const std::string &displayHint) {
2383 if (displayHint.empty()) {
2384 if (group->display() ==
"x11:") {
2387 if (group->display().starts_with(
"x11:")) {
2390 if (group->display() ==
"wayland:") {
2393 if (group->display().starts_with(
"wayland:")) {
2397 if (group->display() == displayHint) {
2400 if (group->display().starts_with(displayHint)) {
2412 d->icManager_.foreachGroup(
2413 [&score, &displayHint, &defaultFocusGroup](
FocusGroup *group) {
2414 auto newScore = scoreForGroup(group, displayHint);
2415 if (newScore > score) {
2416 defaultFocusGroup = group;
2422 return defaultFocusGroup;
2427 FCITX_DEBUG() <<
"Instance::activateInputMethod";
2429 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2430 const auto *entry = inputMethodEntry(ic);
2432 FCITX_DEBUG() <<
"Activate: " 2433 <<
"[Last]:" << inputState->lastIM_
2434 <<
" [Activating]:" << entry->uniqueName();
2435 assert(inputState->lastIM_.empty());
2436 inputState->lastIM_ = entry->uniqueName();
2438 auto *engine = inputMethodEngine(ic);
2439 if (!engine || !entry) {
2442 #ifdef ENABLE_KEYBOARD 2443 if (
auto *xkbState = inputState->customXkbState(
true)) {
2444 if (
auto *mods = findValue(d->stateMask_, ic->
display())) {
2445 FCITX_KEYTRACE() <<
"Update mask to customXkbState";
2446 auto depressed = std::get<0>(*mods);
2447 auto latched = std::get<1>(*mods);
2448 auto locked = std::get<2>(*mods);
2453 FCITX_KEYTRACE() << depressed <<
" " << latched <<
" " << locked;
2454 if (depressed == 0) {
2455 inputState->setModsAllReleased();
2457 xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0,
2463 engine->activate(*entry, event);
2469 FCITX_DEBUG() <<
"Instance::deactivateInputMethod event_type=" 2470 <<
static_cast<uint32_t
>(
event.type());
2472 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2479 FCITX_DEBUG() <<
"Switch reason: " 2480 <<
static_cast<int>(icEvent.reason());
2481 FCITX_DEBUG() <<
"Old Input method: " << icEvent.oldInputMethod();
2482 entry = d->imManager_.entry(icEvent.oldInputMethod());
2484 entry = inputMethodEntry(ic);
2487 FCITX_DEBUG() <<
"Deactivate: " 2488 <<
"[Last]:" << inputState->lastIM_
2489 <<
" [Deactivating]:" << entry->uniqueName();
2490 assert(entry->uniqueName() == inputState->lastIM_);
2492 d->addonManager_.addon(entry->addon()));
2494 inputState->lastIM_.clear();
2495 if (!engine || !entry) {
2498 inputState->overrideDeactivateIM_ = entry->uniqueName();
2500 inputState->overrideDeactivateIM_.clear();
2504 bool Instance::enumerateGroup(
bool forward) {
2505 auto &imManager = inputMethodManager();
2506 auto groups = imManager.groups();
2507 if (groups.size() <= 1) {
2511 imManager.setCurrentGroup(groups[1]);
2513 imManager.setCurrentGroup(groups.back());
2519 FCITX_DEBUG() <<
"Input method switched";
2521 if (!d->globalConfig_.showInputMethodInformation()) {
2524 d->showInputMethodInformation(ic);
2528 const std::string &message) {
2529 FCITX_DEBUG() <<
"Input method switched";
2531 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2532 inputState->showInputMethodInformation(message);
2537 return (isInFlatpak() &&
2538 std::filesystem::is_regular_file(
"/app/.updated")) ||
2539 d->addonManager_.checkUpdate() || d->imManager_.checkUpdate() ||
2544 const std::string &rule,
2545 const std::string &model,
2546 const std::string &options) {
2547 #ifdef ENABLE_KEYBOARD 2549 bool resetState =
false;
2550 if (
auto *param = findValue(d->xkbParams_, display)) {
2551 if (std::get<0>(*param) != rule || std::get<1>(*param) != model ||
2552 std::get<2>(*param) != options) {
2553 std::get<0>(*param) = rule;
2554 std::get<1>(*param) = model;
2555 std::get<2>(*param) = options;
2559 d->xkbParams_.emplace(display, std::make_tuple(rule, model, options));
2563 d->keymapCache_[display].clear();
2564 d->icManager_.foreach([d, &display](
InputContext *ic) {
2565 if (ic->
display() == display ||
2566 !d->xkbParams_.contains(ic->
display())) {
2567 auto *inputState = ic->
propertyFor(&d->inputStateFactory_);
2568 inputState->resetXkbState();
2574 FCITX_UNUSED(display);
2576 FCITX_UNUSED(model);
2577 FCITX_UNUSED(options);
2582 uint32_t depressed_mods,
2583 uint32_t latched_mods, uint32_t locked_mods) {
2585 d->stateMask_[display] =
2586 std::make_tuple(depressed_mods, latched_mods, locked_mods);
2591 d->stateMask_.erase(display);
void updateXkbStateMask(const std::string &display, uint32_t depressed_mods, uint32_t latched_mods, uint32_t locked_mods)
Update xkb state mask for given display.
void restart()
Restart fcitx instance, this should only be used within a regular Fcitx server, not within embedded m...
void reloadAddonConfig(const std::string &addonName)
Reload certain addon config.
CapabilityFlags capabilityFlags() const
Returns the current capability flags.
FCITXCORE_DEPRECATED uint32_t processCompose(InputContext *ic, KeySym keysym)
Handle current XCompose state.
std::string inputMethodIcon(InputContext *ic)
Return the input method icon for input context.
void setXkbParameters(const std::string &display, const std::string &rule, const std::string &model, const std::string &options)
Set xkb RLVMO tuple for given display.
void activate()
Activate last focused input context. (Switch to the active input method)
EventType
Type of input method events.
Switched by alternative trigger key.
void resetCompose(InputContext *inputContext)
Reset the compose state.
T::PropertyType * propertyFor(const T *factory)
Helper function to return the input context property in specific type by given factory.
std::string UCS4ToUTF8(uint32_t code)
Convert UCS4 to UTF8 string.
FocusInEvent is generated when client gets focused.
Formatted string commonly used in user interface.
Whether client request input method to be disabled.
FocusGroup * defaultFocusGroup(const std::string &displayHint={})
Get the default focus group with given display hint.
static uint32_t keySymToUnicode(KeySym sym)
Convert keysym to a unicode.
Switched by activate key.
void flushUI()
All user interface update is batched internally.
This is generated when input method group changed.
std::string commitFilter(InputContext *inputContext, const std::string &orig)
Update the commit string to frontend.
AddonManager & addonManager()
Get the addon manager.
std::string currentInputMethod()
Return the current input method of last focused input context.
Simple file system related API for checking file status.
size_t length(Iter start, Iter end)
Return the number UTF-8 characters in the string iterator range.
bool validate(Iter start, Iter end)
Check if the string iterator range is valid utf8 string.
when user switch to a different input method by hand such as ctrl+shift by default, or by ui, default behavior is reset IM.
InputMethodSwitchedReason
The reason why input method is switched to another.
void deactivate()
Deactivate last focused input context.
int state()
Return a fcitx5-remote compatible value for the state.
InputMethodEngine * inputMethodEngine(InputContext *ic)
Return the input method engine object for given input context.
void setSignalPipe(int fd)
Set the pipe forwarding unix signal information.
InputMethodMode inputMethodMode() const
The current global input method mode.
void initialize()
Initialize fcitx.
EventLoop & eventLoop()
Get the fcitx event loop.
std::string currentUI()
Return the name of current user interface addon.
bool exitWhenMainDisplayDisconnected() const
Check whether command line specify whether to keep fcitx running.
C++ Utility functions for handling utf8 strings.
InputContext * mostRecentInputContext()
Return the most recent focused input context.
FCITX_NODISCARD std::unique_ptr< HandlerTableEntry< EventHandler > > watchEvent(EventType type, EventWatcherPhase phase, EventHandler callback)
Add a callback to for certain event type.
InputContextManager & inputContextManager()
Get the input context manager.
void setEnablePreedit(bool enable)
Override the preedit hint from client.
std::vector< std::string > split(std::string_view str, std::string_view delim, SplitBehavior behavior)
Split the string by delim.
virtual bool filtered() const
Whether a event is filtered by handler.
void clearGroup(StatusGroup group)
Clear only given status group.
bool hasFocus() const
Returns whether the input context holds the input focus.
bool isRunning() const
Whether event loop is started and still running.
A class represents a formatted string.
bool willTryReplace() const
Check whether command line specify if it will replace an existing fcitx server.
Switched by group change.
bool isRestartRequested() const
Whether restart is requested.
Manager class for user interface.
Instance(int argc, char *argv[])
A main function like construct to be used to create Fcitx Instance.
Base class for fcitx event.
bool isValidChar(uint32_t c)
Check the chr value is not two invalid value above.
std::string inputMethodLabel(InputContext *ic)
Return the input method label for input context.
void save()
Save everything including input method profile and addon data.
Enum type for input context capability.
Class for status area in UI.
void resetInputMethodList()
Reset the input method configuration and recreate based on system language.
Switched by capability change (e.g. password field)
Base class for User Interface addon.
A thread safe class to post event to a certain EventLoop.
void clearXkbStateMask(const std::string &display)
Clear xkb state mask for given display.
Enum flag for text formatting.
void configure()
Launch configtool.
bool checkUpdate() const
Check if need to invoke Instance::refresh.
New Utility classes to handle application specific path.
uint32_t getChar(Iter iter, Iter end)
Get next UCS4 char from iter, do not cross end.
InvokeAction event is generated when client click on the preedit.
InputMethodManager & inputMethodManager()
Get the input method manager.
void reloadConfig()
Reload global config.
int exec()
Start the event loop of Fcitx.
C-style utf8 utility functions.
void setBinaryMode()
Set if this instance is running as fcitx5 binary.
bool isModifier() const
Check if the key is a modifier press.
InputContext * lastFocusedInputContext()
Return a focused input context.
std::string display() const
Returns the display server of the client.
void toggle()
Toggle between the first input method and active input method.
void setCurrentInputMethod(const std::string &imName)
Set the input method of last focused input context.
void setRunning(bool running)
Let other know that event loop is already running.
bool canRestart() const
Check if fcitx 5 can safely restart by itself.
void showCustomInputMethodInformation(InputContext *ic, const std::string &message)
Show a small popup with input popup window with current input method information. ...
std::optional< std::string > processComposeString(InputContext *ic, KeySym keysym)
Handle current XCompose state.
void refresh()
Load newly installed input methods and addons.
Input method mode changed.
std::string inputMethod(InputContext *ic)
Return the unique name of input method for given input context.
UserInterfaceManager & userInterfaceManager()
Get the user interface manager.
void enumerate(bool forward)
Enumerate input method with in current group.
bool exiting() const
Check whether fcitx is in exiting process.
void showInputMethodInformation(InputContext *ic)
Show a small popup with input popup window with current input method information. ...
StatusArea & statusArea()
Returns the associated StatusArea.
EventType type() const
Type of event, can be used to decide event class.
bool empty() const
Whether input panel is totally empty.
void setInputMethodMode(InputMethodMode mode)
Set the current global input method mode.
FCITXCORE_DEPRECATED void reset(ResetReason reason)
Called when input context state need to be reset.
ssize_t safeRead(int fd, void *data, size_t maxlen)
a simple wrapper around read(), ignore EINTR.
std::string addonForInputMethod(const std::string &imName)
Return the addon name of given input method.
Input Context Property for Fcitx.
static std::filesystem::path fcitxPath(const char *path, const std::filesystem::path &subPath={})
Return fcitx specific path defined at compile time.
An input context represents a client of Fcitx.
GlobalConfig & globalConfig()
Get the global config.
void exit()
Exit the fcitx event loop.
EventDispatcher & eventDispatcher()
Return a shared event dispatcher that is already attached to instance's event loop.
Key event is generated when client press or release a key.
const InputMethodEntry * inputMethodEntry(InputContext *ic)
Return the input method entry for given input context.
Class to represent a key.
bool isComposing(InputContext *inputContext)
Check whether input context is composing or not.
Switched by deactivate key.
static std::string keyListToString(const Container &container, KeyStringFormat format=KeyStringFormat::Portable)
Convert a key list to string.
Notify the global config is reloaded.
when using lost focus this might be variance case to case.
Switched by enumerate key.
static const char * version()
Return the version string of Fcitx.
Text outputFilter(InputContext *inputContext, const Text &orig)
Update the string that will be displayed in user interface.