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 "PYPPhoneticEditor.h"
23 #include "PYPinyinProperties.h"
24 #include "PYSimpTradConverter.h"
28 /* init static members */
29 LibPinyinPhoneticEditor::LibPinyinPhoneticEditor (PinyinProperties &props,
31 Editor (props, config),
33 m_lookup_table (m_config.pageSize ())
37 LibPinyinPhoneticEditor::~LibPinyinPhoneticEditor (){
41 LibPinyinPhoneticEditor::processSpace (guint keyval, guint keycode,
46 if (cmshm_filter (modifiers) != 0)
49 if (m_lookup_table.size () != 0) {
50 selectCandidate (m_lookup_table.cursorPos ());
61 LibPinyinPhoneticEditor::processFunctionKey (guint keyval, guint keycode, guint modifiers)
67 modifiers = cmshm_filter (modifiers);
69 if (modifiers != 0 && modifiers != IBUS_CONTROL_MASK)
72 /* process some cursor control keys */
73 if (modifiers == 0) { /* no modifiers. */
77 commit (m_text.c_str ());
102 moveCursorToBegin ();
121 case IBUS_KP_Page_Up:
126 case IBUS_KP_Page_Down:
137 } else { /* ctrl key pressed. */
150 moveCursorLeftByWord ();
155 moveCursorRightByWord ();
166 LibPinyinPhoneticEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers)
172 LibPinyinPhoneticEditor::updateLookupTableFast (void)
174 Editor::updateLookupTableFast (m_lookup_table, TRUE);
178 LibPinyinPhoneticEditor::updateLookupTable (void)
180 m_lookup_table.clear ();
182 fillLookupTableByPage ();
183 if (m_lookup_table.size()) {
184 Editor::updateLookupTable (m_lookup_table, TRUE);
191 LibPinyinPhoneticEditor::fillLookupTableByPage (void)
194 pinyin_get_n_candidate (m_instance, &len);
196 guint filled_nr = m_lookup_table.size ();
197 guint page_size = m_lookup_table.pageSize ();
199 /* fill lookup table by libpinyin get candidates. */
200 guint need_nr = MIN (page_size, len - filled_nr);
201 g_assert (need_nr >=0);
206 for (guint i = filled_nr; i < filled_nr + need_nr; i++) {
207 if (i >= len) /* no more candidates */
210 lookup_candidate_t * candidate = NULL;
211 pinyin_get_candidate (m_instance, i, &candidate);
213 const gchar * phrase_string = NULL;
214 pinyin_get_candidate_string (m_instance, candidate, &phrase_string);
216 /* show get candidates. */
217 if (G_LIKELY (m_props.modeSimp ())) {
218 word = phrase_string;
219 } else { /* Traditional Chinese */
221 SimpTradConverter::simpToTrad (phrase_string, word);
225 m_lookup_table.appendCandidate (text);
232 LibPinyinPhoneticEditor::pageUp (void)
234 if (G_LIKELY (m_lookup_table.pageUp ())) {
235 updateLookupTableFast ();
236 updatePreeditText ();
237 updateAuxiliaryText ();
242 LibPinyinPhoneticEditor::pageDown (void)
244 if (G_LIKELY((m_lookup_table.pageDown ()) ||
245 (fillLookupTableByPage () && m_lookup_table.pageDown()))) {
246 updateLookupTableFast ();
247 updatePreeditText ();
248 updateAuxiliaryText ();
253 LibPinyinPhoneticEditor::cursorUp (void)
255 if (G_LIKELY (m_lookup_table.cursorUp ())) {
256 updateLookupTableFast ();
257 updatePreeditText ();
258 updateAuxiliaryText ();
263 LibPinyinPhoneticEditor::cursorDown (void)
265 if (G_LIKELY ((m_lookup_table.cursorPos () == m_lookup_table.size() - 1) &&
266 (fillLookupTableByPage () == FALSE))) {
270 if (G_LIKELY (m_lookup_table.cursorDown ())) {
271 updateLookupTableFast ();
272 updatePreeditText ();
273 updateAuxiliaryText ();
278 LibPinyinPhoneticEditor::candidateClicked (guint index, guint button, guint state)
280 selectCandidateInPage (index);
284 LibPinyinPhoneticEditor::reset (void)
287 m_lookup_table.clear ();
289 pinyin_reset (m_instance);
295 LibPinyinPhoneticEditor::update (void)
297 guint lookup_cursor = getLookupCursor ();
298 pinyin_guess_candidates (m_instance, lookup_cursor);
300 updateLookupTable ();
301 updatePreeditText ();
302 updateAuxiliaryText ();
306 LibPinyinPhoneticEditor::commit (const gchar *str)
308 StaticText text(str);
313 LibPinyinPhoneticEditor::getPinyinCursor ()
316 pinyin_get_n_pinyin (m_instance, &len);
318 /* Translate cursor position to pinyin position. */
319 guint pinyin_cursor = len;
321 guint16 prev_end = 0, cur_end;
322 for (size_t i = 0; i < len; ++i) {
323 PinyinKeyPos *pos = NULL;
324 pinyin_get_pinyin_key_rest (m_instance, i, &pos);
325 pinyin_get_pinyin_key_rest_positions (m_instance, pos, NULL, &cur_end);
327 if (prev_end <= m_cursor && m_cursor < cur_end)
333 g_assert (pinyin_cursor >= 0);
334 return pinyin_cursor;
338 LibPinyinPhoneticEditor::getLookupCursor (void)
341 pinyin_get_n_pinyin (m_instance, &len);
342 guint lookup_cursor = getPinyinCursor ();
344 /* show candidates when pinyin cursor is at end. */
345 if (lookup_cursor == len)
347 return lookup_cursor;
351 LibPinyinPhoneticEditor::selectCandidate (guint i)
354 pinyin_get_n_candidate (m_instance, &len);
356 if (G_UNLIKELY (i >= len))
359 guint lookup_cursor = getLookupCursor ();
361 lookup_candidate_t * candidate = NULL;
362 pinyin_get_candidate (m_instance, i, &candidate);
364 lookup_candidate_type_t type;
365 pinyin_get_candidate_type (m_instance, candidate, &type);
367 if (BEST_MATCH_CANDIDATE == type) {
372 lookup_cursor = pinyin_choose_candidate
373 (m_instance, lookup_cursor, candidate);
375 if (DIVIDED_CANDIDATE == type ||
376 RESPLIT_CANDIDATE == type) {
377 const gchar * str = NULL;
378 pinyin_get_raw_full_pinyin (m_instance, &str);
383 pinyin_guess_sentence (m_instance);
386 pinyin_get_n_pinyin (m_instance, &len);
387 if (lookup_cursor == len) {
388 pinyin_train(m_instance);
393 PinyinKeyPos *pos = NULL;
394 pinyin_get_pinyin_key_rest (m_instance, lookup_cursor, &pos);
397 pinyin_get_pinyin_key_rest_positions (m_instance, pos, &begin, NULL);
404 LibPinyinPhoneticEditor::selectCandidateInPage (guint i)
406 guint page_size = m_lookup_table.pageSize ();
407 guint cursor_pos = m_lookup_table.cursorPos ();
409 if (G_UNLIKELY (i >= page_size))
411 i += (cursor_pos / page_size) * page_size;
413 return selectCandidate (i);
417 LibPinyinPhoneticEditor::removeCharBefore (void)
419 if (G_UNLIKELY (m_cursor == 0))
423 m_text.erase (m_cursor, 1);
432 LibPinyinPhoneticEditor::removeCharAfter (void)
434 if (G_UNLIKELY (m_cursor == m_text.length ()))
437 m_text.erase (m_cursor, 1);
446 LibPinyinPhoneticEditor::moveCursorLeft (void)
448 if (G_UNLIKELY (m_cursor == 0))
457 LibPinyinPhoneticEditor::moveCursorRight (void)
459 if (G_UNLIKELY (m_cursor == m_text.length ()))
468 LibPinyinPhoneticEditor::moveCursorToBegin (void)
470 if (G_UNLIKELY (m_cursor == 0))
479 LibPinyinPhoneticEditor::moveCursorToEnd (void)
481 if (G_UNLIKELY (m_cursor == m_text.length ()))
484 m_cursor = m_text.length ();
490 /* move cursor by word functions */
493 LibPinyinPhoneticEditor::getCursorLeftByWord (void)
497 if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
498 cursor = m_pinyin_len;
501 pinyin_get_n_pinyin (m_instance, &len);
503 guint pinyin_cursor = getPinyinCursor ();
505 PinyinKeyPos *pos = NULL;
507 if (pinyin_cursor < len) {
508 pinyin_get_pinyin_key_rest (m_instance, pinyin_cursor, &pos);
510 pinyin_get_pinyin_key_rest_positions
511 (m_instance, pos, &cursor, NULL);
513 /* at the end of pinyin string. */
517 /* cursor at the begin of one pinyin */
518 g_return_val_if_fail (pinyin_cursor > 0, 0);
519 if ( cursor == m_cursor) {
520 pinyin_get_pinyin_key_rest (m_instance, pinyin_cursor - 1, &pos);
522 pinyin_get_pinyin_key_rest_positions
523 (m_instance, pos, &cursor, NULL);
531 LibPinyinPhoneticEditor::getCursorRightByWord (void)
535 if (G_UNLIKELY (m_cursor > m_pinyin_len)) {
536 cursor = m_text.length ();
538 guint pinyin_cursor = getPinyinCursor ();
539 PinyinKeyPos *pos = NULL;
540 pinyin_get_pinyin_key_rest (m_instance, pinyin_cursor, &pos);
541 pinyin_get_pinyin_key_rest_positions (m_instance, pos, NULL, &cursor);
548 LibPinyinPhoneticEditor::removeWordBefore (void)
550 if (G_UNLIKELY (m_cursor == 0))
553 guint cursor = getCursorLeftByWord ();
554 m_text.erase (cursor, m_cursor - cursor);
562 LibPinyinPhoneticEditor::removeWordAfter (void)
564 if (G_UNLIKELY (m_cursor == m_text.length ()))
567 guint cursor = getCursorRightByWord ();
568 m_text.erase (m_cursor, cursor - m_cursor);
575 LibPinyinPhoneticEditor::moveCursorLeftByWord (void)
577 if (G_UNLIKELY (m_cursor == 0))
580 guint cursor = getCursorLeftByWord ();
588 LibPinyinPhoneticEditor::moveCursorRightByWord (void)
590 if (G_UNLIKELY (m_cursor == m_text.length ()))
593 guint cursor = getCursorRightByWord ();