1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2004 - 2005 Hiroyuki Ikezoe <poincare@ikezoe.net>
4 * Copyright (C) 2004 - 2005 Takuro Ashie <ashie@homa.ne.jp>
5 * SPDX-FileCopyrightText: 2012 CSSlayer <wengxt@gmail.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 /*
11 * The original code is scim_uim_imengine.cpp in scim-uim-0.1.3.
12 * SPDX-FileCopyrightText: 2004 James Su <suzhe@tsinghua.org.cn>
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include <config.h>
17 #endif
18
19 #include <errno.h>
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include "engine.h"
25 #include "state.h"
26 #include "utils.h"
27
28 #include <fcitx-utils/log.h>
29 #include <fcitx/inputcontext.h>
30 #include <fcitx/inputpanel.h>
31 #include <fcitx/statusarea.h>
32
33 #include <clipboard_public.h>
34 #include <fcitx-utils/standardpath.h>
35
AnthyState(fcitx::InputContext * ic,AnthyEngine * engine,fcitx::Instance * instance)36 AnthyState::AnthyState(fcitx::InputContext *ic, AnthyEngine *engine,
37 fcitx::Instance *instance)
38 : ic_(ic), engine_(engine), instance_(instance), preedit_(*this),
39 preeditVisible_(false), lookupTableVisible_(false), nConvKeyPressed_(0),
40 prevInputMode_(InputMode::HIRAGANA), cursorPos_(0), uiUpdate_(false) {
41 configure();
42 }
43
~AnthyState()44 AnthyState::~AnthyState() {}
45
46 // FIXME!
isNicolaThumbShiftKey(const fcitx::KeyEvent & key)47 bool AnthyState::isNicolaThumbShiftKey(const fcitx::KeyEvent &key) {
48 if (typingMethod() != TypingMethod::NICOLA)
49 return false;
50
51 if (util::match_key_event(*config().key->leftThumbKeys, key.rawKey(),
52 fcitx::KeyStates(0xFFFF)) ||
53 util::match_key_event(*config().key->rightThumbKeys, key.rawKey(),
54 fcitx::KeyStates(0xFFFF))) {
55 return true;
56 }
57
58 return false;
59 }
60
processKeyEventInput(const fcitx::KeyEvent & key)61 bool AnthyState::processKeyEventInput(const fcitx::KeyEvent &key) {
62 // prediction while typing
63 if (*config().general->predictOnInput && key.isRelease() &&
64 preedit_.isPreediting() && !preedit_.isConverting()) {
65 preedit_.predict();
66 preedit_.candidates();
67 }
68
69 if (!preedit_.canProcessKeyEvent(key)) {
70 return false;
71 }
72
73 if (preedit_.isConverting()) {
74 if (isRealtimeConversion()) {
75 action_revert();
76 } else if (!isNicolaThumbShiftKey(key)) {
77 action_commit(*config().general->learnOnAutoCommit);
78 }
79 }
80
81 bool need_commit = preedit_.processKeyEvent(key);
82
83 if (need_commit) {
84 if (isRealtimeConversion() && inputMode() != InputMode::LATIN &&
85 inputMode() != InputMode::WIDE_LATIN) {
86 preedit_.convert(FCITX_ANTHY_CANDIDATE_DEFAULT, isSingleSegment());
87 }
88 action_commit(*config().general->learnOnAutoCommit);
89 } else {
90 if (isRealtimeConversion()) {
91 preedit_.convert(FCITX_ANTHY_CANDIDATE_DEFAULT, isSingleSegment());
92 preedit_.selectSegment(-1);
93 }
94 // show_preedit_string ();
95 preeditVisible_ = true;
96 setPreedition();
97 }
98
99 return true;
100 }
101
processKeyEventLookupKeybind(const fcitx::KeyEvent & key)102 bool AnthyState::processKeyEventLookupKeybind(const fcitx::KeyEvent &key) {
103 decltype(actions_)::iterator it;
104
105 if (key.isRelease())
106 return false;
107
108 lastKey_ = key.rawKey();
109
110 /* try to find a "insert a blank" action to be not stolen a blank key
111 * when entering the pseudo ascii mode.
112 */
113 if (pseudoAsciiMode() != 0 &&
114 *config().general->romajiPseudoAsciiBlankBehavior &&
115 preedit_.isPseudoAsciiMode()) {
116 it = std::find_if(actions_.begin(), actions_.end(),
117 [](const Action &action) {
118 return action.name() == "INSERT_SPACE";
119 });
120 if (it != actions_.end() && it->perform(this, key)) {
121 return true;
122 }
123 }
124
125 for (it = actions_.begin(); it != actions_.end(); it++) {
126 if (it->perform(this, key)) {
127 lastKey_ = fcitx::Key();
128 return true;
129 }
130 }
131
132 int choose = key.rawKey().keyListIndex(util::selection_keys());
133 if (choose >= 0) {
134 auto candList = ic_->inputPanel().candidateList();
135 if (candList && candList->size() > choose) {
136 candList->candidate(choose).select(ic_);
137 lastKey_ = fcitx::Key();
138 return true;
139 }
140 }
141
142 lastKey_ = fcitx::Key();
143
144 return false;
145 }
146
processKeyEventLatinMode(const fcitx::KeyEvent & key)147 bool AnthyState::processKeyEventLatinMode(const fcitx::KeyEvent &key) {
148 if (key.isRelease())
149 return false;
150
151 if (util::key_is_keypad(key.rawKey())) {
152 std::string wide;
153 auto str = util::keypad_to_string(key);
154 if (*config().general->tenKeyType == TenKeyType::WIDE)
155 wide = util::convert_to_wide(str);
156 else
157 wide = str;
158 if (!wide.empty()) {
159 commitString(wide);
160 return true;
161 } else {
162 return false;
163 }
164 } else {
165 // for Multi/Dead key
166 return false;
167 }
168 }
169
processKeyEventWideLatinMode(const fcitx::KeyEvent & key)170 bool AnthyState::processKeyEventWideLatinMode(const fcitx::KeyEvent &key) {
171 if (key.isRelease())
172 return false;
173
174 std::string wide;
175 auto str = util::keypad_to_string(key);
176 if (util::key_is_keypad(key.rawKey()) &&
177 *config().general->tenKeyType == TenKeyType::HALF) {
178 wide = str;
179 } else {
180 wide = util::convert_to_wide(str);
181 }
182 if (!wide.empty()) {
183 commitString(wide);
184 return true;
185 }
186
187 return false;
188 }
189
processKeyEvent(const fcitx::KeyEvent & key)190 bool AnthyState::processKeyEvent(const fcitx::KeyEvent &key) {
191 // FIXME!
192 // for NICOLA thumb shift key
193 if (typingMethod() == TypingMethod::NICOLA && isNicolaThumbShiftKey(key)) {
194 if (processKeyEventInput(key))
195 return true;
196 }
197
198 // lookup user defined key bindings
199 if (processKeyEventLookupKeybind(key))
200 return true;
201
202 if (key.rawKey().isDigit() && ic_->inputPanel().candidateList() &&
203 ic_->inputPanel().candidateList()->size()) {
204 return false;
205 }
206
207 // for Latin mode
208 if (preedit_.inputMode() == InputMode::LATIN)
209 return processKeyEventLatinMode(key);
210
211 // for wide Latin mode
212 if (preedit_.inputMode() == InputMode::WIDE_LATIN)
213 return processKeyEventWideLatinMode(key);
214
215 // for other mode
216 if (typingMethod() != TypingMethod::NICOLA || !isNicolaThumbShiftKey(key)) {
217 if (processKeyEventInput(key))
218 return true;
219 }
220
221 if (preedit_.isPreediting())
222 return true;
223 else
224 return false;
225 }
226
movePreeditCaret(unsigned int pos)227 void AnthyState::movePreeditCaret(unsigned int pos) {
228 preedit_.setCaretPosByChar(pos);
229 // TODO
230 }
231
selectCandidateNoDirect(unsigned int item)232 void AnthyState::selectCandidateNoDirect(unsigned int item) {
233 if (preedit_.isPredicting() && !preedit_.isConverting())
234 action_predict();
235
236 // update lookup table
237 cursorPos_ = item;
238
239 // update preedit
240 preedit_.selectCandidate(cursorPos_);
241 setPreedition();
242
243 setLookupTable();
244 if (auto candList = ic_->inputPanel().candidateList()) {
245 if (cursorPos_ >= 0 && cursorPos_ < candList->size()) {
246 auto commonCandList =
247 std::static_pointer_cast<fcitx::CommonCandidateList>(candList);
248 commonCandList->setGlobalCursorIndex(cursorPos_);
249 commonCandList->setPage(cursorPos_ / *config().general->pageSize);
250 }
251 }
252
253 // update aux string
254 if (*config().general->showCandidatesLabel)
255 setAuxString();
256 }
257
selectCandidate(unsigned int item)258 void AnthyState::selectCandidate(unsigned int item) {
259 selectCandidateNoDirect(item);
260
261 unsetLookupTable();
262 action_select_next_segment();
263 }
264
reset()265 void AnthyState::reset() {
266 ic_->inputPanel().reset();
267
268 preedit_.clear();
269 unsetLookupTable();
270
271 preeditVisible_ = false;
272 setPreedition();
273 }
274
init()275 void AnthyState::init() {
276 ic_->inputPanel().reset();
277 if (preeditVisible_) {
278 setPreedition();
279 }
280
281 if (lookupTableVisible_ && isSelectingCandidates()) {
282 if (*config().general->showCandidatesLabel) {
283 setAuxString();
284 }
285 setLookupTable();
286 }
287
288 installProperties();
289 }
290
supportClientPreedit()291 bool AnthyState::supportClientPreedit() {
292 return ic_->capabilityFlags().test(fcitx::CapabilityFlag::Preedit);
293 }
294
setPreedition()295 void AnthyState::setPreedition() {
296 preedit_.updatePreedit();
297 uiUpdate_ = true;
298 }
299
updateUI()300 void AnthyState::updateUI() {
301 if (uiUpdate_) {
302 uiUpdate_ = false;
303 ic_->updateUserInterface(fcitx::UserInterfaceComponent::InputPanel);
304 ic_->updatePreedit();
305 }
306 }
307
setAuxString()308 void AnthyState::setAuxString() {
309 if (!ic_->inputPanel().candidateList() ||
310 !ic_->inputPanel().candidateList()->size())
311 return;
312
313 if (auto bulk = ic_->inputPanel().candidateList()->toBulk()) {
314 char buf[256];
315 sprintf(buf, _("(%d / %d)"), cursorPos_ + 1, bulk->totalSize());
316 updateAuxString(buf);
317 }
318 }
319
setLookupTable()320 int AnthyState::setLookupTable() {
321
322 // if (!is_selecting_candidates ()) {
323 if (isRealtimeConversion() && preedit_.selectedSegment() < 0) {
324 // select latest segment
325 int n = preedit_.nrSegments();
326 if (n < 1)
327 return 0;
328 preedit_.selectSegment(n - 1);
329 }
330
331 // prepare candidates
332 auto candList = preedit_.candidates();
333
334 if (candList->size() == 0) {
335 return 0;
336 }
337
338 // update preedit
339 preedit_.selectCandidate(cursorPos_);
340 setPreedition();
341
342 bool beyond_threshold =
343 *config().general->nTriggersToShowCandWin > 0 &&
344 (int)nConvKeyPressed_ >= *config().general->nTriggersToShowCandWin;
345
346 int len = candList->totalSize();
347
348 if (!lookupTableVisible_ && (preedit_.isPredicting() || beyond_threshold)) {
349 lookupTableVisible_ = true;
350 nConvKeyPressed_ = 0;
351
352 if (*config().general->showCandidatesLabel) {
353 setAuxString();
354 }
355 } else if (!lookupTableVisible_) {
356 candList.reset();
357 }
358
359 ic_->inputPanel().setCandidateList(std::move(candList));
360 uiUpdate_ = true;
361
362 return len;
363 }
364
unsetLookupTable()365 void AnthyState::unsetLookupTable() {
366 ic_->inputPanel().setCandidateList(nullptr);
367 lookupTableVisible_ = false;
368 nConvKeyPressed_ = 0;
369 cursorPos_ = 0;
370
371 ic_->inputPanel().setAuxUp(fcitx::Text());
372 }
373
setPeriodCommaStyle(PeriodCommaStyle period)374 void AnthyState::setPeriodCommaStyle(PeriodCommaStyle period) {
375 config().general.mutableValue()->periodCommaStyle.setValue(period);
376 engine_->periodStyleAction()->update(ic_);
377
378 switch (period) {
379 case PeriodCommaStyle::WIDELATIN:
380 preedit_.setCommaStyle(CommaStyle::WIDE);
381 preedit_.setPeriodStyle(PeriodStyle::WIDE);
382 break;
383 case PeriodCommaStyle::LATIN:
384 preedit_.setCommaStyle(CommaStyle::HALF);
385 preedit_.setPeriodStyle(PeriodStyle::HALF);
386 break;
387 case PeriodCommaStyle::WIDELATIN_JAPANESE:
388 preedit_.setCommaStyle(CommaStyle::WIDE);
389 preedit_.setPeriodStyle(PeriodStyle::JAPANESE);
390 break;
391 case PeriodCommaStyle::JAPANESE:
392 default:
393 preedit_.setCommaStyle(CommaStyle::JAPANESE);
394 preedit_.setPeriodStyle(PeriodStyle::JAPANESE);
395 break;
396 }
397 }
398
setSymbolStyle(SymbolStyle symbol)399 void AnthyState::setSymbolStyle(SymbolStyle symbol) {
400 config().general.mutableValue()->symbolStyle.setValue(symbol);
401 engine_->symbolStyleAction()->update(ic_);
402 switch (symbol) {
403 case SymbolStyle::WIDEBRACKET_WIDESLASH:
404 preedit_.setBracketStyle(BracketStyle::JAPANESE);
405 preedit_.setSlashStyle(SlashStyle::WIDE);
406 break;
407 case SymbolStyle::CORNERBRACKET_WIDESLASH:
408 preedit_.setBracketStyle(BracketStyle::WIDE);
409 preedit_.setSlashStyle(SlashStyle::WIDE);
410 break;
411 case SymbolStyle::CORNERBRACKET_MIDDLEDOT:
412 preedit_.setBracketStyle(BracketStyle::WIDE);
413 preedit_.setSlashStyle(SlashStyle::JAPANESE);
414 break;
415 case SymbolStyle::JAPANESE:
416 default:
417 preedit_.setBracketStyle(BracketStyle::JAPANESE);
418 preedit_.setSlashStyle(SlashStyle::JAPANESE);
419 break;
420 }
421 }
422
installProperties()423 void AnthyState::installProperties() {
424 if (*config().general->showCandidatesLabel) {
425 setInputMode(inputMode());
426 }
427 setConversionMode(*config().general->conversionMode);
428 setTypingMethod(typingMethod());
429 setPeriodCommaStyle(periodCommaStyle());
430 setSymbolStyle(symbolStyle());
431 }
432
setInputMode(InputMode mode)433 void AnthyState::setInputMode(InputMode mode) {
434 if (mode != inputMode()) {
435 config().general.mutableValue()->inputMode.setValue(mode);
436 preedit_.setInputMode(mode);
437 setPreedition();
438 }
439
440 engine_->inputModeAction()->update(ic_);
441 if (!engine_->constructed()) {
442 return;
443 }
444 if (ic_->hasFocus() && instance_->inputMethod(ic_) == "anthy") {
445 instance_->showInputMethodInformation(ic_);
446 }
447 }
448
setConversionMode(ConversionMode mode)449 void AnthyState::setConversionMode(ConversionMode mode) {
450 config().general.mutableValue()->conversionMode.setValue(mode);
451
452 engine_->conversionModeAction()->update(ic_);
453 }
454
setTypingMethod(TypingMethod method)455 void AnthyState::setTypingMethod(TypingMethod method) {
456 if (method != typingMethod()) {
457 preedit_.setTypingMethod(method);
458 preedit_.setPseudoAsciiMode(pseudoAsciiMode());
459 }
460
461 config().general.mutableValue()->typingMethod.setValue(method);
462 engine_->typingMethodAction()->update(ic_);
463 }
464
setPeriodStyle(PeriodStyle period,CommaStyle comma)465 void AnthyState::setPeriodStyle(PeriodStyle period, CommaStyle comma) {
466 std::string label;
467
468 switch (comma) {
469 case CommaStyle::JAPANESE:
470 label = "\xE3\x80\x81";
471 break;
472 case CommaStyle::WIDE:
473 label = "\xEF\xBC\x8C";
474 break;
475 case CommaStyle::HALF:
476 label = ",";
477 break;
478 default:
479 break;
480 }
481
482 switch (period) {
483 case PeriodStyle::JAPANESE:
484 label += "\xE3\x80\x82";
485 break;
486 case PeriodStyle::WIDE:
487 label += "\xEF\xBC\x8E";
488 break;
489 case PeriodStyle::HALF:
490 label += ".";
491 break;
492 default:
493 break;
494 }
495
496 if (period != preedit_.periodStyle()) {
497 preedit_.setPeriodStyle(period);
498 }
499 if (comma != preedit_.commaStyle()) {
500 preedit_.setCommaStyle(comma);
501 }
502 }
503
setSymbolStyle(BracketStyle bracket,SlashStyle slash)504 void AnthyState::setSymbolStyle(BracketStyle bracket, SlashStyle slash) {
505 if (bracket != preedit_.bracketStyle()) {
506 preedit_.setBracketStyle(bracket);
507 }
508 if (slash != preedit_.slashStyle()) {
509 preedit_.setSlashStyle(slash);
510 }
511 }
512
isSelectingCandidates()513 bool AnthyState::isSelectingCandidates() {
514 return ic_->inputPanel().candidateList() &&
515 ic_->inputPanel().candidateList()->size();
516 }
517
deactivate()518 void AnthyState::deactivate() {}
519
action_convert()520 bool AnthyState::action_convert() {
521 if (!preedit_.isPreediting())
522 return false;
523
524 if (!preedit_.isConverting()) {
525 // show conversion string
526 preedit_.finish();
527 preedit_.convert(FCITX_ANTHY_CANDIDATE_DEFAULT, isSingleSegment());
528 setPreedition();
529 nConvKeyPressed_++;
530 setLookupTable();
531 return true;
532 }
533
534 return false;
535 }
536
action_predict()537 bool AnthyState::action_predict() {
538 if (!preedit_.isPreediting())
539 return false;
540
541 if (preedit_.isConverting())
542 return false;
543
544 if (!preedit_.isPredicting())
545 preedit_.predict();
546
547 preedit_.selectCandidate(0);
548 setPreedition();
549 nConvKeyPressed_++;
550 setLookupTable();
551 selectCandidateNoDirect(0);
552
553 return true;
554 }
555
action_revert()556 bool AnthyState::action_revert() {
557 if (preedit_.isReconverting()) {
558 preedit_.revert();
559 commitString(preedit_.string());
560 reset();
561 return true;
562 }
563
564 if (!preedit_.isPreediting())
565 return false;
566
567 if (!preedit_.isConverting()) {
568 reset();
569 return true;
570 }
571
572 if (isSelectingCandidates()) {
573 ic_->inputPanel().setCandidateList(nullptr);
574 }
575
576 unsetLookupTable();
577 preedit_.revert();
578 setPreedition();
579
580 return true;
581 }
582
action_cancel_all()583 bool AnthyState::action_cancel_all() {
584 if (!preedit_.isPreediting())
585 return false;
586
587 reset();
588 return true;
589 }
590
action_commit(bool learn,bool do_real_commit)591 bool AnthyState::action_commit(bool learn, bool do_real_commit) {
592 if (!preedit_.isPreediting())
593 return false;
594
595 if (preedit_.isConverting()) {
596 if (do_real_commit)
597 commitString(preedit_.string());
598 if (learn)
599 preedit_.commit();
600 } else {
601 preedit_.finish();
602 if (do_real_commit)
603 commitString(preedit_.string());
604 }
605
606 reset();
607
608 return true;
609 }
610
action_commit_follow_preference()611 bool AnthyState::action_commit_follow_preference() {
612 return action_commit(*config().general->learnOnManualCommit);
613 }
614
action_commit_reverse_preference()615 bool AnthyState::action_commit_reverse_preference() {
616 return action_commit(!*config().general->learnOnManualCommit);
617 }
618
action_back()619 bool AnthyState::action_back() {
620 if (!preedit_.isPreediting())
621 return false;
622
623 if (preedit_.isConverting()) {
624 action_revert();
625 if (!isRealtimeConversion())
626 return true;
627 }
628
629 preedit_.erase();
630
631 if (preedit_.length() > 0) {
632 if (isRealtimeConversion()) {
633 preedit_.convert(FCITX_ANTHY_CANDIDATE_DEFAULT, isSingleSegment());
634 preedit_.selectSegment(-1);
635 }
636 setPreedition();
637 } else {
638 reset();
639 }
640
641 return true;
642 }
643
action_delete()644 bool AnthyState::action_delete() {
645 if (!preedit_.isPreediting())
646 return false;
647
648 if (preedit_.isConverting()) {
649 action_revert();
650 if (!isRealtimeConversion())
651 return true;
652 }
653
654 preedit_.erase(false);
655
656 if (preedit_.length() > 0) {
657 if (isRealtimeConversion()) {
658 preedit_.convert(FCITX_ANTHY_CANDIDATE_DEFAULT, isSingleSegment());
659 preedit_.selectSegment(-1);
660 }
661 setPreedition();
662 } else {
663 reset();
664 }
665
666 return true;
667 }
668
action_insert_space()669 bool AnthyState::action_insert_space() {
670 std::string str;
671 bool is_wide = false, retval = false;
672
673 if (preedit_.isPreediting() &&
674 !*config().general->romajiPseudoAsciiBlankBehavior)
675 return false;
676
677 if (*config().general->spaceType == SpaceType::FOLLOWMODE) {
678 InputMode mode = inputMode();
679 if (mode == InputMode::LATIN || mode == InputMode::HALF_KATAKANA ||
680 preedit_.isPseudoAsciiMode()) {
681 is_wide = false;
682 } else {
683 is_wide = true;
684 }
685 } else if (*config().general->spaceType == SpaceType::WIDE) {
686 is_wide = true;
687 }
688
689 if (is_wide) {
690 str = "\xE3\x80\x80";
691 retval = true;
692 } else if (typingMethod() == TypingMethod::NICOLA || // FIXME! it's a ad-hoc
693 // solution.
694 preedit_.isPseudoAsciiMode() ||
695 (lastKey_.sym() != FcitxKey_space &&
696 lastKey_.sym() != FcitxKey_KP_Space)) {
697 str = " ";
698 retval = true;
699 }
700
701 if (retval) {
702 if (preedit_.isPseudoAsciiMode()) {
703 preedit_.append(lastKey_, str);
704 // show_preedit_string ();
705 preeditVisible_ = true;
706 setPreedition();
707 } else {
708 commitString(str);
709 }
710 }
711
712 return retval;
713 }
714
action_insert_alternative_space()715 bool AnthyState::action_insert_alternative_space() {
716 bool is_wide = false;
717
718 if (preedit_.isPreediting())
719 return false;
720
721 if (*config().general->spaceType == SpaceType::FOLLOWMODE) {
722 InputMode mode = inputMode();
723 if (mode == InputMode::LATIN || mode == InputMode::HALF_KATAKANA) {
724 is_wide = true;
725 } else {
726 is_wide = false;
727 }
728 } else if (*config().general->spaceType != SpaceType::WIDE) {
729 is_wide = true;
730 }
731
732 if (is_wide) {
733 commitString("\xE3\x80\x80");
734 return true;
735 } else if (typingMethod() == TypingMethod::NICOLA || // FIXME! it's a ad-hoc
736 // solution.
737 (lastKey_.sym() != FcitxKey_space &&
738 lastKey_.sym() != FcitxKey_KP_Space)) {
739 commitString(" ");
740 return true;
741 }
742
743 return false;
744 }
745
action_insert_half_space()746 bool AnthyState::action_insert_half_space() {
747 if (preedit_.isPreediting())
748 return false;
749
750 if (lastKey_.sym() != FcitxKey_space &&
751 lastKey_.sym() != FcitxKey_KP_Space) {
752 commitString(" ");
753 return true;
754 }
755
756 return false;
757 }
758
action_insert_wide_space()759 bool AnthyState::action_insert_wide_space() {
760 if (preedit_.isPreediting())
761 return false;
762
763 commitString("\xE3\x80\x80");
764
765 return true;
766 }
767
action_move_caret_backward()768 bool AnthyState::action_move_caret_backward() {
769 if (!preedit_.isPreediting())
770 return false;
771 if (preedit_.isConverting())
772 return false;
773
774 preedit_.moveCaret(-1);
775 setPreedition();
776
777 return true;
778 }
779
action_move_caret_forward()780 bool AnthyState::action_move_caret_forward() {
781 if (!preedit_.isPreediting())
782 return false;
783 if (preedit_.isConverting())
784 return false;
785
786 preedit_.moveCaret(1);
787 setPreedition();
788
789 return true;
790 }
791
action_move_caret_first()792 bool AnthyState::action_move_caret_first() {
793 if (!preedit_.isPreediting())
794 return false;
795 if (preedit_.isConverting())
796 return false;
797
798 preedit_.setCaretPosByChar(0);
799 setPreedition();
800
801 return true;
802 }
803
action_move_caret_last()804 bool AnthyState::action_move_caret_last() {
805 if (!preedit_.isPreediting())
806 return false;
807 if (preedit_.isConverting())
808 return false;
809
810 preedit_.setCaretPosByChar(preedit_.utf8Length());
811 setPreedition();
812
813 return true;
814 }
815
action_select_prev_segment()816 bool AnthyState::action_select_prev_segment() {
817 if (!preedit_.isConverting())
818 return false;
819
820 unsetLookupTable();
821
822 int idx = preedit_.selectedSegment();
823 if (idx - 1 < 0) {
824 int n = preedit_.nrSegments();
825 if (n <= 0)
826 return false;
827 preedit_.selectSegment(n - 1);
828 } else {
829 preedit_.selectSegment(idx - 1);
830 }
831 setPreedition();
832
833 return true;
834 }
835
action_select_next_segment()836 bool AnthyState::action_select_next_segment() {
837 if (!preedit_.isConverting())
838 return false;
839
840 unsetLookupTable();
841
842 int idx = preedit_.selectedSegment();
843 if (idx < 0) {
844 preedit_.selectSegment(0);
845 } else {
846 int n = preedit_.nrSegments();
847 if (n <= 0)
848 return false;
849 if (idx + 1 >= n)
850 preedit_.selectSegment(0);
851 else
852 preedit_.selectSegment(idx + 1);
853 }
854 setPreedition();
855
856 return true;
857 }
858
action_select_first_segment()859 bool AnthyState::action_select_first_segment() {
860 if (!preedit_.isConverting())
861 return false;
862
863 unsetLookupTable();
864
865 preedit_.selectSegment(0);
866 setPreedition();
867
868 return true;
869 }
870
action_select_last_segment()871 bool AnthyState::action_select_last_segment() {
872 if (!preedit_.isConverting())
873 return false;
874
875 int n = preedit_.nrSegments();
876 if (n <= 0)
877 return false;
878
879 unsetLookupTable();
880
881 preedit_.selectSegment(n - 1);
882 setPreedition();
883
884 return true;
885 }
886
action_shrink_segment()887 bool AnthyState::action_shrink_segment() {
888 if (!preedit_.isConverting())
889 return false;
890
891 unsetLookupTable();
892
893 preedit_.resizeSegment(-1);
894 setPreedition();
895
896 return true;
897 }
898
action_expand_segment()899 bool AnthyState::action_expand_segment() {
900 if (!preedit_.isConverting())
901 return false;
902
903 unsetLookupTable();
904
905 preedit_.resizeSegment(1);
906 setPreedition();
907
908 return true;
909 }
910
action_commit_first_segment()911 bool AnthyState::action_commit_first_segment() {
912 if (!preedit_.isConverting()) {
913 if (preedit_.isPreediting()) {
914 return action_commit(*config().general->learnOnManualCommit);
915 } else {
916 return false;
917 }
918 }
919
920 unsetLookupTable();
921
922 commitString(preedit_.segmentString(0));
923 if (*config().general->learnOnManualCommit)
924 preedit_.commit(0);
925 else
926 preedit_.clear(0);
927
928 setPreedition();
929
930 return true;
931 }
932
action_commit_selected_segment()933 bool AnthyState::action_commit_selected_segment() {
934 if (!preedit_.isConverting()) {
935 if (preedit_.isPreediting()) {
936 return action_commit(*config().general->learnOnManualCommit);
937 } else {
938 return false;
939 }
940 }
941
942 unsetLookupTable();
943
944 for (int i = 0; i <= preedit_.selectedSegment(); i++)
945 commitString(preedit_.segmentString(i));
946 if (*config().general->learnOnManualCommit)
947 preedit_.commit(preedit_.selectedSegment());
948 else
949 preedit_.clear(preedit_.selectedSegment());
950
951 setPreedition();
952
953 return true;
954 }
955
action_commit_first_segment_reverse_preference()956 bool AnthyState::action_commit_first_segment_reverse_preference() {
957 if (!preedit_.isConverting()) {
958 if (preedit_.isPreediting()) {
959 return action_commit(!*config().general->learnOnManualCommit);
960 } else {
961 return false;
962 }
963 }
964
965 unsetLookupTable();
966
967 commitString(preedit_.segmentString(0));
968 if (!*config().general->learnOnManualCommit)
969 preedit_.commit(0);
970 else
971 preedit_.clear(0);
972
973 setPreedition();
974
975 return true;
976 }
977
action_commit_selected_segment_reverse_preference()978 bool AnthyState::action_commit_selected_segment_reverse_preference() {
979 if (!preedit_.isConverting()) {
980 if (preedit_.isPreediting()) {
981 return action_commit(!*config().general->learnOnManualCommit);
982 } else {
983 return false;
984 }
985 }
986
987 unsetLookupTable();
988
989 for (int i = 0; i <= preedit_.selectedSegment(); i++)
990 commitString(preedit_.segmentString(i));
991 if (!*config().general->learnOnManualCommit)
992 preedit_.commit(preedit_.selectedSegment());
993 else
994 preedit_.clear(preedit_.selectedSegment());
995
996 setPreedition();
997
998 return true;
999 }
1000
action_select_next_candidate()1001 bool AnthyState::action_select_next_candidate() {
1002 if (!preedit_.isConverting())
1003 return false;
1004
1005 // if (!is_selecting_candidates ())
1006 int end = setLookupTable();
1007
1008 if (cursorPos_ >= end - 1)
1009 cursorPos_ = 0;
1010 else
1011 cursorPos_++;
1012 nConvKeyPressed_++;
1013
1014 selectCandidateNoDirect(cursorPos_);
1015 return true;
1016 }
1017
action_select_prev_candidate()1018 bool AnthyState::action_select_prev_candidate() {
1019 if (!preedit_.isConverting())
1020 return false;
1021 // if (!is_selecting_candidates ())
1022 int end = setLookupTable();
1023
1024 if (end < 0)
1025 end = 0;
1026 if (cursorPos_ == 0)
1027 cursorPos_ = end - 1;
1028 else
1029 cursorPos_--;
1030 nConvKeyPressed_++;
1031
1032 if (auto candList = ic_->inputPanel().candidateList()) {
1033 if (candList->size() > cursorPos_ && cursorPos_ >= 0) {
1034 auto commonCandList =
1035 std::static_pointer_cast<fcitx::CommonCandidateList>(candList);
1036 commonCandList->setGlobalCursorIndex(cursorPos_);
1037 commonCandList->setPage(cursorPos_ / *config().general->pageSize);
1038 }
1039 }
1040
1041 selectCandidateNoDirect(cursorPos_);
1042
1043 return true;
1044 }
1045
action_select_first_candidate()1046 bool AnthyState::action_select_first_candidate() {
1047 if (!preedit_.isConverting())
1048 return false;
1049 if (!isSelectingCandidates())
1050 return false;
1051
1052 cursorPos_ = 0;
1053 nConvKeyPressed_++;
1054 selectCandidateNoDirect(cursorPos_);
1055 return true;
1056 }
1057
action_select_last_candidate()1058 bool AnthyState::action_select_last_candidate() {
1059 if (!preedit_.isConverting())
1060 return false;
1061 if (!isSelectingCandidates())
1062 return false;
1063
1064 int end = ic_->inputPanel().candidateList()->toBulk()->totalSize() - 1;
1065 if (end < 0)
1066 end = 0;
1067 cursorPos_ = end;
1068 nConvKeyPressed_++;
1069 selectCandidateNoDirect(cursorPos_);
1070 return true;
1071 }
1072
action_candidates_page_up()1073 bool AnthyState::action_candidates_page_up() {
1074 if (!preedit_.isConverting())
1075 return false;
1076 if (!isSelectingCandidates())
1077 return false;
1078 if (!lookupTableVisible_)
1079 return false;
1080
1081 if (cursorPos_ - *config().general->pageSize >= 0) {
1082 cursorPos_ -= *config().general->pageSize;
1083 selectCandidateNoDirect(cursorPos_);
1084 }
1085
1086 return true;
1087 }
1088
action_candidates_page_down()1089 bool AnthyState::action_candidates_page_down() {
1090 if (!preedit_.isConverting())
1091 return false;
1092 if (!isSelectingCandidates())
1093 return false;
1094 if (!lookupTableVisible_)
1095 return false;
1096
1097 int end = ic_->inputPanel().candidateList()->toBulk()->totalSize();
1098
1099 if (cursorPos_ + *config().general->pageSize < end) {
1100 cursorPos_ += *config().general->pageSize;
1101 selectCandidateNoDirect(cursorPos_);
1102 }
1103
1104 return true;
1105 }
1106
actionSelectCandidate(unsigned int i)1107 bool AnthyState::actionSelectCandidate(unsigned int i) {
1108 // FIXME! m_lookup_table_visible should be set as true also on predicting
1109 if (!lookupTableVisible_ && !preedit_.isPredicting())
1110 return false;
1111
1112 if (preedit_.isPredicting() && !preedit_.isConverting() &&
1113 *config().general->useDirectKeyOnPredict) {
1114 ic_->inputPanel().setCandidateList(preedit_.candidates());
1115 selectCandidate(i);
1116 return true;
1117 } else if (preedit_.isConverting() && isSelectingCandidates()) {
1118 selectCandidate(i);
1119 return true;
1120 }
1121
1122 return false;
1123 }
1124
1125 template <typename T>
cycle_enum(T v,T size)1126 T cycle_enum(T v, T size) {
1127 return static_cast<T>((static_cast<int>(v) + 1) % static_cast<int>(size));
1128 }
1129
action_circle_input_mode()1130 bool AnthyState::action_circle_input_mode() {
1131 InputMode mode = inputMode();
1132
1133 mode = cycle_enum(mode, InputMode::LAST);
1134
1135 setInputMode(mode);
1136 saveConfig();
1137
1138 return true;
1139 }
1140
action_circle_typing_method()1141 bool AnthyState::action_circle_typing_method() {
1142 TypingMethod method;
1143
1144 method = typingMethod();
1145 method = cycle_enum(method, TypingMethod::NICOLA);
1146
1147 setTypingMethod(method);
1148 saveConfig();
1149
1150 return true;
1151 }
1152
action_circle_kana_mode()1153 bool AnthyState::action_circle_kana_mode() {
1154 InputMode mode;
1155
1156 if (inputMode() == InputMode::LATIN ||
1157 inputMode() == InputMode::WIDE_LATIN) {
1158 mode = InputMode::HIRAGANA;
1159 } else {
1160 switch (inputMode()) {
1161 case InputMode::HIRAGANA:
1162 mode = InputMode::KATAKANA;
1163 break;
1164 case InputMode::KATAKANA:
1165 mode = InputMode::HALF_KATAKANA;
1166 break;
1167 case InputMode::HALF_KATAKANA:
1168 default:
1169 mode = InputMode::HIRAGANA;
1170 break;
1171 }
1172 }
1173
1174 setInputMode(mode);
1175 saveConfig();
1176
1177 return true;
1178 }
1179
action_circle_latin_hiragana_mode()1180 bool AnthyState::action_circle_latin_hiragana_mode() {
1181 InputMode mode = inputMode();
1182
1183 if (mode == InputMode::LATIN) {
1184 mode = InputMode::HIRAGANA;
1185 } else if (mode == InputMode::HIRAGANA) {
1186 mode = InputMode::LATIN;
1187 }
1188
1189 setInputMode(mode);
1190 saveConfig();
1191
1192 return true;
1193 }
1194
action_latin_mode()1195 bool AnthyState::action_latin_mode() {
1196 setInputMode(InputMode::LATIN);
1197 saveConfig();
1198 return true;
1199 }
1200
action_wide_latin_mode()1201 bool AnthyState::action_wide_latin_mode() {
1202 setInputMode(InputMode::WIDE_LATIN);
1203 saveConfig();
1204 return true;
1205 }
1206
action_hiragana_mode()1207 bool AnthyState::action_hiragana_mode() {
1208 setInputMode(InputMode::HIRAGANA);
1209 saveConfig();
1210 return true;
1211 }
1212
action_katakana_mode()1213 bool AnthyState::action_katakana_mode() {
1214 setInputMode(InputMode::KATAKANA);
1215 saveConfig();
1216 return true;
1217 }
1218
action_half_katakana_mode()1219 bool AnthyState::action_half_katakana_mode() {
1220 setInputMode(InputMode::HALF_KATAKANA);
1221 saveConfig();
1222 return true;
1223 }
1224
action_cancel_pseudo_ascii_mode()1225 bool AnthyState::action_cancel_pseudo_ascii_mode() {
1226 if (!preedit_.isPreediting())
1227 return false;
1228 if (!preedit_.isPseudoAsciiMode())
1229 return false;
1230
1231 preedit_.resetPseudoAsciiMode();
1232
1233 return true;
1234 }
1235
convertKana(CandidateType type)1236 bool AnthyState::convertKana(CandidateType type) {
1237 if (!preedit_.isPreediting())
1238 return false;
1239
1240 if (preedit_.isReconverting())
1241 return false;
1242
1243 unsetLookupTable();
1244
1245 if (preedit_.isConverting()) {
1246 int idx = preedit_.selectedSegment();
1247 if (idx < 0) {
1248 action_revert();
1249 preedit_.finish();
1250 preedit_.convert(type, true);
1251 } else {
1252 preedit_.selectCandidate(type);
1253 }
1254 } else {
1255 preedit_.finish();
1256 preedit_.convert(type, true);
1257 }
1258
1259 setPreedition();
1260
1261 return true;
1262 }
1263
action_convert_to_hiragana()1264 bool AnthyState::action_convert_to_hiragana() {
1265 return convertKana(FCITX_ANTHY_CANDIDATE_HIRAGANA);
1266 }
1267
action_convert_to_katakana()1268 bool AnthyState::action_convert_to_katakana() {
1269 return convertKana(FCITX_ANTHY_CANDIDATE_KATAKANA);
1270 }
1271
action_convert_to_half()1272 bool AnthyState::action_convert_to_half() {
1273 return convertKana(FCITX_ANTHY_CANDIDATE_HALF);
1274 }
1275
action_convert_to_half_katakana()1276 bool AnthyState::action_convert_to_half_katakana() {
1277 return convertKana(FCITX_ANTHY_CANDIDATE_HALF_KATAKANA);
1278 }
1279
action_convert_to_latin()1280 bool AnthyState::action_convert_to_latin() {
1281 return convertKana(FCITX_ANTHY_CANDIDATE_LATIN);
1282 }
1283
action_convert_to_wide_latin()1284 bool AnthyState::action_convert_to_wide_latin() {
1285 return convertKana(FCITX_ANTHY_CANDIDATE_WIDE_LATIN);
1286 }
1287
action_convert_char_type_forward()1288 bool AnthyState::action_convert_char_type_forward() {
1289 if (!preedit_.isPreediting())
1290 return false;
1291
1292 unsetLookupTable();
1293
1294 if (preedit_.isConverting()) {
1295 int idx = preedit_.selectedSegment();
1296 if (idx < 0) {
1297 action_revert();
1298 preedit_.finish();
1299 preedit_.convert(FCITX_ANTHY_CANDIDATE_HIRAGANA, true);
1300 } else {
1301 int cand = preedit_.selectedCandidate();
1302 switch (cand) {
1303 case FCITX_ANTHY_CANDIDATE_HIRAGANA:
1304 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_KATAKANA);
1305 break;
1306 case FCITX_ANTHY_CANDIDATE_KATAKANA:
1307 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_HALF_KATAKANA);
1308 break;
1309 case FCITX_ANTHY_CANDIDATE_HALF_KATAKANA:
1310 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_WIDE_LATIN);
1311 break;
1312 case FCITX_ANTHY_CANDIDATE_WIDE_LATIN:
1313 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_LATIN);
1314 break;
1315 case FCITX_ANTHY_CANDIDATE_LATIN:
1316 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_HIRAGANA);
1317 break;
1318 default:
1319 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_HIRAGANA);
1320 break;
1321 }
1322 }
1323 } else {
1324 preedit_.finish();
1325 preedit_.convert(FCITX_ANTHY_CANDIDATE_HIRAGANA, true);
1326 }
1327
1328 setPreedition();
1329
1330 return true;
1331 }
1332
action_convert_char_type_backward()1333 bool AnthyState::action_convert_char_type_backward() {
1334 if (!preedit_.isPreediting())
1335 return false;
1336
1337 unsetLookupTable();
1338
1339 if (preedit_.isConverting()) {
1340 int idx = preedit_.selectedSegment();
1341 if (idx < 0) {
1342 action_revert();
1343 preedit_.finish();
1344 preedit_.convert(FCITX_ANTHY_CANDIDATE_HIRAGANA, true);
1345 } else {
1346 int cand = preedit_.selectedCandidate();
1347 switch (cand) {
1348 case FCITX_ANTHY_CANDIDATE_HIRAGANA:
1349 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_LATIN);
1350 break;
1351 case FCITX_ANTHY_CANDIDATE_KATAKANA:
1352 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_HIRAGANA);
1353 break;
1354 case FCITX_ANTHY_CANDIDATE_HALF_KATAKANA:
1355 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_KATAKANA);
1356 break;
1357 case FCITX_ANTHY_CANDIDATE_WIDE_LATIN:
1358 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_HALF_KATAKANA);
1359 break;
1360 case FCITX_ANTHY_CANDIDATE_LATIN:
1361 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_WIDE_LATIN);
1362 break;
1363 default:
1364 preedit_.selectCandidate(FCITX_ANTHY_CANDIDATE_HIRAGANA);
1365 break;
1366 }
1367 }
1368 } else {
1369 preedit_.finish();
1370 preedit_.convert(FCITX_ANTHY_CANDIDATE_HIRAGANA, true);
1371 }
1372
1373 setPreedition();
1374
1375 return true;
1376 }
1377
action_reconvert()1378 bool AnthyState::action_reconvert() {
1379 if (preedit_.isPreediting())
1380 return false;
1381
1382 if (!ic_->capabilityFlags().test(fcitx::CapabilityFlag::SurroundingText)) {
1383 return true;
1384 }
1385 if (!ic_->surroundingText().isValid()) {
1386 return true;
1387 }
1388
1389 const std::string surrounding_text(ic_->surroundingText().text());
1390 uint cursor_pos = ic_->surroundingText().cursor();
1391 uint anchor_pos = ic_->surroundingText().anchor();
1392 int32_t relative_selected_length = 0;
1393
1394 if (cursor_pos == anchor_pos) {
1395 if (engine_->clipboard()) {
1396 auto primary_text =
1397 engine_->clipboard()->call<fcitx::IClipboard::primary>(ic_);
1398 uint new_anchor_pos = 0;
1399 if (util::surrounding_get_anchor_pos_from_selection(
1400 surrounding_text, primary_text, cursor_pos,
1401 &new_anchor_pos)) {
1402 anchor_pos = new_anchor_pos;
1403 } else {
1404 return true;
1405 }
1406 } else {
1407 // There is no selection text.
1408 return true;
1409 }
1410 }
1411
1412 if (!util::surrounding_get_safe_delta(cursor_pos, anchor_pos,
1413 &relative_selected_length)) {
1414 return true;
1415 }
1416
1417 const uint32_t selection_start = std::min(cursor_pos, anchor_pos);
1418 const uint32_t selection_length = abs(relative_selected_length);
1419 std::string text = util::utf8_string_substr(
1420 surrounding_text, selection_start, selection_length);
1421
1422 ic_->surroundingText().deleteText(
1423 cursor_pos > anchor_pos ? -relative_selected_length : 0,
1424 selection_length);
1425
1426 preedit_.convert(text);
1427 setPreedition();
1428 setLookupTable();
1429
1430 return true;
1431 }
1432
action_add_word()1433 bool AnthyState::action_add_word() {
1434 util::launch_program(*config().command->addWordCommand);
1435
1436 return true;
1437 }
1438
action_launch_dict_admin_tool()1439 bool AnthyState::action_launch_dict_admin_tool() {
1440 util::launch_program(*config().command->dictAdminCommand);
1441
1442 return true;
1443 }
1444
typingMethod()1445 TypingMethod AnthyState::typingMethod() { return preedit_.typingMethod(); }
1446
inputMode()1447 InputMode AnthyState::inputMode() { return preedit_.inputMode(); }
1448
isSingleSegment()1449 bool AnthyState::isSingleSegment() {
1450 return (conversionMode() == ConversionMode::SINGLE_SEGMENT ||
1451 conversionMode() == ConversionMode::SINGLE_SEGMENT_IMMEDIATE);
1452 }
1453
isRealtimeConversion()1454 bool AnthyState::isRealtimeConversion() {
1455 return (conversionMode() == ConversionMode::MULTI_SEGMENT_IMMEDIATE ||
1456 conversionMode() == ConversionMode::SINGLE_SEGMENT_IMMEDIATE);
1457 }
1458
pseudoAsciiMode()1459 int AnthyState::pseudoAsciiMode() {
1460 int retval = 0;
1461 TypingMethod m = typingMethod();
1462
1463 if (m == TypingMethod::ROMAJI) {
1464 if (*config().general->romajiPseudoAsciiMode)
1465 retval |= FCITX_ANTHY_PSEUDO_ASCII_TRIGGERED_CAPITALIZED;
1466 }
1467
1468 return retval;
1469 }
1470
commitString(const std::string & str)1471 void AnthyState::commitString(const std::string &str) {
1472 ic_->commitString(str);
1473 }
1474
1475 #define APPEND_ACTION(key, func) \
1476 { \
1477 const fcitx::KeyList *hk; \
1478 std::string name = #key; \
1479 if (loaded) { \
1480 std::string str = (ACTION_CONFIG_##key##_KEY); \
1481 std::string keystr; \
1482 style.getString(keystr, "KeyBindings", str); \
1483 key_profile().hk_##key = fcitx::Key::keyListFromString(keystr); \
1484 hk = &key_profile().hk_##key; \
1485 } else \
1486 hk = &*config().m_key->hk_##key; \
1487 PMF f; \
1488 f = &AnthyState::func; \
1489 actions_[name] = Action(name, *hk, f); \
1490 }
1491
configure()1492 void AnthyState::configure() {
1493 auto keyProfile = engine_->keyProfile();
1494
1495 // clear old actions
1496 actions_.clear();
1497 #define FOREACH_ACTION(KEY, func) \
1498 { \
1499 std::string name = #KEY; \
1500 const fcitx::KeyList *hk; \
1501 if (keyProfile) { \
1502 hk = &keyProfile->hk_##KEY; \
1503 } else \
1504 hk = &*config().key->hk_##KEY; \
1505 PMF f; \
1506 f = &AnthyState::func; \
1507 actions_.emplace_back(name, *hk, f); \
1508 }
1509 #include "action_defs.h"
1510 #undef FOREACH_ACTION
1511
1512 // set romaji settings
1513 preedit_.setSymbolHalf(*config().general->romajiHalfSymbol);
1514 preedit_.setNumberHalf(*config().general->romajiHalfNumber);
1515
1516 // set input mode
1517 preedit_.setInputMode(*config().general->inputMode);
1518
1519 // set typing method and pseudo ASCII mode
1520 preedit_.setTypingMethod(*config().general->typingMethod);
1521 preedit_.setPseudoAsciiMode(pseudoAsciiMode());
1522
1523 // set period style
1524 setPeriodCommaStyle(*config().general->periodCommaStyle);
1525
1526 // set symbol style
1527 setSymbolStyle(*config().general->symbolStyle);
1528
1529 // setup toolbar
1530 installProperties();
1531 }
1532
updateAuxString(const std::string & str)1533 void AnthyState::updateAuxString(const std::string &str) {
1534 fcitx::Text aux;
1535 aux.append(str);
1536 ic_->inputPanel().setAuxUp(std::move(aux));
1537 uiUpdate_ = true;
1538 }
1539
resetCursor(int cursor)1540 void AnthyState::resetCursor(int cursor) {
1541 if (cursor >= 0)
1542 cursorPos_ = cursor;
1543 else
1544 cursor = 0;
1545 }
1546
autoCommit(fcitx::InputContextEvent & event)1547 void AnthyState::autoCommit(fcitx::InputContextEvent &event) {
1548 if (event.type() == fcitx::EventType::InputContextFocusOut) {
1549 action_commit(*config().general->learnOnAutoCommit, false);
1550 } else if (event.type() ==
1551 fcitx::EventType::InputContextSwitchInputMethod) {
1552 action_commit(*config().general->learnOnAutoCommit);
1553 }
1554 reset();
1555 }
1556
1557 /*
1558 vi:ts=4:nowrap:ai:expandtab
1559 */
1560