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,
180  Option<bool> activeByDefault{this, "ActiveByDefault",
181  _("Activate input method by default")};
182  OptionWithAnnotation<PropertyPropagatePolicy,
183  PropertyPropagatePolicyI18NAnnotation>
184  resetStateWhenFocusIn{this, "resetStateWhenFocusIn",
185  _("Reset state on Focus In"),
186  PropertyPropagatePolicy::No};
187  OptionWithAnnotation<PropertyPropagatePolicy,
188  PropertyPropagatePolicyI18NAnnotation>
189  shareState{this, "ShareInputState", _("Share Input State"),
190  isAndroid() ? PropertyPropagatePolicy::All
191  : PropertyPropagatePolicy::No};
192  Option<bool> preeditEnabledByDefault{this, "PreeditEnabledByDefault",
193  _("Show preedit in application"),
194  true};
195  Option<bool> showInputMethodInformation{
196  this, "ShowInputMethodInformation",
197  _("Show Input Method Information when switch input method"), true};
198  Option<bool> showInputMethodInformationWhenFocusIn{
199  this, "showInputMethodInformationWhenFocusIn",
200  _("Show Input Method Information when changing focus"), false};
201  Option<bool> compactInputMethodInformation{
202  this, "CompactInputMethodInformation",
203  _("Show compact input method information"), true};
204  Option<bool> showFirstInputMethodInformation{
205  this, "ShowFirstInputMethodInformation",
206  _("Show first input method information"), true};
207  Option<int, IntConstrain> defaultPageSize{this, "DefaultPageSize",
208  _("Default Candidates per page"),
209  5, IntConstrain(1, 10)};
210  ConditionalHidden<!hasKeyboard,
211  OptionWithAnnotation<bool, ToolTipAnnotation>>
212  overrideXkbOption{
213  this,
214  "OverrideXkbOption",
215  _("Override XKB Option"),
216  false,
217  {},
218  {},
219  {_("Override the XKB option from display server. It "
220  "will not affect the XKB option send to display, but just the "
221  "XKB options for custom XKB layout. This is a workaround when "
222  "there is no way to get the current XKB option from Wayland "
223  "Compositor.")}};
224  ConditionalHidden<!hasKeyboard, Option<std::string>> customXkbOption{
225  this, "CustomXkbOption", _("Custom XKB Option"), ""};
226  HiddenOption<std::vector<std::string>> enabledAddons{
227  this, "EnabledAddons", "Force Enabled Addons"};
228  HiddenOption<std::vector<std::string>> disabledAddons{
229  this, "DisabledAddons", "Force Disabled Addons"};
230  HiddenOption<bool> preloadInputMethod{
231  this, "PreloadInputMethod",
232  "Preload input method to be used by default", true};
233  Option<bool> allowInputMethodForPassword{
234  this, "AllowInputMethodForPassword",
235  _("Allow input method in the password field"), false};
236  Option<bool> showPreeditForPassword{
237  this, "ShowPreeditForPassword",
238  _("Show preedit text when typing password"), false};
239  Option<int, IntConstrain, DefaultMarshaller<int>, ToolTipAnnotation>
240  autoSavePeriod{this,
241  "AutoSavePeriod",
242  _("Interval of saving user data in minutes"),
243  30,
244  IntConstrain(0, 1440),
245  {},
246  {_("If value is 0, the user data may only be saved when "
247  "fcitx quits (e.g. logout).")}};);
248 
249 FCITX_CONFIGURATION(GlobalConfig,
250  Option<HotkeyConfig> hotkey{this, "Hotkey", _("Hotkey")};
251  Option<BehaviorConfig> behavior{this, "Behavior",
252  _("Behavior")};);
253 } // namespace impl
254 
255 class GlobalConfigPrivate : public impl::GlobalConfig {};
256 
257 GlobalConfig::GlobalConfig() : d_ptr(std::make_unique<GlobalConfigPrivate>()) {}
258 
259 GlobalConfig::~GlobalConfig() {}
260 
261 void GlobalConfig::load(const RawConfig &rawConfig, bool partial) {
262  FCITX_D();
263  d->load(rawConfig, partial);
264 }
265 
266 void GlobalConfig::save(RawConfig &config) const {
267  FCITX_D();
268  d->save(config);
269 }
270 
271 bool GlobalConfig::safeSave(const std::string &path) const {
272  FCITX_D();
273  return safeSaveAsIni(*d, path);
274 }
275 
276 const KeyList &GlobalConfig::triggerKeys() const {
277  FCITX_D();
278  return *d->hotkey->triggerKeys;
279 }
280 
281 bool GlobalConfig::enumerateWithTriggerKeys() const {
282  FCITX_D();
283  return *d->hotkey->enumerateWithTriggerKeys;
284 }
285 
286 const KeyList &GlobalConfig::altTriggerKeys() const {
287  FCITX_D();
288  return *d->hotkey->altTriggerKeys;
289 }
290 
291 const KeyList &GlobalConfig::activateKeys() const {
292  FCITX_D();
293  return *d->hotkey->activateKeys;
294 }
295 
296 const KeyList &GlobalConfig::deactivateKeys() const {
297  FCITX_D();
298  return d->hotkey->deactivateKeys.value();
299 }
300 
301 const KeyList &GlobalConfig::enumerateForwardKeys() const {
302  FCITX_D();
303  return d->hotkey->enumerateForwardKeys.value();
304 }
305 
306 const KeyList &GlobalConfig::enumerateBackwardKeys() const {
307  FCITX_D();
308  return d->hotkey->enumerateBackwardKeys.value();
309 }
310 
311 bool GlobalConfig::enumerateSkipFirst() const {
312  FCITX_D();
313  return *d->hotkey->enumerateSkipFirst;
314 }
315 
316 const KeyList &GlobalConfig::enumerateGroupForwardKeys() const {
317  FCITX_D();
318  return *d->hotkey->enumerateGroupForwardKeys;
319 }
320 
321 const KeyList &GlobalConfig::enumerateGroupBackwardKeys() const {
322  FCITX_D();
323  return *d->hotkey->enumerateGroupBackwardKeys;
324 }
325 
326 const KeyList &GlobalConfig::togglePreeditKeys() const {
327  FCITX_D();
328  return *d->hotkey->togglePreedit;
329 }
330 
331 bool GlobalConfig::activeByDefault() const {
332  FCITX_D();
333  return d->behavior->activeByDefault.value();
334 }
335 
336 PropertyPropagatePolicy GlobalConfig::resetStateWhenFocusIn() const {
337  FCITX_D();
338  return d->behavior->resetStateWhenFocusIn.value();
339 }
340 
341 bool GlobalConfig::showInputMethodInformation() const {
342  FCITX_D();
343  return d->behavior->showInputMethodInformation.value();
344 }
345 
346 bool GlobalConfig::showInputMethodInformationWhenFocusIn() const {
347  FCITX_D();
348  return d->behavior->showInputMethodInformationWhenFocusIn.value();
349 }
350 
351 bool GlobalConfig::compactInputMethodInformation() const {
352  FCITX_D();
353  return d->behavior->compactInputMethodInformation.value();
354 }
355 
356 bool GlobalConfig::showFirstInputMethodInformation() const {
357  FCITX_D();
358  return d->behavior->showFirstInputMethodInformation.value();
359 }
360 
361 PropertyPropagatePolicy GlobalConfig::shareInputState() const {
362  FCITX_D();
363  return d->behavior->shareState.value();
364 }
365 
366 bool GlobalConfig::preeditEnabledByDefault() const {
367  FCITX_D();
368  return d->behavior->preeditEnabledByDefault.value();
369 }
370 
371 const KeyList &GlobalConfig::defaultPrevPage() const {
372  FCITX_D();
373  return d->hotkey->defaultPrevPage.value();
374 }
375 
376 const KeyList &GlobalConfig::defaultNextPage() const {
377  FCITX_D();
378  return d->hotkey->defaultNextPage.value();
379 }
380 
381 const KeyList &GlobalConfig::defaultPrevCandidate() const {
382  FCITX_D();
383  return d->hotkey->defaultPrevCandidate.value();
384 }
385 
386 const KeyList &GlobalConfig::defaultNextCandidate() const {
387  FCITX_D();
388  return d->hotkey->defaultNextCandidate.value();
389 }
390 
391 int GlobalConfig::defaultPageSize() const {
392  FCITX_D();
393  return d->behavior->defaultPageSize.value();
394 }
395 
397  FCITX_D();
398  return d->behavior->overrideXkbOption.value();
399 }
400 
401 const std::string &GlobalConfig::customXkbOption() const {
402  FCITX_D();
403  return d->behavior->customXkbOption.value();
404 }
405 
406 const std::vector<std::string> &GlobalConfig::enabledAddons() const {
407  FCITX_D();
408  return *d->behavior->enabledAddons;
409 }
410 
411 const std::vector<std::string> &GlobalConfig::disabledAddons() const {
412  FCITX_D();
413  return *d->behavior->disabledAddons;
414 }
415 
416 void GlobalConfig::setEnabledAddons(const std::vector<std::string> &addons) {
417  FCITX_D();
418  d->behavior.mutableValue()->enabledAddons.setValue(addons);
419 }
420 
421 void GlobalConfig::setDisabledAddons(const std::vector<std::string> &addons) {
422  FCITX_D();
423  d->behavior.mutableValue()->disabledAddons.setValue(addons);
424 }
425 
426 bool GlobalConfig::preloadInputMethod() const {
427  FCITX_D();
428  return *d->behavior->preloadInputMethod;
429 }
430 
432  FCITX_D();
433  return *d->behavior->allowInputMethodForPassword;
434 }
435 
437  FCITX_D();
438  return *d->behavior->showPreeditForPassword;
439 }
440 
442  FCITX_D();
443  return *d->behavior->autoSavePeriod;
444 }
445 
447  FCITX_D();
448  return *d->hotkey->modifierOnlyKeyTimeout;
449 }
450 
451 bool GlobalConfig::checkModifierOnlyKeyTimeout(uint64_t lastPressedTime) const {
452  const auto timeout = modifierOnlyKeyTimeout();
453  if (timeout < 0) {
454  return true;
455  }
456  return now(CLOCK_MONOTONIC) <=
457  (lastPressedTime + static_cast<uint64_t>(timeout) * 1000ULL);
458 }
459 
460 const Configuration &GlobalConfig::config() const {
461  FCITX_D();
462  return *d;
463 }
464 
465 Configuration &GlobalConfig::config() {
466  FCITX_D();
467  return *d;
468 }
469 
470 } // 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.