+ int from = mtext_property_start (prop);
+ int to = mtext_property_end (prop);
+ int start;
+ MPlist *candidate_list = mtext_property_value (prop);
+ MPlist *group = find_candidates_group (candidate_list, idx, &start,
+ NULL, NULL);
+ int ingroup_index = idx - start;
+ MText *mt;
+
+ if (MPLIST_MTEXT_P (group))
+ {
+ mt = MPLIST_MTEXT (group);
+ preedit_replace (ic, from, to, NULL, mtext_ref_char (mt, ingroup_index));
+ to = from + 1;
+ }
+ else
+ {
+ int i;
+ MPlist *plist;
+
+ for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index;
+ i++, plist = MPLIST_NEXT (plist));
+ mt = MPLIST_MTEXT (plist);
+ preedit_replace (ic, from, to, mt, 0);
+ to = from + mtext_nchars (mt);
+ }
+ mtext_put_prop (ic->preedit, from, to, Mcandidate_list, candidate_list);
+ mtext_put_prop (ic->preedit, from, to, Mcandidate_index, (void *) idx);
+ ic->cursor_pos = to;
+}
+
+static MCharset *
+get_select_charset (MInputContextInfo * ic_info)
+{
+ MPlist *plist = resolve_variable (ic_info, Mcandidates_charset);
+ MSymbol sym;
+
+ if (! MPLIST_VAL (plist))
+ return NULL;
+ sym = MPLIST_SYMBOL (plist);
+ if (sym == Mnil)
+ return NULL;
+ return MCHARSET (sym);
+}
+
+static MPlist *
+adjust_candidates (MPlist *plist, MCharset *charset)
+{
+ MPlist *pl;
+
+ /* plist ::= MTEXT ... | PLIST ... */
+ plist = mplist_copy (plist);
+ if (MPLIST_MTEXT_P (plist))
+ {
+ pl = plist;
+ while (! MPLIST_TAIL_P (pl))
+ {
+ /* pl ::= MTEXT ... */
+ MText *mt = MPLIST_MTEXT (pl);
+ int mt_copied = 0;
+ int i, c;
+
+ for (i = mtext_nchars (mt) - 1; i >= 0; i--)
+ {
+ c = mtext_ref_char (mt, i);
+ if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
+ {
+ if (! mt_copied)
+ {
+ mt = mtext_dup (mt);
+ mplist_set (pl, Mtext, mt);
+ M17N_OBJECT_UNREF (mt);
+ mt_copied = 1;
+ }
+ mtext_del (mt, i, i + 1);
+ }
+ }
+ if (mtext_len (mt) > 0)
+ pl = MPLIST_NEXT (pl);
+ else
+ {
+ mplist_pop (pl);
+ M17N_OBJECT_UNREF (mt);
+ }
+ }
+ }
+ else /* MPLIST_PLIST_P (plist) */
+ {
+ pl = plist;
+ while (! MPLIST_TAIL_P (pl))
+ {
+ /* pl ::= (MTEXT ...) ... */
+ MPlist *p = MPLIST_PLIST (pl);
+ int p_copied = 0;
+ /* p ::= MTEXT ... */
+ MPlist *p0 = p;
+ int n = 0;
+
+ while (! MPLIST_TAIL_P (p0))
+ {
+ MText *mt = MPLIST_MTEXT (p0);
+ int i, c;
+
+ for (i = mtext_nchars (mt) - 1; i >= 0; i--)
+ {
+ c = mtext_ref_char (mt, i);
+ if (ENCODE_CHAR (charset, c) == MCHAR_INVALID_CODE)
+ break;
+ }
+ if (i < 0)
+ {
+ p0 = MPLIST_NEXT (p0);
+ n++;
+ }
+ else
+ {
+ if (! p_copied)
+ {
+ p = mplist_copy (p);
+ mplist_set (pl, Mplist, p);
+ M17N_OBJECT_UNREF (p);
+ p_copied = 1;
+ p0 = p;
+ while (n-- > 0)
+ p0 = MPLIST_NEXT (p0);
+ }
+ mplist_pop (p0);
+ M17N_OBJECT_UNREF (mt);
+ }
+ }
+ if (! MPLIST_TAIL_P (p))
+ pl = MPLIST_NEXT (pl);
+ else
+ {
+ mplist_pop (pl);
+ M17N_OBJECT_UNREF (p);
+ }
+ }
+ }
+ if (MPLIST_TAIL_P (plist))
+ {
+ M17N_OBJECT_UNREF (plist);
+ return NULL;
+ }
+ return plist;
+}
+
+static MPlist *
+get_candidate_list (MInputContextInfo *ic_info, MPlist *args)
+{
+ MCharset *charset = get_select_charset (ic_info);
+ MPlist *plist;
+ int column;
+ int i, len;
+
+ plist = resolve_variable (ic_info, Mcandidates_group_size);
+ column = MPLIST_INTEGER (plist);
+
+ plist = MPLIST_PLIST (args);
+ if (charset)
+ plist = adjust_candidates (plist, charset);
+
+ if (plist && column > 0)
+ {
+ if (MPLIST_MTEXT_P (plist))
+ {
+ MText *mt = MPLIST_MTEXT (plist);
+ MPlist *next = MPLIST_NEXT (plist);
+
+ if (MPLIST_TAIL_P (next))
+ M17N_OBJECT_REF (mt);
+ else
+ {
+ mt = mtext_dup (mt);
+ while (! MPLIST_TAIL_P (next))
+ {
+ mt = mtext_cat (mt, MPLIST_MTEXT (next));
+ next = MPLIST_NEXT (next);
+ }
+ }
+ if (charset)
+ M17N_OBJECT_UNREF (plist);
+ plist = mplist ();
+ len = mtext_nchars (mt);
+ if (len <= column)
+ mplist_add (plist, Mtext, mt);
+ else
+ {
+ for (i = 0; i < len; i += column)
+ {
+ int to = (i + column < len ? i + column : len);
+ MText *sub = mtext_copy (mtext (), 0, mt, i, to);
+
+ mplist_add (plist, Mtext, sub);
+ M17N_OBJECT_UNREF (sub);
+ }
+ }
+ M17N_OBJECT_UNREF (mt);
+ }
+ else if (! MPLIST_TAIL_P (plist))
+ {
+ MPlist *tail = plist;
+ MPlist *new = mplist ();
+ MPlist *this = mplist ();
+ int count = 0;
+
+ MPLIST_DO (tail, tail)
+ {
+ MPlist *p = MPLIST_PLIST (tail);
+
+ MPLIST_DO (p, p)
+ {
+ MText *mt = MPLIST_MTEXT (p);
+
+ if (count == column)
+ {
+ mplist_add (new, Mplist, this);
+ M17N_OBJECT_UNREF (this);
+ this = mplist ();
+ count = 0;
+ }
+ mplist_add (this, Mtext, mt);
+ count++;
+ }
+ }
+ mplist_add (new, Mplist, this);
+ M17N_OBJECT_UNREF (this);
+ mplist_set (plist, Mnil, NULL);
+ MPLIST_DO (tail, new)
+ {
+ MPlist *elt = MPLIST_PLIST (tail);
+
+ mplist_add (plist, Mplist, elt);
+ }
+ M17N_OBJECT_UNREF (new);
+ }
+ }
+
+ return plist;
+}
+
+
+static MPlist *
+regularize_action (MPlist *action_list, MInputContextInfo *ic_info)
+{
+ MPlist *action = NULL;
+ MSymbol name;
+ MPlist *args;
+
+ if (MPLIST_SYMBOL_P (action_list))
+ {
+ MSymbol var = MPLIST_SYMBOL (action_list);
+ MPlist *p;
+
+ MPLIST_DO (p, ic_info->vars)
+ if (MPLIST_SYMBOL (MPLIST_PLIST (p)) == var)
+ break;
+ if (MPLIST_TAIL_P (p))
+ return NULL;
+ action = MPLIST_NEXT (MPLIST_PLIST (p));
+ mplist_set (action_list, MPLIST_KEY (action), MPLIST_VAL (action));
+ }
+
+ if (MPLIST_PLIST_P (action_list))
+ {
+ action = MPLIST_PLIST (action_list);
+ if (MPLIST_SYMBOL_P (action))
+ {
+ name = MPLIST_SYMBOL (action);
+ args = MPLIST_NEXT (action);
+ if (name == Minsert
+ && MPLIST_PLIST_P (args))
+ mplist_set (action, Msymbol, M_candidates);
+ }
+ else if (MPLIST_MTEXT_P (action) || MPLIST_PLIST_P (action))
+ {
+ action = mplist ();
+ mplist_push (action, Mplist, MPLIST_VAL (action_list));
+ mplist_push (action, Msymbol, M_candidates);
+ mplist_set (action_list, Mplist, action);
+ M17N_OBJECT_UNREF (action);
+ }
+ }
+ else if (MPLIST_MTEXT_P (action_list) || MPLIST_INTEGER_P (action_list))
+ {
+ action = mplist ();
+ mplist_push (action, MPLIST_KEY (action_list), MPLIST_VAL (action_list));
+ mplist_push (action, Msymbol, Minsert);
+ mplist_set (action_list, Mplist, action);
+ M17N_OBJECT_UNREF (action);
+ }
+ return action;
+}
+
+/* Perform list of actions in ACTION_LIST for the current input
+ context IC. If unhandle action was not performed, return 0.
+ Otherwise, return -1. */
+
+static int
+take_action_list (MInputContext *ic, MPlist *action_list)
+{
+ MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
+ MPlist *candidate_list = ic->candidate_list;
+ int candidate_index = ic->candidate_index;
+ int candidate_show = ic->candidate_show;
+ MTextProperty *prop;
+
+ MPLIST_DO (action_list, action_list)
+ {
+ MPlist *action = regularize_action (action_list, ic_info);
+ MSymbol name;
+ MPlist *args;
+
+ if (! action)
+ continue;
+ name = MPLIST_SYMBOL (action);
+ args = MPLIST_NEXT (action);
+
+ MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name));
+ if (name == Minsert)
+ {
+ if (MPLIST_SYMBOL_P (args))
+ {
+ args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
+ if (! MPLIST_MTEXT_P (args) && ! MPLIST_INTEGER_P (args))
+ continue;
+ }
+ if (MPLIST_MTEXT_P (args))
+ preedit_insert (ic, ic->cursor_pos, MPLIST_MTEXT (args), 0);
+ else /* MPLIST_INTEGER_P (args)) */
+ preedit_insert (ic, ic->cursor_pos, NULL, MPLIST_INTEGER (args));
+ }
+ else if (name == M_candidates)
+ {
+ MPlist *plist = get_candidate_list (ic_info, args);
+ int len;
+
+ if (! plist || (MPLIST_PLIST_P (plist) && MPLIST_TAIL_P (plist)))
+ continue;
+ if (MPLIST_MTEXT_P (plist))
+ {
+ preedit_insert (ic, ic->cursor_pos, NULL,
+ mtext_ref_char (MPLIST_MTEXT (plist), 0));
+ len = 1;
+ }
+ else if (MPLIST_TAIL_P (MPLIST_PLIST (plist)))
+ continue;
+ else
+ {
+ MText * mt = MPLIST_MTEXT (MPLIST_PLIST (plist));
+
+ preedit_insert (ic, ic->cursor_pos, mt, 0);
+ len = mtext_nchars (mt);
+ }
+ mtext_put_prop (ic->preedit,
+ ic->cursor_pos - len, ic->cursor_pos,
+ Mcandidate_list, plist);
+ mtext_put_prop (ic->preedit,
+ ic->cursor_pos - len, ic->cursor_pos,
+ Mcandidate_index, (void *) 0);
+ }
+ else if (name == Mselect)
+ {
+ int start, end;
+ int code, idx, gindex;
+ int pos = ic->cursor_pos;
+ MPlist *group;
+ int idx_decided = 0;
+
+ if (pos == 0
+ || ! (prop = mtext_get_property (ic->preedit, pos - 1,
+ Mcandidate_list)))
+ continue;
+ idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index);
+ group = find_candidates_group (mtext_property_value (prop), idx,
+ &start, &end, &gindex);
+ if (MPLIST_SYMBOL_P (args))
+ {
+ code = marker_code (MPLIST_SYMBOL (args), 0);
+ if (code < 0)
+ {
+ args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
+ if (! MPLIST_INTEGER_P (args))
+ continue;
+ idx = start + MPLIST_INTEGER (args);
+ if (idx < start || idx >= end)
+ continue;
+ idx_decided = 1;
+ }
+ }
+ else
+ code = -1;
+
+ if (code != '[' && code != ']')
+ {
+ if (! idx_decided)
+ idx = (start
+ + (code >= 0
+ ? new_index (NULL, ic->candidate_index - start,
+ end - start - 1, MPLIST_SYMBOL (args),
+ NULL)
+ : MPLIST_INTEGER (args)));
+ if (idx < 0)
+ {
+ find_candidates_group (mtext_property_value (prop), -1,
+ NULL, &end, NULL);
+ idx = end - 1;
+ }
+ else if (idx >= end
+ && MPLIST_TAIL_P (MPLIST_NEXT (group)))
+ idx = 0;
+ }
+ else
+ {
+ int ingroup_index = idx - start;
+ int len;
+
+ group = mtext_property_value (prop);
+ len = mplist_length (group);
+ if (code == '[')
+ {
+ gindex--;
+ if (gindex < 0)
+ gindex = len - 1;;
+ }
+ else
+ {
+ gindex++;
+ if (gindex >= len)
+ gindex = 0;
+ }
+ for (idx = 0; gindex > 0; gindex--, group = MPLIST_NEXT (group))
+ idx += (MPLIST_MTEXT_P (group)
+ ? mtext_nchars (MPLIST_MTEXT (group))
+ : mplist_length (MPLIST_PLIST (group)));
+ len = (MPLIST_MTEXT_P (group)
+ ? mtext_nchars (MPLIST_MTEXT (group))
+ : mplist_length (MPLIST_PLIST (group)));
+ if (ingroup_index >= len)
+ ingroup_index = len - 1;
+ idx += ingroup_index;
+ }
+ update_candidate (ic, prop, idx);
+ MDEBUG_PRINT1 ("(%d)", idx);
+ }
+ else if (name == Mshow)
+ ic->candidate_show = 1;
+ else if (name == Mhide)
+ ic->candidate_show = 0;
+ else if (name == Mdelete)
+ {
+ int len = mtext_nchars (ic->preedit);
+ int pos;
+ int to;
+
+ if (MPLIST_SYMBOL_P (args)
+ && (pos = surrounding_pos (MPLIST_SYMBOL (args))) != 0)
+ {
+ to = ic->cursor_pos + pos;
+ if (to < 0)
+ {
+ delete_surrounding_text (ic, to);
+ to = 0;
+ }
+ else if (to > len)
+ {
+ delete_surrounding_text (ic, to - len);
+ to = len;
+ }
+ }
+ else
+ {
+ to = (MPLIST_SYMBOL_P (args)
+ ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
+ ic->preedit)
+ : MPLIST_INTEGER (args));
+ if (to < 0)
+ to = 0;
+ else if (to > len)
+ to = len;
+ }
+ MDEBUG_PRINT1 ("(%d)", to - ic->cursor_pos);
+ if (to < ic->cursor_pos)
+ preedit_delete (ic, to, ic->cursor_pos);
+ else if (to > ic->cursor_pos)
+ preedit_delete (ic, ic->cursor_pos, to);
+ }
+ else if (name == Mmove)
+ {
+ int len = mtext_nchars (ic->preedit);
+ int pos
+ = (MPLIST_SYMBOL_P (args)
+ ? new_index (ic, ic->cursor_pos, len, MPLIST_SYMBOL (args),
+ ic->preedit)
+ : MPLIST_INTEGER (args));
+
+ if (pos < 0)
+ pos = 0;
+ else if (pos > len)
+ pos = len;
+ if (pos != ic->cursor_pos)
+ {
+ ic->cursor_pos = pos;
+ ic->preedit_changed = 1;
+ }
+ MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
+ }
+ else if (name == Mmark)
+ {
+ int code = marker_code (MPLIST_SYMBOL (args), 0);
+
+ if (code < 0)
+ {
+ mplist_put (ic_info->markers, MPLIST_SYMBOL (args),
+ (void *) ic->cursor_pos);
+ MDEBUG_PRINT1 ("(%d)", ic->cursor_pos);
+ }
+ }
+ else if (name == Mpushback)
+ {
+ if (MPLIST_INTEGER_P (args) || MPLIST_SYMBOL_P (args))
+ {
+ int num;
+
+ if (MPLIST_SYMBOL_P (args))
+ {
+ args = resolve_variable (ic_info, MPLIST_SYMBOL (args));
+ if (MPLIST_INTEGER_P (args))
+ num = MPLIST_INTEGER (args);
+ else
+ num = 0;
+ }
+ else
+ num = MPLIST_INTEGER (args);
+
+ if (num > 0)
+ ic_info->key_head -= num;
+ else if (num == 0)
+ ic_info->key_head = 0;
+ else
+ ic_info->key_head = - num;
+ if (ic_info->key_head > ic_info->used)
+ ic_info->key_head = ic_info->used;
+ }
+ else if (MPLIST_MTEXT_P (args))
+ {
+ MText *mt = MPLIST_MTEXT (args);
+ int i, len = mtext_nchars (mt);
+ MSymbol key;
+
+ ic_info->key_head--;
+ for (i = 0; i < len; i++)
+ {
+ key = one_char_symbol[MTEXT_DATA (mt)[i]];
+ if (ic_info->key_head + i < ic_info->used)
+ ic_info->keys[ic_info->key_head + i] = key;
+ else
+ MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
+ }
+ }
+ else
+ {
+ MPlist *plist = MPLIST_PLIST (args), *pl;
+ int i = 0;
+ MSymbol key;
+
+ ic_info->key_head--;
+
+ MPLIST_DO (pl, plist)
+ {
+ key = MPLIST_SYMBOL (pl);
+ if (ic_info->key_head < ic_info->used)
+ ic_info->keys[ic_info->key_head + i] = key;
+ else
+ MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
+ i++;
+ }
+ }
+ }
+ else if (name == Mpop)
+ {
+ if (ic_info->key_head < ic_info->used)
+ MLIST_DELETE1 (ic_info, keys, ic_info->key_head, 1);
+ }
+ else if (name == Mcall)
+ {
+ MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
+ MIMExternalFunc func = NULL;
+ MSymbol module, func_name;
+ MPlist *func_args, *val;
+ int ret = 0;
+
+ module = MPLIST_SYMBOL (args);
+ args = MPLIST_NEXT (args);
+ func_name = MPLIST_SYMBOL (args);
+
+ if (im_info->externals)
+ {
+ MIMExternalModule *external
+ = (MIMExternalModule *) mplist_get (im_info->externals,
+ module);
+ if (external)
+ func = ((MIMExternalFunc)
+ mplist_get_func (external->func_list, func_name));
+ }
+ if (! func)
+ continue;
+ func_args = mplist ();
+ mplist_add (func_args, Mt, ic);
+ MPLIST_DO (args, MPLIST_NEXT (args))
+ {
+ int code;
+
+ if (MPLIST_KEY (args) == Msymbol
+ && MPLIST_KEY (args) != Mnil
+ && (code = marker_code (MPLIST_SYMBOL (args), 0)) >= 0)
+ {
+ code = new_index (ic, ic->cursor_pos,
+ mtext_nchars (ic->preedit),
+ MPLIST_SYMBOL (args), ic->preedit);
+ mplist_add (func_args, Minteger, (void *) code);
+ }
+ else
+ mplist_add (func_args, MPLIST_KEY (args), MPLIST_VAL (args));
+ }
+ val = (func) (func_args);
+ M17N_OBJECT_UNREF (func_args);
+ if (val && ! MPLIST_TAIL_P (val))
+ ret = take_action_list (ic, val);
+ M17N_OBJECT_UNREF (val);
+ if (ret < 0)
+ return ret;
+ }
+ else if (name == Mshift)
+ {
+ shift_state (ic, MPLIST_SYMBOL (args));
+ }
+ else if (name == Mundo)
+ {
+ int intarg = (MPLIST_TAIL_P (args)
+ ? ic_info->used - 2
+ : integer_value (ic, args, NULL, 0));
+
+ mtext_reset (ic->preedit);
+ mtext_reset (ic_info->preedit_saved);
+ mtext_reset (ic->produced);
+ M17N_OBJECT_UNREF (ic_info->vars);
+ ic_info->vars = mplist_copy (ic_info->vars_saved);
+ ic->cursor_pos = ic_info->state_pos = 0;
+ ic_info->state_key_head = ic_info->key_head
+ = ic_info->commit_key_head = 0;
+
+ shift_state (ic, Mnil);
+ if (intarg < 0)
+ {
+ if (MPLIST_TAIL_P (args))
+ {
+ ic_info->used = 0;
+ return -1;
+ }
+ ic_info->used += intarg;
+ }
+ else
+ ic_info->used = intarg;
+ break;
+ }
+ else if (name == Mset || name == Madd || name == Msub
+ || name == Mmul || name == Mdiv)
+ {
+ MSymbol sym = MPLIST_SYMBOL (args);
+ int val1, val2;
+ MPlist *value;
+ char *op;
+
+ val1 = integer_value (ic, args, &value, 0);
+ args = MPLIST_NEXT (args);
+ val2 = resolve_expression (ic, args);
+ if (name == Mset)
+ val1 = val2, op = "=";
+ else if (name == Madd)
+ val1 += val2, op = "+=";
+ else if (name == Msub)
+ val1 -= val2, op = "-=";
+ else if (name == Mmul)
+ val1 *= val2, op = "*=";
+ else
+ val1 /= val2, op = "/=";
+ MDEBUG_PRINT4 ("(%s %s 0x%X(%d))",
+ MSYMBOL_NAME (sym), op, val1, val1);
+ if (value)
+ mplist_set (value, Minteger, (void *) val1);
+ }
+ else if (name == Mequal || name == Mless || name == Mgreater
+ || name == Mless_equal || name == Mgreater_equal)
+ {
+ int val1, val2;
+ MPlist *actions1, *actions2;
+ int ret = 0;
+
+ val1 = resolve_expression (ic, args);
+ args = MPLIST_NEXT (args);
+ val2 = resolve_expression (ic, args);
+ args = MPLIST_NEXT (args);
+ actions1 = MPLIST_PLIST (args);
+ args = MPLIST_NEXT (args);
+ if (MPLIST_TAIL_P (args))
+ actions2 = NULL;
+ else
+ actions2 = MPLIST_PLIST (args);
+ MDEBUG_PRINT3 ("(%d %s %d)? ", val1, MSYMBOL_NAME (name), val2);
+ if (name == Mequal ? val1 == val2
+ : name == Mless ? val1 < val2
+ : name == Mgreater ? val1 > val2
+ : name == Mless_equal ? val1 <= val2
+ : val1 >= val2)
+ {
+ MDEBUG_PRINT ("ok");
+ ret = take_action_list (ic, actions1);
+ }
+ else
+ {
+ MDEBUG_PRINT ("no");
+ if (actions2)
+ ret = take_action_list (ic, actions2);
+ }
+ if (ret < 0)
+ return ret;
+ }
+ else if (name == Mcond)
+ {
+ int idx = 0;
+
+ MPLIST_DO (args, args)
+ {
+ MPlist *cond;
+
+ idx++;
+ if (! MPLIST_PLIST (args))
+ continue;
+ cond = MPLIST_PLIST (args);
+ if (resolve_expression (ic, cond) != 0)
+ {
+ MDEBUG_PRINT1 ("(%dth)", idx);
+ if (take_action_list (ic, MPLIST_NEXT (cond)) < 0)
+ return -1;;
+ break;
+ }
+ }
+ }
+ else if (name == Mcommit)
+ {
+ preedit_commit (ic);
+ }
+ else if (name == Munhandle)
+ {
+ preedit_commit (ic);
+ return -1;
+ }
+ else
+ {
+ MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
+ MPlist *actions;
+
+ if (im_info->macros
+ && (actions = mplist_get (im_info->macros, name)))
+ {
+ if (take_action_list (ic, actions) < 0)
+ return -1;
+ };
+ }
+ }
+
+ if (ic->candidate_list)
+ {
+ M17N_OBJECT_UNREF (ic->candidate_list);
+ ic->candidate_list = NULL;
+ }
+ if (ic->cursor_pos > 0
+ && (prop = mtext_get_property (ic->preedit, ic->cursor_pos - 1,
+ Mcandidate_list)))
+ {
+ ic->candidate_list = mtext_property_value (prop);
+ M17N_OBJECT_REF (ic->candidate_list);
+ ic->candidate_index
+ = (int) mtext_get_prop (ic->preedit, ic->cursor_pos - 1,
+ Mcandidate_index);
+ ic->candidate_from = mtext_property_start (prop);
+ ic->candidate_to = mtext_property_end (prop);
+ }
+
+ if (candidate_list != ic->candidate_list)
+ ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
+ if (candidate_index != ic->candidate_index)
+ ic->candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
+ if (candidate_show != ic->candidate_show)
+ ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
+ return 0;
+}
+
+
+/* Handle the input key KEY in the current state and map specified in
+ the input context IC. If KEY is handled correctly, return 0.
+ Otherwise, return -1. */
+
+static int
+handle_key (MInputContext *ic)
+{
+ MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
+ MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
+ MIMMap *map = ic_info->map;
+ MIMMap *submap = NULL;
+ MSymbol key = ic_info->keys[ic_info->key_head];
+ MSymbol alias = Mnil;
+ int i;
+
+ MDEBUG_PRINT2 (" [IM] handle `%s' in state %s",
+ msymbol_name (key), MSYMBOL_NAME (ic_info->state->name));
+
+ if (map->submaps)
+ {
+ submap = mplist_get (map->submaps, key);
+ alias = key;
+ while (! submap
+ && (alias = msymbol_get (alias, M_key_alias))
+ && alias != key)
+ submap = mplist_get (map->submaps, alias);
+ }
+
+ if (submap)
+ {
+ if (! alias || alias == key)
+ MDEBUG_PRINT (" submap-found");
+ else
+ MDEBUG_PRINT1 (" submap-found (by alias `%s')", MSYMBOL_NAME (alias));
+ mtext_cpy (ic->preedit, ic_info->preedit_saved);
+ ic->preedit_changed = 1;
+ ic->cursor_pos = ic_info->state_pos;
+ ic_info->key_head++;
+ ic_info->map = map = submap;
+ if (map->map_actions)
+ {
+ MDEBUG_PRINT (" map-actions:");
+ if (take_action_list (ic, map->map_actions) < 0)
+ {
+ MDEBUG_PRINT ("\n");
+ return -1;
+ }
+ }
+ else if (map->submaps)
+ {
+ for (i = ic_info->state_key_head; i < ic_info->key_head; i++)
+ {
+ MSymbol key = ic_info->keys[i];
+ char *name = msymbol_name (key);
+
+ if (! name[0] || ! name[1])
+ mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1);
+ }
+ }
+
+ /* If this is the terminal map or we have shifted to another
+ state, perform branch actions (if any). */
+ if (! map->submaps || map != ic_info->map)
+ {
+ if (map->branch_actions)
+ {
+ MDEBUG_PRINT (" branch-actions:");
+ if (take_action_list (ic, map->branch_actions) < 0)
+ {
+ MDEBUG_PRINT ("\n");
+ return -1;
+ }
+ }
+ /* If MAP is still not the root map, shift to the current
+ state. */
+ if (ic_info->map != ic_info->state->map)
+ shift_state (ic, ic_info->state->name);
+ }
+ }
+ else
+ {
+ /* MAP can not handle KEY. */
+
+ /* Perform branch actions if any. */
+ if (map->branch_actions)
+ {
+ MDEBUG_PRINT (" branch-actions:");
+ if (take_action_list (ic, map->branch_actions) < 0)
+ {
+ MDEBUG_PRINT ("\n");
+ return -1;
+ }
+ }
+
+ if (map == ic_info->map)
+ {
+ /* The above branch actions didn't change the state. */
+
+ /* If MAP is the root map of the initial state, and there
+ still exist an unhandled key, it means that the current
+ input method can not handle it. */
+ if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map
+ && ic_info->key_head < ic_info->used)
+ {
+ MDEBUG_PRINT (" unhandled\n");
+ return -1;
+ }
+
+ if (map != ic_info->state->map)
+ {
+ /* MAP is not the root map. Shift to the root map of the
+ current state. */
+ shift_state (ic, ic_info->state->name);
+ }
+ else if (! map->branch_actions)
+ {
+ /* MAP is the root map without any default branch
+ actions. Shift to the initial state. */
+ shift_state (ic, Mnil);
+ }
+ }
+ }
+ MDEBUG_PRINT ("\n");
+ return 0;
+}
+
+/* Initialize IC->ic_info. */
+
+static void
+init_ic_info (MInputContext *ic)
+{
+ MInputMethodInfo *im_info = ic->im->info;
+ MInputContextInfo *ic_info = ic->info;
+ MPlist *plist;
+
+ MLIST_INIT1 (ic_info, keys, 8);;
+
+ ic_info->markers = mplist ();
+
+ ic_info->vars = mplist ();
+ if (im_info->configured_vars)
+ MPLIST_DO (plist, im_info->configured_vars)
+ {
+ MPlist *pl = MPLIST_PLIST (plist);
+ MSymbol name = MPLIST_SYMBOL (pl);
+
+ pl = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (pl)));
+ if (MPLIST_KEY (pl) != Mt)
+ {
+ MPlist *p = mplist ();
+
+ mplist_push (ic_info->vars, Mplist, p);
+ M17N_OBJECT_UNREF (p);
+ mplist_add (p, Msymbol, name);
+ mplist_add (p, MPLIST_KEY (pl), MPLIST_VAL (pl));
+ }
+ }
+ ic_info->vars_saved = mplist_copy (ic_info->vars);
+
+ if (im_info->externals)
+ {
+ MPlist *func_args = mplist (), *plist;
+
+ mplist_add (func_args, Mt, ic);
+ MPLIST_DO (plist, im_info->externals)
+ {
+ MIMExternalModule *external = MPLIST_VAL (plist);
+ MIMExternalFunc func
+ = (MIMExternalFunc) mplist_get_func (external->func_list, Minit);
+
+ if (func)
+ (func) (func_args);
+ }
+ M17N_OBJECT_UNREF (func_args);
+ }
+
+ ic_info->preedit_saved = mtext ();
+ ic_info->tick = im_info->tick;
+}
+
+/* Finalize IC->ic_info. */
+
+static void
+fini_ic_info (MInputContext *ic)
+{
+ MInputMethodInfo *im_info = ic->im->info;
+ MInputContextInfo *ic_info = ic->info;
+
+ if (im_info->externals)
+ {
+ MPlist *func_args = mplist (), *plist;
+
+ mplist_add (func_args, Mt, ic);
+ MPLIST_DO (plist, im_info->externals)
+ {
+ MIMExternalModule *external = MPLIST_VAL (plist);
+ MIMExternalFunc func
+ = (MIMExternalFunc) mplist_get_func (external->func_list, Mfini);
+
+ if (func)
+ (func) (func_args);
+ }
+ M17N_OBJECT_UNREF (func_args);
+ }
+
+ MLIST_FREE1 (ic_info, keys);
+ M17N_OBJECT_UNREF (ic_info->preedit_saved);
+ M17N_OBJECT_UNREF (ic_info->markers);
+ M17N_OBJECT_UNREF (ic_info->vars);
+ M17N_OBJECT_UNREF (ic_info->vars_saved);
+ M17N_OBJECT_UNREF (ic_info->preceding_text);
+ M17N_OBJECT_UNREF (ic_info->following_text);
+
+ memset (ic_info, 0, sizeof (MInputContextInfo));
+}
+
+static void
+re_init_ic (MInputContext *ic, int reload)
+{
+ MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
+ MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
+ int status_changed, preedit_changed, cursor_pos_changed, candidates_changed;
+
+ status_changed = ic_info->state != (MIMState *) MPLIST_VAL (im_info->states);
+ preedit_changed = mtext_nchars (ic->preedit) > 0;
+ cursor_pos_changed = ic->cursor_pos > 0;
+ candidates_changed = 0;
+ if (ic->candidate_list)
+ {
+ candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED;
+ M17N_OBJECT_UNREF (ic->candidate_list);
+ ic->candidate_list = NULL;
+ }
+ if (ic->candidate_show)
+ {
+ candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED;
+ ic->candidate_show = 0;
+ }
+ if (ic->candidate_index > 0)
+ {
+ candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED;
+ ic->candidate_index = 0;
+ ic->candidate_from = ic->candidate_to = 0;
+ }
+ if (mtext_nchars (ic->produced) > 0)
+ mtext_reset (ic->produced);
+ if (mtext_nchars (ic->preedit) > 0)
+ mtext_reset (ic->preedit);
+ ic->cursor_pos = 0;
+ M17N_OBJECT_UNREF (ic->plist);
+ ic->plist = mplist ();
+
+ fini_ic_info (ic);
+ if (reload)
+ reload_im_info (im_info);
+ init_ic_info (ic);
+ shift_state (ic, Mnil);
+ ic->status_changed = status_changed;
+ ic->preedit_changed = preedit_changed;
+ ic->cursor_pos_changed = cursor_pos_changed;
+ ic->candidates_changed = candidates_changed;
+}
+
+static void
+reset_ic (MInputContext *ic, MSymbol ignore)
+{
+ MDEBUG_PRINT ("\n [IM] reset\n");
+ re_init_ic (ic, 0);
+}
+
+static int
+open_im (MInputMethod *im)
+{
+ MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil, Mnil);
+
+ if (! im_info)
+ MERROR (MERROR_IM, -1);
+ im->info = im_info;
+
+ return 0;
+}
+
+static void
+close_im (MInputMethod *im)
+{
+ im->info = NULL;
+}
+
+static int
+create_ic (MInputContext *ic)
+{
+ MInputContextInfo *ic_info;
+
+ MSTRUCT_CALLOC (ic_info, MERROR_IM);
+ ic->info = ic_info;
+ init_ic_info (ic);
+ shift_state (ic, Mnil);
+ return 0;
+}
+
+static void
+destroy_ic (MInputContext *ic)
+{
+ fini_ic_info (ic);
+ free (ic->info);
+}
+
+static int
+check_reload (MInputContext *ic, MSymbol key)
+{
+ MInputMethodInfo *im_info = ic->im->info;
+ MPlist *plist = resolve_command (im_info->configured_cmds, Mat_reload);
+
+ if (! plist)
+ {
+ plist = resolve_command (global_info->configured_cmds, Mat_reload);
+ if (! plist)
+ return 0;
+ }
+ MPLIST_DO (plist, plist)
+ {
+ MSymbol this_key, alias;
+
+ if (MPLIST_MTEXT_P (plist))
+ {
+ MText *mt = MPLIST_MTEXT (plist);
+ int c = mtext_ref_char (mt, 0);
+
+ if (c >= 256)
+ continue;
+ this_key = one_char_symbol[c];
+ }
+ else
+ {
+ MPlist *pl = MPLIST_PLIST (plist);
+
+ this_key = MPLIST_SYMBOL (pl);
+ }
+ alias = this_key;
+ while (alias != key
+ && (alias = msymbol_get (alias, M_key_alias))
+ && alias != this_key);
+ if (alias == key)
+ break;
+ }
+ if (MPLIST_TAIL_P (plist))
+ return 0;
+
+ MDEBUG_PRINT ("\n [IM] reload");
+ re_init_ic (ic, 1);
+ return 1;
+}
+
+
+/** Handle the input key KEY in the current state and map of IC->info.
+ If KEY is handled but no text is produced, return 0, otherwise
+ return 1.
+
+ Ignore ARG. */
+
+static int
+filter (MInputContext *ic, MSymbol key, void *arg)
+{
+ MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info;
+ MInputContextInfo *ic_info = (MInputContextInfo *) ic->info;
+ int i = 0;
+
+ if (check_reload (ic, key))
+ return 0;
+
+ if (! ic_info->state)
+ {
+ ic_info->key_unhandled = 1;
+ return 0;
+ }
+ mtext_reset (ic->produced);
+ ic->status_changed = ic->preedit_changed = ic->candidates_changed = 0;
+ M17N_OBJECT_UNREF (ic_info->preceding_text);
+ M17N_OBJECT_UNREF (ic_info->following_text);
+ ic_info->preceding_text = ic_info->following_text = NULL;
+ MLIST_APPEND1 (ic_info, keys, key, MERROR_IM);
+ ic_info->key_unhandled = 0;
+
+ do {
+ if (handle_key (ic) < 0)
+ {
+ /* KEY was not handled. Delete it from the current key sequence. */
+ if (ic_info->used > 0)
+ {
+ memmove (ic_info->keys, ic_info->keys + 1,
+ sizeof (int) * (ic_info->used - 1));
+ ic_info->used--;
+ if (ic_info->state_key_head > 0)
+ ic_info->state_key_head--;
+ if (ic_info->commit_key_head > 0)
+ ic_info->commit_key_head--;
+ }
+ /* This forces returning 1. */
+ ic_info->key_unhandled = 1;
+ break;
+ }
+ if (i++ == 100)
+ {
+ mdebug_hook ();
+ reset_ic (ic, Mnil);
+ ic_info->key_unhandled = 1;
+ break;
+ }
+ /* Break the loop if all keys were handled. */
+ } while (ic_info->key_head < ic_info->used);
+
+ /* If the current map is the root of the initial state, we should
+ produce any preedit text in ic->produced. */
+ if (ic_info->map == ((MIMState *) MPLIST_VAL (im_info->states))->map)
+ preedit_commit (ic);
+
+ if (mtext_nchars (ic->produced) > 0)
+ {
+ MSymbol lang = msymbol_get (ic->im->language, Mlanguage);
+
+ if (mdebug__flag & mdebug_mask)
+ {
+ MDEBUG_PRINT (" (produced");
+ for (i = 0; i < mtext_nchars (ic->produced); i++)
+ MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->produced, i));
+ MDEBUG_PRINT (")");
+ }
+
+ if (lang != Mnil)
+ mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced),
+ Mlanguage, ic->im->language);
+ }
+ if (ic_info->commit_key_head > 0)
+ {
+ memmove (ic_info->keys, ic_info->keys + ic_info->commit_key_head,
+ sizeof (int) * (ic_info->used - ic_info->commit_key_head));
+ ic_info->used -= ic_info->commit_key_head;
+ ic_info->key_head -= ic_info->commit_key_head;
+ ic_info->state_key_head -= ic_info->commit_key_head;
+ ic_info->commit_key_head = 0;
+ }
+ if (ic_info->key_unhandled)
+ {
+ ic_info->used = 0;
+ ic_info->key_head = ic_info->state_key_head
+ = ic_info->commit_key_head = 0;
+ }
+
+ return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0);
+}
+
+
+/** Return 1 if the last event or key was not handled, otherwise
+ return 0.
+
+ There is no need of looking up because ic->produced should already
+ contain the produced text (if any).
+
+ Ignore KEY. */
+
+static int
+lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
+{
+ mtext_cat (mt, ic->produced);
+ mtext_reset (ic->produced);
+ return (((MInputContextInfo *) ic->info)->key_unhandled ? -1 : 0);
+}
+
+\f
+/* Input method command handler. */
+
+/* List of all (global and local) commands.
+ (LANG:(IM-NAME:(COMMAND ...) ...) ...) ...
+ COMMAND is CMD-NAME:(mtext:DESCRIPTION plist:KEYSEQ ...))
+ Global commands are stored as (t (t COMMAND ...)) */
+
+\f
+/* Input method variable handler. */
+
+
+/* Support functions for mdebug_dump_im. */
+
+static void
+dump_im_map (MPlist *map_list, int indent)
+{
+ char *prefix;
+ MSymbol key = MPLIST_KEY (map_list);
+ MIMMap *map = (MIMMap *) MPLIST_VAL (map_list);
+
+ prefix = (char *) alloca (indent + 1);
+ memset (prefix, 32, indent);
+ prefix[indent] = '\0';
+
+ fprintf (stderr, "(\"%s\" ", msymbol_name (key));
+ if (map->map_actions)
+ mdebug_dump_plist (map->map_actions, indent + 2);
+ if (map->submaps)
+ {
+ MPLIST_DO (map_list, map->submaps)
+ {
+ fprintf (stderr, "\n%s ", prefix);
+ dump_im_map (map_list, indent + 2);
+ }
+ }
+ if (map->branch_actions)
+ {
+ fprintf (stderr, "\n%s (branch\n%s ", prefix, prefix);
+ mdebug_dump_plist (map->branch_actions, indent + 4);
+ fprintf (stderr, ")");
+ }
+ fprintf (stderr, ")");
+}
+
+
+static void
+dump_im_state (MIMState *state, int indent)
+{
+ char *prefix;
+ MPlist *map_list;
+
+ prefix = (char *) alloca (indent + 1);
+ memset (prefix, 32, indent);
+ prefix[indent] = '\0';
+
+ fprintf (stderr, "(%s", msymbol_name (state->name));
+ if (state->map->submaps)
+ {
+ MPLIST_DO (map_list, state->map->submaps)
+ {
+ fprintf (stderr, "\n%s ", prefix);
+ dump_im_map (map_list, indent + 2);
+ }
+ }
+ fprintf (stderr, ")");
+}
+
+\f
+
+int
+minput__init ()
+{
+ Minput_driver = msymbol ("input-driver");
+
+ Minput_preedit_start = msymbol ("input-preedit-start");
+ Minput_preedit_done = msymbol ("input-preedit-done");
+ Minput_preedit_draw = msymbol ("input-preedit-draw");
+ Minput_status_start = msymbol ("input-status-start");
+ Minput_status_done = msymbol ("input-status-done");
+ Minput_status_draw = msymbol ("input-status-draw");
+ Minput_candidates_start = msymbol ("input-candidates-start");
+ Minput_candidates_done = msymbol ("input-candidates-done");
+ Minput_candidates_draw = msymbol ("input-candidates-draw");
+ Minput_set_spot = msymbol ("input-set-spot");
+ Minput_focus_move = msymbol ("input-focus-move");
+ Minput_focus_in = msymbol ("input-focus-in");
+ Minput_focus_out = msymbol ("input-focus-out");
+ Minput_toggle = msymbol ("input-toggle");
+ Minput_reset = msymbol ("input-reset");
+ Minput_get_surrounding_text = msymbol ("input-get-surrounding-text");
+ Minput_delete_surrounding_text = msymbol ("input-delete-surrounding-text");
+ Mcustomized = msymbol ("customized");
+ Mconfigured = msymbol ("configured");
+ Minherited = msymbol ("inherited");
+
+ minput_default_driver.open_im = open_im;
+ minput_default_driver.close_im = close_im;
+ minput_default_driver.create_ic = create_ic;
+ minput_default_driver.destroy_ic = destroy_ic;
+ minput_default_driver.filter = filter;
+ minput_default_driver.lookup = lookup;
+ minput_default_driver.callback_list = mplist ();
+ mplist_put_func (minput_default_driver.callback_list, Minput_reset,
+ M17N_FUNC (reset_ic));
+ minput_driver = &minput_default_driver;
+
+ fully_initialized = 0;
+ return 0;
+}
+
+void
+minput__fini ()
+{
+ if (fully_initialized)
+ {
+ free_im_list (im_info_list);
+ if (im_custom_list)
+ free_im_list (im_custom_list);
+ if (im_config_list)
+ free_im_list (im_config_list);
+ M17N_OBJECT_UNREF (load_im_info_keys);
+ }
+
+ M17N_OBJECT_UNREF (minput_default_driver.callback_list);
+ M17N_OBJECT_UNREF (minput_driver->callback_list);
+
+}
+
+MSymbol
+minput__char_to_key (int c)
+{
+ if (c < 0 || c >= 0x100)
+ return Mnil;
+
+ return one_char_symbol[c];
+}
+
+/*** @} */
+#endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
+
+\f
+/* External API */
+
+/*** @addtogroup m17nInputMethod */
+/*** @{ */
+/*=*/
+
+/***en
+ @name Variables: Predefined symbols for callback commands.
+
+ These are the predefined symbols that are used as the @c COMMAND
+ argument of callback functions of an input method driver (see
+ #MInputDriver::callback_list).
+
+ Most of them do not require extra argument nor return any value;
+ exceptions are these:
+
+ Minput_get_surrounding_text: When a callback function assigned for
+ this command is called, the first element of #MInputContext::plist
+ has key #Minteger and the value specifies which portion of the
+ surrounding text should be retrieved. If the value is positive,
+ it specifies the number of characters following the current cursor
+ position. If the value is negative, the absolute value specifies
+ the number of characters preceding the current cursor position.
+ If the value is zero, it means that the caller just wants to know
+ if the surrounding text is currently supported or not.
+
+ If the surrounding text is currently supported, the callback
+ function must set the key of this element to #Mtext and the value
+ to the retrieved M-text. The length of the M-text may be shorter
+ than the requested number of characters, if the available text is
+ not that long. The length can be zero in the worst case. Or, the
+ length may be longer if an application thinks it is more efficient
+ to return that length.
+
+ If the surrounding text is not currently supported, the callback
+ function should return without changing the first element of
+ #MInputContext::plist.
+
+ Minput_delete_surrounding_text: When a callback function assigned
+ for this command is called, the first element of
+ #MInputContext::plist has key #Minteger and the value specifies
+ which portion of the surrounding text should be deleted in the
+ same way as the case of Minput_get_surrounding_text. The callback
+ function must delete the specified text. It should not alter
+ #MInputContext::plist. */
+/***ja
+ @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
+
+ ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND
+ °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£
+
+ ¤Û¤È¤ó¤É¤ÏÄɲäΰú¿ô¤òɬÍפȤ·¤Ê¤¤¤·ÃͤòÊÖ¤µ¤Ê¤¤¤¬¡¢°Ê²¼¤ÏÎã³°¤Ç¤¢¤ë¡£
+
+ Minput_get_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë¥Ð¥Ã
+ ¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢ #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϥ¡¼¤È¤·
+ ¤Æ#Minteger ¤ò¤È¤ê¡¢¤½¤ÎÃͤϥµ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥¥¹¥È¤Î¤¦¤Á¤É¤ÎÉôʬ
+ ¤ò¼è¤Ã¤ÆÍè¤ë¤«¤ò»ØÄꤹ¤ë¡£Ãͤ¬Àµ¤Ç¤¢¤ì¤Ð¡¢¸½ºß¤Î¥«¡¼¥½¥ë°ÌÃ֤˳¤¯
+ ÃͤθĿôʬ¤Îʸ»ú¤ò¼è¤ë¡£Éé¤Ç¤¢¤ì¤Ð¡¢¥«¡¼¥½¥ë°ÌÃÖ¤ËÀè¹Ô¤¹¤ëÃͤÎÀäÂÐ
+ ÃÍʬ¤Îʸ»ú¤ò¼è¤ë¡£¸½ºß¥µ¥é¥¦¥ó¥É¥Æ¥¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë¤«¤É¤¦
+ ¤«¤òÃΤꤿ¤¤¤À¤±¤Ç¤¢¤ì¤Ð¡¢¤³¤ÎÃͤϥ¼¥í¤Ç¤âÎɤ¤¡£
+
+ ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ï
+ ¤³¤ÎÍ×ÁǤΥ¡¼¤ò #Mtext ¤Ë¡¢Ãͤò¼è¤ê¹þ¤ó¤ÀM-text ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê
+ ¤é¤Ê¤¤¡£¤â¤·¥Æ¥¥¹¥È¤ÎŤµ¤¬½¼Ê¬¤Ç¤Ê¤±¤ì¤Ð¡¢¤³¤Î M-text ¤ÎŤµ¤ÏÍ×
+ µá¤µ¤ì¤Æ¤¤¤ëʸ»ú¿ô¤è¤êû¤¯¤ÆÎɤ¤¡£ºÇ°¤Î¾ì¹ç 0 ¤Ç¤â¤è¤¤¤·¡¢¥¢¥×¥ê¥±¡¼
+ ¥·¥ç¥ó¦¤ÇɬÍפǸúΨŪ¤À¤È»×¤¨¤ÐŤ¯¤Æ¤âÎɤ¤¡£
+
+ ¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥¥¹¥È¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤±¤ì¤Ð¡¢¥³¡¼¥ë¥Ð¥Ã¥¯´Ø
+ ¿ô¤Ï #MInputContext::plist ¤ÎÂè°ìÍ×ÁǤòÊѹ¹¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+
+ Minput_delete_surrounding_text: ¤³¤Î¥³¥Þ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿¥³¡¼¥ë
+ ¥Ð¥Ã¥¯´Ø¿ô¤¬¸Æ¤Ð¤ì¤¿ºÝ¤Ë¤Ï¡¢#MInputContext::plist ¤ÎÂè°ìÍ×ÁǤϡ¢¥¡¼
+ ¤È¤·¤Æ#Minteger ¤ò¤È¤ê¡¢ÃͤϺï½ü¤¹¤ë¤Ù¤¥µ¥é¥¦¥ó¥Ç¥£¥ó¥°¥Æ¥¥¹¥È¤ò
+ Minput_get_surrounding_text ¤ÈƱÍͤΤä¤êÊý¤Ç»ØÄꤹ¤ë¡£¥³¡¼¥ë¥Ð¥Ã¥¯
+ ´Ø¿ô¤Ï»ØÄꤵ¤ì¤¿¥Æ¥¥¹¥È¤òºï½ü¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤Þ¤¿
+ #MInputContext::plist ¤òÊѤ¨¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ */
+/*** @{ */
+/*=*/
+
+MSymbol Minput_preedit_start;
+MSymbol Minput_preedit_done;
+MSymbol Minput_preedit_draw;
+MSymbol Minput_status_start;
+MSymbol Minput_status_done;
+MSymbol Minput_status_draw;
+MSymbol Minput_candidates_start;
+MSymbol Minput_candidates_done;
+MSymbol Minput_candidates_draw;
+MSymbol Minput_set_spot;
+MSymbol Minput_toggle;
+MSymbol Minput_reset;
+MSymbol Minput_get_surrounding_text;
+MSymbol Minput_delete_surrounding_text;
+/*** @} */
+
+/*=*/
+
+/***en
+ @name Variables: Predefined symbols for special input events.
+
+ These are the predefined symbols that are used as the @c KEY
+ argument of minput_filter (). */
+/***ja
+ @name ÊÑ¿ô: ÆÃÊ̤ÊÆþÎÏ¥¤¥Ù¥ó¥ÈÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
+
+ minput_filter () ¤Î @c KEY °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£ */
+
+/*** @{ */
+/*=*/
+
+MSymbol Minput_focus_out;
+MSymbol Minput_focus_in;
+MSymbol Minput_focus_move;
+
+/*** @} */
+
+/*=*/
+/***en
+ @name Variables: Predefined symbols used in input method information.
+
+ These are the predefined symbols describing status of input method
+ command and variable, and are used in a return value of
+ minput_get_command () and minput_get_variable (). */
+/***ja
+ @name ÊÑ¿ô: ÆþÎϥ᥽¥Ã¥É¾ðÊóÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë.
+
+ ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤äÊÑ¿ô¤Î¾õÂÖ¤òɽ¤·¡¢minput_get_command () ¤È
+ minput_get_variable () ¤ÎÌá¤êÃͤȤ·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë¡£ */
+/*** @{ */
+/*=*/
+MSymbol Minherited;
+MSymbol Mcustomized;
+MSymbol Mconfigured;
+/*** @} */
+
+/*=*/
+
+/***en
+ @brief The default driver for internal input methods.
+
+ The variable #minput_default_driver is the default driver for
+ internal input methods.
+
+ The member MInputDriver::open_im () searches the m17n database for
+ an input method that matches the tag \< #Minput_method, $LANGUAGE,
+ $NAME\> and loads it.
+
+ The member MInputDriver::callback_list () is @c NULL. Thus, it is
+ programmers responsibility to set it to a plist of proper callback
+ functions. Otherwise, no feedback information (e.g. preedit text)
+ can be shown to users.
+
+ The macro M17N_INIT () sets the variable #minput_driver to the
+ pointer to this driver so that all internal input methods use it.
+
+ Therefore, unless @c minput_driver is set differently, the driver
+ dependent arguments $ARG of the functions whose name begins with
+ "minput_" are all ignored. */
+/***ja
+ @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð.
+
+ ÊÑ¿ô #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë¥È¤Î¥É¥é¥¤¥Ð¤òɽ¤¹¡£
+
+ ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥°
+ \< #Minput_method, $LANGUAGE, $NAME\>
+ ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£
+
+ ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ç¤¢¤ê¡¢
+ ¤·¤¿¤¬¤Ã¤Æ¡¢¥×¥í¥°¥é¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ ŬÀڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist
+ ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit
+ ¥Æ¥¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊ󤬥桼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£
+
+ ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver
+ ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£
+
+ ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_
+ ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£ */
+
+MInputDriver minput_default_driver;
+/*=*/
+
+/***en
+ @brief The driver for internal input methods.
+
+ The variable #minput_driver is a pointer to the input method
+ driver that is used by internal input methods. The macro
+ M17N_INIT () initializes it to a pointer to #minput_default_driver
+ if <m17n<EM></EM>.h> is included. */
+/***ja
+ @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð.
+
+ ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á
+ ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥í M17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó
+ ¥¿¤ò#minput_default_driver (<m17n<EM></EM>.h> ¤¬ include ¤µ¤ì¤Æ¤¤¤ë
+ »þ) ¤Ë½é´ü²½¤¹¤ë¡£ */
+
+MInputDriver *minput_driver;
+
+MSymbol Minput_driver;
+
+/*=*/
+
+/***en
+ @name Functions
+*/
+/***ja
+ @name ´Ø¿ô
+*/
+/*** @{ */
+
+/*=*/
+
+/***en
+ @brief Open an input method.
+
+ The minput_open_im () function opens an input method whose
+ language and name match $LANGUAGE and $NAME, and returns a pointer
+ to the input method object newly allocated.
+
+ This function at first decides a driver for the input method as
+ described below.
+
+ If $LANGUAGE is not #Mnil, the driver pointed by the variable
+ #minput_driver is used.
+
+ If $LANGUAGE is #Mnil and $NAME has the property #Minput_driver, the
+ driver pointed to by the property value is used to open the input
+ method. If $NAME has no such a property, @c NULL is returned.
+
+ Then, the member MInputDriver::open_im () of the driver is
+ called.
+
+ $ARG is set in the member @c arg of the structure MInputMethod so
+ that the driver can refer to it. */
+/***ja
+ @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë.
+
+ ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME
+ ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
+
+ ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£
+
+ $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver
+ ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£
+
+ $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver
+ ¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£
+ $NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
+
+ ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£
+
+ $ARG ¤Ï¹½Â¤ÂÎ MInputMethod ¤Î¥á¥ó¥Ð @c arg ¤ËÀßÄꤵ¤ì¡¢¥É¥é¥¤¥Ð¤«¤é»²¾È¤Ç¤¤ë¡£
+
+ @latexonly \IPAlabel{minput_open} @endlatexonly
+
+*/
+
+MInputMethod *
+minput_open_im (MSymbol language, MSymbol name, void *arg)
+{
+ MInputMethod *im;
+ MInputDriver *driver;
+
+ MINPUT__INIT ();
+
+ MDEBUG_PRINT2 (" [IM] opening (%s %s) ... ",
+ msymbol_name (language), msymbol_name (name));
+ if (language)
+ driver = minput_driver;
+ else
+ {
+ driver = (MInputDriver *) msymbol_get (name, Minput_driver);
+ if (! driver)
+ MERROR (MERROR_IM, NULL);
+ }
+
+ MSTRUCT_CALLOC (im, MERROR_IM);
+ im->language = language;
+ im->name = name;
+ im->arg = arg;
+ im->driver = *driver;
+ if ((*im->driver.open_im) (im) < 0)
+ {
+ MDEBUG_PRINT (" failed\n");
+ free (im);
+ return NULL;
+ }
+ MDEBUG_PRINT (" ok\n");
+ return im;
+}
+
+/*=*/
+
+/***en
+ @brief Close an input method.
+
+ The minput_close_im () function closes the input method $IM, which
+ must have been created by minput_open_im (). */
+
+/***ja
+ @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë.
+
+ ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£
+ ¤³¤ÎÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ */
+
+void
+minput_close_im (MInputMethod *im)
+{
+ MDEBUG_PRINT2 (" [IM] closing (%s %s) ... ",
+ msymbol_name (im->name), msymbol_name (im->language));
+ (*im->driver.close_im) (im);
+ free (im);
+ MDEBUG_PRINT (" done\n");
+}
+
+/*=*/
+
+/***en
+ @brief Create an input context.
+
+ The minput_create_ic () function creates an input context object
+ associated with input method $IM, and calls callback functions
+ corresponding to #Minput_preedit_start, #Minput_status_start, and
+ #Minput_status_draw in this order.
+
+ @return
+ If an input context is successfully created, minput_create_ic ()
+ returns a pointer to it. Otherwise it returns @c NULL. */
+
+/***ja
+ @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë.
+
+ ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM
+ ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢
+ #Minput_preedit_start, #Minput_status_start, #Minput_status_draw
+ ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
+
+ @return
+ ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic ()
+ ¤Ï¤½¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£
+ */
+
+MInputContext *
+minput_create_ic (MInputMethod *im, void *arg)
+{
+ MInputContext *ic;
+
+ MDEBUG_PRINT2 (" [IM] creating context (%s %s) ... ",
+ msymbol_name (im->name), msymbol_name (im->language));
+ MSTRUCT_CALLOC (ic, MERROR_IM);
+ ic->im = im;
+ ic->arg = arg;
+ ic->preedit = mtext ();
+ ic->candidate_list = NULL;
+ ic->produced = mtext ();
+ ic->spot.x = ic->spot.y = 0;
+ ic->active = 1;
+ ic->plist = mplist ();
+ if ((*im->driver.create_ic) (ic) < 0)
+ {
+ MDEBUG_PRINT (" failed\n");
+ M17N_OBJECT_UNREF (ic->preedit);
+ M17N_OBJECT_UNREF (ic->produced);
+ M17N_OBJECT_UNREF (ic->plist);
+ free (ic);
+ return NULL;
+ };
+
+ if (im->driver.callback_list)
+ {
+ minput_callback (ic, Minput_preedit_start);
+ minput_callback (ic, Minput_status_start);
+ minput_callback (ic, Minput_status_draw);
+ }
+
+ MDEBUG_PRINT (" ok\n");
+ return ic;
+}
+
+/*=*/
+
+/***en
+ @brief Destroy an input context.
+
+ The minput_destroy_ic () function destroys the input context $IC,
+ which must have been created by minput_create_ic (). It calls
+ callback functions corresponding to #Minput_preedit_done,
+ #Minput_status_done, and #Minput_candidates_done in this order. */
+
+/***ja
+ @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë.
+
+ ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£
+ ¤³¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic ()
+ ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï
+ #Minput_preedit_done, #Minput_status_done, #Minput_candidates_done
+ ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£
+ */
+
+void
+minput_destroy_ic (MInputContext *ic)
+{
+ MDEBUG_PRINT2 (" [IM] destroying context (%s %s) ... ",
+ msymbol_name (ic->im->name), msymbol_name (ic->im->language));
+ if (ic->im->driver.callback_list)
+ {
+ minput_callback (ic, Minput_preedit_done);
+ minput_callback (ic, Minput_status_done);
+ minput_callback (ic, Minput_candidates_done);
+ }
+ (*ic->im->driver.destroy_ic) (ic);
+ M17N_OBJECT_UNREF (ic->preedit);
+ M17N_OBJECT_UNREF (ic->produced);
+ M17N_OBJECT_UNREF (ic->plist);
+ MDEBUG_PRINT (" done\n");
+ free (ic);
+}
+
+/*=*/
+
+/***en
+ @brief Filter an input key.
+
+ The minput_filter () function filters input key $KEY according to
+ input context $IC, and calls callback functions corresponding to
+ #Minput_preedit_draw, #Minput_status_draw, and
+ #Minput_candidates_draw if the preedit text, the status, and the
+ current candidate are changed respectively.
+
+ To make the input method commit the current preedit text (if any)
+ and shift to the initial state, call this function with #Mnil as
+ $KEY.
+
+ To inform the input method about the focus-out event, call this
+ function with #Minput_focus_out as $KEY.
+
+ To inform the input method about the focus-in event, call this
+ function with #Minput_focus_in as $KEY.
+
+ To inform the input method about the focus-move event (i.e. input
+ spot change within the same input context), call this function
+ with #Minput_focus_move as $KEY.
+
+ @return
+ If $KEY is filtered out, this function returns 1. In that case,
+ the caller should discard the key. Otherwise, it returns 0, and
+ the caller should handle the key, for instance, by calling the
+ function minput_lookup () with the same key. */
+
+/***ja
+ @brief ÆþÎÏ¥¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë.
+
+ ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC
+ ¤Ë±þ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½¤·¤¿»þÅÀ¤Ç¡¢¤½¤ì¤¾¤ì
+ #Minput_preedit_draw, #Minput_status_draw,
+ #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£
+
+ @return
+ $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£
+ ¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥¡¼¤ò¼Î¤Æ¤ë¤Ù¤¤Ç¤¢¤ë¡£
+ ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥¡¼¤Ç´Ø¿ô minput_lookup ()
+ ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥¡¼¤ò½èÍý¤¹¤ë¡£
+
+ @latexonly \IPAlabel{minput_filter} @endlatexonly
+*/
+
+int
+minput_filter (MInputContext *ic, MSymbol key, void *arg)
+{
+ int ret;
+
+ if (! ic
+ || ! ic->active)
+ return 0;
+ if (ic->im->driver.callback_list
+ && mtext_nchars (ic->preedit) > 0)
+ minput_callback (ic, Minput_preedit_draw);
+
+ ret = (*ic->im->driver.filter) (ic, key, arg);
+
+ if (ic->im->driver.callback_list)
+ {
+ if (ic->preedit_changed)
+ minput_callback (ic, Minput_preedit_draw);
+ if (ic->status_changed)
+ minput_callback (ic, Minput_status_draw);
+ if (ic->candidates_changed)
+ minput_callback (ic, Minput_candidates_draw);
+ }
+
+ return ret;
+}
+
+/*=*/
+
+/***en
+ @brief Look up a text produced in the input context.
+
+ The minput_lookup () function looks up a text in the input context
+ $IC. $KEY must be identical to the one that was used in the previous call of
+ minput_filter ().
+
+ If a text was produced by the input method, it is concatenated
+ to M-text $MT.
+
+ This function calls #MInputDriver::lookup .
+
+ @return
+ If $KEY was correctly handled by the input method, this function
+ returns 0. Otherwise, it returns -1, even though some text
+ might be produced in $MT. */
+
+/***ja
+ @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥¥¹¥È¤òõ¤¹.
+
+ ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥¥¹¥È¤òõ¤¹¡£
+ $KEY ¤Ï´Ø¿ô minput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£
+
+ ¥Æ¥¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥¥¹¥È¤Ï M-text
+ $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£
+
+ ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£
+
+ @return
+ $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£
+ ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£
+ ¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£
+
+ @latexonly \IPAlabel{minput_lookup} @endlatexonly */
+
+int
+minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
+{
+ return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1);
+}
+/*=*/
+
+/***en
+ @brief Set the spot of the input context.
+
+ The minput_set_spot () function sets the spot of input context $IC
+ to coordinate ($X, $Y ) with the height specified by $ASCENT and $DESCENT .
+ The semantics of these values depends on the input method driver.
+
+ For instance, a driver designed to work in a CUI environment may
+ use $X and $Y as the column- and row numbers, and may ignore $ASCENT and
+ $DESCENT . A driver designed to work in a window system may
+ interpret $X and $Y as the pixel offsets relative to the origin of the
+ client window, and may interpret $ASCENT and $DESCENT as the ascent- and
+ descent pixels of the line at ($X . $Y ).
+
+ $FONTSIZE specifies the fontsize of preedit text in 1/10 point.
+
+ $MT and $POS are the M-text and the character position at the spot.
+ $MT may be @c NULL, in which case, the input method cannot get
+ information about the text around the spot. */
+
+/***ja
+ @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë.
+
+ ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂɸ ($X, $Y )
+ ¤Î°ÌÃÖ¤Ë ¡¢¹â¤µ $ASCENT¡¢ $DESCENT
+ ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤΰÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£
+
+ ¤¿¤È¤¨¤Ð CUI ´Ä¶¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y
+ ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT
+ ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï
+ $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢
+ $ASCENT ¤È $DESCENT ¤ò ($X . $Y )
+ ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£
+
+ $FONTSIZE ¤Ë¤Ï preedit ¥Æ¥¥¹¥È¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£
+
+ $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c
+ NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ¥¹¥È¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤¤Ê¤¤¡£
+ */
+
+void
+minput_set_spot (MInputContext *ic, int x, int y,
+ int ascent, int descent, int fontsize,
+ MText *mt, int pos)
+{
+ ic->spot.x = x;
+ ic->spot.y = y;
+ ic->spot.ascent = ascent;
+ ic->spot.descent = descent;
+ ic->spot.fontsize = fontsize;
+ ic->spot.mt = mt;
+ ic->spot.pos = pos;
+ if (ic->im->driver.callback_list)
+ minput_callback (ic, Minput_set_spot);
+}
+/*=*/
+
+/***en
+ @brief Toggle input method.
+
+ The minput_toggle () function toggles the input method associated
+ with input context $IC. */
+/***ja
+ @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë.
+
+ ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC
+ ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£
+ */
+
+void
+minput_toggle (MInputContext *ic)
+{
+ if (ic->im->driver.callback_list)
+ minput_callback (ic, Minput_toggle);
+ ic->active = ! ic->active;
+}
+
+/*=*/
+
+/***en
+ @brief Reset an input context.
+
+ The minput_reset_ic () function resets input context $IC by
+ calling a callback function corresponding to #Minput_reset. It
+ resets the status of $IC to its initial one. As the
+ current preedit text is deleted without commitment, if necessary,
+ call minput_filter () with the arg @r key #Mnil to force the input
+ method to commit the preedit in advance. */
+
+/***ja
+ @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë.
+
+ ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô
+ ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¥ê¥»¥Ã¥È¤È¤Ï¡¢
+ ¼ÂºÝ¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˰ܤ¹¤³¤È¤Ç¤¢¤ë¡£¸½ºßÆþÎÏÃæ¤Î¥Æ¥¥¹
+ ¥È¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¤³¤È¤Ê¤¯ºï½ü¤µ¤ì¤ë¤Î¤Ç¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é
+ ¥à¤Ï¡¢É¬Íפʤé¤Ðͽ¤á minput_filter () ¤ò°ú¿ô @r key #Mnil ¤Ç¸Æ¤ó¤Ç
+ ¶¯À©Åª¤Ë¥×¥ê¥¨¥Ç¥£¥Ã¥È¥Æ¥¥¹¥È¤ò¥³¥ß¥Ã¥È¤µ¤»¤ë¤³¤È¡£ */
+
+void
+minput_reset_ic (MInputContext *ic)
+{
+ if (ic->im->driver.callback_list)
+ minput_callback (ic, Minput_reset);
+}
+
+/*=*/
+
+/***en
+ @brief Get title and icon filename of an input method.
+
+ The minput_get_title_icon () function returns a plist containing a
+ title and icon filename (if any) of an input method specified by
+ $LANGUAGE and $NAME.
+
+ The first element of the plist has key #Mtext and the value is an
+ M-text of the title for identifying the input method. The second
+ element (if any) has key #Mtext and the value is an M-text of the
+ icon image (absolute) filename for the same purpose.
+
+ @return
+ If there exists a specified input method and it defines an title,
+ a plist is returned. Otherwise, NULL is returned. The caller
+ must free the plist by m17n_object_unref (). */
+/***ja
+ @brief ÆþÎϥ᥽¥Ã¥É¤Î¥¿¥¤¥È¥ë¤È¥¢¥¤¥³¥óÍÑ¥Õ¥¡¥¤¥ë̾¤òÆÀ¤ë.
+
+ ´Ø¿ô minput_get_title_icon () ¤Ï¡¢ $LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ë
+ ÆþÎϥ᥽¥Ã¥É¤Î¥¿¥¤¥È¥ë¤È¡Ê¤¢¤ì¤Ð¡Ë¥¢¥¤¥³¥óÍÑ¥Õ¥¡¥¤¥ë¤ò´Þ¤à plist ¤ò
+ ÊÖ¤¹¡£
+
+ plist ¤ÎÂè°ìÍ×ÁǤϡ¢#Mtext ¤ò¥¡¼¤Ë»ý¤Á¡¢ÃͤÏÆþÎϥ᥽¥Ã¥É¤ò¼±Ê̤¹¤ë
+ ¥¿¥¤¥È¥ë¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£ÂèÆóÍ×ÁǤ¬¤¢¤ì¤Ð¡¢¥¡¼¤Ï #Mtext ¤Ç¤¢
+ ¤ê¡¢Ãͤϼ±ÊÌÍÑ¥¢¥¤¥³¥ó²èÁü¥Õ¥¡¥¤¥ë¤ÎÀäÂХѥ¹¤òɽ¤¹ M-text ¤Ç¤¢¤ë¡£
+
+ @return
+ »ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¡¢¥¿¥¤¥È¥ë¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ì¤Ð
+ plist ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð NULL ¤òÊÖ¤¹¡£¸Æ½Ð¦¤Ï
+ ´Ø¿ô m17n_object_unref () ¤òÍѤ¤¤Æ plist ¤ò²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ */
+
+MPlist *
+minput_get_title_icon (MSymbol language, MSymbol name)
+{
+ MInputMethodInfo *im_info;