Fcitx
globalconfig.cpp
1 /*
2  * SPDX-FileCopyrightText: 2016-2016 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 
8 #include "globalconfig.h"
9 #include <cstdint>
10 #include <memory>
11 #include <string>
12 #include <vector>
13 #include "fcitx-config/configuration.h"
14 #include "fcitx-config/enum.h"
15 #include "fcitx-config/iniparser.h"
16 #include "fcitx-config/option.h"
17 #include "fcitx-config/rawconfig.h"
18 #include "fcitx-utils/eventloopinterface.h"
19 #include "fcitx-utils/i18n.h"
20 #include "fcitx-utils/key.h"
21 #include "fcitx-utils/macros.h"
22 #include "fcitx-utils/misc.h"
23 #include "config.h"
24 #include "inputcontextmanager.h"
25 
26 namespace fcitx {
27 
28 namespace impl {
29 
30 #ifdef ENABLE_KEYBOARD
31 constexpr bool hasKeyboard = true;
32 #else
33 constexpr bool hasKeyboard = false;
34 #endif
35 
36 FCITX_CONFIG_ENUM_I18N_ANNOTATION(PropertyPropagatePolicy, N_("All"),
37  N_("Program"), N_("No"));
38 
39 FCITX_CONFIGURATION(
40  HotkeyConfig,
41  KeyListOption triggerKeys{
42  this,
43  "TriggerKeys",
44  _("Toggle Input Method"),
45  {isApple() ? Key("Control+Shift_L") : Key("Control+space"),
46  Key("Zenkaku_Hankaku"), Key("Hangul")},
47  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
48  KeyConstrainFlag::AllowModifierOnly})};
49  OptionWithAnnotation<bool, ToolTipAnnotation> enumerateWithTriggerKeys{{
50  .parent = this,
51  .path{"EnumerateWithTriggerKeys"},
52  .description{_("Enumerate when holding modifier of Toggle key")},
53  .defaultValue = true,
54  .annotation{
55  _("For example, if Control+Space is the toggle key, after pressing "
56  "Control+Space for the first time, if Control is held, following "
57  "key press of Space will enumerate the input method.")},
58  }};
59  KeyListOption activateKeys{
60  this,
61  "ActivateKeys",
62  _("Activate Input Method"),
63  {
64  Key("Hangul_Hanja"),
65  },
66  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
67  KeyConstrainFlag::AllowModifierOnly})};
68  KeyListOption deactivateKeys{
69  this,
70  "DeactivateKeys",
71  _("Deactivate Input Method"),
72  {Key("Hangul_Romaja")},
73  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
74  KeyConstrainFlag::AllowModifierOnly})};
75  KeyListOptionWithAnnotation<ToolTipAnnotation> altTriggerKeys{
76  {.parent = this,
77  .path{"AltTriggerKeys"},
78  .description{_("Temporarily Toggle Input Method")},
79  .defaultValue{{Key("Shift_L")}},
80  .constrain{KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
81  KeyConstrainFlag::AllowModifierOnly})},
82  .annotation{_(
83  "This key can only be used if current state is active, or is "
84  "deactivated with this key. For example, you have two input "
85  "methods: English as the inactive state, Pinyin as the active "
86  "state. It can be used to switch from Pinyin back to English, and "
87  "switch back to Pinyin again afterwards. If the initial state is "
88  "English will do nothing. This key can be configured to be some "
89  "simple single modifier key like Shift, so it can be used with "
90  "just a single key press, but won't be triggered by accident if "
91  "you never activate input method.")}}};
92  KeyListOption enumerateForwardKeys{
93  this,
94  "EnumerateForwardKeys",
95  _("Enumerate Input Method Forward"),
96  {},
97  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
98  KeyConstrainFlag::AllowModifierOnly})};
99  KeyListOption enumerateBackwardKeys{
100  this,
101  "EnumerateBackwardKeys",
102  _("Enumerate Input Method Backward"),
103  {},
104  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
105  KeyConstrainFlag::AllowModifierOnly})};
106  Option<bool> enumerateSkipFirst{
107  this, "EnumerateSkipFirst",
108  _("Skip first input method while enumerating"), false};
109  KeyListOption enumerateGroupForwardKeys{
110  this,
111  "EnumerateGroupForwardKeys",
112  _("Enumerate Input Method Group Forward"),
113  {Key("Super+space")},
114  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
115  KeyConstrainFlag::AllowModifierOnly})};
116  KeyListOption enumerateGroupBackwardKeys{
117  this,
118  "EnumerateGroupBackwardKeys",
119  _("Enumerate Input Method Group Backward"),
120  {Key("Super+Shift+space")},
121  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
122  KeyConstrainFlag::AllowModifierOnly})};
123  Option<KeyList, ListConstrain<KeyConstrain>, DefaultMarshaller<KeyList>,
124  ToolTipAnnotation>
125  defaultPrevPage{{
126  .parent = this,
127  .path{"PrevPage"},
128  .description{_("Fallback Previous page")},
129  .defaultValue{{Key("Up")}},
130  .constrain{{KeyConstrainFlag::AllowModifierLess}},
131  .annotation{_("Input methods may have different setup in their "
132  "own configuration. This is commonly used by "
133  "modules like clipboard or quickphrase.")},
134  }};
135 
136  Option<KeyList, ListConstrain<KeyConstrain>, DefaultMarshaller<KeyList>,
137  ToolTipAnnotation>
138  defaultNextPage{this,
139  "NextPage",
140  _("Fallback Next page"),
141  {Key("Down")},
142  KeyListConstrain({KeyConstrainFlag::AllowModifierLess}),
143  {},
144  {_("Input methods may have different setup in their "
145  "own configuration. This is commonly used by "
146  "modules like clipboard or quickphrase.")}};
147  KeyListOption defaultPrevCandidate{
148  this,
149  "PrevCandidate",
150  _("Fallback Previous Candidate"),
151  {Key("Shift+Tab")},
152  KeyListConstrain({KeyConstrainFlag::AllowModifierLess})};
153  KeyListOption defaultNextCandidate{
154  this,
155  "NextCandidate",
156  _("Fallback Next Candidate"),
157  {Key("Tab")},
158  KeyListConstrain({KeyConstrainFlag::AllowModifierLess})};
159  KeyListOption togglePreedit{this,
160  "TogglePreedit",
161  _("Toggle embedded preedit"),
162  {Key("Control+Alt+P")},
163  KeyListConstrain()};
164  Option<int, IntConstrain, DefaultMarshaller<int>, ToolTipAnnotation>
165  modifierOnlyKeyTimeout{
166  this,
167  "ModifierOnlyKeyTimeout",
168  _("Time limit in milliseconds for triggering modifier key "
169  "shortcuts"),
170  250,
171  IntConstrain{-1, 5000},
172  {},
173  ToolTipAnnotation{
174  _("When using modifier only hotkey, the action may "
175  "only be triggered if the modifier key is released within "
176  "the timeout. -1 means there is no limit.")}};);
177 
178 FCITX_CONFIGURATION(
179  BehaviorConfig, Option<bool> activeByDefault{this, "ActiveByDefault",
180  _("Active By Default")};
181  OptionWithAnnotation<PropertyPropagatePolicy,
182  PropertyPropagatePolicyI18NAnnotation>
183  resetStateWhenFocusIn{this, "resetStateWhenFocusIn",
184  _("Reset state on Focus In"),
185  PropertyPropagatePolicy::No};
186  OptionWithAnnotation<PropertyPropagatePolicy,
187  PropertyPropagatePolicyI18NAnnotation>
188  shareState{this, "ShareInputState", _("Share Input State"),
189  isAndroid() ? PropertyPropagatePolicy::All
190  : PropertyPropagatePolicy::No};
191  Option<bool> preeditEnabledByDefault{this, "PreeditEnabledByDefault",
192  _("Show preedit in application"),
193  true};
194  Option<bool> showInputMethodInformation{
195  this, "ShowInputMethodInformation",
196  _("Show Input Method Information when switch input method"), true};
197  Option<bool> showInputMethodInformationWhenFocusIn{
198  this, "showInputMethodInformationWhenFocusIn",
199  _("Show Input Method Information when changing focus"), false};
200  Option<bool> compactInputMethodInformation{
201  this, "CompactInputMethodInformation",
202  _("Show compact input method information"), true};
203  Option<bool> showFirstInputMethodInformation{
204  this, "ShowFirstInputMethodInformation",
205  _("Show first input method information"), true};
206  Option<int, IntConstrain> defaultPageSize{this, "DefaultPageSize",
207  _("Default page size"), 5,
208  IntConstrain(1, 10)};
209  ConditionalHidden<!hasKeyboard,
210  OptionWithAnnotation<bool, ToolTipAnnotation>>
211  overrideXkbOption{
212  this,
213  "OverrideXkbOption",
214  _("Override XKB Option"),
215  false,
216  {},
217  {},
218  {_("Whether to override the XKB option from display server. It "
219  "will not affect the XKB option send to display, but just the "
220  "XKB options for custom XKB layout. This is a workaround when "
221  "there is no way to get the current XKB option from Wayland "
222  "Compositor.")}};
223  ConditionalHidden<!hasKeyboard, Option<std::string>> customXkbOption{
224  this, "CustomXkbOption", _("Custom XKB Option"), ""};
225  HiddenOption<std::vector<std::string>> enabledAddons{
226  this, "EnabledAddons", "Force Enabled Addons"};
227  HiddenOption<std::vector<std::string>> disabledAddons{
228  this, "DisabledAddons", "Force Disabled Addons"};
229  HiddenOption<bool> preloadInputMethod{
230  this, "PreloadInputMethod",
231  "Preload input method to be used by default", true};
232  Option<bool> allowInputMethodForPassword{
233  this, "AllowInputMethodForPassword",
234  _("Allow input method in the password field"), false};
235  Option<bool> showPreeditForPassword{
236  this, "ShowPreeditForPassword",
237  _("Show preedit text when typing password"), false};
238  Option<int, IntConstrain, DefaultMarshaller<int>, ToolTipAnnotation>
239  autoSavePeriod{this,
240  "AutoSavePeriod",
241  _("Interval of saving user data in minutes"),
242  30,
243  IntConstrain(0, 1440),
244  {},
245  {_("If value is 0, the user data may only be saved when "
246  "fcitx quits (e.g. logout).")}};);
247 
248 FCITX_CONFIGURATION(GlobalConfig,
249  Option<HotkeyConfig> hotkey{this, "Hotkey", _("Hotkey")};
250  Option<BehaviorConfig> behavior{this, "Behavior",
251  _("Behavior")};);
252 } // namespace impl
253 
254 class GlobalConfigPrivate : public impl::GlobalConfig {};
255 
256 GlobalConfig::GlobalConfig() : d_ptr(std::make_unique<GlobalConfigPrivate>()) {}
257 
258 GlobalConfig::~GlobalConfig() {}
259 
260 void GlobalConfig::load(const RawConfig &rawConfig, bool partial) {
261  FCITX_D();
262  d->load(rawConfig, partial);
263 }
264 
265 void GlobalConfig::save(RawConfig &config) const {
266  FCITX_D();
267  d->save(config);
268 }
269 
270 bool GlobalConfig::safeSave(const std::string &path) const {
271  FCITX_D();
272  return safeSaveAsIni(*d, path);
273 }
274 
275 const KeyList &GlobalConfig::triggerKeys() const {
276  FCITX_D();
277  return *d->hotkey->triggerKeys;
278 }
279 
280 bool GlobalConfig::enumerateWithTriggerKeys() const {
281  FCITX_D();
282  return *d->hotkey->enumerateWithTriggerKeys;
283 }
284 
285 const KeyList &GlobalConfig::altTriggerKeys() const {
286  FCITX_D();
287  return *d->hotkey->altTriggerKeys;
288 }
289 
290 const KeyList &GlobalConfig::activateKeys() const {
291  FCITX_D();
292  return *d->hotkey->activateKeys;
293 }
294 
295 const KeyList &GlobalConfig::deactivateKeys() const {
296  FCITX_D();
297  return d->hotkey->deactivateKeys.value();
298 }
299 
300 const KeyList &GlobalConfig::enumerateForwardKeys() const {
301  FCITX_D();
302  return d->hotkey->enumerateForwardKeys.value();
303 }
304 
305 const KeyList &GlobalConfig::enumerateBackwardKeys() const {
306  FCITX_D();
307  return d->hotkey->enumerateBackwardKeys.value();
308 }
309 
310 bool GlobalConfig::enumerateSkipFirst() const {
311  FCITX_D();
312  return *d->hotkey->enumerateSkipFirst;
313 }
314 
315 const KeyList &GlobalConfig::enumerateGroupForwardKeys() const {
316  FCITX_D();
317  return *d->hotkey->enumerateGroupForwardKeys;
318 }
319 
320 const KeyList &GlobalConfig::enumerateGroupBackwardKeys() const {
321  FCITX_D();
322  return *d->hotkey->enumerateGroupBackwardKeys;
323 }
324 
325 const KeyList &GlobalConfig::togglePreeditKeys() const {
326  FCITX_D();
327  return *d->hotkey->togglePreedit;
328 }
329 
330 bool GlobalConfig::activeByDefault() const {
331  FCITX_D();
332  return d->behavior->activeByDefault.value();
333 }
334 
335 PropertyPropagatePolicy GlobalConfig::resetStateWhenFocusIn() const {
336  FCITX_D();
337  return d->behavior->resetStateWhenFocusIn.value();
338 }
339 
340 bool GlobalConfig::showInputMethodInformation() const {
341  FCITX_D();
342  return d->behavior->showInputMethodInformation.value();
343 }
344 
345 bool GlobalConfig::showInputMethodInformationWhenFocusIn() const {
346  FCITX_D();
347  return d->behavior->showInputMethodInformationWhenFocusIn.value();
348 }
349 
350 bool GlobalConfig::compactInputMethodInformation() const {
351  FCITX_D();
352  return d->behavior->compactInputMethodInformation.value();
353 }
354 
355 bool GlobalConfig::showFirstInputMethodInformation() const {
356  FCITX_D();
357  return d->behavior->showFirstInputMethodInformation.value();
358 }
359 
360 PropertyPropagatePolicy GlobalConfig::shareInputState() const {
361  FCITX_D();
362  return d->behavior->shareState.value();
363 }
364 
365 bool GlobalConfig::preeditEnabledByDefault() const {
366  FCITX_D();
367  return d->behavior->preeditEnabledByDefault.value();
368 }
369 
370 const KeyList &GlobalConfig::defaultPrevPage() const {
371  FCITX_D();
372  return d->hotkey->defaultPrevPage.value();
373 }
374 
375 const KeyList &GlobalConfig::defaultNextPage() const {
376  FCITX_D();
377  return d->hotkey->defaultNextPage.value();
378 }
379 
380 const KeyList &GlobalConfig::defaultPrevCandidate() const {
381  FCITX_D();
382  return d->hotkey->defaultPrevCandidate.value();
383 }
384 
385 const KeyList &GlobalConfig::defaultNextCandidate() const {
386  FCITX_D();
387  return d->hotkey->defaultNextCandidate.value();
388 }
389 
390 int GlobalConfig::defaultPageSize() const {
391  FCITX_D();
392  return d->behavior->defaultPageSize.value();
393 }
394 
396  FCITX_D();
397  return d->behavior->overrideXkbOption.value();
398 }
399 
400 const std::string &GlobalConfig::customXkbOption() const {
401  FCITX_D();
402  return d->behavior->customXkbOption.value();
403 }
404 
405 const std::vector<std::string> &GlobalConfig::enabledAddons() const {
406  FCITX_D();
407  return *d->behavior->enabledAddons;
408 }
409 
410 const std::vector<std::string> &GlobalConfig::disabledAddons() const {
411  FCITX_D();
412  return *d->behavior->disabledAddons;
413 }
414 
415 void GlobalConfig::setEnabledAddons(const std::vector<std::string> &addons) {
416  FCITX_D();
417  d->behavior.mutableValue()->enabledAddons.setValue(addons);
418 }
419 
420 void GlobalConfig::setDisabledAddons(const std::vector<std::string> &addons) {
421  FCITX_D();
422  d->behavior.mutableValue()->disabledAddons.setValue(addons);
423 }
424 
425 bool GlobalConfig::preloadInputMethod() const {
426  FCITX_D();
427  return *d->behavior->preloadInputMethod;
428 }
429 
431  FCITX_D();
432  return *d->behavior->allowInputMethodForPassword;
433 }
434 
436  FCITX_D();
437  return *d->behavior->showPreeditForPassword;
438 }
439 
441  FCITX_D();
442  return *d->behavior->autoSavePeriod;
443 }
444 
446  FCITX_D();
447  return *d->hotkey->modifierOnlyKeyTimeout;
448 }
449 
450 bool GlobalConfig::checkModifierOnlyKeyTimeout(uint64_t lastPressedTime) const {
451  const auto timeout = modifierOnlyKeyTimeout();
452  if (timeout < 0) {
453  return true;
454  }
455  return now(CLOCK_MONOTONIC) <=
456  (lastPressedTime + static_cast<uint64_t>(timeout) * 1000ULL);
457 }
458 
459 const Configuration &GlobalConfig::config() const {
460  FCITX_D();
461  return *d;
462 }
463 
464 Configuration &GlobalConfig::config() {
465  FCITX_D();
466  return *d;
467 }
468 
469 } // namespace fcitx
int autoSavePeriod() const
Number of minutes that fcitx will automatically save user data.
const std::string & customXkbOption() const
The enforce the xkb option for custom xkb state.
int modifierOnlyKeyTimeout() const
Number of milliseconds that modifier only key can be triggered with key release.
Definition: action.cpp:17
bool showPreeditForPassword() const
Show preedit when typing in password field.
PropertyPropagatePolicy resetStateWhenFocusIn() const
Reset active state to the value of activeByDefault on Focus In.
bool overrideXkbOption() const
Override the xkb option from display.
bool allowInputMethodForPassword() const
Allow use input method in password field.
bool checkModifierOnlyKeyTimeout(uint64_t lastPressedTime) const
Helper function to check whether the modifier only key should be triggered.
Class to represent a key.