12
12
* SPDX-FileCopyrightText: Copyright (c) 2021 Naoaki Iwakiri
13
13
*/
14
14
#include " cskk.h"
15
+ #include " cskkcandidatelist.h"
16
+ #include " log.h"
15
17
#include < cstdlib>
18
+ #include < cstring>
16
19
#include < fcitx-config/iniparser.h>
17
- #include < fcitx-utils/log.h>
18
20
#include < fcitx/addonmanager.h>
19
21
#include < fcitx/inputpanel.h>
20
22
#include < filesystem>
24
26
using std::getenv;
25
27
using std::string;
26
28
27
- namespace fcitx {
28
29
FCITX_DEFINE_LOG_CATEGORY (cskk_log, " cskk" );
29
30
30
- #define CSKK_DEBUG () FCITX_LOGC(cskk_log, Debug) << " \t **CSKK** "
31
- #define CSKK_WARN () FCITX_LOGC(cskk_log, Warn) << " \t **CSKK** "
31
+ namespace fcitx {
32
32
33
33
/* ******************************************************************************
34
- * CskkEngine
34
+ * FcitxCskkEngine
35
35
******************************************************************************/
36
- const string CskkEngine::config_file_path = " conf/fcitx5-cskk" ;
37
- CskkEngine::CskkEngine (Instance *instance)
36
+ const string FcitxCskkEngine::config_file_path = string{" conf/fcitx5-cskk" };
37
+
38
+ const uint FcitxCskkEngine::pageStartIdx = 3 ;
39
+ const CandidateLayoutHint FcitxCskkEngine::layoutHint =
40
+ CandidateLayoutHint::Horizontal;
41
+
42
+ FcitxCskkEngine::FcitxCskkEngine (Instance *instance)
38
43
: instance_{instance}, factory_([this ](InputContext &ic) {
39
44
auto newCskkContext = new FcitxCskkContext (this , &ic);
40
45
newCskkContext->applyConfig ();
@@ -43,39 +48,39 @@ CskkEngine::CskkEngine(Instance *instance)
43
48
reloadConfig ();
44
49
instance_->inputContextManager ().registerProperty (" cskkcontext" , &factory_);
45
50
}
46
- CskkEngine ::~CskkEngine () = default ;
47
- void CskkEngine ::keyEvent (const InputMethodEntry &, KeyEvent &keyEvent) {
51
+ FcitxCskkEngine ::~FcitxCskkEngine () = default ;
52
+ void FcitxCskkEngine ::keyEvent (const InputMethodEntry &, KeyEvent &keyEvent) {
48
53
CSKK_DEBUG () << " Engine keyEvent start: " << keyEvent.rawKey ();
49
54
// delegate to context
50
55
auto ic = keyEvent.inputContext ();
51
56
auto context = ic->propertyFor (&factory_);
52
57
context->keyEvent (keyEvent);
53
58
CSKK_DEBUG () << " Engine keyEvent end" ;
54
59
}
55
- void CskkEngine ::save () {}
56
- void CskkEngine ::activate (const InputMethodEntry &, InputContextEvent &) {}
57
- void CskkEngine ::deactivate (const InputMethodEntry &entry,
58
- InputContextEvent &event) {
60
+ void FcitxCskkEngine ::save () {}
61
+ void FcitxCskkEngine ::activate (const InputMethodEntry &, InputContextEvent &) {}
62
+ void FcitxCskkEngine ::deactivate (const InputMethodEntry &entry,
63
+ InputContextEvent &event) {
59
64
FCITX_UNUSED (entry);
60
65
reset (entry, event);
61
66
}
62
- void CskkEngine ::reset (const InputMethodEntry &entry,
63
- InputContextEvent &event) {
67
+ void FcitxCskkEngine ::reset (const InputMethodEntry &entry,
68
+ InputContextEvent &event) {
64
69
FCITX_UNUSED (entry);
65
70
CSKK_DEBUG () << " Reset" ;
66
71
auto ic = event.inputContext ();
67
72
auto context = ic->propertyFor (&factory_);
68
73
context->reset ();
69
74
}
70
- void CskkEngine ::setConfig (const RawConfig &config) {
75
+ void FcitxCskkEngine ::setConfig (const RawConfig &config) {
71
76
CSKK_DEBUG () << " Cskk setconfig" ;
72
77
config_.load (config, true );
73
- safeSaveAsIni (config_, CskkEngine ::config_file_path);
78
+ safeSaveAsIni (config_, FcitxCskkEngine ::config_file_path);
74
79
reloadConfig ();
75
80
}
76
- void CskkEngine ::reloadConfig () {
81
+ void FcitxCskkEngine ::reloadConfig () {
77
82
CSKK_DEBUG () << " Cskkengine reload config" ;
78
- readAsIni (config_, CskkEngine ::config_file_path);
83
+ readAsIni (config_, FcitxCskkEngine ::config_file_path);
79
84
80
85
loadDictionary ();
81
86
if (factory_.registered ()) {
@@ -86,7 +91,7 @@ void CskkEngine::reloadConfig() {
86
91
});
87
92
}
88
93
}
89
- void CskkEngine ::loadDictionary () {
94
+ void FcitxCskkEngine ::loadDictionary () {
90
95
freeDictionaries ();
91
96
92
97
const std::filesystem::directory_options directoryOptions =
@@ -128,7 +133,7 @@ void CskkEngine::loadDictionary() {
128
133
}
129
134
}
130
135
}
131
- std::string CskkEngine ::getXDGDataHome () {
136
+ std::string FcitxCskkEngine ::getXDGDataHome () {
132
137
const char *xdgDataHomeEnv = getenv (" XDG_DATA_HOME" );
133
138
const char *homeEnv = getenv (" $HOME" );
134
139
if (xdgDataHomeEnv) {
@@ -139,7 +144,7 @@ std::string CskkEngine::getXDGDataHome() {
139
144
return " " ;
140
145
}
141
146
142
- std::vector<std::string> CskkEngine ::getXDGDataDirs () {
147
+ std::vector<std::string> FcitxCskkEngine ::getXDGDataDirs () {
143
148
const char *xdgDataDirEnv = getenv (" XDG_DATA_DIRS" );
144
149
string rawDirs;
145
150
@@ -164,7 +169,7 @@ std::vector<std::string> CskkEngine::getXDGDataDirs() {
164
169
CSKK_DEBUG () << xdgDataDirs;
165
170
return xdgDataDirs;
166
171
}
167
- void CskkEngine ::freeDictionaries () {
172
+ void FcitxCskkEngine ::freeDictionaries () {
168
173
CSKK_DEBUG () << " Cskk free dict" ;
169
174
for (auto dictionary : dictionaries_) {
170
175
skk_free_dictionary (dictionary);
@@ -176,57 +181,119 @@ void CskkEngine::freeDictionaries() {
176
181
* CskkContext
177
182
******************************************************************************/
178
183
179
- FcitxCskkContext::FcitxCskkContext (CskkEngine *engine, InputContext *ic)
184
+ FcitxCskkContext::FcitxCskkContext (FcitxCskkEngine *engine, InputContext *ic)
180
185
: context_(skk_context_new(nullptr , 0 )), ic_(ic), engine_(engine) {
181
186
CSKK_DEBUG () << " Cskk context new" ;
182
187
skk_context_set_input_mode (context_, *engine_->config ().inputMode );
183
188
}
184
189
FcitxCskkContext::~FcitxCskkContext () = default ;
185
190
void FcitxCskkContext::keyEvent (KeyEvent &keyEvent) {
186
- // TODO: handleCandidate to utilize fcitx's paged candidate list
191
+ auto candidateList = std::dynamic_pointer_cast<FcitxCskkCandidateList>(
192
+ ic_->inputPanel ().candidateList ());
193
+ if (candidateList != nullptr && !candidateList->empty ()) {
194
+ if (handleCandidateSelection (candidateList, keyEvent)) {
195
+ updateUI ();
196
+ return ;
197
+ }
198
+ }
199
+
200
+ if (skk_context_get_composition_mode (context_) !=
201
+ CompositionMode::CompositionSelection) {
202
+ CSKK_DEBUG () << " not composition selection. destroy candidate list." ;
203
+ ic_->inputPanel ().setCandidateList (nullptr );
204
+ }
187
205
188
206
uint32_t modifiers =
189
207
static_cast <uint32_t >(keyEvent.rawKey ().states () & KeyState::SimpleMask);
190
-
191
208
CskkKeyEvent *cskkKeyEvent = skk_key_event_new_from_fcitx_keyevent (
192
209
keyEvent.rawKey ().sym (), modifiers, keyEvent.isRelease ());
193
210
194
211
if (skk_context_process_key_event (context_, cskkKeyEvent)) {
195
212
CSKK_DEBUG () << " Key processed in context." ;
196
213
keyEvent.filterAndAccept ();
197
214
}
215
+
198
216
if (keyEvent.filtered ()) {
199
217
updateUI ();
200
218
}
201
219
}
202
- void FcitxCskkContext::commitPreedit () {
203
- auto str = skk_context_get_preedit (context_);
204
- ic_->commitString (str);
205
- skk_free_string (str);
220
+ bool FcitxCskkContext::handleCandidateSelection (
221
+ const std::shared_ptr<FcitxCskkCandidateList> &candidateList,
222
+ KeyEvent &keyEvent) {
223
+ if (keyEvent.isRelease ()) {
224
+ return false ;
225
+ }
226
+ CSKK_DEBUG () << " handleCandidateSelection" ;
227
+
228
+ if (keyEvent.key ().checkKeyList (std::vector{Key (FcitxKey_Up)})) {
229
+ candidateList->prevCandidate ();
230
+ keyEvent.filterAndAccept ();
231
+ } else if (keyEvent.key ().checkKeyList (
232
+ std::vector{Key (FcitxKey_Down), Key (FcitxKey_space)})) {
233
+ CSKK_DEBUG () << " space key caught in handle candidate" ;
234
+
235
+ candidateList->nextCandidate ();
236
+ keyEvent.filterAndAccept ();
237
+ } else if (keyEvent.key ().check (Key (FcitxKey_Page_Down))) {
238
+ keyEvent.filterAndAccept ();
239
+ } else if (keyEvent.key ().check (Key (FcitxKey_Page_Up))) {
240
+ keyEvent.filterAndAccept ();
241
+ } else if (keyEvent.key ().check (Key (FcitxKey_Return))) {
242
+ CSKK_DEBUG () << " return key caught in handle candidate" ;
243
+ candidateList->candidate (candidateList->cursorIndex ()).select (ic_);
244
+ keyEvent.filterAndAccept ();
245
+ }
246
+
247
+ return keyEvent.filtered ();
248
+ }
249
+
250
+ void FcitxCskkContext::reset () {
251
+ skk_context_reset (context_);
252
+ updateUI ();
206
253
}
207
- void FcitxCskkContext::reset () { skk_context_reset (context_); }
208
254
void FcitxCskkContext::updateUI () {
209
255
auto &inputPanel = ic_->inputPanel ();
210
256
211
257
// Output
212
258
if (auto output = skk_context_poll_output (context_)) {
213
- FCITX_DEBUG () << " **** CSKK output " << output;
259
+ CSKK_DEBUG () << " output: " << output;
214
260
if (strlen (output) > 0 ) {
215
261
ic_->commitString (output);
216
262
}
217
263
skk_free_string (output);
218
264
}
219
265
220
266
// Preedit
221
- // TODO: candidate in preedit?
222
- inputPanel.reset ();
223
267
auto preedit = skk_context_get_preedit (context_);
224
268
Text preeditText;
225
269
// FIXME: Pretty text format someday.
226
270
preeditText.append (std::string (preedit));
227
- // FIXME: Narrowing conversion without check
228
271
preeditText.setCursor (static_cast <int >(strlen (preedit)));
229
272
273
+ // CandidateList
274
+ int current_idx = skk_context_get_current_canddiate_selection_at (context_);
275
+ if (current_idx >= static_cast <int >(FcitxCskkEngine::pageStartIdx)) {
276
+ char *current_to_composite = skk_context_get_current_to_composite (context_);
277
+ auto candidateList = std::dynamic_pointer_cast<FcitxCskkCandidateList>(
278
+ ic_->inputPanel ().candidateList ());
279
+ if (candidateList == nullptr || candidateList->empty () ||
280
+ (strcmp (candidateList->to_composite ().c_str (), current_to_composite) !=
281
+ 0 )) {
282
+ // update whole candidateList only if needed
283
+ CSKK_DEBUG () << " Set new candidate list on UI update" ;
284
+
285
+ inputPanel.setCandidateList (
286
+ std::make_unique<FcitxCskkCandidateList>(engine_, ic_));
287
+ } else {
288
+ // Sync in case idx has changed out of input panel
289
+ candidateList->setCursorIndex (
290
+ static_cast <int >(current_idx - FcitxCskkEngine::pageStartIdx));
291
+ }
292
+
293
+ } else {
294
+ inputPanel.setCandidateList (nullptr );
295
+ }
296
+
230
297
if (ic_->capabilityFlags ().test (CapabilityFlag::Preedit)) {
231
298
inputPanel.setClientPreedit (preeditText);
232
299
ic_->updatePreedit ();
@@ -247,17 +314,17 @@ void FcitxCskkContext::copyTo(InputContextProperty *context) {
247
314
}
248
315
249
316
/* ******************************************************************************
250
- * CskkFactory
317
+ * FcitxCskkFactory
251
318
******************************************************************************/
252
319
253
- AddonInstance *CskkFactory ::create (AddonManager *manager) {
320
+ AddonInstance *FcitxCskkFactory ::create (AddonManager *manager) {
254
321
{
255
- CSKK_DEBUG () << " **** CSKK CskkFactory Create ****" ;
322
+ CSKK_DEBUG () << " **** CSKK FcitxCskkFactory Create ****" ;
256
323
registerDomain (" fcitx5-cskk" , FCITX_INSTALL_LOCALEDIR);
257
- auto engine = new CskkEngine (manager->instance ());
324
+ auto engine = new FcitxCskkEngine (manager->instance ());
258
325
return engine;
259
326
}
260
327
}
261
328
} // namespace fcitx
262
329
263
- FCITX_ADDON_FACTORY (fcitx::CskkFactory );
330
+ FCITX_ADDON_FACTORY (fcitx::FcitxCskkFactory );
0 commit comments