| requires 2.0.0 |
| |
| %alltop{ |
| /* |
| * Copyright © 2009 Red Hat, Inc. All rights reserved. |
| * Copyright © 2009 Ding-Yi Chen <dchen at redhat.com> |
| * |
| * This file is part of the ibus-chewing Project. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| */ |
| #include <stdlib.h> |
| #include <libintl.h> |
| #include <ibus.h> |
| #include <chewing.h> |
| #include <string.h> |
| #include <stdio.h> |
| #define GETTEXT_PACKAGE "gtk20" |
| #include <glib/gi18n.h> |
| #include <gtk/gtk.h> |
| #include <X11/extensions/XTest.h> |
| #include <X11/Xlib.h> |
| #include <ctype.h> |
| %} |
| |
| enum CHEWING_KBTYPE{ |
| INVALID=-1, |
| DEFAULT, |
| HSU, |
| IBM, |
| GIN_YIEH, |
| ETEN, |
| ETEN26, |
| DVORAK, |
| DVORAK_HSU, |
| DACHEN_CP26, |
| HAN_YU |
| } Chewing:KbType; |
| |
| enum CHEWING_MODIFIER_SYNC{ |
| DISABLE, |
| FROM_KEYBOARD, |
| FROM_IM |
| } Chewing:Modifier:Sync; |
| |
| enum CHEWING_INPUT_STYLE{ |
| IN_APPLICATION, |
| IN_CANDIDATE, |
| } Chewing:Input:Style; |
| |
| /** |
| * ChewingInputMode: |
| * @BYPASS: Bypass the cursor movement keys. |
| * @EDITING: Forming Chinese character (in pre-edit buffer). |
| * @SELECTING: Selecting candidate. Immediately after character is formed. |
| * @SELECTING_DONE: A candidate is manually selected. |
| * |
| * Chewing input (key handling) mode. |
| * Note for EDITING_ENGLISH: |
| * It is possible that chewing status bar shows Chinese mode, |
| * yet still inputting English. |
| * This mode is for mix-typing English and Chinese. |
| */ |
| enum CHEWING_INPUT_MODE{ |
| BYPASS, |
| EDITING, |
| SELECTING, |
| SELECTING_DONE |
| } Chewing:Input:Mode; |
| |
| enum CHEWING_OUTPUT_CHARSET{ |
| AUTO, |
| BIG5, |
| UTF8 |
| } Chewing:Output:Charset; |
| |
| /** |
| * ChewingFlag: |
| * @PLAIN_CHEWING: Plain chewing mode (non AI). |
| * @FORCE_LOWERCASE_ENGLISH: Force Lowercase even when CapsLock is on. |
| */ |
| enum CHEWING_FLAG{ |
| PLAIN_ZHUYIN= 0x1, |
| FORCE_LOWERCASE_ENGLISH= 0x2, |
| NUMPAD_ALWAYS_NUMBER= 0x4, |
| EASY_SYMBOL_INPUT= 0x8, |
| } Chewing:Flag; |
| |
| /** |
| * EngineStatus: |
| * @INITIALIZED: Engine is initialized. |
| */ |
| enum ENGINE_STATUS{ |
| INITIALIZED= 0x1, |
| ENABLED= 0x2, |
| FOCUS_IN= 0x4, |
| SHOW_CANDIDATE= 0x8, |
| NEED_COMMIT= 0x10, |
| FORCE_COMMIT= 0x20, |
| } Engine:Status; |
| |
| %h{ |
| #include "maker-dialog.h" |
| #define GCONF_KEY_PREFIX "/desktop/ibus/engine/Chewing/" |
| /* For easy symbol input work around */ |
| #define EASY_SYMBOL_INPUT_WORK_AROUND |
| |
| extern PropertySpec propSpecs[]; |
| extern const gchar *page_labels[]; |
| extern const gchar *button_labels[]; |
| extern GtkResponseType button_responses[]; |
| #define ZHUYIN_BUFFER_SIZE 12 |
| |
| #define ibus_chewing_engine_set_status_flag(cengine,f) cengine->_priv->statusFlags |= f |
| #define ibus_chewing_engine_clear_status_flag(cengine,f) cengine->_priv->statusFlags &= ~f |
| |
| #ifdef IBUS_1_1 |
| /* |
| * Dummy data structure for ibus 1.1 and early. |
| */ |
| typedef void IBusKeymap; |
| IBusKeymap *ibus_keymap_get(gchar *keymap_name); |
| #endif /* IBUS_1_1 */ |
| |
| #define G_DEBUG_MSG(level, msg, args...) if (level<=ibus_chewing_verbose) g_debug(msg, ##args) |
| %} |
| |
| %privateheader{ |
| gboolean ibus_chewing_engine_process_key_event(IBusEngine *engine, |
| guint keyval, guint modifiers); |
| void ibus_chewing_engine_candidate_clicked(IBusEngine *engine, guint index, |
| guint button, guint state); |
| |
| #ifndef IBUS_1_1 |
| gboolean ibus_chewing_engine_process_key_event_1_2(IBusEngine *engine, |
| guint keyval_ignore, guint keycode, guint modifiers); |
| |
| #endif /* IBUS_1_1 */ |
| %} |
| |
| %{ |
| extern gboolean ibus_chewing_verbose; |
| //extern IBusConfig *iConfig; |
| |
| #define IBUS_CHEWING_MAIN |
| #include "IBusChewingEngine-def.c" |
| |
| #ifndef IBUS_1_3 |
| IBusKeymap *ibus_keymap_get(gchar *keymap_name){ |
| #ifdef IBUS_1_1 |
| return NULL; |
| #endif /* IBUS_1_1 */ |
| #ifdef IBUS_1_2 |
| return ibus_keymap_new(keymap_name); |
| #endif /* IBUS_1_2 */ |
| } |
| #endif /* IBUS_1_3 */ |
| %} |
| |
| class IBus:Chewing:Engine from IBus:Engine{ |
| public ChewingContext *context=NULL |
| destroywith chewing_delete; |
| |
| public Chewing:Modifier:Sync syncCapsLock_local=CHEWING_MODIFIER_SYNC_FROM_KEYBOARD; |
| |
| //public GtkWidget *setting_dialog={ |
| //GTK_WIDGET(maker_dialog_new_full(_("Setting"),3,page_labels,1,button_labels,button_responses))}; |
| |
| protected gint selKeys[MAX_SELKEY]; |
| |
| protected ChewingInputMode inputMode=CHEWING_INPUT_MODE_BYPASS; |
| |
| /* Controlling flags */ |
| protected ChewingFlag flags=0; |
| |
| private guint statusFlags=0; |
| |
| /* For easy symbol input work around */ |
| private ChewingInputStyle inputStyle; |
| |
| protected IBusLookupTable *table=NULL |
| destroywith ibus_lookup_table_clear; |
| |
| public IBusProperty *chieng_prop={ |
| g_object_ref_sink ( |
| ibus_property_new("chewing_chieng_prop",PROP_TYPE_NORMAL, |
| SELF_GET_CLASS(self)->chieng_prop_label_chi, |
| NULL, NULL, TRUE, TRUE, |
| PROP_STATE_UNCHECKED, NULL)) |
| } |
| destroywith g_object_unref; |
| |
| public IBusProperty *alnumSize_prop={ |
| g_object_ref_sink ( |
| ibus_property_new("chewing_alnumSize_prop",PROP_TYPE_NORMAL, |
| SELF_GET_CLASS(self)->alnumSize_prop_label_half, |
| NULL, NULL, TRUE, TRUE, |
| PROP_STATE_UNCHECKED, NULL)) |
| } |
| destroywith g_object_unref; |
| |
| public IBusProperty *settings_prop={ |
| g_object_ref_sink ( |
| ibus_property_new("chewing_settings_prop",PROP_TYPE_TOGGLE, |
| SELF_GET_CLASS(self)->settings_prop_label, |
| PKGDATADIR "/icons/settings.png", NULL, TRUE, TRUE, |
| PROP_STATE_UNCHECKED, NULL)) |
| } |
| destroywith g_object_unref; |
| |
| public IBusPropList *prop_list={ g_object_ref_sink (ibus_prop_list_new()) } |
| destroywith g_object_unref; |
| |
| public IBusConfig *config=NULL; |
| |
| protected IBusKeymap *keymap_us={ibus_keymap_get("us")}; |
| |
| private Display *pDisplay = {XOpenDisplay( NULL )} |
| destroywith XCloseDisplay; |
| |
| private guint key_last=0; |
| private gchar zhuyin_latest[ZHUYIN_BUFFER_SIZE]; |
| |
| classwide IBusText *chieng_prop_label_chi={g_object_ref_sink(ibus_text_new_from_static_string(_("Chi")))}; |
| classwide IBusText *chieng_prop_label_eng={g_object_ref_sink(ibus_text_new_from_static_string(_("Eng")))}; |
| classwide IBusText *alnumSize_prop_label_full={g_object_ref_sink(ibus_text_new_from_static_string(_("Full")))}; |
| classwide IBusText *alnumSize_prop_label_half={g_object_ref_sink(ibus_text_new_from_static_string(_("Half")))}; |
| |
| classwide IBusText *settings_prop_label={g_object_ref_sink(ibus_text_new_from_static_string(_("Settings")))}; |
| classwide IBusText *emptyText={g_object_ref_sink(ibus_text_new_from_static_string(""))}; |
| |
| init (self) { |
| /* initialize the object here */ |
| G_DEBUG_MSG(1,"[I1] init()"); |
| if (!(self->_priv->statusFlags & ENGINE_STATUS_INITIALIZED)){ |
| //maker_dialog_set_verbose_level(MAKER_DIALOG(self->setting_dialog),ibus_chewing_verbose); |
| gchar buf[100]; |
| g_snprintf(buf,100,"%s/.chewing",getenv("HOME")); |
| |
| chewing_Init(CHEWING_DATADIR, buf); |
| |
| self->context=chewing_new(); |
| chewing_set_ChiEngMode(self->context,CHINESE_MODE); |
| self->inputMode=CHEWING_INPUT_MODE_SELECTING_DONE; |
| |
| /* init properties */ |
| ibus_prop_list_append(self->prop_list,self->chieng_prop); |
| ibus_prop_list_append(self->prop_list,self->alnumSize_prop); |
| ibus_prop_list_append(self->prop_list,self->settings_prop); |
| |
| ibus_chewing_engine_set_status_flag(self,ENGINE_STATUS_INITIALIZED); |
| } |
| } |
| |
| class_init(klass){ |
| #ifdef IBUS_1_1 |
| ibus_engine_class->process_key_event = ibus_chewing_engine_process_key_event; |
| #else |
| ibus_engine_class->process_key_event = ibus_chewing_engine_process_key_event_1_2; |
| #endif /* IBUS_1_1 */ |
| ibus_engine_class->candidate_clicked = ibus_chewing_engine_candidate_clicked; |
| } |
| |
| private void load_setting(self){ |
| #define BUFFER_SIZE_LOCAL 200 |
| G_DEBUG_MSG(3,"[I3] load_setting()"); |
| int i; |
| //gchar buf[BUFFER_SIZE_LOCAL]; |
| PropertyContext context = {NULL, self}; |
| |
| for (i=0; propSpecs[i].valueType!=G_TYPE_INVALID;i++){ |
| GValue gValue={0}; |
| |
| G_DEBUG_MSG(4,"[I4] load_setting(), i=%d",i); |
| if (ibus_config_get_value(self->config, "engine/Chewing",propSpecs[i].key, &gValue)){ |
| // TODO: Read in the config on Chromium OS. |
| /*switch(propSpecs[i].valueType){ |
| case G_TYPE_BOOLEAN: |
| buf[0]=(g_value_get_boolean(gValue))? '1' : '0'; |
| buf[1]='\0'; |
| break; |
| case G_TYPE_UINT: |
| g_snprintf(buf,BUFFER_SIZE_LOCAL,"%u", |
| g_value_get_uint(gValue)); |
| break; |
| case G_TYPE_INT: |
| g_snprintf(buf,BUFFER_SIZE_LOCAL,"%d", |
| g_value_get_int(gValue)); |
| break; |
| case G_TYPE_STRING: |
| g_strlcpy(buf,g_value_get_string(gValue), BUFFER_SIZE_LOCAL); |
| break; |
| default: |
| break; |
| |
| }*/ |
| }else{ |
| g_warning("[WW] %s /desktop/ibus/engine/Chewing/%s, %s %s", |
| _("Warning: cannot load configure key"), |
| propSpecs[i].key, |
| (propSpecs[i].defaultValue)? _(" Use default value:") : _(" No default value, skipped.") , |
| (propSpecs[i].defaultValue)? propSpecs[i].defaultValue : "" |
| ); |
| if (propSpecs[i].defaultValue){ |
| g_value_init(&gValue, propSpecs[i].valueType); |
| |
| switch(propSpecs[i].valueType){ |
| case G_TYPE_BOOLEAN: |
| g_value_set_boolean(&gValue, '0' == *(propSpecs[i].defaultValue) ? 0 : 1); |
| break; |
| case G_TYPE_UINT: |
| g_value_set_uint(&gValue, atoi(propSpecs[i].defaultValue)); |
| break; |
| case G_TYPE_INT: |
| g_value_set_int(&gValue, atoi(propSpecs[i].defaultValue)); |
| break; |
| case G_TYPE_STRING: |
| g_value_set_string(&gValue, propSpecs[i].defaultValue); |
| break; |
| default: |
| break; |
| |
| } |
| //g_strlcpy(buf,propSpecs[i].defaultValue, BUFFER_SIZE_LOCAL); |
| }else{ |
| continue; |
| } |
| } |
| /* Add property to dialog */ |
| //maker_dialog_add_property(MAKER_DIALOG(self->setting_dialog),&propSpecs[i],buf,self); |
| //maker_dialog_apply_widget_value(MAKER_DIALOG(self->setting_dialog),propSpecs[i].key); |
| propSpecs[i].setFunc(&context, &gValue); |
| if (G_IS_VALUE(&gValue)) { |
| g_value_unset(&gValue); |
| } |
| } |
| |
| //for (i=0; page_labels[i]!=NULL;i++){ |
| //maker_dialog_align_labels(MAKER_DIALOG(self->setting_dialog),page_labels[i],1.0f, 0.5f); |
| //} |
| //gtk_widget_hide(self->setting_dialog); |
| #undef BUFFER_SIZE_LOCAL |
| } |
| |
| protected void set_lookup_table_label(self,const gchar *labels){ |
| int i,len=strlen(labels); |
| g_array_set_size(self->table->labels,0); |
| for(i=0;i<len;i++){ |
| IBusText *text=ibus_text_new_from_unichar((gunichar) labels[i]); |
| ibus_lookup_table_append_label (self->table,text); |
| } |
| } |
| |
| private gchar *make_preedit_string(self, glong *zhuyin_item_written_ptr){ |
| gchar *buff_str=chewing_buffer_String(self->context); |
| G_DEBUG_MSG(4, "[I4] make_preedit_string(): chewing_buffer_String=%s ", |
| buff_str); |
| |
| int chiSymbolCursor = chewing_cursor_Current(self->context); |
| int zhuyin_count; |
| int zhuyin_tone=-1; |
| |
| gchar *zhuyin_str=chewing_zuin_String(self->context,&zhuyin_count); |
| *zhuyin_item_written_ptr= (glong) zhuyin_count; |
| G_DEBUG_MSG(5, "[I5] make_preedit_string(): chewing_zuin_String=%s count=%d inputMode=%d", |
| zhuyin_str,zhuyin_count,self->inputMode); |
| |
| switch(self->inputMode){ |
| case CHEWING_INPUT_MODE_EDITING: |
| g_strlcpy(self->_priv->zhuyin_latest,zhuyin_str,ZHUYIN_BUFFER_SIZE); |
| zhuyin_tone=0; |
| break; |
| case CHEWING_INPUT_MODE_SELECTING: |
| zhuyin_tone=get_tone(chewing_get_KBType(self->context),self->_priv->key_last); |
| add_tone(self->_priv->zhuyin_latest,zhuyin_tone); |
| if (zhuyin_tone>0 ){ |
| if (self->flags & CHEWING_FLAG_PLAIN_ZHUYIN){ |
| /* Open candidate selection window */ |
| if (chewing_get_spaceAsSelection(self->context)){ |
| chewing_handle_Space(self->context); |
| }else{ |
| chewing_handle_Down(self->context); |
| } |
| } |
| } |
| break; |
| case CHEWING_INPUT_MODE_SELECTING_DONE: |
| self->_priv->zhuyin_latest[0]='\0'; |
| zhuyin_tone=-1; |
| if (zhuyin_count) |
| self->inputMode=CHEWING_INPUT_MODE_EDITING; |
| break; |
| default: |
| /* BYPASS */ |
| break; |
| |
| } |
| |
| gsize len=strlen(zhuyin_str)+strlen(buff_str); |
| gchar *preeditBuf=g_new(gchar, len+1); |
| preeditBuf[0]='\0'; |
| if (chiSymbolCursor>0){ |
| g_utf8_strncpy(preeditBuf, buff_str, chiSymbolCursor); |
| } |
| gsize zhuyin_start=strlen(preeditBuf); |
| /* Inserting zhuyinBuf */ |
| if (zhuyin_count>0){ |
| g_strlcat(preeditBuf,zhuyin_str,len+1); |
| } |
| /* Append rest chiSymbolBuf */ |
| g_strlcat(preeditBuf,buff_str+zhuyin_start, len+1); |
| |
| g_free(buff_str); |
| g_free(zhuyin_str); |
| G_DEBUG_MSG(4, "[I4] make_preedit_string(): return preedit=%s zhuyin_latest=%s zhuyin_tone=%d inputMode=%d", |
| preeditBuf, self->_priv->zhuyin_latest,zhuyin_tone,self->inputMode); |
| |
| return preeditBuf; |
| } |
| |
| private void show_lookup_table(self, gboolean isShow){ |
| ibus_engine_update_lookup_table(IBUS_ENGINE(self),self->table,isShow); |
| if (isShow){ |
| ibus_engine_show_lookup_table(IBUS_ENGINE(self)); |
| ibus_chewing_engine_set_status_flag(self,ENGINE_STATUS_SHOW_CANDIDATE); |
| }else{ |
| ibus_engine_hide_lookup_table(IBUS_ENGINE(self)); |
| ibus_chewing_engine_clear_status_flag(self,ENGINE_STATUS_SHOW_CANDIDATE); |
| } |
| } |
| |
| private void update_lookup_table(self){ |
| if (!self->table){ |
| self->table=ibus_lookup_table_new(1,0,TRUE,TRUE); |
| g_object_ref_sink(self->table); |
| } |
| ibus_lookup_table_clear(self->table); |
| int choicePerPage=chewing_cand_ChoicePerPage(self->context); |
| int i=0; |
| char *candidate=NULL; |
| IBusText *iText=NULL; |
| |
| G_DEBUG_MSG(4,"[I4] update_lookup_table() TotalChoice=%d CurrentPage=%d", |
| chewing_cand_TotalChoice(self->context),chewing_cand_CurrentPage(self->context)); |
| if (chewing_cand_TotalChoice(self->context) >0){ |
| chewing_cand_Enumerate(self->context); |
| for(i=0;i<choicePerPage;i++){ |
| if (chewing_cand_hasNext(self->context)){ |
| candidate=chewing_cand_String(self->context); |
| iText=g_object_ref_sink(ibus_text_new_from_string (candidate)); |
| ibus_lookup_table_append_candidate(self->table,iText); |
| g_free(candidate); |
| g_object_unref (iText); |
| }else{ |
| break; |
| } |
| } |
| self_show_lookup_table(self, TRUE); |
| }else{ |
| self_show_lookup_table(self, FALSE); |
| } |
| } |
| |
| /* Apply IBusText attributes */ |
| private IBusText *decorate_preedit(self, gchar *preeditBuf, gint *chiSymbolCursor, gint zhuyin_item_written){ |
| IBusText *iText=g_object_ref_sink(ibus_text_new_from_string(preeditBuf)); |
| *chiSymbolCursor = chewing_cursor_Current(self->context); |
| G_DEBUG_MSG(4,"[I4] decorate_preedit() chiSymbolCursor=%d preeditBuf=%s statusFlags=%x", |
| *chiSymbolCursor,preeditBuf, self->_priv->statusFlags); |
| g_free(preeditBuf); |
| |
| gint cursorRight=0; |
| gint charLen=(gint) g_utf8_strlen(iText->text, -1); |
| switch(self->inputMode){ |
| case CHEWING_INPUT_MODE_SELECTING: |
| cursorRight=*chiSymbolCursor + MAX(zhuyin_item_written, 1); |
| break; |
| case CHEWING_INPUT_MODE_EDITING: |
| case CHEWING_INPUT_MODE_SELECTING_DONE: |
| default: /* BYPASS */ |
| cursorRight=*chiSymbolCursor + MAX(zhuyin_item_written, 1); |
| break; |
| } |
| |
| G_DEBUG_MSG(5,"[I5] decorate_preedit() charLen=%d cursorRight=%d", charLen, cursorRight); |
| if (*chiSymbolCursor< cursorRight){ |
| ibus_text_append_attribute (iText, IBUS_ATTR_TYPE_FOREGROUND, 0x00ffffff, |
| *chiSymbolCursor, cursorRight); |
| ibus_text_append_attribute (iText, IBUS_ATTR_TYPE_BACKGROUND, 0x00000000, |
| *chiSymbolCursor, cursorRight); |
| } |
| |
| IntervalType it; |
| chewing_interval_Enumerate(self->context); |
| while(chewing_interval_hasNext(self->context)){ |
| chewing_interval_Get(self->context,&it); |
| G_DEBUG_MSG(6,"[I6] decorate_preedit() it.from=%d it.to=%d", it.from, it.to); |
| if (it.to-it.from >1){ |
| ibus_text_append_attribute (iText, IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_DOUBLE, |
| it.from, it.to); |
| } |
| } |
| ibus_text_append_attribute (iText, IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, |
| 0, -1); |
| return iText; |
| } |
| |
| private void update_aux_string(self, IBusText *preeditIText){ |
| G_DEBUG_MSG(4,"[I4] update_aux_string() statusFlags=%x", self->_priv->statusFlags); |
| IBusText *iText=NULL; |
| switch (self->_priv->inputStyle){ |
| case CHEWING_INPUT_STYLE_IN_APPLICATION: |
| if (chewing_aux_Length(self->context)>0){ |
| gchar *aux_string=chewing_aux_String(self->context); |
| iText=g_object_ref_sink(ibus_text_new_from_string (aux_string)); |
| ibus_engine_update_auxiliary_text(IBUS_ENGINE(self),iText,TRUE); |
| g_object_unref (iText); |
| ibus_engine_show_auxiliary_text(IBUS_ENGINE(self)); |
| g_free(aux_string); |
| }else{ |
| ibus_engine_hide_auxiliary_text(IBUS_ENGINE(self)); |
| } |
| break; |
| case CHEWING_INPUT_STYLE_IN_CANDIDATE: |
| ibus_engine_update_auxiliary_text(IBUS_ENGINE(self),preeditIText,TRUE); |
| ibus_engine_show_auxiliary_text(IBUS_ENGINE(self)); |
| break; |
| } |
| } |
| |
| private void update_preedit(self, IBusText *preeditIText,gint chiSymbolCursor){ |
| G_DEBUG_MSG(5,"[I5] update_preedit() text=%s statusFlags=%x", preeditIText->text, self->_priv->statusFlags); |
| switch (self->_priv->inputStyle){ |
| case CHEWING_INPUT_STYLE_IN_APPLICATION: |
| ibus_engine_update_preedit_text (IBUS_ENGINE(self),preeditIText, chiSymbolCursor, TRUE); |
| break; |
| case CHEWING_INPUT_STYLE_IN_CANDIDATE: |
| ibus_engine_update_preedit_text (IBUS_ENGINE(self),SELF_GET_CLASS(self)->emptyText, 0, TRUE); |
| break; |
| } |
| G_DEBUG_MSG(5,"[I5] update_preedit(): return"); |
| } |
| |
| protected gboolean update(self){ |
| G_DEBUG_MSG(3,"[I3] update() statusFlags=%x", self->_priv->statusFlags); |
| self_determine_input_mode(self); |
| gint chiSymbolCursor; |
| glong zhuyin_item_written; |
| self_commit(self); |
| gchar *preeditBuf=self_make_preedit_string(self, &zhuyin_item_written); |
| IBusText *iText=self_decorate_preedit(self, preeditBuf, &chiSymbolCursor, zhuyin_item_written); |
| if (g_object_is_floating(iText)){ |
| g_object_ref_sink(iText); |
| } |
| |
| self_update_aux_string(self, iText); |
| self_update_preedit(self, iText, chiSymbolCursor); |
| g_object_unref (iText); |
| uint16 *phoneSeq=(chewing_get_phoneSeqLen(self->context)>0)? chewing_get_phoneSeq(self->context): NULL; |
| G_DEBUG_MSG(4,"[I4] update() inputMode=%d nPhoneSeq=%d statusFlags=%u", |
| self->inputMode, |
| chewing_get_phoneSeqLen(self->context), |
| self->_priv->statusFlags); |
| if (phoneSeq){ |
| int i=0; |
| for(i=0;i<chewing_get_phoneSeqLen(self->context);i++){ |
| G_DEBUG_MSG(5,"[I5] update() phoneSeq[%d]=%x",i,phoneSeq[i]); |
| } |
| free(phoneSeq); |
| } |
| self_update_lookup_table(self); |
| //self_commit(self); |
| gboolean ret=TRUE; |
| |
| if (chewing_keystroke_CheckAbsorb(self->context)){ |
| ret=TRUE; |
| }else if (chewing_keystroke_CheckIgnore(self->context)){ |
| ret=FALSE; |
| } |
| G_DEBUG_MSG(4,"[I4] update() return %s",(ret)? "TRUE": "FALSE"); |
| return ret; |
| } |
| |
| protected void refresh_property(self,const gchar *prop_name){ |
| G_DEBUG_MSG(2,"[I2] refresh_property(%s)",prop_name); |
| if (strcmp(prop_name,"chewing_chieng_prop")==0){ |
| if (chewing_get_ChiEngMode(self->context)){ |
| /* Chinese */ |
| ibus_property_set_label(self->chieng_prop,SELF_GET_CLASS(self)->chieng_prop_label_chi); |
| }else{ |
| /* English */ |
| ibus_property_set_label(self->chieng_prop,SELF_GET_CLASS(self)->chieng_prop_label_eng); |
| } |
| ibus_engine_update_property(IBUS_ENGINE(self),self->chieng_prop); |
| }else if (strcmp(prop_name,"chewing_alnumSize_prop")==0){ |
| if (chewing_get_ShapeMode(self->context)){ |
| /* Full-Sized Shape */ |
| ibus_property_set_label(self->alnumSize_prop,SELF_GET_CLASS(self)->alnumSize_prop_label_full); |
| }else{ |
| /* Half-Sized Shape */ |
| ibus_property_set_label(self->alnumSize_prop,SELF_GET_CLASS(self)->alnumSize_prop_label_half); |
| } |
| ibus_engine_update_property(IBUS_ENGINE(self),self->alnumSize_prop); |
| } |
| } |
| |
| /** |
| * refresh_property_list: |
| * @self: this instances. |
| * |
| * Refresh the property list (language bar). |
| */ |
| public void refresh_property_list(self){ |
| self_refresh_property(self,"chewing_chieng_prop"); |
| |
| self_refresh_property(self,"chewing_alnumSize_prop"); |
| |
| self_refresh_property(self,"chewing_settings_prop"); |
| if (self->_priv->statusFlags & (ENGINE_STATUS_ENABLED | ENGINE_STATUS_FOCUS_IN)){ |
| ibus_engine_register_properties(IBUS_ENGINE(self),self->prop_list); |
| IBUS_ENGINE_GET_CLASS(self)->property_show(IBUS_ENGINE(self),"chewing_chieng_prop"); |
| IBUS_ENGINE_GET_CLASS(self)->property_show(IBUS_ENGINE(self),"chewing_alnumSize_prop"); |
| IBUS_ENGINE_GET_CLASS(self)->property_show(IBUS_ENGINE(self),"chewing_settings_prop"); |
| } |
| } |
| |
| /** |
| * hide_property_list: |
| * @self: this instances. |
| * |
| * Hide the property list (language bar). |
| */ |
| public void hide_property_list(self){ |
| IBUS_ENGINE_GET_CLASS(self)->property_hide(IBUS_ENGINE(self),"chewing_chieng_prop"); |
| IBUS_ENGINE_GET_CLASS(self)->property_hide(IBUS_ENGINE(self),"chewing_alnumSize_prop"); |
| IBUS_ENGINE_GET_CLASS(self)->property_hide(IBUS_ENGINE(self),"chewing_settings_prop"); |
| } |
| |
| /** |
| * save_config: |
| * @self: this instances. |
| * @key_suffix: key to be set. |
| * @returns: TRUE if successful, FALSE otherwise. |
| * |
| * Save the property value to disk. |
| */ |
| public gboolean save_config(self, const gchar *key_suffix){ |
| G_DEBUG_MSG(1,"[I1] save_config(%s,-)",key_suffix); |
| GValue gValue={0}; |
| // TODO: Save the config on Chromium OS. |
| //maker_dialog_get_widget_value(MAKER_DIALOG(self->setting_dialog),key_suffix,&gValue); |
| //return ibus_config_set_value (self->config,"engine/Chewing",key_suffix,&gValue); |
| return TRUE; |
| } |
| |
| /** |
| * save_config_all: |
| * @self: this instances. |
| * @key_suffix: key to be set. |
| * @returns: TRUE if all successful, FALSE otherwise. |
| * |
| * Save alll property values to disk. |
| */ |
| public gboolean save_config_all(self){ |
| int i; |
| gboolean success=TRUE; |
| for(i=0;propSpecs[i].valueType!=G_TYPE_INVALID;i++){ |
| if (!self_save_config(self,propSpecs[i].key)){ |
| success=FALSE; |
| } |
| } |
| return success; |
| } |
| |
| protected gboolean is_selectKey(self, guint keyval){ |
| int j; |
| for (j=0;j< MAX_SELKEY;j++){ |
| if (self->selKeys[j]==keyval){ |
| return TRUE; |
| } |
| } |
| return FALSE; |
| } |
| |
| protected void set_selKeys_string(self,const gchar* selKeys_str){ |
| int j; |
| int len_min= MIN(strlen(selKeys_str), MAX_SELKEY); |
| for (j=0;j< len_min;j++){ |
| self->selKeys[j]=(int) selKeys_str[j]; |
| } |
| chewing_set_selKey(self->context, self->selKeys,len_min); |
| } |
| |
| private IBusProperty* get_iBusProperty(self, const gchar *prop_name){ |
| if (strcmp(prop_name,"chewing_chieng_prop")==0){ |
| return self->chieng_prop; |
| }else if (strcmp(prop_name,"chewing_alnumSize_prop")==0){ |
| return self->alnumSize_prop; |
| }else if (strcmp(prop_name,"chewing_settings_prop")==0){ |
| return self->settings_prop; |
| } |
| G_DEBUG_MSG(2,"[I2] get_iBusProperty(%s): NULL is returned",prop_name); |
| return NULL; |
| } |
| |
| protected void handle_Default(self, guint keyval, gboolean shiftPressed){ |
| G_DEBUG_MSG(2,"[I2] handle_Default(-,%u) plainZhuyin=%s inputMode=%d", |
| keyval,(self->flags & CHEWING_FLAG_PLAIN_ZHUYIN)? "TRUE": "FALSE",self->inputMode); |
| ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_NEED_COMMIT); |
| #ifdef EASY_SYMBOL_INPUT_WORK_AROUND |
| if (self->flags & CHEWING_FLAG_EASY_SYMBOL_INPUT){ |
| /* If shift is pressed, turn on the easySymbolInput, turn off |
| * otherwise |
| */ |
| chewing_set_easySymbolInput(self->context,(shiftPressed)? 1:0); |
| } |
| #endif |
| if (self->flags & CHEWING_FLAG_FORCE_LOWERCASE_ENGLISH){ |
| if (isupper(keyval) && !shiftPressed){ |
| keyval=tolower(keyval); |
| }else if (islower(keyval) && shiftPressed){ |
| keyval=toupper(keyval); |
| } |
| } |
| chewing_handle_Default(self->context,keyval); |
| if (self->flags & CHEWING_FLAG_PLAIN_ZHUYIN){ |
| if (self_is_selectKey(self,self->_priv->key_last) && |
| self->inputMode==CHEWING_INPUT_MODE_SELECTING){ |
| chewing_handle_Enter(self->context); |
| self->inputMode= CHEWING_INPUT_MODE_SELECTING_DONE; |
| } |
| } |
| } |
| |
| protected void handle_candidate_clicked(self, guint index, guint button, guint state){ |
| if (index >= chewing_get_candPerPage(self->context)) { |
| G_DEBUG_MSG(3,"[I3] handle_cadidate_clicked(-, %u, %u, %u) ... index out of range.", index, button, state); |
| return; |
| } |
| if (self->inputMode==CHEWING_INPUT_MODE_SELECTING_DONE){ |
| int* keys = chewing_get_selKey(self->context); |
| if (!keys) { |
| G_DEBUG_MSG(3,"[I3] handle_cadidate_clicked(-, %u, %u, %u) ... No sel keys.", index, button, state); |
| return; |
| } |
| ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_NEED_COMMIT); |
| chewing_handle_Default(self->context, keys[index]); |
| chewing_free(keys); |
| self_update(self); |
| } else { |
| G_DEBUG_MSG(3,"[I3] handle_cadidate_clicked() ... Wrong mode: %u", self->inputMode); |
| } |
| } |
| |
| /* |
| * determine_input_mode: |
| * |
| * Determine input mode. |
| */ |
| private void determine_input_mode(self){ |
| gint zhuyin_count=-1; |
| gchar *str_ptr=chewing_zuin_String(self->context,&zhuyin_count); |
| G_DEBUG_MSG(3, "[I3] determine_input_mode(): chewing_zuin_String=%s count=%d inputMode=%d", |
| str_ptr,zhuyin_count,self->inputMode); |
| |
| int zhuyin_tone=-1; |
| if (zhuyin_count>0){ |
| /* Incomplete Character*/ |
| self->inputMode=CHEWING_INPUT_MODE_EDITING; |
| }else{ |
| /* Character/Phrase is completed. */ |
| if (self->inputMode==CHEWING_INPUT_MODE_EDITING){ |
| /* In EDITING mode */ |
| zhuyin_tone=get_tone(chewing_get_KBType(self->context),self->_priv->key_last); |
| if (zhuyin_tone>0 ){ |
| if (self->flags & CHEWING_FLAG_PLAIN_ZHUYIN){ |
| /* For plain zhuyin, Enter SELECTING mode */ |
| self->inputMode=CHEWING_INPUT_MODE_SELECTING; |
| }else{ |
| /* For normal zhuyin, Enter SELECTING mode */ |
| self->inputMode=CHEWING_INPUT_MODE_SELECTING_DONE; |
| } |
| } |
| }else if (self->inputMode==CHEWING_INPUT_MODE_SELECTING_DONE){ |
| /* In SELECTING_DONE mode */ |
| /* One of selection keys is pressed */ |
| }else{ |
| /* In SELECTING mode */ |
| } |
| } |
| |
| if (chewing_buffer_Len(self->context)+ zhuyin_count==0){ |
| /* If preedit buffer is empty, then enter BYPASS mode.*/ |
| /* So cursor keys can be used freely. */ |
| self->inputMode=CHEWING_INPUT_MODE_BYPASS; |
| self->_priv->zhuyin_latest[0]='\0'; |
| } |
| g_free(str_ptr); |
| G_DEBUG_MSG(3, "[I3] determine_input_mode() return: zhuyin_latest=%s zhuyin_tone=%d inputMode=%d", |
| self->_priv->zhuyin_latest,zhuyin_tone,self->inputMode); |
| } |
| |
| /* commit string */ |
| protected gboolean commit(self){ |
| gint commit=chewing_commit_Check(self->context); |
| G_DEBUG_MSG(2,"[I2] commit() %s statusFlags=%x", (commit) ? "TRUE": "FALSE", self->_priv->statusFlags); |
| if ((self->_priv->statusFlags & ENGINE_STATUS_NEED_COMMIT) && commit){ |
| IBusText *iText=NULL; |
| |
| gchar *commit_string=chewing_commit_String(self->context); |
| G_DEBUG_MSG(3,"[I3] commit() commit_string=%s", commit_string); |
| iText=g_object_ref_sink(ibus_text_new_from_string(commit_string)); |
| ibus_engine_commit_text(IBUS_ENGINE(self),iText); |
| g_free(commit_string); |
| g_object_unref(iText); |
| if (!chewing_buffer_Check(self->context)){ |
| /* Buffer is clean */ |
| ibus_chewing_engine_clear_status_flag(self, ENGINE_STATUS_NEED_COMMIT | ENGINE_STATUS_FORCE_COMMIT ); |
| }else if (self->_priv->statusFlags & ENGINE_STATUS_FORCE_COMMIT){ |
| /* Flush the buffer */ |
| chewing_handle_Enter(self->context); |
| commit_string=chewing_commit_String(self->context); |
| iText=g_object_ref_sink(ibus_text_new_from_string(commit_string)); |
| ibus_engine_commit_text(IBUS_ENGINE(self),iText); |
| g_free(commit_string); |
| g_object_unref(iText); |
| ibus_chewing_engine_clear_status_flag(self, ENGINE_STATUS_FORCE_COMMIT ); |
| } |
| } |
| return commit; |
| } |
| |
| protected void force_commit(self){ |
| G_DEBUG_MSG(3,"[I3] force_commit() buffer=%d, commit=%d statusFlags=%x", |
| chewing_buffer_Check(self->context),chewing_commit_Check(self->context), self->_priv->statusFlags); |
| /* Remove the incomplete zhuyin symbol */ |
| if (self->inputMode==CHEWING_INPUT_MODE_EDITING) |
| chewing_handle_Esc(self->context); |
| if (chewing_buffer_Check(self->context)){ |
| if (!chewing_commit_Check(self->context)){ |
| /* Close candidate window */ |
| if (self->_priv->statusFlags & ENGINE_STATUS_SHOW_CANDIDATE){ |
| chewing_handle_Esc(self->context); |
| } |
| chewing_handle_Enter(self->context); |
| } |
| ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_NEED_COMMIT | ENGINE_STATUS_FORCE_COMMIT); |
| self_update(self); |
| } |
| } |
| |
| /*============================================ |
| * Overridden Parent (IBusEngine) methods |
| */ |
| override (IBus:Engine) void |
| reset(IBus:Engine *engine){ |
| G_DEBUG_MSG(1,"[I1] reset"); |
| Self *self=SELF(engine); |
| if (self->_priv->statusFlags & ENGINE_STATUS_NEED_COMMIT){ |
| /* Force commit non-empty preedit buffer */ |
| self_force_commit(self); |
| } |
| ibus_lookup_table_clear(self->table); |
| /* Save KBType type, becaue chewing_Reset() will reset it to default. |
| */ |
| int kbType=chewing_get_KBType(self->context); |
| chewing_Reset(self->context); |
| chewing_set_KBType(self->context,kbType); |
| ibus_engine_hide_auxiliary_text(IBUS_ENGINE(engine)); |
| ibus_engine_hide_lookup_table(IBUS_ENGINE(self)); |
| } |
| |
| override (IBus:Engine) void |
| page_up(IBus:Engine *engine){ |
| Self *self=SELF(engine); |
| chewing_handle_PageUp(self->context); |
| self_update(self); |
| } |
| |
| |
| override (IBus:Engine) void |
| page_down(IBus:Engine *engine){ |
| Self *self=SELF(engine); |
| chewing_handle_PageDown(self->context); |
| self_update(self); |
| } |
| |
| override (IBus:Engine) void |
| cursor_up(IBus:Engine *engine){ |
| Self *self=SELF(engine); |
| chewing_handle_Up(self->context); |
| self_update(self); |
| } |
| |
| override (IBus:Engine) void |
| cursor_down(IBus:Engine *engine){ |
| Self *self=SELF(engine); |
| chewing_handle_Down(self->context); |
| self_update(self); |
| } |
| |
| override (IBus:Engine) void |
| enable(IBus:Engine *engine){ |
| G_DEBUG_MSG(2,"[I2] enable()"); |
| Self *self=SELF(engine); |
| |
| if (!self->config){ |
| |
| /* connections_list is not avail in init, so we put it here */ |
| GList *connections_list=ibus_service_get_connections(IBUS_SERVICE(engine)); |
| g_assert(connections_list); |
| g_assert(connections_list->data); |
| IBusConnection *iConnection=(IBusConnection *) connections_list->data; |
| self->config=ibus_config_new(iConnection); |
| self_load_setting(self); |
| } |
| self_refresh_property_list(self); |
| self->inputMode=CHEWING_INPUT_MODE_SELECTING_DONE; |
| ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_ENABLED); |
| } |
| |
| override (IBus:Engine) void |
| disable(IBus:Engine *engine){ |
| G_DEBUG_MSG(2,"[I2] disable()"); |
| Self *self=SELF(engine); |
| self_force_commit(self); |
| self_hide_property_list(self); |
| self->inputMode=CHEWING_INPUT_MODE_BYPASS; |
| ibus_chewing_engine_clear_status_flag(self,ENGINE_STATUS_ENABLED); |
| } |
| |
| override (IBus:Engine) void |
| focus_in(IBus:Engine *engine){ |
| Self *self=SELF(engine); |
| |
| /* Sync Caps_Lock and ChiEngMode */ |
| guint modifiers=keyModifier_get(self->_priv->pDisplay); |
| gint caps_is_lock=(modifiers & IBUS_LOCK_MASK)!=0; |
| G_DEBUG_MSG(2,"[I2] focus_in(): statusFlags=%d ChiEng=%d IBUS_LOCK=%d", |
| self->_priv->statusFlags, |
| chewing_get_ChiEngMode(self->context),caps_is_lock); |
| if (chewing_get_ChiEngMode(self->context)==caps_is_lock){ |
| /* Caps_lock and ChiEngMode does not agree each other */ |
| switch(self->syncCapsLock_local){ |
| case CHEWING_MODIFIER_SYNC_FROM_KEYBOARD: |
| chewing_set_ChiEngMode(self->context,!caps_is_lock); |
| break; |
| case CHEWING_MODIFIER_SYNC_FROM_IM: |
| /* fake event won't go through process_key_event */ |
| key_send_fake_event(IBUS_Caps_Lock,self->_priv->pDisplay); |
| break; |
| default: |
| g_warning("Caps_lock and ChiEngMode does not agree each other!"); |
| break; |
| |
| } |
| } |
| self_refresh_property_list(self); |
| self_update(self); |
| ibus_chewing_engine_set_status_flag(self, ENGINE_STATUS_FOCUS_IN); |
| G_DEBUG_MSG(4,"[I4] focus_in(): return"); |
| } |
| |
| override (IBus:Engine) void |
| focus_out(IBus:Engine *engine){ |
| Self *self=SELF(engine); |
| G_DEBUG_MSG(2,"[I2] focus_out(): statusFlags=%d",self->_priv->statusFlags); |
| self_force_commit(self); |
| ibus_chewing_engine_clear_status_flag(self, ENGINE_STATUS_FOCUS_IN); |
| G_DEBUG_MSG(5,"[I5] focus_out(): return"); |
| } |
| |
| override (IBus:Engine) void |
| property_activate(IBus:Engine *engine, const gchar *prop_name, guint prop_state){ |
| G_DEBUG_MSG(2,"[I2] property_activate(-, %s, %u)", prop_name, prop_state); |
| Self *self=SELF(engine); |
| gboolean needRefresh=TRUE; |
| if (strcmp(prop_name,"chewing_chieng_prop")==0){ |
| /* Toggle Chinese <-> English */ |
| chewing_set_ChiEngMode(self->context, !chewing_get_ChiEngMode(self->context)); |
| }else if (strcmp(prop_name,"chewing_alnumSize_prop")==0){ |
| /* Toggle Full <-> Half */ |
| chewing_set_ShapeMode(self->context, !chewing_get_ShapeMode(self->context)); |
| //}else if (strcmp(prop_name,"chewing_settings_prop")==0){ |
| // if (self->settings_prop->state==PROP_STATE_UNCHECKED){ |
| // if (gtk_dialog_run(GTK_DIALOG(self->setting_dialog))==GTK_RESPONSE_OK){ |
| // self_save_config_all(self); |
| // } |
| // gtk_widget_hide(self->setting_dialog); |
| // self->settings_prop->state=PROP_STATE_UNCHECKED; |
| // } |
| }else{ |
| G_DEBUG_MSG(2,"[I2] property_activate(-, %s, %u) not recognized",prop_name, prop_state); |
| needRefresh=FALSE; |
| } |
| if (needRefresh) |
| self_refresh_property(self,prop_name); |
| } |
| |
| override (IBus:Engine) void |
| property_show(IBus:Engine *engine, const gchar *prop_name){ |
| G_DEBUG_MSG(2,"[I2] property_show(-, %s)",prop_name); |
| Self *self=SELF(engine); |
| IBusProperty *prop=self_get_iBusProperty(self, prop_name); |
| ibus_property_set_visible(prop,TRUE); |
| ibus_engine_update_property(engine,prop); |
| } |
| |
| override (IBus:Engine) void |
| property_hide(IBus:Engine *engine, const gchar *prop_name){ |
| G_DEBUG_MSG(2,"[I2] property_hide(-, %s)",prop_name); |
| Self *self=SELF(engine); |
| IBusProperty *prop=self_get_iBusProperty(self, prop_name); |
| ibus_property_set_visible(prop,FALSE); |
| ibus_engine_update_property(engine,prop); |
| } |
| } |
| |
| %{ |
| #include "IBusChewingEngine-keys.c" |
| %} |
| |