/** * @ingroup hangulic * @brief 키 입력을 처리하여 실제로 한글 조합을 하는 함수 * @param hic @ref HangulInputContext 오브젝트 * @param ascii 키 이벤트 * @return @ref HangulInputContext 가 이 키를 사용했으면 true, * 사용하지 않았으면 false * * ascii 값으로 주어진 키 이벤트를 받아서 내부의 한글 조합 상태를 * 변화시키고, preedit, commit 스트링을 저장한다. * * libhangul의 키 이벤트 프로세스는 ASCII 코드 값을 기준으로 처리한다. * 이 키 값은 US Qwerty 자판 배열에서의 키 값에 해당한다. * 따라서 유럽어 자판을 사용하는 경우에는 해당 키의 ASCII 코드를 직접 * 전달하면 안되고, 그 키가 US Qwerty 자판이었을 경우에 발생할 수 있는 * ASCII 코드 값을 주어야 한다. * 또한 ASCII 코드 이므로 Shift 상태는 대문자로 전달이 된다. * Capslock이 눌린 경우에는 대소문자를 뒤바꾸어 보내주지 않으면 * 마치 Shift가 눌린 것 처럼 동작할 수 있으므로 주의한다. * preedit, commit 스트링은 hangul_ic_get_preedit_string(), * hangul_ic_get_commit_string() 함수를 이용하여 구할 수 있다. * * 이 함수의 사용법에 대한 설명은 @ref hangulicusage 부분을 참조한다. * * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시킨다. */ bool hangul_ic_process(HangulInputContext *hic, int ascii) { ucschar c; if (hic == NULL) return false; hic->preedit_string[0] = 0; hic->commit_string[0] = 0; c = hangul_keyboard_get_mapping(hic->keyboard, 0, ascii); if (hic->on_translate != NULL) hic->on_translate(hic, ascii, &c, hic->on_translate_data); if (ascii == '\b') { return hangul_ic_backspace(hic); } int type = hangul_keyboard_get_type(hic->keyboard); switch (type) { case HANGUL_KEYBOARD_TYPE_JASO: case HANGUL_KEYBOARD_TYPE_JASO_YET: return hangul_ic_process_jaso(hic, c); case HANGUL_KEYBOARD_TYPE_ROMAJA: return hangul_ic_process_romaja(hic, ascii, c); default: return hangul_ic_process_jamo(hic, c); } }
bool QHangulPlatformInputContext::backspace() { bool ret = hangul_ic_backspace(m_hic); if (ret) { QString str = getPreeditString(); updatePreedit(str); } return ret; }
static PyObject *_pyhangulic_backspace(PY_HANGULIC *self, PyObject *args) { int ret; ret = hangul_ic_backspace(self->hic); return Py_BuildValue("i", ret); }
END_TEST START_TEST(test_hangul_ic_process_romaja) { HangulInputContext* ic; const ucschar* preedit; const ucschar* commit; // romaja keyboard test ic = hangul_ic_new("ro"); // basic test: han produces 한 hangul_ic_process(ic, 'h'); hangul_ic_process(ic, 'a'); hangul_ic_process(ic, 'n'); preedit = hangul_ic_get_preedit_string(ic); commit = hangul_ic_get_commit_string(ic); fail_unless(preedit[0] == L'한'); fail_unless(commit[0] == 0); hangul_ic_reset(ic); // insert ㅇ when a syllable is not started with consonant hangul_ic_process(ic, 'a'); preedit = hangul_ic_get_preedit_string(ic); commit = hangul_ic_get_commit_string(ic); fail_unless(preedit[0] == L'아'); fail_unless(commit[0] == 0); // remove correctly when automatically ㅇ was inserted hangul_ic_backspace(ic); preedit = hangul_ic_get_preedit_string(ic); commit = hangul_ic_get_commit_string(ic); fail_unless(preedit[0] == 0); fail_unless(commit[0] == 0); // append ㅡ when a syllable is not ended with vowel hangul_ic_process(ic, 't'); hangul_ic_process(ic, 't'); preedit = hangul_ic_get_preedit_string(ic); commit = hangul_ic_get_commit_string(ic); fail_unless(preedit[0] == 0x314c); // ㅌ fail_unless(commit[0] == L'트'); // ng makes trailing ㅇ hangul_ic_reset(ic); hangul_ic_process(ic, 'g'); hangul_ic_process(ic, 'a'); hangul_ic_process(ic, 'n'); hangul_ic_process(ic, 'g'); preedit = hangul_ic_get_preedit_string(ic); commit = hangul_ic_get_commit_string(ic); fail_unless(preedit[0] == L'강'); // 강 fail_unless(commit[0] == 0); // gangi makes 강이 hangul_ic_process(ic, 'i'); preedit = hangul_ic_get_preedit_string(ic); commit = hangul_ic_get_commit_string(ic); fail_unless(preedit[0] == L'이'); fail_unless(commit[0] == L'강'); // 강 // nanG makes 난ㄱ // uppercase makes new syllable hangul_ic_process(ic, 'n'); hangul_ic_process(ic, 'a'); hangul_ic_process(ic, 'n'); hangul_ic_process(ic, 'G'); preedit = hangul_ic_get_preedit_string(ic); commit = hangul_ic_get_commit_string(ic); fail_unless(preedit[0] == 0x3131); // ㄱ fail_unless(commit[0] == L'난'); // 난 // special operation for x // x generate ㅈ for leading consonant hangul_ic_reset(ic); hangul_ic_process(ic, 'x'); hangul_ic_process(ic, 'x'); preedit = hangul_ic_get_preedit_string(ic); commit = hangul_ic_get_commit_string(ic); fail_unless(preedit[0] == 0x3148); // 지 fail_unless(commit[0] == L'즈'); hangul_ic_reset(ic); hangul_ic_process(ic, 'x'); hangul_ic_process(ic, 'y'); preedit = hangul_ic_get_preedit_string(ic); commit = hangul_ic_get_commit_string(ic); fail_unless(preedit[0] == L'지'); // 지 fail_unless(commit[0] == 0x0); // x generate ㄱㅅ for trailing consonant // and ㅅ will be transferred to next syllable when next input // character is vowel. hangul_ic_reset(ic); hangul_ic_process(ic, 's'); hangul_ic_process(ic, 'e'); hangul_ic_process(ic, 'x'); hangul_ic_process(ic, 'y'); preedit = hangul_ic_get_preedit_string(ic); commit = hangul_ic_get_commit_string(ic); fail_unless(preedit[0] == L'시'); // 시 fail_unless(commit[0] == L'섹'); // 섹 hangul_ic_delete(ic); }
bool HangulInstance::process_key_event (const KeyEvent& rawkey) { SCIM_DEBUG_IMENGINE(1) << "process_key_event.\n"; KeyEvent key = rawkey.map_to_layout(SCIM_KEYBOARD_Default); m_prev_key = key; if (use_ascii_mode() && !is_hangul_mode()) { if (is_hangul_key(key)) { toggle_hangul_mode(); return true; } return false; } /* ignore key release. */ if (key.is_key_release ()) return false; /* mode change */ if (use_ascii_mode() && is_hangul_key(key)) { toggle_hangul_mode(); return true; } /* hanja mode */ if (is_hanja_mode_key (key)) { toggle_hanja_mode(); } /* toggle candidate table */ if (is_hanja_key (key)) { if (is_hanja_mode()) { update_candidates (); } else { if (m_lookup_table.number_of_candidates ()) delete_candidates (); else update_candidates (); } return true; } /* ignore shift keys */ if (key.code == SCIM_KEY_Shift_L || key.code == SCIM_KEY_Shift_R) return false; /* flush on modifier-on keys */ if (key.is_control_down() || key.is_alt_down()) { flush (); return false; } /* candidate keys */ if (m_lookup_table.number_of_candidates ()) { if (candidate_key_event(key)) return true; } /* change to ascii mode on ESCAPE key, for vi users. * We should process this key after processing candidate keys, * or input mode will be changed to non-hangul mode when the user presses * escape key to close candidate window. */ if (use_ascii_mode() && !is_hanja_mode()) { if (key.code == SCIM_KEY_Escape) { toggle_hangul_mode(); } } /* backspace */ if (is_backspace_key(key)) { bool ret = hangul_ic_backspace(m_hic); if (ret) { hangul_update_preedit_string (); } else if (m_preedit.length() > 0) { ret = true; m_preedit.erase(m_preedit.length() - 1, 1); hangul_update_preedit_string(); } else { if (m_surrounding_text.length() > 0) { m_surrounding_text.erase(m_surrounding_text.length() - 1, 1); if (m_surrounding_text.empty()) { delete_candidates(); return ret; } } } if (is_hanja_mode() && m_lookup_table.number_of_candidates()) { update_candidates(); } return ret; } if (key.code >= SCIM_KEY_exclam && key.code <= SCIM_KEY_asciitilde) { /* main hangul composing process */ int ascii = key.get_ascii_code(); if (key.is_caps_lock_down()) { if (isupper(ascii)) ascii = tolower(ascii); else if (islower(ascii)) ascii = toupper(ascii); } bool ret = hangul_ic_process(m_hic, ascii); WideString wstr; wstr = get_commit_string (); if (wstr.length ()) { /* Before commit, we set preedit string to null to work arround * some buggy IM implementation, ex) Qt, Evolution */ hide_preedit_string (); if (is_hanja_mode() || m_factory->m_commit_by_word) { m_preedit += wstr; } else { commit_string(wstr); } } if (is_hanja_mode() || m_factory->m_commit_by_word) { if (hangul_ic_is_empty(m_hic)) { flush(); } } hangul_update_preedit_string (); if (is_hanja_mode()) { update_candidates(); } return ret; } flush(); return false; }
static gboolean ibus_hangul_engine_process_key_event (IBusEngine *engine, guint keyval, guint keycode, guint modifiers) { IBusHangulEngine *hangul = (IBusHangulEngine *) engine; guint mask; gboolean retval; const ucschar *str; if (modifiers & IBUS_RELEASE_MASK) return FALSE; // if we don't ignore shift keys, shift key will make flush the preedit // string. So you cannot input shift+key. // Let's think about these examples: // dlTek (2 set) // qhRdmaqkq (2 set) if (keyval == IBUS_Shift_L || keyval == IBUS_Shift_R) return FALSE; // If hanja key has any modifiers, we ignore that modifier keyval, // or we cannot make the hanja key work. // Because when we get the modifier key alone, we commit the // current preedit string. So after that, even if we get the // right hanja key event, we don't have preedit string to be changed // to hanja word. // See this bug: http://code.google.com/p/ibus/issues/detail?id=1036 if (hanja_key_list_has_modifier(&hanja_keys, keyval)) return FALSE; if (hanja_key_list_match(&hanja_keys, keyval, modifiers)) { if (hangul->hanja_list == NULL) { ibus_hangul_engine_update_lookup_table (hangul); } else { ibus_hangul_engine_hide_lookup_table (hangul); } return TRUE; } if (hangul->hanja_list != NULL) { retval = ibus_hangul_engine_process_candidate_key_event (hangul, keyval, modifiers); if (hangul->hanja_mode) { if (retval) return TRUE; } else { return TRUE; } } // If we've got a key event with some modifiers, commit current // preedit string and ignore this key event. // So, if you want to add some key event handler, put it // before this code. // Ignore key event with control, alt, super or mod5 mask = IBUS_CONTROL_MASK | IBUS_MOD1_MASK | IBUS_MOD3_MASK | IBUS_MOD4_MASK | IBUS_MOD5_MASK; if (modifiers & mask) { ibus_hangul_engine_flush (hangul); return FALSE; } if (keyval == IBUS_BackSpace) { retval = hangul_ic_backspace (hangul->context); if (!retval) { guint preedit_len = ustring_length (hangul->preedit); if (preedit_len > 0) { ustring_erase (hangul->preedit, preedit_len - 1, 1); retval = TRUE; } } ibus_hangul_engine_update_preedit_text (hangul); if (hangul->hanja_mode) { if (ibus_hangul_engine_has_preedit (hangul)) { ibus_hangul_engine_update_lookup_table (hangul); } else { ibus_hangul_engine_hide_lookup_table (hangul); } } } else { // We need to normalize the keyval to US qwerty keylayout, // because the korean input method is depend on the position of // each key, not the character. We make the keyval from keycode // as if the keyboard is US qwerty layout. Then we can assume the // keyval represent the position of the each key. // But if the hic is in transliteration mode, then we should not // normalize the keyval. bool is_transliteration_mode = hangul_ic_is_transliteration(hangul->context); if (!is_transliteration_mode) { if (keymap != NULL) keyval = ibus_keymap_lookup_keysym(keymap, keycode, modifiers); } // ignore capslock if (modifiers & IBUS_LOCK_MASK) { if (keyval >= 'A' && keyval <= 'z') { if (isupper(keyval)) keyval = tolower(keyval); else keyval = toupper(keyval); } } retval = hangul_ic_process (hangul->context, keyval); str = hangul_ic_get_commit_string (hangul->context); if (word_commit || hangul->hanja_mode) { const ucschar* hic_preedit; hic_preedit = hangul_ic_get_preedit_string (hangul->context); if (hic_preedit != NULL && hic_preedit[0] != 0) { ustring_append_ucs4 (hangul->preedit, str, -1); } else { IBusText *text; const ucschar* preedit; ustring_append_ucs4 (hangul->preedit, str, -1); if (ustring_length (hangul->preedit) > 0) { /* clear preedit text before commit */ ibus_hangul_engine_clear_preedit_text (hangul); preedit = ustring_begin (hangul->preedit); text = ibus_text_new_from_ucs4 ((gunichar*)preedit); ibus_engine_commit_text (engine, text); } ustring_clear (hangul->preedit); } } else { if (str != NULL && str[0] != 0) { IBusText *text; /* clear preedit text before commit */ ibus_hangul_engine_clear_preedit_text (hangul); text = ibus_text_new_from_ucs4 (str); ibus_engine_commit_text (engine, text); } } ibus_hangul_engine_update_preedit_text (hangul); if (hangul->hanja_mode) { ibus_hangul_engine_update_lookup_table (hangul); } if (!retval) ibus_hangul_engine_flush (hangul); } return retval; }
gboolean nimf_libhangul_filter_event (NimfEngine *engine, NimfServiceIC *target, NimfEvent *event) { g_debug (G_STRLOC ": %s", G_STRFUNC); guint keyval; gboolean retval = FALSE; NimfLibhangul *hangul = NIMF_LIBHANGUL (engine); if (event->key.type == NIMF_EVENT_KEY_RELEASE || event->key.keyval == NIMF_KEY_Shift_L || event->key.keyval == NIMF_KEY_Shift_R) return FALSE; if (event->key.state & (NIMF_CONTROL_MASK | NIMF_MOD1_MASK)) { nimf_libhangul_reset (engine, target); return FALSE; } if (G_UNLIKELY (nimf_event_matches (event, (const NimfKey **) hangul->hanja_keys))) { if (nimf_candidatable_is_visible (hangul->candidatable) == FALSE) { gchar item[4]; const char *key = hangul->preedit_string; gboolean use_preedit; if (hangul->preedit_string[0] == 0) { gchar *text; gint cursor_pos; nimf_engine_get_surrounding (engine, target, &text, &cursor_pos); if (text && cursor_pos > 0) { gchar *p = g_utf8_offset_to_pointer (text, cursor_pos - 1); g_utf8_strncpy (item, p, 1); if (g_utf8_validate (item, -1, NULL)) key = item; } g_free (text); } hanja_list_delete (hangul->hanja_list); nimf_candidatable_clear (hangul->candidatable, target); hangul->hanja_list = hanja_table_match_exact (nimf_libhangul_hanja_table, key); if (hangul->hanja_list == NULL) hangul->hanja_list = hanja_table_match_exact (nimf_libhangul_symbol_table, key); hangul->n_pages = (hanja_list_get_size (hangul->hanja_list) + 9) / 10; hangul->current_page = 1; nimf_libhangul_update_page (engine, target); use_preedit = nimf_service_ic_get_use_preedit (target); if (!use_preedit) nimf_candidatable_set_auxiliary_text (hangul->candidatable, key, g_utf8_strlen (key, -1)); nimf_candidatable_show (hangul->candidatable, target, !use_preedit); nimf_candidatable_select_first_item_in_page (hangul->candidatable); } else { nimf_candidatable_hide (hangul->candidatable); nimf_candidatable_clear (hangul->candidatable, target); hanja_list_delete (hangul->hanja_list); hangul->hanja_list = NULL; hangul->current_page = 0; hangul->n_pages = 0; } return TRUE; } if (nimf_candidatable_is_visible (hangul->candidatable)) { switch (event->key.keyval) { case NIMF_KEY_Return: case NIMF_KEY_KP_Enter: { gchar *text; text = nimf_candidatable_get_selected_text (hangul->candidatable); on_candidate_clicked (engine, target, text, -1); g_free (text); } break; case NIMF_KEY_Up: case NIMF_KEY_KP_Up: nimf_candidatable_select_previous_item (hangul->candidatable); break; case NIMF_KEY_Down: case NIMF_KEY_KP_Down: nimf_candidatable_select_next_item (hangul->candidatable); break; case NIMF_KEY_Page_Up: case NIMF_KEY_KP_Page_Up: nimf_libhangul_page_up (engine, target); break; case NIMF_KEY_Page_Down: case NIMF_KEY_KP_Page_Down: nimf_libhangul_page_down (engine, target); break; case NIMF_KEY_Home: nimf_libhangul_page_home (engine, target); break; case NIMF_KEY_End: nimf_libhangul_page_end (engine, target); break; case NIMF_KEY_Escape: nimf_candidatable_hide (hangul->candidatable); break; case NIMF_KEY_0: case NIMF_KEY_1: case NIMF_KEY_2: case NIMF_KEY_3: case NIMF_KEY_4: case NIMF_KEY_5: case NIMF_KEY_6: case NIMF_KEY_7: case NIMF_KEY_8: case NIMF_KEY_9: case NIMF_KEY_KP_0: case NIMF_KEY_KP_1: case NIMF_KEY_KP_2: case NIMF_KEY_KP_3: case NIMF_KEY_KP_4: case NIMF_KEY_KP_5: case NIMF_KEY_KP_6: case NIMF_KEY_KP_7: case NIMF_KEY_KP_8: case NIMF_KEY_KP_9: { if (hangul->hanja_list == NULL || hangul->current_page < 1) break; gint i, n; gint list_len = hanja_list_get_size (hangul->hanja_list); if (event->key.keyval >= NIMF_KEY_0 && event->key.keyval <= NIMF_KEY_9) n = (event->key.keyval - NIMF_KEY_0 + 9) % 10; else if (event->key.keyval >= NIMF_KEY_KP_0 && event->key.keyval <= NIMF_KEY_KP_9) n = (event->key.keyval - NIMF_KEY_KP_0 + 9) % 10; else break; i = (hangul->current_page - 1) * 10 + n; if (i < MIN (hangul->current_page * 10, list_len)) { const Hanja *hanja = hanja_list_get_nth (hangul->hanja_list, i); const char *text = hanja_get_value (hanja); on_candidate_clicked (engine, target, (gchar *) text, -1); } } break; default: break; } return TRUE; } const ucschar *ucs_commit; const ucschar *ucs_preedit; if (G_UNLIKELY (event->key.keyval == NIMF_KEY_BackSpace)) { retval = hangul_ic_backspace (hangul->context); if (retval) { ucs_preedit = hangul_ic_get_preedit_string (hangul->context); gchar *new_preedit = g_ucs4_to_utf8 (ucs_preedit, -1, NULL, NULL, NULL); nimf_libhangul_update_preedit (engine, target, new_preedit); } return retval; } if (G_UNLIKELY (g_strcmp0 (hangul->method, "ro") == 0)) keyval = event->key.keyval; else keyval = nimf_event_keycode_to_qwerty_keyval (event); if (!hangul->is_double_consonant_rule && (g_strcmp0 (hangul->method, "2") == 0) && nimf_libhangul_filter_leading_consonant (engine, target, keyval)) return TRUE; retval = hangul_ic_process (hangul->context, keyval); ucs_commit = hangul_ic_get_commit_string (hangul->context); ucs_preedit = hangul_ic_get_preedit_string (hangul->context); gchar *new_commit = g_ucs4_to_utf8 (ucs_commit, -1, NULL, NULL, NULL); if (ucs_commit[0] != 0) nimf_libhangul_emit_commit (engine, target, new_commit); g_free (new_commit); gchar *new_preedit = g_ucs4_to_utf8 (ucs_preedit, -1, NULL, NULL, NULL); nimf_libhangul_update_preedit (engine, target, new_preedit); return retval; }