1 /* 2 * SPDX-FileCopyrightText: 2017-2017 CSSlayer <wengxt@gmail.com> 3 * 4 * SPDX-License-Identifier: LGPL-2.1-or-later 5 * 6 */ 7 #ifndef _PINYIN_PINYIN_H_ 8 #define _PINYIN_PINYIN_H_ 9 10 #include <fcitx-config/configuration.h> 11 #include <fcitx-config/iniparser.h> 12 #include <fcitx-utils/event.h> 13 #include <fcitx-utils/i18n.h> 14 #include <fcitx-utils/standardpath.h> 15 #include <fcitx/action.h> 16 #include <fcitx/addonfactory.h> 17 #include <fcitx/addonmanager.h> 18 #include <fcitx/inputcontextproperty.h> 19 #include <fcitx/inputmethodengine.h> 20 #include <fcitx/instance.h> 21 #include <libime/core/prediction.h> 22 #include <libime/pinyin/pinyincontext.h> 23 #include <libime/pinyin/pinyinime.h> 24 #include <memory> 25 #include <unordered_map> 26 #include <unordered_set> 27 28 namespace fcitx { 29 30 FCITX_CONFIG_ENUM(ShuangpinProfileEnum, Ziranma, MS, Ziguang, ABC, 31 Zhongwenzhixing, PinyinJiajia, Xiaohe, Custom) 32 33 FCITX_CONFIG_ENUM_I18N_ANNOTATION(ShuangpinProfileEnum, N_("Ziranma"), N_("MS"), 34 N_("Ziguang"), N_("ABC"), 35 N_("Zhongwenzhixing"), N_("PinyinJiajia"), 36 N_("Xiaohe"), N_("Custom")) 37 38 FCITX_CONFIGURATION( 39 FuzzyConfig, Option<bool> ue{this, "VE_UE", _("ue -> ve"), true}; 40 Option<bool> ng{this, "NG_GN", _("gn -> ng"), true}; 41 Option<bool> inner{this, "Inner", _("Inner Segment (xian -> xi'an)"), true}; 42 Option<bool> innerShort{this, "InnerShort", 43 _("Inner Segment for Short Pinyin (qie -> qi'e)"), 44 true}; 45 Option<bool> partialFinal{this, "PartialFinal", 46 _("Match partial finals (e -> en, eng, ei)"), 47 true}; 48 Option<bool> v{this, "V_U", _("u <-> v"), false}; 49 Option<bool> an{this, "AN_ANG", _("an <-> ang"), false}; 50 Option<bool> en{this, "EN_ENG", _("en <-> eng"), false}; 51 Option<bool> ian{this, "IAN_IANG", _("ian <-> iang"), false}; 52 Option<bool> in{this, "IN_ING", _("in <-> ing"), false}; 53 Option<bool> ou{this, "U_OU", _("u <-> ou"), false}; 54 Option<bool> uan{this, "UAN_UANG", _("uan <-> uang"), false}; 55 Option<bool> c{this, "C_CH", _("c <-> ch"), false}; 56 Option<bool> f{this, "F_H", _("f <-> h"), false}; 57 Option<bool> l{this, "L_N", _("l <-> n"), false}; 58 Option<bool> s{this, "S_SH", _("s <-> sh"), false}; 59 Option<bool> z{this, "Z_ZH", _("z <-> zh"), false};) 60 61 FCITX_CONFIGURATION( 62 PinyinEngineConfig, 63 OptionWithAnnotation<ShuangpinProfileEnum, 64 ShuangpinProfileEnumI18NAnnotation> 65 shuangpinProfile{this, "ShuangpinProfile", _("Shuangpin Profile"), 66 ShuangpinProfileEnum::Ziranma}; 67 Option<bool> showShuangpinMode{this, "ShowShuangpinMode", 68 _("Show current shuangpin mode"), true}; 69 Option<int, IntConstrain> pageSize{this, "PageSize", _("Page size"), 5, 70 IntConstrain(3, 10)}; 71 Option<bool> spellEnabled{this, "SpellEnabled", _("Enable Spell"), true}; 72 Option<bool> emojiEnabled{this, "EmojiEnabled", _("Enable Emoji"), true}; 73 Option<bool> chaiziEnabled{this, "ChaiziEnabled", _("Enable Chaizi"), true}; 74 Option<bool> cloudPinyinEnabled{this, "CloudPinyinEnabled", 75 _("Enable Cloud Pinyin"), false}; 76 Option<int, IntConstrain> cloudPinyinIndex{this, "CloudPinyinIndex", 77 _("Cloud Pinyin Index"), 2, 78 IntConstrain(1, 10)}; 79 Option<bool> showPreeditInApplication{this, "PreeditInApplication", 80 _("Show preedit within application"), 81 false}; 82 Option<bool> preeditCursorPositionAtBeginning{ 83 this, "PreeditCursorPositionAtBeginning", 84 _("Fix embedded preedit cursor at the beginning of the preedit"), true}; 85 Option<bool> showActualPinyinInPreedit{ 86 this, "PinyinInPreedit", _("Show complete pinyin in preedit"), false}; 87 Option<bool> predictionEnabled{this, "Prediction", _("Enable Prediction"), 88 false}; 89 Option<int, IntConstrain> predictionSize{ 90 this, "PredictionSize", _("Prediction Size"), 10, IntConstrain(3, 20)}; 91 KeyListOption forgetWord{this, 92 "ForgetWord", 93 _("Forget word"), 94 {Key("Control+7")}, 95 KeyListConstrain()}; 96 KeyListOption prevPage{ 97 this, 98 "PrevPage", 99 _("Prev Page"), 100 {Key(FcitxKey_minus), Key(FcitxKey_Up), Key(FcitxKey_KP_Up)}, 101 KeyListConstrain({KeyConstrainFlag::AllowModifierLess})}; 102 KeyListOption nextPage{ 103 this, 104 "NextPage", 105 _("Next Page"), 106 {Key(FcitxKey_equal), Key(FcitxKey_Down), Key(FcitxKey_KP_Down)}, 107 KeyListConstrain({KeyConstrainFlag::AllowModifierLess})}; 108 KeyListOption prevCandidate{ 109 this, 110 "PrevCandidate", 111 _("Prev Candidate"), 112 {Key("Shift+Tab")}, 113 KeyListConstrain({KeyConstrainFlag::AllowModifierLess})}; 114 KeyListOption nextCandidate{ 115 this, 116 "NextCandidate", 117 _("Next Candidate"), 118 {Key("Tab")}, 119 KeyListConstrain({KeyConstrainFlag::AllowModifierLess})}; 120 KeyListOption secondCandidate{ 121 this, 122 "SecondCandidate", 123 _("Select 2nd Candidate"), 124 {}, 125 KeyListConstrain({KeyConstrainFlag::AllowModifierLess, 126 KeyConstrainFlag::AllowModifierOnly})}; 127 KeyListOption thirdCandidate{ 128 this, 129 "ThirdCandidate", 130 _("Select 3rd Candidate"), 131 {}, 132 KeyListConstrain({KeyConstrainFlag::AllowModifierLess, 133 KeyConstrainFlag::AllowModifierOnly})}; 134 KeyListOption selectCharFromPhrase{ 135 this, 136 "ChooseCharFromPhrase", 137 _("Choose Character from Phrase"), 138 {Key("["), Key("]")}, 139 KeyListConstrain({KeyConstrainFlag::AllowModifierLess})}; 140 KeyListOption selectByStroke{ 141 this, 142 "FilterByStroke", 143 _("Filter by stroke"), 144 {Key("grave")}, 145 KeyListConstrain({KeyConstrainFlag::AllowModifierLess})}; 146 Option<int, IntConstrain> nbest{this, "Number of sentence", 147 _("Number of Sentence"), 2, 148 IntConstrain(1, 3)}; 149 Option<int, IntConstrain> longWordLimit{ 150 this, "LongWordLengthLimit", 151 _("Prompt long word length when input length over (0 for disable)"), 4, 152 IntConstrain(0, 10)}; 153 ExternalOption dictmanager{this, "DictManager", _("Dictionaries"), 154 "fcitx://config/addon/pinyin/dictmanager"}; 155 SubConfigOption punctuationMap{ 156 this, "Punctuation", _("Punctuation"), 157 "fcitx://config/addon/punctuation/punctuationmap/zh_CN"}; 158 SubConfigOption chttrans{ 159 this, "Chttrans", _("Simplified and Traditional Chinese Translation"), 160 "fcitx://config/addon/chttrans"}; 161 SubConfigOption cloudpinyin{this, "CloudPinyin", _("Cloud Pinyin"), 162 "fcitx://config/addon/cloudpinyin"}; 163 Option<Key, KeyConstrain> quickphraseKey{ 164 this, 165 "QuickPhraseKey", 166 _("Key to trigger quickphrase"), 167 Key{FcitxKey_semicolon}, 168 {KeyConstrainFlag::AllowModifierLess}}; 169 Option<bool> useVAsQuickphrase{this, "VAsQuickphrase", 170 _("Use V to trigger quickphrase"), true}; 171 ExternalOption quickphrase{this, "QuickPhrase", _("Quick Phrase"), 172 "fcitx://config/addon/quickphrase/editor"}; 173 OptionWithAnnotation<std::vector<std::string>, ToolTipAnnotation> 174 quickphraseTrigger{this, 175 "QuickPhrase trigger", 176 _("Strings to trigger quick phrase"), 177 {"www.", "ftp.", "http:", "mail.", "bbs.", "forum.", 178 "https:", "ftp:", "telnet:", "mailto:"}, 179 {}, 180 {}, 181 {_("Enter a string from the list will make it enter " 182 "quickphrase mode.")}}; 183 Option<FuzzyConfig> fuzzyConfig{this, "Fuzzy", _("Fuzzy Pinyin Settings")}; 184 HiddenOption<bool> firstRun{this, "FirstRun", "FirstRun", true};); 185 186 class PinyinState; 187 class EventSourceTime; 188 class CandidateList; 189 190 class PinyinEngine final : public InputMethodEngine { 191 public: 192 PinyinEngine(Instance *instance); 193 ~PinyinEngine(); instance()194 Instance *instance() { return instance_; } 195 void activate(const InputMethodEntry &entry, 196 InputContextEvent &event) override; 197 void deactivate(const InputMethodEntry &entry, 198 InputContextEvent &event) override; 199 void keyEvent(const InputMethodEntry &entry, KeyEvent &keyEvent) override; 200 void reloadConfig() override; 201 void reset(const InputMethodEntry &entry, 202 InputContextEvent &event) override; 203 void doReset(InputContext *inputContext); 204 void save() override; factory()205 auto &factory() { return factory_; } 206 std::string subMode(const InputMethodEntry &entry, 207 InputContext &inputContext) override; 208 getConfig()209 const Configuration *getConfig() const override { return &config_; } setConfig(const RawConfig & config)210 void setConfig(const RawConfig &config) override { 211 config_.load(config, true); 212 safeSaveAsIni(config_, "conf/pinyin.conf"); 213 reloadConfig(); 214 } 215 void setSubConfig(const std::string &path, 216 const fcitx::RawConfig &) override; 217 ime()218 libime::PinyinIME *ime() { return ime_.get(); } 219 220 void initPredict(InputContext *inputContext); 221 void updatePredict(InputContext *inputContext); 222 std::unique_ptr<CandidateList> 223 predictCandidateList(const std::vector<std::string> &words); 224 void updateUI(InputContext *inputContext); 225 226 void resetStroke(InputContext *inputContext); 227 void resetForgetCandidate(InputContext *inputContext); 228 229 private: 230 void cloudPinyinSelected(InputContext *inputContext, 231 const std::string &selected, 232 const std::string &word); 233 234 bool handleCloudpinyinTrigger(KeyEvent &event); 235 bool handle2nd3rdSelection(KeyEvent &event); 236 bool handleCandidateList(KeyEvent &event); 237 bool handleStrokeFilter(KeyEvent &event); 238 bool handleForgetCandidate(KeyEvent &event); 239 bool handlePunc(KeyEvent &event); 240 241 void updateStroke(InputContext *inputContext); 242 void updateForgetCandidate(InputContext *inputContext); 243 244 void updatePreedit(InputContext *inputContext) const; 245 246 #ifdef FCITX_HAS_LUA 247 std::vector<std::string> 248 luaCandidateTrigger(InputContext *ic, const std::string &candidateString); 249 #endif 250 void loadExtraDict(); 251 void loadDict(const StandardPathFile &file); 252 253 Instance *instance_; 254 PinyinEngineConfig config_; 255 std::unique_ptr<libime::PinyinIME> ime_; 256 std::unordered_map<std::string, std::unordered_set<uint32_t>> 257 quickphraseTriggerDict_; 258 KeyList selectionKeys_; 259 FactoryFor<PinyinState> factory_; 260 SimpleAction predictionAction_; 261 libime::Prediction prediction_; 262 std::unique_ptr<EventSource> deferEvent_; 263 std::unique_ptr<HandlerTableEntry<EventHandler>> event_; 264 265 FCITX_ADDON_DEPENDENCY_LOADER(quickphrase, instance_->addonManager()); 266 FCITX_ADDON_DEPENDENCY_LOADER(cloudpinyin, instance_->addonManager()); 267 FCITX_ADDON_DEPENDENCY_LOADER(fullwidth, instance_->addonManager()); 268 FCITX_ADDON_DEPENDENCY_LOADER(chttrans, instance_->addonManager()); 269 FCITX_ADDON_DEPENDENCY_LOADER(punctuation, instance_->addonManager()); 270 FCITX_ADDON_DEPENDENCY_LOADER(notifications, instance_->addonManager()); 271 FCITX_ADDON_DEPENDENCY_LOADER(pinyinhelper, instance_->addonManager()); 272 FCITX_ADDON_DEPENDENCY_LOADER(spell, instance_->addonManager()); 273 FCITX_ADDON_DEPENDENCY_LOADER(imeapi, instance_->addonManager()); 274 }; 275 276 class PinyinEngineFactory : public AddonFactory { 277 public: create(AddonManager * manager)278 AddonInstance *create(AddonManager *manager) override { 279 registerDomain("fcitx5-chinese-addons", FCITX_INSTALL_LOCALEDIR); 280 return new PinyinEngine(manager->instance()); 281 } 282 }; 283 } // namespace fcitx 284 285 #endif // _PINYIN_PINYIN_H_ 286