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  OptionWithAnnotation<bool, ToolTipAnnotation> consumeRedundantActivateKeys{{
76  .parent = this,
77  .path{"ConsumeRedundantActivateKeys"},
78  .description{_("Consume redundant Activate/Deactivate key")},
79  .defaultValue = false,
80  .annotation{
81  _("When the input method is already in the state the key "
82  "requests, pressing an Activate/Deactivate key changes "
83  "nothing; consume the key event in that case instead of "
84  "forwarding it to the application. Modifier only keys are "
85  "never consumed.")},
86  }};
87  KeyListOptionWithAnnotation<ToolTipAnnotation> altTriggerKeys{
88  {.parent = this,
89  .path{"AltTriggerKeys"},
90  .description{_("Temporarily Toggle Input Method")},
91  .defaultValue{{Key("Shift_L")}},
92  .constrain{KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
93  KeyConstrainFlag::AllowModifierOnly})},
94  .annotation{_(
95  "This key can only be used if current state is active, or is "
96  "deactivated with this key. For example, you have two input "
97  "methods: English as the inactive state, Pinyin as the active "
98  "state. It can be used to switch from Pinyin back to English, and "
99  "switch back to Pinyin again afterwards. If the initial state is "
100  "English will do nothing. This key can be configured to be some "
101  "simple single modifier key like Shift, so it can be used with "
102  "just a single key press, but won't be triggered by accident if "
103  "you never activate input method.")}}};
104  KeyListOption enumerateForwardKeys{
105  this,
106  "EnumerateForwardKeys",
107  _("Enumerate Input Method Forward"),
108  {},
109  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
110  KeyConstrainFlag::AllowModifierOnly})};
111  KeyListOption enumerateBackwardKeys{
112  this,
113  "EnumerateBackwardKeys",
114  _("Enumerate Input Method Backward"),
115  {},
116  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
117  KeyConstrainFlag::AllowModifierOnly})};
118  Option<bool> enumerateSkipFirst{
119  this, "EnumerateSkipFirst",
120  _("Skip first input method while enumerating"), false};
121  KeyListOption enumerateGroupForwardKeys{
122  this,
123  "EnumerateGroupForwardKeys",
124  _("Enumerate Input Method Group Forward"),
125  {Key("Super+space")},
126  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
127  KeyConstrainFlag::AllowModifierOnly})};
128  KeyListOption enumerateGroupBackwardKeys{
129  this,
130  "EnumerateGroupBackwardKeys",
131  _("Enumerate Input Method Group Backward"),
132  {Key("Super+Shift+space")},
133  KeyListConstrain({KeyConstrainFlag::AllowModifierLess,
134  KeyConstrainFlag::AllowModifierOnly})};
135  Option<KeyList, ListConstrain<KeyConstrain>, DefaultMarshaller<KeyList>,
136  ToolTipAnnotation>
137  defaultPrevPage{{
138  .parent = this,
139  .path{"PrevPage"},
140  .description{_("Fallback Previous page")},
141  .defaultValue{{Key("Up")}},
142  .constrain{{KeyConstrainFlag::AllowModifierLess}},
143  .annotation{_("Input methods may have different setup in their "
144  "own configuration. This is commonly used by "
145  "modules like clipboard or quickphrase.")},
146  }};
147 
148  Option<KeyList, ListConstrain<KeyConstrain>, DefaultMarshaller<KeyList>,
149  ToolTipAnnotation>
150  defaultNextPage{this,
151  "NextPage",
152  _("Fallback Next page"),
153  {Key("Down")},
154  KeyListConstrain({KeyConstrainFlag::AllowModifierLess}),
155  {},
156  {_("Input methods may have different setup in their "
157  "own configuration. This is commonly used by "
158  "modules like clipboard or quickphrase.")}};
159  KeyListOption defaultPrevCandidate{
160  this,
161  "PrevCandidate",
162  _("Fallback Previous Candidate"),
163  {Key("Shift+Tab")},
164  KeyListConstrain({KeyConstrainFlag::AllowModifierLess})};
165  KeyListOption defaultNextCandidate{
166  this,
167  "NextCandidate",
168  _("Fallback Next Candidate"),
169  {Key("Tab")},
170  KeyListConstrain({KeyConstrainFlag::AllowModifierLess})};
171  KeyListOption togglePreedit{this,
172  "TogglePreedit",
173  _("Toggle embedded preedit"),
174  {Key("Control+Alt+P")},
175  KeyListConstrain()};
176  Option<int, IntConstrain, DefaultMarshaller<int>, ToolTipAnnotation>
177  modifierOnlyKeyTimeout{
178  this,
179  "ModifierOnlyKeyTimeout",
180  _("Time limit in milliseconds for triggering modifier key "
181  "shortcuts"),
182  250,
183  IntConstrain{-1, 5000},
184  {},
185  ToolTipAnnotation{
186  _("When using modifier only hotkey, the action may "
187  "only be triggered if the modifier key is released within "
188  "the timeout. -1 means there is no limit.")}};);
189 
190 FCITX_CONFIGURATION(
191  BehaviorConfig,
192  Option<bool> activeByDefault{this, "ActiveByDefault",
193  _("Activate input method by default")};
194  OptionWithAnnotation<PropertyPropagatePolicy,
195  PropertyPropagatePolicyI18NAnnotation>
196  resetStateWhenFocusIn{this, "resetStateWhenFocusIn",
197  _("Reset state on Focus In"),
198  PropertyPropagatePolicy::No};
199  OptionWithAnnotation<PropertyPropagatePolicy,
200  PropertyPropagatePolicyI18NAnnotation>
201  shareState{this, "ShareInputState", _("Share Input State"),
202  isAndroid() ? PropertyPropagatePolicy::All
203  : PropertyPropagatePolicy::No};
204  Option<bool> preeditEnabledByDefault{this, "PreeditEnabledByDefault",
205  _("Show preedit in application"),
206  true};
207  Option<bool> showInputMethodInformation{
208  this, "ShowInputMethodInformation",
209  _("Show Input Method Information when switch input method"), true};
210  Option<bool> showInputMethodInformationWhenFocusIn{
211  this, "showInputMethodInformationWhenFocusIn",
212  _("Show Input Method Information when changing focus"), false};
213  Option<bool> compactInputMethodInformation{
214  this, "CompactInputMethodInformation",
215  _("Show compact input method information"), true};
216  Option<bool> showFirstInputMethodInformation{
217  this, "ShowFirstInputMethodInformation",
218  _("Show first input method information"), true};
219  Option<int, IntConstrain> defaultPageSize{this, "DefaultPageSize",
220  _("Default Candidates per page"),
221  5, IntConstrain(1, 10)};
222  ConditionalHidden<!hasKeyboard,
223  OptionWithAnnotation<bool, ToolTipAnnotation>>
224  overrideXkbOption{
225  this,
226  "OverrideXkbOption",
227  _("Override XKB Option"),
228  false,
229  {},
230  {},
231  {_("Override the XKB option from display server. It "
232  "will not affect the XKB option send to display, but just the "
233  "XKB options for custom XKB layout. This is a workaround when "
234  "there is no way to get the current XKB option from Wayland "
235  "Compositor.")}};
236  ConditionalHidden<!hasKeyboard, Option<std::string>> customXkbOption{
237  this, "CustomXkbOption", _("Custom XKB Option"), ""};
238  HiddenOption<std::vector<std::string>> enabledAddons{
239  this, "EnabledAddons", "Force Enabled Addons"};
240  HiddenOption<std::vector<std::string>> disabledAddons{
241  this, "DisabledAddons", "Force Disabled Addons"};
242  HiddenOption<bool> preloadInputMethod{
243  this, "PreloadInputMethod",
244  "Preload input method to be used by default", true};
245  Option<bool> allowInputMethodForPassword{
246  this, "AllowInputMethodForPassword",
247  _("Allow input method in the password field"), false};
248  Option<bool> showPreeditForPassword{
249  this, "ShowPreeditForPassword",
250  _("Show preedit text when typing password"), false};
251  Option<int, IntConstrain, DefaultMarshaller<int>, ToolTipAnnotation>
252  autoSavePeriod{this,
253  "AutoSavePeriod",
254  _("Interval of saving user data in minutes"),
255  30,
256  IntConstrain(0, 1440),
257  {},
258  {_("If value is 0, the user data may only be saved when "
259  "fcitx quits (e.g. logout).")}};);
260 
261 FCITX_CONFIGURATION(GlobalConfig,
262  Option<HotkeyConfig> hotkey{this, "Hotkey", _("Hotkey")};
263  Option<BehaviorConfig> behavior{this, "Behavior",
264  _("Behavior")};);
265 } // namespace impl
266 
267 class GlobalConfigPrivate : public impl::GlobalConfig {};
268 
269 GlobalConfig::GlobalConfig() : d_ptr(std::make_unique<GlobalConfigPrivate>()) {}
270 
271 GlobalConfig::~GlobalConfig() {}
272 
273 void GlobalConfig::load(const RawConfig &rawConfig, bool partial) {
274  FCITX_D();
275  d->load(rawConfig, partial);
276 }
277 
278 void GlobalConfig::save(RawConfig &config) const {
279  FCITX_D();
280  d->save(config);
281 }
282 
283 bool GlobalConfig::safeSave(const std::string &path) const {
284  FCITX_D();
285  return safeSaveAsIni(*d, path);
286 }
287 
288 const KeyList &GlobalConfig::triggerKeys() const {
289  FCITX_D();
290  return *d->hotkey->triggerKeys;
291 }
292 
293 bool GlobalConfig::enumerateWithTriggerKeys() const {
294  FCITX_D();
295  return *d->hotkey->enumerateWithTriggerKeys;
296 }
297 
298 const KeyList &GlobalConfig::altTriggerKeys() const {
299  FCITX_D();
300  return *d->hotkey->altTriggerKeys;
301 }
302 
303 const KeyList &GlobalConfig::activateKeys() const {
304  FCITX_D();
305  return *d->hotkey->activateKeys;
306 }
307 
308 const KeyList &GlobalConfig::deactivateKeys() const {
309  FCITX_D();
310  return d->hotkey->deactivateKeys.value();
311 }
312 
314  FCITX_D();
315  return *d->hotkey->consumeRedundantActivateKeys;
316 }
317 
318 const KeyList &GlobalConfig::enumerateForwardKeys() const {
319  FCITX_D();
320  return d->hotkey->enumerateForwardKeys.value();
321 }
322 
323 const KeyList &GlobalConfig::enumerateBackwardKeys() const {
324  FCITX_D();
325  return d->hotkey->enumerateBackwardKeys.value();
326 }
327 
328 bool GlobalConfig::enumerateSkipFirst() const {
329  FCITX_D();
330  return *d->hotkey->enumerateSkipFirst;
331 }
332 
333 const KeyList &GlobalConfig::enumerateGroupForwardKeys() const {
334  FCITX_D();
335  return *d->hotkey->enumerateGroupForwardKeys;
336 }
337 
338 const KeyList &GlobalConfig::enumerateGroupBackwardKeys() const {
339  FCITX_D();
340  return *d->hotkey->enumerateGroupBackwardKeys;
341 }
342 
343 const KeyList &GlobalConfig::togglePreeditKeys() const {
344  FCITX_D();
345  return *d->hotkey->togglePreedit;
346 }
347 
348 bool GlobalConfig::activeByDefault() const {
349  FCITX_D();
350  return d->behavior->activeByDefault.value();
351 }
352 
353 PropertyPropagatePolicy GlobalConfig::resetStateWhenFocusIn() const {
354  FCITX_D();
355  return d->behavior->resetStateWhenFocusIn.value();
356 }
357 
358 bool GlobalConfig::showInputMethodInformation() const {
359  FCITX_D();
360  return d->behavior->showInputMethodInformation.value();
361 }
362 
363 bool GlobalConfig::showInputMethodInformationWhenFocusIn() const {
364  FCITX_D();
365  return d->behavior->showInputMethodInformationWhenFocusIn.value();
366 }
367 
368 bool GlobalConfig::compactInputMethodInformation() const {
369  FCITX_D();
370  return d->behavior->compactInputMethodInformation.value();
371 }
372 
373 bool GlobalConfig::showFirstInputMethodInformation() const {
374  FCITX_D();
375  return d->behavior->showFirstInputMethodInformation.value();
376 }
377 
378 PropertyPropagatePolicy GlobalConfig::shareInputState() const {
379  FCITX_D();
380  return d->behavior->shareState.value();
381 }
382 
383 bool GlobalConfig::preeditEnabledByDefault() const {
384  FCITX_D();
385  return d->behavior->preeditEnabledByDefault.value();
386 }
387 
388 const KeyList &GlobalConfig::defaultPrevPage() const {
389  FCITX_D();
390  return d->hotkey->defaultPrevPage.value();
391 }
392 
393 const KeyList &GlobalConfig::defaultNextPage() const {
394  FCITX_D();
395  return d->hotkey->defaultNextPage.value();
396 }
397 
398 const KeyList &GlobalConfig::defaultPrevCandidate() const {
399  FCITX_D();
400  return d->hotkey->defaultPrevCandidate.value();
401 }
402 
403 const KeyList &GlobalConfig::defaultNextCandidate() const {
404  FCITX_D();
405  return d->hotkey->defaultNextCandidate.value();
406 }
407 
408 int GlobalConfig::defaultPageSize() const {
409  FCITX_D();
410  return d->behavior->defaultPageSize.value();
411 }
412 
414  FCITX_D();
415  return d->behavior->overrideXkbOption.value();
416 }
417 
418 const std::string &GlobalConfig::customXkbOption() const {
419  FCITX_D();
420  return d->behavior->customXkbOption.value();
421 }
422 
423 const std::vector<std::string> &GlobalConfig::enabledAddons() const {
424  FCITX_D();
425  return *d->behavior->enabledAddons;
426 }
427 
428 const std::vector<std::string> &GlobalConfig::disabledAddons() const {
429  FCITX_D();
430  return *d->behavior->disabledAddons;
431 }
432 
433 void GlobalConfig::setEnabledAddons(const std::vector<std::string> &addons) {
434  FCITX_D();
435  d->behavior.mutableValue()->enabledAddons.setValue(addons);
436 }
437 
438 void GlobalConfig::setDisabledAddons(const std::vector<std::string> &addons) {
439  FCITX_D();
440  d->behavior.mutableValue()->disabledAddons.setValue(addons);
441 }
442 
443 bool GlobalConfig::preloadInputMethod() const {
444  FCITX_D();
445  return *d->behavior->preloadInputMethod;
446 }
447 
449  FCITX_D();
450  return *d->behavior->allowInputMethodForPassword;
451 }
452 
454  FCITX_D();
455  return *d->behavior->showPreeditForPassword;
456 }
457 
459  FCITX_D();
460  return *d->behavior->autoSavePeriod;
461 }
462 
464  FCITX_D();
465  return *d->hotkey->modifierOnlyKeyTimeout;
466 }
467 
468 bool GlobalConfig::checkModifierOnlyKeyTimeout(uint64_t lastPressedTime) const {
469  const auto timeout = modifierOnlyKeyTimeout();
470  if (timeout < 0) {
471  return true;
472  }
473  return now(CLOCK_MONOTONIC) <=
474  (lastPressedTime + static_cast<uint64_t>(timeout) * 1000ULL);
475 }
476 
477 const Configuration &GlobalConfig::config() const {
478  FCITX_D();
479  return *d;
480 }
481 
482 Configuration &GlobalConfig::config() {
483  FCITX_D();
484  return *d;
485 }
486 
487 } // 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.
A raw configuration tree that stores key-value pairs in a hierarchical structure. ...
Definition: rawconfig.h:37
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 consumeRedundantActivateKeys() const
Consume Activate/Deactivate keys even when the state does not change.
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.