1 /* vim:set et ts=4 sts=4:
3 * ibus-libpinyin - Intelligent Pinyin engine based on libpinyin for IBus
5 * Copyright (c) 2011 Peng Wu <alexepico@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "PYPBopomofoEditor.h"
23 #include "PYLibPinyin.h"
24 #include "PYPinyinProperties.h"
25 #include "PYSimpTradConverter.h"
26 #include "PYHalfFullConverter.h"
31 const static gchar * bopomofo_select_keys[] = {
43 LibPinyinBopomofoEditor::LibPinyinBopomofoEditor
44 (PinyinProperties & props, Config & config)
45 : LibPinyinPhoneticEditor (props, config),
48 m_instance = LibPinyinBackEnd::instance ().allocChewingInstance ();
51 LibPinyinBopomofoEditor::~LibPinyinBopomofoEditor (void)
53 LibPinyinBackEnd::instance ().freeChewingInstance (m_instance);
58 LibPinyinBopomofoEditor::reset (void)
60 m_select_mode = FALSE;
61 LibPinyinPhoneticEditor::reset ();
65 LibPinyinBopomofoEditor::insert (gint ch)
68 if (G_UNLIKELY (m_text.length () >= MAX_PINYIN_LEN))
71 m_text.insert (m_cursor++, ch);
80 LibPinyinBopomofoEditor::processGuideKey (guint keyval, guint keycode,
83 if (!m_config.guideKey ())
86 if (G_UNLIKELY (cmshm_filter (modifiers) != 0))
89 if (G_LIKELY (m_select_mode))
92 if (G_UNLIKELY (keyval == IBUS_space)) {
102 LibPinyinBopomofoEditor::processAuxiliarySelectKey
103 (guint keyval, guint keycode, guint modifiers)
105 if (G_UNLIKELY (cmshm_filter (modifiers) != 0))
113 if (!m_config.auxiliarySelectKeyKP ())
116 case IBUS_KP_1 ... IBUS_KP_9:
117 i = keyval - IBUS_KP_1;
118 if (!m_config.auxiliarySelectKeyKP ())
121 case IBUS_F1 ... IBUS_F10:
122 i = keyval - IBUS_F1;
123 if (!m_config.auxiliarySelectKeyF ())
130 m_select_mode = TRUE;
131 selectCandidateInPage (i);
138 LibPinyinBopomofoEditor::processSelectKey (guint keyval, guint keycode,
141 if (G_UNLIKELY (!m_text))
144 if (G_LIKELY (!m_select_mode && ((modifiers & IBUS_MOD1_MASK) == 0)))
147 const gchar * pos = NULL;
148 const gchar * keys = bopomofo_select_keys[m_config.selectKeys ()];
149 for ( const gchar * p = keys; *p; ++p ) {
157 m_select_mode = TRUE;
159 guint i = pos - keys;
160 selectCandidateInPage (i);
167 LibPinyinBopomofoEditor::processBopomofo (guint keyval, guint keycode,
170 if (G_UNLIKELY (cmshm_filter (modifiers) != 0))
171 return m_text ? TRUE : FALSE;
173 if (!(pinyin_in_chewing_keyboard (m_instance, keyval, NULL)))
176 if (keyval == IBUS_space)
179 m_select_mode = FALSE;
181 return insert (keyval);
185 LibPinyinBopomofoEditor::processKeyEvent (guint keyval, guint keycode,
188 modifiers &= (IBUS_SHIFT_MASK |
196 if (G_UNLIKELY (processGuideKey (keyval, keycode, modifiers)))
198 if (G_UNLIKELY (processSelectKey (keyval, keycode, modifiers)))
200 if (G_UNLIKELY (processAuxiliarySelectKey (keyval, keycode,
203 if (G_LIKELY (processBopomofo (keyval, keycode, modifiers)))
208 m_select_mode = TRUE;
209 return processSpace (keyval, keycode, modifiers);
211 case IBUS_Up: case IBUS_KP_Up:
212 case IBUS_Down: case IBUS_KP_Down:
213 case IBUS_Page_Up: case IBUS_KP_Page_Up:
214 case IBUS_Page_Down: case IBUS_KP_Page_Down:
216 m_select_mode = TRUE;
217 return LibPinyinPhoneticEditor::processFunctionKey
218 (keyval, keycode, modifiers);
221 case IBUS_Delete: case IBUS_KP_Delete:
222 case IBUS_Left: case IBUS_KP_Left:
223 case IBUS_Right: case IBUS_KP_Right:
224 case IBUS_Home: case IBUS_KP_Home:
225 case IBUS_End: case IBUS_KP_End:
226 m_select_mode = FALSE;
227 return LibPinyinPhoneticEditor::processFunctionKey
228 (keyval, keycode, modifiers);
231 return LibPinyinPhoneticEditor::processFunctionKey
232 (keyval, keycode, modifiers);
238 LibPinyinBopomofoEditor::updatePinyin (void)
240 if (G_UNLIKELY (m_text.empty ())) {
242 /* TODO: check whether to replace "" with NULL. */
243 pinyin_parse_more_chewings (m_instance, "");
244 pinyin_guess_sentence (m_instance);
249 pinyin_parse_more_chewings (m_instance, m_text.c_str ());
250 pinyin_guess_sentence (m_instance);
254 LibPinyinBopomofoEditor::commit ()
256 if (G_UNLIKELY (m_text.empty ()))
261 /* sentence candidate */
263 pinyin_get_sentence (m_instance, &tmp);
265 if (m_props.modeSimp ()) {
268 SimpTradConverter::simpToTrad (tmp, m_buffer);
273 /* text after pinyin */
274 const gchar *p = m_text.c_str() + m_pinyin_len;
276 const char * symbol = NULL;
277 if (pinyin_in_chewing_keyboard(m_instance, *p, &symbol)) {
280 if (G_UNLIKELY (m_props.modeFull ())) {
281 m_buffer.appendUnichar (HalfFullConverter::toFull (*p));
289 pinyin_train(m_instance);
290 LibPinyinBackEnd::instance ().modified();
291 LibPinyinPhoneticEditor::commit ((const gchar *)m_buffer);
296 LibPinyinBopomofoEditor::updatePreeditText ()
298 /* preedit text = guessed sentence + un-parsed pinyin text */
299 if (G_UNLIKELY (m_text.empty ())) {
306 pinyin_get_sentence(m_instance, &tmp);
308 if (m_props.modeSimp ()) {
311 SimpTradConverter::simpToTrad (tmp, m_buffer);
317 /* append rest text */
318 const gchar *p = m_text.c_str () + m_pinyin_len;
321 StaticText preedit_text (m_buffer);
323 preedit_text.appendAttribute (IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, -1);
325 guint pinyin_cursor = getPinyinCursor ();
326 Editor::updatePreeditText (preedit_text, pinyin_cursor, TRUE);
330 LibPinyinBopomofoEditor::updateAuxiliaryText (void)
332 if (G_UNLIKELY (m_text.empty ())) {
333 hideAuxiliaryText ();
340 pinyin_get_n_pinyin (m_instance, &len);
342 for (guint i = 0; i < len; ++i) {
343 PinyinKey *key = NULL;
344 pinyin_get_pinyin_key (m_instance, i, &key);
346 PinyinKeyPos *pos = NULL;
347 pinyin_get_pinyin_key_rest (m_instance, i, &pos);
349 guint16 cursor = 0, end = 0;
350 pinyin_get_pinyin_key_rest_positions (m_instance, pos, &cursor, &end);
353 if (G_UNLIKELY (cursor == m_cursor)) { /* at word boundary. */
354 pinyin_get_chewing_string (m_instance, key, &str);
355 m_buffer << '|' << str;
357 } else if (G_LIKELY (cursor < m_cursor &&
358 m_cursor < end)) { /* in word */
361 pinyin_get_pinyin_key_rest_length (m_instance, pos, &length);
363 String raw = m_text.substr (cursor, length);
364 guint offset = m_cursor - cursor;
366 String before = raw.substr (0, offset);
367 String after = raw.substr (offset);
368 String::const_iterator iter;
369 const char * symbol = NULL;
370 for ( iter = before.begin (); iter != before.end (); ++iter) {
371 if ( pinyin_in_chewing_keyboard(m_instance, *iter, &symbol))
377 for ( iter = after.begin (); iter != after.end (); ++iter) {
378 if ( pinyin_in_chewing_keyboard (m_instance, *iter, &symbol))
383 } else { /* other words */
384 pinyin_get_chewing_string (m_instance, key, &str);
385 m_buffer << ' ' << str;
390 if (m_cursor == m_pinyin_len)
393 /* append rest text */
394 const gchar * p = m_text.c_str() + m_pinyin_len;
397 StaticText aux_text (m_buffer);
398 Editor::updateAuxiliaryText (aux_text, TRUE);