1 /* vim:set et ts=4 sts=4:
3 * ibus-libpinyin - Intelligent Pinyin engine based on libpinyin for IBus
5 * Copyright (c) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
6 * Copyright (c) 2011 Peng Wu <alexepico@gmail.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "PYPPinyinEngine.h"
25 #include "PYPConfig.h"
26 #include "PYPunctEditor.h"
27 #include "PYRawEditor.h"
28 #ifdef IBUS_BUILD_LUA_EXTENSION
29 #include "PYExtEditor.h"
31 #ifdef IBUS_BUILD_ENGLISH_INPUT_MODE
32 #include "PYEnglishEditor.h"
34 #ifdef IBUS_BUILD_STROKE_INPUT_MODE
35 #include "PYStrokeEditor.h"
37 #include "PYPFullPinyinEditor.h"
38 #include "PYPDoublePinyinEditor.h"
39 #include "PYFallbackEditor.h"
44 LibPinyinPinyinEngine::LibPinyinPinyinEngine (IBusEngine *engine)
46 m_props (LibPinyinPinyinConfig::instance ()),
47 m_prev_pressed_key (IBUS_VoidSymbol),
48 m_input_mode (MODE_INIT),
49 m_fallback_editor (new FallbackEditor (m_props, LibPinyinPinyinConfig::instance ()))
53 m_double_pinyin = LibPinyinPinyinConfig::instance ().doublePinyin ();
56 m_editors[MODE_INIT].reset
57 (new LibPinyinDoublePinyinEditor (m_props, LibPinyinPinyinConfig::instance ()));
59 m_editors[MODE_INIT].reset
60 (new LibPinyinFullPinyinEditor (m_props, LibPinyinPinyinConfig::instance ()));
62 m_editors[MODE_PUNCT].reset
63 (new PunctEditor (m_props, LibPinyinPinyinConfig::instance ()));
64 m_editors[MODE_RAW].reset
65 (new RawEditor (m_props, LibPinyinPinyinConfig::instance ()));
67 #ifdef IBUS_BUILD_LUA_EXTENSION
68 m_editors[MODE_EXTENSION].reset (new ExtEditor (m_props, LibPinyinPinyinConfig::instance ()));
70 m_editors[MODE_EXTENSION].reset (new Editor (m_props, LibPinyinPinyinConfig::instance ()));
72 #ifdef IBUS_BUILD_ENGLISH_INPUT_MODE
73 m_editors[MODE_ENGLISH].reset (new EnglishEditor (m_props, LibPinyinPinyinConfig::instance ()));
75 m_editors[MODE_ENGLISH].reset (new Editor (m_props, LibPinyinPinyinConfig::instance ()));
77 #ifdef IBUS_BUILD_STROKE_INPUT_MODE
78 m_editors[MODE_STROKE].reset (new StrokeEditor (m_props, LibPinyinPinyinConfig::instance ()));
80 m_editors[MODE_STROKE].reset (new Editor (m_props, LibPinyinPinyinConfig::instance ()));
83 m_props.signalUpdateProperty ().connect
84 (std::bind (&LibPinyinPinyinEngine::updateProperty, this, _1));
86 for (i = MODE_INIT; i < MODE_LAST; i++) {
87 connectEditorSignals (m_editors[i]);
90 connectEditorSignals (m_fallback_editor);
94 LibPinyinPinyinEngine::~LibPinyinPinyinEngine (void)
99 LibPinyinPinyinEngine::processKeyEvent (guint keyval, guint keycode, guint modifiers)
101 gboolean retval = FALSE;
103 /* check Shift or Ctrl + Release hotkey,
104 * and then ignore other Release key event */
105 if (modifiers & IBUS_RELEASE_MASK) {
106 /* press and release keyval are same,
107 * and no other key event between the press and release key event */
108 gboolean triggered = FALSE;
110 if (m_prev_pressed_key == keyval){
111 if (LibPinyinPinyinConfig::instance ().ctrlSwitch ()) {
112 if (keyval == IBUS_Control_L || keyval == IBUS_Control_R)
115 if (keyval == IBUS_Shift_L || keyval == IBUS_Shift_R)
121 if (!m_editors[MODE_INIT]->text ().empty ())
122 m_editors[MODE_INIT]->reset ();
123 m_props.toggleModeChinese ();
127 if (m_input_mode == MODE_INIT &&
128 m_editors[MODE_INIT]->text ().empty ()) {
129 /* If it is in init mode, and no any previous input text,
130 * we will let client applications to handle release key event */
138 /* Toggle simp/trad Chinese Mode when hotkey Ctrl + Shift + F pressed */
139 if (keyval == IBUS_F && scmshm_test (modifiers, (IBUS_SHIFT_MASK | IBUS_CONTROL_MASK))) {
140 m_props.toggleModeSimp ();
141 m_prev_pressed_key = IBUS_F;
145 if (m_props.modeChinese ()) {
146 if (m_input_mode == MODE_INIT &&
147 (cmshm_filter (modifiers) == 0)) {
148 const String & text = m_editors[MODE_INIT]->text ();
152 m_input_mode = MODE_PUNCT;
154 #ifdef IBUS_BUILD_LUA_EXTENSION
156 // do not enable lua extension when use double pinyin.
157 if (LibPinyinPinyinConfig::instance ().doublePinyin ())
159 m_input_mode = MODE_EXTENSION;
162 #ifdef IBUS_BUILD_ENGLISH_INPUT_MODE
164 // do not enable english mode when use double pinyin.
165 if (LibPinyinPinyinConfig::instance ().doublePinyin ())
167 m_input_mode = MODE_ENGLISH;
170 #ifdef IBUS_BUILD_STROKE_INPUT_MODE
172 // do not enable stroke mode when use double pinyin.
173 if (LibPinyinPinyinConfig::instance ().doublePinyin ())
175 m_input_mode = MODE_STROKE;
183 retval = m_editors[m_input_mode]->processKeyEvent (keyval, keycode, modifiers);
184 if (G_UNLIKELY (retval &&
185 m_input_mode != MODE_INIT &&
186 m_editors[m_input_mode]->text ().empty ()))
187 m_input_mode = MODE_INIT;
190 if (G_UNLIKELY (!retval))
191 retval = m_fallback_editor->processKeyEvent (keyval, keycode, modifiers);
193 /* store ignored key event by editors */
194 m_prev_pressed_key = retval ? IBUS_VoidSymbol : keyval;
200 LibPinyinPinyinEngine::focusIn (void)
202 /* TODO: check memory leak here,
203 * or switch full/double pinyin when pinyin config is changed.*/
204 if (LibPinyinPinyinConfig::instance ().doublePinyin ()) {
205 if (!m_double_pinyin) {
206 m_editors[MODE_INIT].reset (new LibPinyinDoublePinyinEditor (m_props, LibPinyinPinyinConfig::instance ()));
207 connectEditorSignals (m_editors[MODE_INIT]);
209 m_double_pinyin = TRUE;
212 if (m_double_pinyin) {
213 m_editors[MODE_INIT].reset (new LibPinyinFullPinyinEditor (m_props, LibPinyinPinyinConfig::instance ()));
214 connectEditorSignals (m_editors[MODE_INIT]);
216 m_double_pinyin = FALSE;
219 registerProperties (m_props.properties ());
223 LibPinyinPinyinEngine::focusOut (void)
229 LibPinyinPinyinEngine::reset (void)
231 m_prev_pressed_key = IBUS_VoidSymbol;
232 m_input_mode = MODE_INIT;
233 for (gint i = 0; i < MODE_LAST; i++) {
234 m_editors[i]->reset ();
236 m_fallback_editor->reset ();
240 LibPinyinPinyinEngine::enable (void)
246 LibPinyinPinyinEngine::disable (void)
251 LibPinyinPinyinEngine::pageUp (void)
253 m_editors[m_input_mode]->pageUp ();
257 LibPinyinPinyinEngine::pageDown (void)
259 m_editors[m_input_mode]->pageDown ();
263 LibPinyinPinyinEngine::cursorUp (void)
265 m_editors[m_input_mode]->cursorUp ();
269 LibPinyinPinyinEngine::cursorDown (void)
271 m_editors[m_input_mode]->cursorDown ();
275 LibPinyinPinyinEngine::showSetupDialog (void)
277 g_spawn_command_line_async
278 (LIBEXECDIR"/ibus-setup-libpinyin pinyin", NULL);
282 LibPinyinPinyinEngine::propertyActivate (const char *prop_name, guint prop_state)
284 const static String setup ("setup");
285 if (m_props.propertyActivate (prop_name, prop_state)) {
288 else if (setup == prop_name) {
296 LibPinyinPinyinEngine::candidateClicked (guint index, guint button, guint state)
298 m_editors[m_input_mode]->candidateClicked (index, button, state);
302 LibPinyinPinyinEngine::commitText (Text & text)
304 Engine::commitText (text);
305 if (m_input_mode != MODE_INIT)
306 m_input_mode = MODE_INIT;
308 /* handle "<num>+.<num>+" here */
310 static_cast<FallbackEditor*> (m_fallback_editor.get ())->setPrevCommittedChar (*text.text ());
312 static_cast<FallbackEditor*> (m_fallback_editor.get ())->setPrevCommittedChar (0);
317 LibPinyinPinyinEngine::connectEditorSignals (EditorPtr editor)
319 editor->signalCommitText ().connect (
320 std::bind (&LibPinyinPinyinEngine::commitText, this, _1));
322 editor->signalUpdatePreeditText ().connect (
323 std::bind (&LibPinyinPinyinEngine::updatePreeditText, this, _1, _2, _3));
324 editor->signalShowPreeditText ().connect (
325 std::bind (&LibPinyinPinyinEngine::showPreeditText, this));
326 editor->signalHidePreeditText ().connect (
327 std::bind (&LibPinyinPinyinEngine::hidePreeditText, this));
329 editor->signalUpdateAuxiliaryText ().connect (
330 std::bind (&LibPinyinPinyinEngine::updateAuxiliaryText, this, _1, _2));
331 editor->signalShowAuxiliaryText ().connect (
332 std::bind (&LibPinyinPinyinEngine::showAuxiliaryText, this));
333 editor->signalHideAuxiliaryText ().connect (
334 std::bind (&LibPinyinPinyinEngine::hideAuxiliaryText, this));
336 editor->signalUpdateLookupTable ().connect (
337 std::bind (&LibPinyinPinyinEngine::updateLookupTable, this, _1, _2));
338 editor->signalUpdateLookupTableFast ().connect (
339 std::bind (&LibPinyinPinyinEngine::updateLookupTableFast, this, _1, _2));
340 editor->signalShowLookupTable ().connect (
341 std::bind (&LibPinyinPinyinEngine::showLookupTable, this));
342 editor->signalHideLookupTable ().connect (
343 std::bind (&LibPinyinPinyinEngine::hideLookupTable, this));