X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Finput.c;h=bb26b491df84d98bdf17866f41e28aa03bfaf701;hb=6ef8fd1014e24f7fcb5cbee454ac57a0d7abdeb6;hp=4f2fa900cd8e35add4ff39ae0650bb620c55765d;hpb=f085560e63ea5b1bc541e7ff50819a1b758a17ac;p=m17n%2Fm17n-lib.git diff --git a/src/input.c b/src/input.c index 4f2fa90..bb26b49 100644 --- a/src/input.c +++ b/src/input.c @@ -91,33 +91,35 @@ @@ -143,6 +145,7 @@ #include #include #include +#include #include "config.h" @@ -162,6 +165,8 @@ static int mdebug_mask = MDEBUG_INPUT; +static int fully_initialized; + static MSymbol Minput_method; /** Symbols to load an input method data. */ @@ -173,7 +178,10 @@ static MSymbol Mselect, Mshow, Mhide, Mcommit, Munhandle; static MSymbol Mset, Madd, Msub, Mmul, Mdiv, Mequal, Mless, Mgreater; static MSymbol Mless_equal, Mgreater_equal; static MSymbol Mcond; -static MSymbol Mplus, Mminus, Mstar, Mslush, Mand, Mor, Mnot; +static MSymbol Mplus, Mminus, Mstar, Mslash, Mand, Mor, Mnot; + +/** Special action symbol. */ +static MSymbol Mat_reload; static MSymbol M_candidates; @@ -189,14 +197,14 @@ static MSymbol one_char_symbol[256]; static MSymbol M_key_alias; -static MSymbol M_description, M_command, M_variable; +static MSymbol Mdescription, Mcommand, Mvariable, Mglobal, Mconfig; /** Structure to hold a map. */ struct MIMMap { /** List of actions to take when we reach the map. In a root map, - the actions are executed only when there's no more key. */ + the actions are executed only when there is no more key. */ MPlist *map_actions; /** List of deeper maps. If NULL, this is a terminal map. */ @@ -231,209 +239,232 @@ struct MIMState MIMMap *map; }; -/* Lookup keys KEY1,2,3 in the nested plist PLIST, and return the - value. */ - -static MPlist * -lookup_nested_list (MPlist *plist, MSymbol key1, MSymbol key2, MSymbol key3) -{ - MSymbol key[3]; - int i; - - key[0] = key1, key[1] = key2, key[2] = key3; - for (i = 0; i < 3; i++) - { - plist = mplist_find_by_value (plist, key[i]); - if (! plist) - return NULL; - plist = MPLIST_NEXT (plist); - plist = MPLIST_PLIST (plist); - } - return plist; -} +#define CUSTOM_FILE "config.mic" -/* Set VAL for keys KEY1,2,3 in the nested plist PLIST. */ +static MPlist *load_im_info_keys; -static MPlist * -set_nested_list (MPlist *plist, MSymbol key1, MSymbol key2, MSymbol key3, - MPlist *val) -{ - MSymbol key[3]; - int i; - MPlist *pl; +/* List of input method information. The format is: + (LANGUAGE NAME t:IM_INFO ... ... ...) */ +static MPlist *im_info_list; - key[0] = key1, key[1] = key2, key[2] = key3; - for (i = 0; i < 3; i++) - { - pl = mplist_find_by_value (plist, key[i]); - if (pl) - { - pl = MPLIST_NEXT (pl); - plist = MPLIST_PLIST (pl); - } - else - { - pl = mplist_add (plist, Msymbol, key[i]); - plist = mplist (); - pl = mplist_add (pl, Mplist, plist); - M17N_OBJECT_UNREF (plist); - } - } - mplist_set (pl, Mplist, val); - M17N_OBJECT_UNREF (val); - return pl; -} +/* Database for user's customization file. */ +static MDatabase *im_custom_mdb; -/* Parse PLIST as a value of nested list and return an adjusted list. - - PLIST has this form; - (symbol:command - plist:(symbol:KEY - [ mtext:DESCRIPTION | symbol:nil ] - ;; The remaining elements are checked CHECK_FUNC. - ...) - plist:(symbol:KEY - [ mtext:DESCRIPTION | symbol:nil ] - ;; The remaining elements are checked CHECK_FUNC. - ...) - ...) +/* List of input method information loaded from im_custom_mdb. The + format is the same as im_info_list. */ +static MPlist *im_custom_list; - GLOBAL is a global list. If a description text is missing, it is - extracted from GLOBAL. +/* List of input method information configured by + minput_config_command and minput_config_variable. The format is + the same as im_info_list. */ +static MPlist *im_config_list; - The return value is a plist of this format: - (symbol:KEY - plist:([ mtext:DESCRIPTION | symbol:nil ] - ...) - symbol:KEY - plist:([ mtext:DESCRIPTION | symbol:nil ] - ...) - ...) +/* Global input method information. It points into the element of + im_info_list corresponding to LANGUAGE == `nil' and NAME == + `global'. */ +static MInputMethodInfo *global_info; - PLIST itself is unref-ed. */ +static int update_global_info (void); +static int update_custom_info (void); +static MInputMethodInfo *get_im_info (MSymbol, MSymbol, MSymbol, MSymbol); -static MPlist * -parse_nested_list_value (MPlist *plist, MPlist *global, MSymbol key, - int (*check_func) (MPlist *)) + +void +fully_initialize () { - MPlist *val, *pl, *p, *p0; + char *key_names[32] + = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL }; + char buf[6], buf2[32]; + int i, j; + /* Maximum case: C-M-a, C-M-A, M-Return, C-A-a, C-A-A, A-Return. */ + MSymbol alias[7]; - val = mplist (); - if (! MPLIST_PLIST_P (plist)) + M_key_alias = msymbol (" key-alias"); + + buf[0] = 'C'; + buf[1] = '-'; + buf[3] = '\0'; + for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++) { - M17N_OBJECT_UNREF (plist); - return val; + one_char_symbol[i] = msymbol (buf); + if (key_names[i] || (buf[2] >= 'A' && buf[2] <= 'Z')) + { + j = 0; + alias[j++] = one_char_symbol[i]; + if (key_names[i]) + { + /* Ex: `Escape' == `C-[' */ + alias[j++] = msymbol (key_names[i]); + } + if (buf[2] >= 'A' && buf[2] <= 'Z') + { + /* Ex: `C-a' == `C-A' */ + buf[2] += 32; + alias[j++] = msymbol (buf); + buf[2] -= 32; + } + /* Establish cyclic alias chain. */ + alias[j] = alias[0]; + while (--j >= 0) + msymbol_put (alias[j], M_key_alias, alias[j + 1]); + } } - pl = MPLIST_PLIST (plist); - if (! MPLIST_SYMBOL_P (pl) - || MPLIST_SYMBOL (pl) != key) + buf[0] = 'S'; + for (i = buf[2] = ' '; i < 127; i++, buf[2]++) { - M17N_OBJECT_UNREF (plist); - return val; + one_char_symbol[i] = msymbol (buf + 2); + if (i >= 'A' && i <= 'Z') + { + /* Ex: `A' == `S-A' == `S-a'. */ + alias[0] = alias[3] = one_char_symbol[i]; + alias[1] = msymbol (buf); + buf[2] += 32; + alias[2] = msymbol (buf); + buf[2] -= 32; + for (j = 0; j < 3; j++) + msymbol_put (alias[j], M_key_alias, alias[j + 1]); + } } + buf[0] = 'C'; - MPLIST_DO (pl, MPLIST_NEXT (pl)) - { - MSymbol name; - MPlist *global_def = NULL; + alias[0] = alias[2] = one_char_symbol[127] = msymbol ("Delete"); + alias[1] = msymbol ("C-?"); + for (j = 0; j < 2; j++) + msymbol_put (alias[j], M_key_alias, alias[j + 1]); - if (! MPLIST_PLIST_P (pl)) - continue; - p = MPLIST_PLIST (pl); - if (! MPLIST_SYMBOL_P (p)) - continue; - name = MPLIST_SYMBOL (p); - p = MPLIST_NEXT (p); - if (MPLIST_TAIL_P (p)) + buf[3] = '-'; + buf[5] = '\0'; + buf2[1] = '-'; + for (i = 128, buf[4] = '@'; i < 160; i++, buf[4]++) + { + j = 0; + /* `C-M-a' == `C-A-a' */ + buf[2] = 'M'; + alias[j++] = one_char_symbol[i] = msymbol (buf); + buf[2] = 'A'; + alias[j++] = msymbol (buf); + if (key_names[i - 128]) { - if (! global) - continue; - global_def = mplist_find_by_value (global, name); - if (! global_def) - continue; - global_def = MPLIST_PLIST (MPLIST_NEXT (global_def)); - mplist__conc (p, global_def); + /* Ex: `M-Escape' == `A-Escape' == `C-M-['. */ + buf2[0] = 'M'; + strcpy (buf2 + 2, key_names[i - 128]); + alias[j++] = msymbol (buf2); + buf2[0] = 'A'; + alias[j++] = msymbol (buf2); } - p0 = MPLIST_NEXT (p); - if (MPLIST_TAIL_P (p0)) + if (buf[4] >= 'A' && buf[4] <= 'Z') { - if (! global || global_def) - continue; - global_def = mplist_find_by_value (global, name); - if (! global_def) - continue; - global_def = MPLIST_PLIST (MPLIST_NEXT (global_def)); - global_def = MPLIST_NEXT (global_def); - if (MPLIST_TAIL_P (global_def)) - continue; - mplist__conc (p0, global_def); + /* Ex: `C-M-a' == `C-M-A'. */ + buf[4] += 32; + buf[2] = 'M'; + alias[j++] = msymbol (buf); + buf[2] = 'A'; + alias[j++] = msymbol (buf); + buf[4] -= 32; } - if ((*check_func) (p0) < 0) - continue; - mplist_add (val, Msymbol, name); - mplist_add (val, Mplist, p); + /* Establish cyclic alias chain. */ + alias[j] = alias[0]; + while (--j >= 0) + msymbol_put (alias[j], M_key_alias, alias[j + 1]); + } + for (i = 160, buf[4] = ' '; i < 256; i++, buf[4]++) + { + buf[2] = 'M'; + alias[0] = alias[2] = one_char_symbol[i] = msymbol (buf + 2); + buf[2] = 'A'; + alias[1] = msymbol (buf + 2); + for (j = 0; j < 2; j++) + msymbol_put (alias[j], M_key_alias, alias[j + 1]); } - M17N_OBJECT_UNREF (plist); - return val; -} + alias[0] = alias[4] = one_char_symbol[255] = msymbol ("M-Delete"); + alias[1] = msymbol ("A-Delete"); + alias[2] = msymbol ("C-M-?"); + alias[3] = msymbol ("C-A-?"); + for (j = 0; j < 4; j++) + msymbol_put (alias[j], M_key_alias, alias[j + 1]); -static MPlist *variable_list, *command_list; -static int check_variable_list (MPlist *plist); -static int check_command_list (MPlist *plist); -static MPlist *load_partial_im_info (MSymbol language, MSymbol name, - MSymbol extra, MSymbol key); + Minput_method = msymbol ("input-method"); + Mtitle = msymbol ("title"); + Mmacro = msymbol ("macro"); + Mmodule = msymbol ("module"); + Mmap = msymbol ("map"); + Mstate = msymbol ("state"); + Minclude = msymbol ("include"); + Minsert = msymbol ("insert"); + M_candidates = msymbol (" candidates"); + Mdelete = msymbol ("delete"); + Mmove = msymbol ("move"); + Mmark = msymbol ("mark"); + Mpushback = msymbol ("pushback"); + Mundo = msymbol ("undo"); + Mcall = msymbol ("call"); + Mshift = msymbol ("shift"); + Mselect = msymbol ("select"); + Mshow = msymbol ("show"); + Mhide = msymbol ("hide"); + Mcommit = msymbol ("commit"); + Munhandle = msymbol ("unhandle"); + Mset = msymbol ("set"); + Madd = msymbol ("add"); + Msub = msymbol ("sub"); + Mmul = msymbol ("mul"); + Mdiv = msymbol ("div"); + Mequal = msymbol ("="); + Mless = msymbol ("<"); + Mgreater = msymbol (">"); + Mless_equal = msymbol ("<="); + Mgreater_equal = msymbol (">="); + Mcond = msymbol ("cond"); + Mplus = msymbol ("+"); + Mminus = msymbol ("-"); + Mstar = msymbol ("*"); + Mslash = msymbol ("/"); + Mand = msymbol ("&"); + Mor = msymbol ("|"); + Mnot = msymbol ("!"); -static MPlist * -get_nested_list (MSymbol language, MSymbol name, MSymbol extra, MSymbol key) -{ - MPlist *total_list; - int (*check_func) (MPlist *); - MPlist *plist, *global; + Mat_reload = msymbol ("@reload"); - if (key == M_variable) - { - if (! variable_list) - variable_list = mplist (); - total_list = variable_list; - check_func = check_variable_list; - } - else - { - if (! command_list) - command_list = mplist (); - total_list = command_list; - check_func = check_command_list; - } + Mcandidates_group_size = msymbol ("candidates-group-size"); + Mcandidates_charset = msymbol ("candidates-charset"); - if (MPLIST_TAIL_P (total_list)) - { - plist = load_partial_im_info (Mt, Mnil, key, key); - if (plist) - global = parse_nested_list_value (plist, NULL, key, check_func); - else - global = mplist (); - set_nested_list (total_list, Mt, Mnil, key, global); - } - else - global = lookup_nested_list (total_list, Mt, Mnil, key); + Mcandidate_list = msymbol_as_managing_key (" candidate-list"); + Mcandidate_index = msymbol (" candidate-index"); + + Minit = msymbol ("init"); + Mfini = msymbol ("fini"); - if (name == Mnil) - return global; + Mdescription = msymbol ("description"); + Mcommand = msymbol ("command"); + Mvariable = msymbol ("variable"); + Mglobal = msymbol ("global"); + Mconfig = msymbol ("config"); - plist = lookup_nested_list (total_list, language, name, extra); - if (plist) - return plist; + load_im_info_keys = mplist (); + mplist_add (load_im_info_keys, Mstate, Mnil); + mplist_push (load_im_info_keys, Mmap, Mnil); - plist = load_partial_im_info (language, name, extra, key); - if (plist) - plist = parse_nested_list_value (plist, global, key, check_func); - else - plist = mplist (); - set_nested_list (total_list, language, name, extra, plist); - return plist; + im_info_list = mplist (); + im_config_list = im_custom_list = NULL; + im_custom_mdb = NULL; + update_custom_info (); + global_info = NULL; + update_global_info (); + + fully_initialized = 1; } +#define MINPUT__INIT() \ + do { \ + if (! fully_initialized) \ + fully_initialize (); \ + } while (0) + + static int marker_code (MSymbol sym) { @@ -456,21 +487,20 @@ marker_code (MSymbol sym) static MPlist * resolve_variable (MInputContextInfo *ic_info, MSymbol var) { - MPlist *p; + MPlist *plist = mplist__assq (ic_info->vars, var); - MPLIST_DO (p, ic_info->vars) - { - if (MPLIST_SYMBOL (p) == var) - break; - p = MPLIST_NEXT (p); - } - if (MPLIST_TAIL_P (p)) + if (plist) { - p = ic_info->vars; - mplist_push (p, Minteger, (void *) 0); - mplist_push (p, Msymbol, var); + plist = MPLIST_PLIST (plist); + return MPLIST_NEXT (plist); } - return (MPLIST_NEXT (p)); + + plist = mplist (); + mplist_push (ic_info->vars, Mplist, plist); + M17N_OBJECT_UNREF (plist); + plist = mplist_add (plist, Msymbol, var); + plist = mplist_add (plist, Minteger, (void *) 0); + return plist; } static MText * @@ -479,8 +509,8 @@ get_surrounding_text (MInputContext *ic, int len) MText *mt = NULL; mplist_push (ic->plist, Minteger, (void *) len); - minput__callback (ic, Minput_get_surrounding_text); - if (MPLIST_MTEXT_P (ic->plist)) + if (minput__callback (ic, Minput_get_surrounding_text) >= 0 + && MPLIST_MTEXT_P (ic->plist)) mt = MPLIST_MTEXT (ic->plist); mplist_pop (ic->plist); return mt; @@ -491,8 +521,7 @@ delete_surrounding_text (MInputContext *ic, int pos) { MInputContextInfo *ic_info = (MInputContextInfo *) ic->info; - mplist_push (ic->plist, Minteger, (void *) pos); - minput__callback (ic, Minput_delete_surrounding_text); + mplist_push (ic->plist minput__callback (ic, Minput_delete_surrounding_text); mplist_pop (ic->plist); if (pos < 0) M17N_OBJECT_UNREF (ic_info->preceding_text); @@ -515,7 +544,7 @@ get_preceding_char (MInputContext *ic, int pos) } mt = get_surrounding_text (ic, - pos); if (! mt) - return -1; + return -2; len = mtext_nchars (mt); if (ic_info->preceding_text) { @@ -547,7 +576,7 @@ get_following_char (MInputContext *ic, int pos) } mt = get_surrounding_text (ic, pos); if (! mt) - return -1; + return -2; len = mtext_nchars (mt); if (ic_info->following_text) { @@ -632,7 +661,7 @@ parse_expression (MPlist *plist) return -1; plist = MPLIST_PLIST (plist); op = MPLIST_SYMBOL (plist); - if (op != Mplus && op != Mminus && op != Mstar && op != Mslush + if (op != Mplus && op != Mminus && op != Mstar && op != Mslash && op != Mand && op != Mor && op != Mnot && op != Mless && op != Mgreater && op != Mequal && op != Mless_equal && op != Mgreater_equal) @@ -670,7 +699,7 @@ resolve_expression (MInputContext *ic, MPlist *plist) else if (op == Mstar) MPLIST_DO (plist, MPLIST_NEXT (plist)) val *= resolve_expression (ic, plist); - else if (op == Mslush) + else if (op == Mslash) MPLIST_DO (plist, MPLIST_NEXT (plist)) val /= resolve_expression (ic, plist); else if (op == Mand) @@ -863,7 +892,7 @@ parse_action_list (MPlist *plist, MPlist *macros) else if (! macros || ! mplist_get (macros, action_name)) MERROR (MERROR_IM, -1); } - else + else if (! MPLIST_SYMBOL_P (plist)) MERROR (MERROR_IM, -1); } @@ -871,24 +900,16 @@ parse_action_list (MPlist *plist, MPlist *macros) } static MPlist * -resolve_command (MSymbol language, MSymbol name, MSymbol command) +resolve_command (MPlist *cmds, MSymbol command) { - MPlist *plist = get_nested_list (language, name, Mnil, M_command); + MPlist *plist; - if (! plist) - MERROR (MERROR_IM, NULL); - MPLIST_DO (plist, plist) - { - if (MPLIST_SYMBOL (plist) == command) - break; - plist = MPLIST_NEXT (plist); - } - if (MPLIST_TAIL_P (plist)) - MERROR (MERROR_IM, NULL); - plist = MPLIST_NEXT (plist); - if (! MPLIST_PLIST_P (plist)) - MERROR (MERROR_IM, NULL); - plist = MPLIST_NEXT (MPLIST_PLIST (plist)); + if (! cmds || ! (plist = mplist__assq (cmds, command))) + return NULL; + plist = MPLIST_PLIST (plist); /* (NAME DESC STATUS [KEYSEQ ...]) */ + plist = MPLIST_NEXT (plist); + plist = MPLIST_NEXT (plist); + plist = MPLIST_NEXT (plist); return plist; } @@ -908,19 +929,22 @@ load_translation (MIMMap *map, MPlist *keylist, MPlist *map_actions, MText *mt = MPLIST_MTEXT (keylist); len = mtext_nchars (mt); - if (len == 0 || len != mtext_nbytes (mt)) - MERROR (MERROR_IM, -1); + if (MFAILP (len > 0 && len == mtext_nbytes (mt))) + return -1; keyseq = (MSymbol *) alloca (sizeof (MSymbol) * len); for (i = 0; i < len; i++) keyseq[i] = one_char_symbol[MTEXT_DATA (mt)[i]]; } - else if (MPLIST_PLIST_P (keylist)) + else { - MPlist *elt = MPLIST_PLIST (keylist); + MPlist *elt; + if (MFAILP (MPLIST_PLIST_P (keylist))) + return -1; + elt = MPLIST_PLIST (keylist); len = MPLIST_LENGTH (elt); - if (len == 0) - MERROR (MERROR_IM, -1); + if (MFAILP (len > 0)) + return -1; keyseq = (MSymbol *) alloca (sizeof (int) * len); for (i = 0; i < len; i++, elt = MPLIST_NEXT (elt)) { @@ -928,18 +952,18 @@ load_translation (MIMMap *map, MPlist *keylist, MPlist *map_actions, { int c = MPLIST_INTEGER (elt); - if (c < 0 || c >= 0x100) - MERROR (MERROR_IM, -1); + if (MFAILP (c >= 0 && c < 0x100)) + return -1; keyseq[i] = one_char_symbol[c]; } - else if (MPLIST_SYMBOL_P (elt)) - keyseq[i] = MPLIST_SYMBOL (elt); else - MERROR (MERROR_IM, -1); + { + if (MFAILP (MPLIST_SYMBOL_P (elt))) + return -1; + keyseq[i] = MPLIST_SYMBOL (elt); + } } } - else - MERROR (MERROR_IM, -1); for (i = 0; i < len; i++) { @@ -980,25 +1004,22 @@ load_translation (MIMMap *map, MPlist *keylist, MPlist *map_actions, } /* Load a branch from PLIST into MAP. PLIST has this form: - PLIST ::= ( MAP-NAME BRANCH-ACTION * ) - MAPS is a plist of raw maps. - STATE is the current state. */ + PLIST ::= ( MAP-NAME BRANCH-ACTION * ) */ static int -load_branch (MPlist *plist, MPlist *maps, MIMMap *map, - MSymbol language, MSymbol name, MPlist *macros) +load_branch (MInputMethodInfo *im_info, MPlist *plist, MIMMap *map) { MSymbol map_name; MPlist *branch_actions; - if (! MPLIST_SYMBOL_P (plist)) - MERROR (MERROR_IM, -1); + if (MFAILP (MPLIST_SYMBOL_P (plist))) + return -1; map_name = MPLIST_SYMBOL (plist); plist = MPLIST_NEXT (plist); if (MPLIST_TAIL_P (plist)) branch_actions = NULL; - else if (parse_action_list (plist, macros) < 0) - MERROR (MERROR_IM, -1); + else if (MFAILP (parse_action_list (plist, im_info->macros) >= 0)) + return -1; else branch_actions = plist; if (map_name == Mnil) @@ -1013,7 +1034,8 @@ load_branch (MPlist *plist, MPlist *maps, MIMMap *map, if (branch_actions) M17N_OBJECT_REF (branch_actions); } - else if (maps && (plist = (MPlist *) mplist_get (maps, map_name))) + else if (im_info->maps + && (plist = (MPlist *) mplist_get (im_info->maps, map_name))) { MPLIST_DO (plist, plist) { @@ -1026,31 +1048,33 @@ load_branch (MPlist *plist, MPlist *maps, MIMMap *map, if (MPLIST_SYMBOL_P (keylist)) { MSymbol command = MPLIST_SYMBOL (keylist); - MPlist *pl = resolve_command (language, name, command); + MPlist *pl; - if (! pl) - return -1; + if (MFAILP (command != Mat_reload)) + continue; + pl = resolve_command (im_info->configured_cmds, command); + if (MFAILP (pl)) + continue; MPLIST_DO (pl, pl) - if (load_translation (map, pl, map_actions, branch_actions, - macros) < 0) - MERROR (MERROR_IM, -1); + load_translation (map, pl, map_actions, branch_actions, + im_info->macros); } else - if (load_translation (map, keylist, map_actions, branch_actions, - macros) < 0) - MERROR (MERROR_IM, -1); + load_translation (map, keylist, map_actions, branch_actions, + im_info->macros); } } return 0; } -/* Load a macro from PLIST into MACROS. +/* Load a macro from PLIST into IM_INFO->macros. PLIST has this from: PLIST ::= ( MACRO-NAME ACTION * ) - MACROS is a plist of macro names vs action list. */ + IM_INFO->macros is a plist of macro names vs action list. */ + static int -load_macros (MPlist *plist, MPlist *macros) +load_macros (MInputMethodInfo *im_info, MPlist *plist) { MSymbol name; MPlist *pl; @@ -1060,23 +1084,22 @@ load_macros (MPlist *plist, MPlist *macros) name = MPLIST_SYMBOL (plist); plist = MPLIST_NEXT (plist); if (MPLIST_TAIL_P (plist) - || parse_action_list (plist, macros) < 0) + || parse_action_list (plist, im_info->macros) < 0) MERROR (MERROR_IM, -1); - pl = mplist_get (macros, name); - if (pl) - M17N_OBJECT_UNREF (pl); - mplist_put (macros, name, plist); + pl = mplist_get (im_info->macros, name); + M17N_OBJECT_UNREF (pl); + mplist_put (im_info->macros, name, plist); M17N_OBJECT_REF (plist); return 0; } -/* Load an external module from PLIST into EXTERNALS. +/* Load an external module from PLIST into IM_INFO->externals. PLIST has this form: PLIST ::= ( MODULE-NAME FUNCTION * ) - EXTERNALS is a plist of MODULE-NAME vs (MIMExternalModule *). */ + IM_INFO->externals is a plist of MODULE-NAME vs (MIMExternalModule *). */ static int -load_external_module (MPlist *plist, MPlist *externals) +load_external_module (MInputMethodInfo *im_info, MPlist *plist) { void *handle; MSymbol module; @@ -1094,10 +1117,10 @@ load_external_module (MPlist *plist, MPlist *externals) sprintf (module_file, "%s%s", MSYMBOL_NAME (module), DLOPEN_SHLIB_EXT); handle = dlopen (module_file, RTLD_NOW); - if (! handle) + if (MFAILP (handle)) { fprintf (stderr, "%s\n", dlerror ()); - MERROR (MERROR_IM, -1); + return -1; } func_list = mplist (); MPLIST_DO (plist, MPLIST_NEXT (plist)) @@ -1105,15 +1128,15 @@ load_external_module (MPlist *plist, MPlist *externals) if (! MPLIST_SYMBOL_P (plist)) MERROR_GOTO (MERROR_IM, err_label); func = dlsym (handle, MSYMBOL_NAME (MPLIST_SYMBOL (plist))); - if (! func) - MERROR_GOTO (MERROR_IM, err_label); + if (MFAILP (func)) + goto err_label; mplist_add (func_list, MPLIST_SYMBOL (plist), func); } MSTRUCT_MALLOC (external, MERROR_IM); external->handle = handle; external->func_list = func_list; - mplist_add (externals, module, external); + mplist_add (im_info->externals, module, external); return 0; err_label: @@ -1144,8 +1167,7 @@ free_state (void *object) { MIMState *state = object; - if (state->title) - M17N_OBJECT_UNREF (state->title); + M17N_OBJECT_UNREF (state->title); if (state->map) free_map (state->map, 1); free (state); @@ -1155,17 +1177,15 @@ free_state (void *object) PLIST has this form: PLIST ::= ( STATE-NAME STATE-TITLE ? BRANCH * ) BRANCH ::= ( MAP-NAME BRANCH-ACTION * ) - MAPS is a plist of defined maps. Return the state object. */ static MIMState * -load_state (MPlist *plist, MPlist *maps, MSymbol language, MSymbol name, - MPlist *macros) +load_state (MInputMethodInfo *im_info, MPlist *plist) { MIMState *state; - if (! MPLIST_SYMBOL_P (plist)) - MERROR (MERROR_IM, NULL); + if (MFAILP (MPLIST_SYMBOL_P (plist))) + return NULL; M17N_OBJECT (state, free_state, MERROR_IM); state->name = MPLIST_SYMBOL (plist); plist = MPLIST_NEXT (plist); @@ -1173,29 +1193,62 @@ load_state (MPlist *plist, MPlist *maps, MSymbol language, MSymbol name, { state->title = MPLIST_MTEXT (plist); mtext_put_prop (state->title, 0, mtext_nchars (state->title), - Mlanguage, language); + Mlanguage, im_info->language); M17N_OBJECT_REF (state->title); plist = MPLIST_NEXT (plist); } MSTRUCT_CALLOC (state->map, MERROR_IM); MPLIST_DO (plist, plist) - if (! MPLIST_PLIST_P (plist) - || load_branch (MPLIST_PLIST (plist), maps, state->map, language, name, - macros) < 0) - MERROR (MERROR_IM, NULL); + { + if (MFAILP (MPLIST_PLIST_P (plist))) + continue; + load_branch (im_info, MPLIST_PLIST (plist), state->map); + } return state; } +/* Return a newly created IM_INFO for an input method specified by + LANUAGE, NAME, and EXTRA. IM_INFO is stored in PLIST. */ -static MPlist *im_info_list; +static MInputMethodInfo * +new_im_info (MDatabase *mdb, MSymbol language, MSymbol name, MSymbol extra, + MPlist *plist) +{ + MInputMethodInfo *im_info; + MPlist *elt; + + if (name == Mnil && extra == Mnil) + language = Mt, extra = Mglobal; + MSTRUCT_CALLOC (im_info, MERROR_IM); + im_info->mdb = mdb; + im_info->language = language; + im_info->name = name; + im_info->extra = extra; + + elt = mplist (); + mplist_add (plist, Mplist, elt); + M17N_OBJECT_UNREF (elt); + elt = mplist_add (elt, Msymbol, language); + elt = mplist_add (elt, Msymbol, name); + elt = mplist_add (elt, Msymbol, extra); + mplist_add (elt, Mt, im_info); + + return im_info; +} static void -free_im_info (MInputMethodInfo *im_info) +fini_im_info (MInputMethodInfo *im_info) { MPlist *plist; - if (im_info->title) - M17N_OBJECT_UNREF (im_info->title); + M17N_OBJECT_UNREF (im_info->cmds); + M17N_OBJECT_UNREF (im_info->configured_cmds); + M17N_OBJECT_UNREF (im_info->bc_cmds); + M17N_OBJECT_UNREF (im_info->vars); + M17N_OBJECT_UNREF (im_info->configured_vars); + M17N_OBJECT_UNREF (im_info->bc_vars); + M17N_OBJECT_UNREF (im_info->description); + M17N_OBJECT_UNREF (im_info->title); if (im_info->states) { MPLIST_DO (plist, im_info->states) @@ -1238,2681 +1291,4298 @@ free_im_info (MInputMethodInfo *im_info) M17N_OBJECT_UNREF (im_info->maps); } - free (im_info); + im_info->tick = 0; } -static MInputMethodInfo *get_im_info (MSymbol language, MSymbol name, - MSymbol extra); +static void +free_im_info (MInputMethodInfo *im_info) +{ + fini_im_info (im_info); + free (im_info); +} -static MInputMethodInfo * -get_im_info_by_tags (MPlist *plist) +static void +free_im_list (MPlist *plist) { - MSymbol tag[3]; - int i; + MPlist *pl, *elt; - for (i = 0; i < 3 && MPLIST_SYMBOL_P (plist); - i++, plist = MPLIST_NEXT (plist)) - tag[i] = MPLIST_SYMBOL (plist); - if (i < 2) - return NULL; - for (; i < 3; i++) - tag[i] = Mnil; - return get_im_info (tag[0], tag[1], tag[2]); -} + MPLIST_DO (pl, plist) + { + MInputMethodInfo *im_info; -/* Load an input method from PLIST into IM_INTO, and return it. */ + elt = MPLIST_NEXT (MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (pl)))); + im_info = MPLIST_VAL (elt); + free_im_info (im_info); + } + M17N_OBJECT_UNREF (plist); +} static MInputMethodInfo * -load_im_info (MSymbol language, MSymbol name, MPlist *plist) +lookup_im_info (MPlist *plist, MSymbol language, MSymbol name, MSymbol extra) { - MInputMethodInfo *im_info; - MText *title = NULL; - MPlist *maps = NULL; - MPlist *states = NULL; - MPlist *externals = NULL; - MPlist *macros = NULL; - MPlist *elt; - - MSTRUCT_CALLOC (im_info, MERROR_IM); - - while (MPLIST_PLIST_P (plist)) + if (name == Mnil && extra == Mnil) + language = Mt, extra = Mglobal; + while ((plist = mplist__assq (plist, language))) { - elt = MPLIST_PLIST (plist); - if (! MPLIST_SYMBOL_P (elt)) - MERROR_GOTO (MERROR_IM, err); - if (MPLIST_SYMBOL (elt) == Mtitle) - { - elt = MPLIST_NEXT (elt); - if (! MPLIST_MTEXT_P (elt)) - MERROR_GOTO (MERROR_IM, err); - im_info->title = title = MPLIST_MTEXT (elt); - M17N_OBJECT_REF (title); - } - else if (MPLIST_SYMBOL (elt) == Mmap) - { - MPlist *pl = mplist__from_alist (MPLIST_NEXT (elt)); + MPlist *elt = MPLIST_PLIST (plist); - if (! pl) - MERROR_GOTO (MERROR_IM, err); - if (! maps) - im_info->maps = maps = pl; - else - maps = mplist__conc (maps, pl); - } - else if (MPLIST_SYMBOL (elt) == Mmacro) - { - if (! macros) - im_info->macros = macros = mplist (); - MPLIST_DO (elt, MPLIST_NEXT (elt)) - { - if (! MPLIST_PLIST_P (elt) - || load_macros (MPLIST_PLIST (elt), macros) < 0) - MERROR_GOTO (MERROR_IM, err); - } - } - else if (MPLIST_SYMBOL (elt) == Mmodule) - { - if (! externals) - im_info->externals = externals = mplist (); - MPLIST_DO (elt, MPLIST_NEXT (elt)) - { - if (! MPLIST_PLIST_P (elt) - || load_external_module (MPLIST_PLIST (elt), externals) < 0) - MERROR_GOTO (MERROR_IM, err); - } - } - else if (MPLIST_SYMBOL (elt) == Mstate) - { - MPLIST_DO (elt, MPLIST_NEXT (elt)) - { - MIMState *state; - - if (! MPLIST_PLIST_P (elt)) - MERROR_GOTO (MERROR_IM, err); - state = load_state (MPLIST_PLIST (elt), maps, language, name, - macros); - if (! state) - MERROR_GOTO (MERROR_IM, err); - if (! states) - im_info->states = states = mplist (); - mplist_put (states, state->name, state); - } - } - else if (MPLIST_SYMBOL (elt) == Minclude) - { - /* elt ::= include (tag1 tag2 ...) key item ... */ - MSymbol key; - MInputMethodInfo *temp; - MPlist *pl, *p; - - elt = MPLIST_NEXT (elt); - if (! MPLIST_PLIST_P (elt)) - MERROR_GOTO (MERROR_IM, err); - temp = get_im_info_by_tags (MPLIST_PLIST (elt)); - if (! temp) - MERROR_GOTO (MERROR_IM, err); - elt = MPLIST_NEXT (elt); - if (! MPLIST_SYMBOL_P (elt)) - MERROR_GOTO (MERROR_IM, err); - key = MPLIST_SYMBOL (elt); - elt = MPLIST_NEXT (elt); - if (key == Mmap) - { - if (! maps) - im_info->maps = maps = mplist (); - MPLIST_DO (pl, temp->maps) - { - p = MPLIST_VAL (pl); - MPLIST_ADD_PLIST (maps, MPLIST_KEY (pl), p); - M17N_OBJECT_REF (p); - } - } - else if (key == Mmacro) - { - if (! macros) - im_info->macros = macros = mplist (); - MPLIST_DO (pl, temp->macros) - { - p = MPLIST_VAL (pl); - MPLIST_ADD_PLIST (macros, MPLIST_KEY (pl), p); - M17N_OBJECT_REF (p); - } - } - else if (key == Mstate) - { - if (! states) - im_info->states = states = mplist (); - MPLIST_DO (pl, temp->states) - { - MIMState *state = MPLIST_VAL (pl); - - mplist_add (states, MPLIST_KEY (pl), state); - M17N_OBJECT_REF (state); - } - } - else - MERROR_GOTO (MERROR_IM, err); - } plist = MPLIST_NEXT (plist); + elt = MPLIST_NEXT (elt); + if (MPLIST_SYMBOL (elt) != name) + continue; + elt = MPLIST_NEXT (elt); + if (MPLIST_SYMBOL (elt) != extra) + continue; + elt = MPLIST_NEXT (elt); + return MPLIST_VAL (elt); } - - if (! states) - goto err; - if (! title && name) - im_info->title - = title = mtext_from_data (MSYMBOL_NAME (name), MSYMBOL_NAMELEN (name), - MTEXT_FORMAT_US_ASCII); - return im_info; - - err: - free_im_info (im_info); return NULL; } - +static void load_im_info (MPlist *, MInputMethodInfo *); -static int take_action_list (MInputContext *ic, MPlist *action_list); -static void preedit_commit (MInputContext *ic); +#define get_custom_info(im_info) \ + (im_custom_list \ + ? lookup_im_info (im_custom_list, (im_info)->language, \ + (im_info)->name, (im_info)->extra) \ + : NULL) -static void -shift_state (MInputContext *ic, MSymbol state_name) +#define get_config_info(im_info) \ + (im_config_list \ + ? lookup_im_info (im_config_list, (im_info)->language, \ + (im_info)->name, (im_info)->extra) \ + : NULL) + +static int +update_custom_info (void) { - MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info; - MInputContextInfo *ic_info = (MInputContextInfo *) ic->info; - MIMState *orig_state = ic_info->state, *state; + MPlist *plist, *pl; - /* Find a state to shift to. If not found, shift to the initial - state. */ - if (state_name == Mt) + if (im_custom_mdb) { - if (! ic_info->prev_state) - return; - state = ic_info->prev_state; + if (mdatabase__check (im_custom_mdb) > 0) + return 1; } else { - state = (MIMState *) mplist_get (im_info->states, state_name); - if (! state) - state = (MIMState *) MPLIST_VAL (im_info->states); + MDatabaseInfo *custom_dir_info; + char custom_path[PATH_MAX + 1]; + + custom_dir_info = MPLIST_VAL (mdatabase__dir_list); + if (! custom_dir_info->filename + || custom_dir_info->len + strlen (CUSTOM_FILE) > PATH_MAX) + return -1; + strcpy (custom_path, custom_dir_info->filename); + strcat (custom_path, CUSTOM_FILE); + im_custom_mdb = mdatabase_define (Minput_method, Mt, Mnil, Mconfig, + NULL, custom_path); } - MDEBUG_PRINT1 ("\n [IM] (shift %s)", MSYMBOL_NAME (state->name)); + if (im_custom_list) + { + free_im_list (im_custom_list); + im_custom_list = NULL; + } + plist = mdatabase_load (im_custom_mdb); + if (! plist) + return -1; + im_custom_list = mplist (); - /* Enter the new state. */ - ic_info->state = state; - ic_info->map = state->map; - ic_info->state_key_head = ic_info->key_head; - if (state == (MIMState *) MPLIST_VAL (im_info->states)) - /* We have shifted to the initial state. */ - preedit_commit (ic); - mtext_cpy (ic_info->preedit_saved, ic->preedit); - ic_info->state_pos = ic->cursor_pos; - if (state != orig_state ) + MPLIST_DO (pl, plist) { - if (state == (MIMState *) MPLIST_VAL (im_info->states)) - ic_info->prev_state = NULL; - else - ic_info->prev_state = orig_state; + MSymbol language, name, extra; + MInputMethodInfo *im_info; + MPlist *im_data, *p; - if (state->title) - ic->status = state->title; + if (! MPLIST_PLIST_P (pl)) + continue; + p = MPLIST_PLIST (pl); + im_data = MPLIST_NEXT (p); + if (! MPLIST_PLIST_P (p)) + continue; + p = MPLIST_PLIST (p); + if (! MPLIST_SYMBOL_P (p) + || MPLIST_SYMBOL (p) != Minput_method) + continue; + p = MPLIST_NEXT (p); + if (! MPLIST_SYMBOL_P (p)) + continue; + language = MPLIST_SYMBOL (p); + p = MPLIST_NEXT (p); + if (! MPLIST_SYMBOL_P (p)) + continue; + name = MPLIST_SYMBOL (p); + if (language == Mnil || name == Mnil) + continue; + p = MPLIST_NEXT (p); + if (MPLIST_TAIL_P (p)) + extra = Mnil; + else if (MPLIST_SYMBOL_P (p)) + extra = MPLIST_SYMBOL (p); else - ic->status = im_info->title; - ic->status_changed = 1; - if (ic_info->map == ic_info->state->map - && ic_info->map->map_actions) - { - MDEBUG_PRINT (" init-actions:"); - take_action_list (ic, ic_info->map->map_actions); - } + continue; + im_info = new_im_info (NULL, language, name, extra, im_custom_list); + load_im_info (im_data, im_info); } + M17N_OBJECT_UNREF (plist); + return 0; } -/* Find a candidate group that contains a candidate number INDEX from - PLIST. Set START_INDEX to the first candidate number of the group, - END_INDEX to the last candidate number plus 1, GROUP_INDEX to the - candidate group number if they are non-NULL. If INDEX is -1, find - the last candidate group. */ - -static MPlist * -find_candidates_group (MPlist *plist, int index, - int *start_index, int *end_index, int *group_index) +static int +update_global_info (void) { - int i = 0, gidx = 0, len; + MPlist *plist; - MPLIST_DO (plist, plist) + if (global_info) { - if (MPLIST_MTEXT_P (plist)) - len = mtext_nchars (MPLIST_MTEXT (plist)); - else - len = mplist_length (MPLIST_PLIST (plist)); - if (index < 0 ? MPLIST_TAIL_P (MPLIST_NEXT (plist)) - : i + len > index) - { - if (start_index) - *start_index = i; - if (end_index) - *end_index = i + len; - if (group_index) - *group_index = gidx; - return plist; - } - i += len; - gidx++; + int ret = mdatabase__check (global_info->mdb); + + if (ret) + return ret; + fini_im_info (global_info); } - return NULL; + else + { + MDatabase *mdb = mdatabase_find (Minput_method, Mt, Mnil, Mglobal); + + global_info = new_im_info (mdb, Mt, Mnil, Mglobal, im_info_list); + } + if (! global_info->mdb + || ! (plist = mdatabase_load (global_info->mdb))) + return -1; + + load_im_info (plist, global_info); + M17N_OBJECT_UNREF (plist); + return 0; } -static void -preedit_insert (MInputContext *ic, int pos, MText *mt, int c) + +/* Return an IM_INFO for the an method specified by LANGUAGE, NAME, + and EXTRA. KEY, if not Mnil, tells which kind of information about + the input method is necessary, and the returned IM_INFO may contain + only that information. */ + +static MInputMethodInfo * +get_im_info (MSymbol language, MSymbol name, MSymbol extra, MSymbol key) { - MInputContextInfo *ic_info = ((MInputContext *) ic)->info; - MPlist *markers; - int nchars = mt ? mtext_nchars (mt) : 1; + MPlist *plist; + MInputMethodInfo *im_info; + MDatabase *mdb; - if (mt) - mtext_ins (ic->preedit, pos, mt); + if (name == Mnil && extra == Mnil) + language = Mt, extra = Mglobal; + im_info = lookup_im_info (im_info_list, language, name, extra); + if (im_info) + { + if (key == Mnil ? im_info->states != NULL + : key == Mcommand ? im_info->cmds != NULL + : key == Mvariable ? im_info->vars != NULL + : key == Mtitle ? im_info->title != NULL + : key == Mdescription ? im_info->description != NULL + : 1) + /* IM_INFO already contains required information. */ + return im_info; + /* We have not yet loaded required information. */ + } else - mtext_ins_char (ic->preedit, pos, c, 1); - MPLIST_DO (markers, ic_info->markers) - if (MPLIST_INTEGER (markers) > pos) - MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars); - if (ic->cursor_pos >= pos) - ic->cursor_pos += nchars; - ic->preedit_changed = 1; + { + mdb = mdatabase_find (Minput_method, language, name, extra); + if (! mdb) + return NULL; + im_info = new_im_info (mdb, language, name, extra, im_info_list); + } + + if (key == Mnil) + { + plist = mdatabase_load (im_info->mdb); + } + else + { + mplist_push (load_im_info_keys, key, Mt); + plist = mdatabase__load_for_keys (im_info->mdb, load_im_info_keys); + mplist_pop (load_im_info_keys); + } + im_info->tick = 0; + if (! plist) + MERROR (MERROR_IM, im_info); + update_global_info (); + load_im_info (plist, im_info); + M17N_OBJECT_UNREF (plist); + if (key == Mnil) + { + if (! im_info->cmds) + im_info->cmds = mplist (); + if (! im_info->vars) + im_info->vars = mplist (); + } + if (! im_info->title + && (key == Mnil || key == Mtitle)) + im_info->title = (name == Mnil ? mtext () + : mtext_from_data (MSYMBOL_NAME (name), + MSYMBOL_NAMELEN (name), + MTEXT_FORMAT_US_ASCII)); + return im_info; } +/* Check if IM_INFO->mdb is updated or not. If not updated, return 0. + If updated, but got unloadable, return -1. Otherwise, update + contents of IM_INFO from the new database, and return 1. */ -static void -preedit_delete (MInputContext *ic, int from, int to) +static int +reload_im_info (MInputMethodInfo *im_info) { - MInputContextInfo *ic_info = ((MInputContext *) ic)->info; - MPlist *markers; + int check; + MPlist *plist; - mtext_del (ic->preedit, from, to); - MPLIST_DO (markers, ic_info->markers) + check = mdatabase__check (im_info->mdb); + if (check > 0) + return 0; + if (check < 0) + return -1; + plist = mdatabase_load (im_info->mdb); + if (! plist) + return -1; + fini_im_info (im_info); + load_im_info (plist, im_info); + M17N_OBJECT_UNREF (plist); + return 1; +} + +static MInputMethodInfo * +get_im_info_by_tags (MPlist *plist) +{ + MSymbol tag[3]; + int i; + + for (i = 0; i < 3 && MPLIST_SYMBOL_P (plist); + i++, plist = MPLIST_NEXT (plist)) + tag[i] = MPLIST_SYMBOL (plist); + if (i < 2) + return NULL; + for (; i < 3; i++) + tag[i] = Mnil; + return get_im_info (tag[0], tag[1], tag[2], Mnil); +} + +/* Check KEYSEQ, and return 1 if it is valid as a key sequence, return + 0 if not. */ + +static int +check_command_keyseq (MPlist *keyseq) +{ + if (MPLIST_PLIST_P (keyseq)) { - if (MPLIST_INTEGER (markers) > to) - MPLIST_VAL (markers) - = (void *) (MPLIST_INTEGER (markers) - (to - from)); - else if (MPLIST_INTEGER (markers) > from); - MPLIST_VAL (markers) = (void *) from; + MPlist *p = MPLIST_PLIST (keyseq); + + MPLIST_DO (p, p) + if (! MPLIST_SYMBOL_P (p) && ! MPLIST_INTEGER_P (p)) + return 0; + return 1; } - if (ic->cursor_pos >= to) - ic->cursor_pos -= to - from; - else if (ic->cursor_pos > from) - ic->cursor_pos = from; - ic->preedit_changed = 1; + if (MPLIST_MTEXT_P (keyseq)) + { + MText *mt = MPLIST_MTEXT (keyseq); + int i; + + for (i = 0; i < mtext_nchars (mt); i++) + if (mtext_ref_char (mt, i) >= 256) + return 0; + return 1; + } + return 0; } +/* Load command defitions from PLIST into IM_INFO->cmds. + + PLIST is well-formed and has this form; + (command (NAME [DESCRIPTION KEYSEQ ...]) ...) + NAME is a symbol. DESCRIPTION is an M-text or `nil'. KEYSEQ is an + M-text or a plist of symbols. + + The returned list has the same form, but for each element... + + (1) If DESCRIPTION and the rest are omitted, the element is not + stored in the returned list. + + (2) If DESCRIPTION is nil, it is complemented by the corresponding + description in global_info->cmds (if any). */ + static void -preedit_commit (MInputContext *ic) +load_commands (MInputMethodInfo *im_info, MPlist *plist) { - MInputContextInfo *ic_info = (MInputContextInfo *) ic->info; - int preedit_len = mtext_nchars (ic->preedit); + MPlist *tail; - if (preedit_len > 0) + im_info->cmds = tail = mplist (); + + MPLIST_DO (plist, MPLIST_NEXT (plist)) { - MPlist *p; + /* PLIST ::= ((NAME DESC KEYSEQ ...) ...) */ + MPlist *pl, *p; - mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit), - Mcandidate_list, NULL, 0); - mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit), - Mcandidate_index, NULL, 0); - mtext_cat (ic->produced, ic->preedit); - if ((mdebug__flag & mdebug_mask) - && mtext_nchars (ic->preedit) > 0) + if (MFAILP (MPLIST_PLIST_P (plist))) + continue; + pl = MPLIST_PLIST (plist); /* PL ::= (NAME DESC KEYSEQ ...) */ + if (MFAILP (MPLIST_SYMBOL_P (pl))) + continue; + p = MPLIST_NEXT (pl); /* P ::= (DESC KEYSEQ ...) */ + if (MPLIST_TAIL_P (p)) /* PL ::= (NAME) */ { - int i; - - MDEBUG_PRINT (" (produced"); - for (i = 0; i < mtext_nchars (ic->preedit); i++) - MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->preedit, i)); - MDEBUG_PRINT (")"); + if (MFAILP (im_info != global_info)) + mplist_add (p, Msymbol, Mnil); /* PL ::= (NAME nil) */ } - mtext_reset (ic->preedit); - mtext_reset (ic_info->preedit_saved); - MPLIST_DO (p, ic_info->markers) - MPLIST_VAL (p) = 0; - ic->cursor_pos = ic_info->state_pos = 0; - ic->preedit_changed = 1; - } - if (ic->candidate_list) - { - M17N_OBJECT_UNREF (ic->candidate_list); - ic->candidate_list = NULL; - ic->candidates_changed = MINPUT_CANDIDATES_LIST_CHANGED; - if (ic->candidate_show) + else { - ic->candidate_show = 0; - ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED; + if (! MPLIST_MTEXT_P (p) + && (! MPLIST_SYMBOL_P (p) || MPLIST_SYMBOL (p) != Mnil)) + mplist_set (p, Msymbol, Mnil); + p = MPLIST_NEXT (p); + while (! MPLIST_TAIL_P (p)) + { + if (MFAILP (check_command_keyseq (p))) + mplist__pop_unref (p); + else + p = MPLIST_NEXT (p); + } } + tail = mplist_add (tail, Mplist, pl); } - - memmove (ic_info->keys, ic_info->keys + ic_info->key_head, - sizeof (int) * (ic_info->used - ic_info->key_head)); - ic_info->used -= ic_info->key_head; - ic_info->state_key_head = ic_info->key_head = 0; } -static int -new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt) +static MPlist * +config_command (MPlist *plist, MPlist *global_cmds, MPlist *custom_cmds, + MPlist *config_cmds) { - int code = marker_code (sym); + MPlist *global = NULL, *custom = NULL, *config = NULL; + MSymbol name; + MText *description = NULL; + MSymbol status; + MPlist *keyseq; - if (mt && (code == '[' || code == ']')) + name = MPLIST_SYMBOL (plist); + plist = MPLIST_NEXT (plist); + if (MPLIST_MTEXT_P (plist)) + description = MPLIST_MTEXT (plist); + else if (global_cmds && ((global = mplist__assq (global_cmds, name)))) { - int pos = current; + global = MPLIST_NEXT (MPLIST_PLIST (global)); + description = MPLIST_MTEXT_P (global) ? MPLIST_MTEXT (global) : NULL; + } + if (MPLIST_TAIL_P (plist)) + { + if (! global + && global_cmds && ((global = mplist__assq (global_cmds, name)))) + global = MPLIST_NEXT (MPLIST_PLIST (global)); + if (global) + { + keyseq = MPLIST_NEXT (global); + status = Minherited; + } + else + { + keyseq = plist; + status = Mnil; + } + } + else + { + keyseq = MPLIST_NEXT (plist); + status = Mnil; + } - if (code == '[' && current > 0) + if (config_cmds && (config = mplist__assq (config_cmds, name))) + { + config = MPLIST_NEXT (MPLIST_PLIST (config)); + if (! MPLIST_TAIL_P (config)) { - if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1) - && pos > 0) - current = pos; + keyseq = MPLIST_NEXT (config); + status = Mconfigured; } - else if (code == ']' && current < mtext_nchars (mt)) + } + else if (custom_cmds && (custom = mplist__assq (custom_cmds, name))) + { + custom = MPLIST_NEXT (MPLIST_PLIST (custom)); + if (! MPLIST_TAIL_P (custom)) { - if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1)) - current = pos; + keyseq = MPLIST_NEXT (custom); + status = Mcustomized; } - return current; } - if (code >= 0) - return (code == '<' ? 0 - : code == '>' ? limit - : code == '-' ? current - 1 - : code == '+' ? current + 1 - : code == '=' ? current - : code - '0' > limit ? limit - : code - '0'); - if (! ic) - return 0; - return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym); + + plist = mplist (); + mplist_add (plist, Msymbol, name); + if (description) + mplist_add (plist, Mtext, description); + else + mplist_add (plist, Msymbol, Mnil); + mplist_add (plist, Msymbol, status); + mplist__conc (plist, keyseq); + return plist; } static void -update_candidate (MInputContext *ic, MTextProperty *prop, int idx) +config_all_commands (MInputMethodInfo *im_info) { - 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; + MPlist *global_cmds, *custom_cmds, *config_cmds; + MInputMethodInfo *temp; + MPlist *tail, *plist; - preedit_delete (ic, from, to); - if (MPLIST_MTEXT_P (group)) + M17N_OBJECT_UNREF (im_info->configured_cmds); + + if (MPLIST_TAIL_P (im_info->cmds) + || ! im_info->mdb) + return; + + global_cmds = im_info != global_info ? global_info->cmds : NULL; + custom_cmds = ((temp = get_custom_info (im_info)) ? temp->cmds : NULL); + config_cmds = ((temp = get_config_info (im_info)) ? temp->cmds : NULL); + + im_info->configured_cmds = tail = mplist (); + MPLIST_DO (plist, im_info->cmds) { - mt = MPLIST_MTEXT (group); - preedit_insert (ic, from, NULL, mtext_ref_char (mt, ingroup_index)); - to = from + 1; + MPlist *pl = config_command (MPLIST_PLIST (plist), + global_cmds, custom_cmds, config_cmds); + if (pl) + tail = mplist_add (tail, Mplist, pl); + } +} + +/* Check VAL's value against VALID_VALUES, and return 1 if it is + valid, return 0 if not. */ + +static int +check_variable_value (MPlist *val, MPlist *global) +{ + MSymbol type = MPLIST_KEY (val); + MPlist *valids = MPLIST_NEXT (val); + + if (type != Minteger && type != Mtext && type != Msymbol) + return 0; + if (global) + { + if (MPLIST_KEY (global) != Mt + && MPLIST_KEY (global) != MPLIST_KEY (val)) + return 0; + if (MPLIST_TAIL_P (valids)) + valids = MPLIST_NEXT (global); + } + if (MPLIST_TAIL_P (valids)) + return 1; + + if (type == Minteger) + { + int n = MPLIST_INTEGER (val); + + MPLIST_DO (valids, valids) + { + if (MPLIST_INTEGER_P (valids)) + { + if (n == MPLIST_INTEGER (valids)) + break; + } + else if (MPLIST_PLIST_P (valids)) + { + MPlist *p = MPLIST_PLIST (valids); + int min_bound, max_bound; + + if (! MPLIST_INTEGER_P (p)) + MERROR (MERROR_IM, 0); + min_bound = MPLIST_INTEGER (p); + p = MPLIST_NEXT (p); + if (! MPLIST_INTEGER_P (p)) + MERROR (MERROR_IM, 0); + max_bound = MPLIST_INTEGER (p); + if (n >= min_bound && n <= max_bound) + break; + } + } + } + else if (type == Msymbol) + { + MSymbol sym = MPLIST_SYMBOL (val); + + MPLIST_DO (valids, valids) + { + if (! MPLIST_SYMBOL_P (valids)) + MERROR (MERROR_IM, 0); + if (sym == MPLIST_SYMBOL (valids)) + break; + } } else { - int i; - MPlist *plist; + MText *mt = MPLIST_MTEXT (val); - for (i = 0, plist = MPLIST_PLIST (group); i < ingroup_index; - i++, plist = MPLIST_NEXT (plist)); - mt = MPLIST_MTEXT (plist); - preedit_insert (ic, from, mt, 0); - to = from + mtext_nchars (mt); + MPLIST_DO (valids, valids) + { + if (! MPLIST_MTEXT_P (valids)) + MERROR (MERROR_IM, 0); + if (mtext_cmp (mt, MPLIST_MTEXT (valids)) == 0) + break; + } } - 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; + + return (MPLIST_TAIL_P (valids)); } -static MCharset * -get_select_charset (MInputContextInfo * ic_info) -{ - MPlist *plist = resolve_variable (ic_info, Mcandidates_charset); - MSymbol sym; +/* Load variable defitions from PLIST into IM_INFO->vars. - if (! MPLIST_VAL (plist)) - return NULL; - sym = MPLIST_SYMBOL (plist); - if (sym == Mnil) - return NULL; - return MCHARSET (sym); -} + PLIST is well-formed and has this form; + ((NAME [DESCRIPTION DEFAULT-VALUE VALID-VALUE ...]) + ...) + NAME is a symbol. DESCRIPTION is an M-text or `nil'. -static MPlist * -adjust_candidates (MPlist *plist, MCharset *charset) + The returned list has the same form, but for each element... + + (1) If DESCRIPTION and the rest are omitted, the element is not + stored in the returned list. + + (2) If DESCRIPTION is nil, it is complemented by the corresponding + description in global_info->vars (if any). */ + +static void +load_variables (MInputMethodInfo *im_info, MPlist *plist) { - MPlist *pl; + MPlist *global_vars = ((im_info->mdb && im_info != global_info) + ? global_info->vars : NULL); + MPlist *tail; - /* plist ::= MTEXT ... | PLIST ... */ - plist = mplist_copy (plist); - if (MPLIST_MTEXT_P (plist)) + im_info->vars = tail = mplist (); + MPLIST_DO (plist, MPLIST_NEXT (plist)) { - pl = plist; - while (! MPLIST_TAIL_P (pl)) - { - /* pl ::= MTEXT ... */ - MText *mt = MPLIST_MTEXT (pl); - int mt_copied = 0; - int i, c; + MPlist *pl, *p; - 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); + if (MFAILP (MPLIST_PLIST_P (plist))) + continue; + pl = MPLIST_PLIST (plist); /* PL ::= (NAME DESC VALUE VALID ...) */ + if (MFAILP (MPLIST_SYMBOL_P (pl))) + continue; + if (im_info == global_info) + { + /* Loading a global variable. */ + p = MPLIST_NEXT (pl); + if (MPLIST_TAIL_P (p)) + mplist_add (p, Msymbol, Mnil); else { - mplist_pop (pl); - M17N_OBJECT_UNREF (mt); + if (MFAILP (MPLIST_MTEXT_P (p))) + mplist_set (p, Msymbol, Mnil); + p = MPLIST_NEXT (p); + if (MFAILP (! MPLIST_TAIL_P (p) + && check_variable_value (p, NULL))) + mplist_set (p, Mt, NULL); } } - } - else /* MPLIST_PLIST_P (plist) */ - { - pl = plist; - while (! MPLIST_TAIL_P (pl)) + else if (im_info->mdb) { - /* pl ::= (MTEXT ...) ... */ - MPlist *p = MPLIST_PLIST (pl); - int p_copied = 0; - /* p ::= MTEXT ... */ - MPlist *p0 = p; - int n = 0; + /* Loading a local variable. */ + MSymbol name = MPLIST_SYMBOL (pl); + MPlist *global = NULL; - while (! MPLIST_TAIL_P (p0)) + if (global_vars + && (p = mplist__assq (global_vars, name))) { - MText *mt = MPLIST_MTEXT (p0); - int i, c; + /* P ::= ((NAME DESC ...) ...) */ + p = MPLIST_PLIST (p); /* P ::= (NAME DESC ...) */ + global = MPLIST_NEXT (p); /* P ::= (DESC VALUE ...) */ + global = MPLIST_NEXT (p); /* P ::= (VALUE ...) */ + } - 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++; - } + p = MPLIST_NEXT (pl); /* P ::= (DESC VALUE VALID ...) */ + if (! MPLIST_TAIL_P (p)) + { + if (MFAILP (MPLIST_MTEXT_P (p) + || (MPLIST_SYMBOL_P (p) + && MPLIST_SYMBOL (p) == Mnil))) + mplist_set (p, Msymbol, Mnil); + p = MPLIST_NEXT (p); /* P ::= (VALUE VALID ...) */ + if (MFAILP (! MPLIST_TAIL_P (p))) + mplist_set (p, Mt, NULL); 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); + MPlist *valid_values = MPLIST_NEXT (p); + + if (! MPLIST_TAIL_P (valid_values) + ? MFAILP (check_variable_value (p, NULL)) + : global && MFAILP (check_variable_value (p, global))) + mplist_set (p, Mt, NULL); } } - if (! MPLIST_TAIL_P (p)) - pl = MPLIST_NEXT (pl); - else - { - mplist_pop (pl); - M17N_OBJECT_UNREF (p); - } } + else + { + /* Loading a variable customization. */ + p = MPLIST_NEXT (pl); /* P ::= (nil VALUE) */ + if (MFAILP (! MPLIST_TAIL_P (p))) + continue; + p = MPLIST_NEXT (p); /* P ::= (VALUE) */ + if (MFAILP (MPLIST_INTEGER_P (p) || MPLIST_SYMBOL_P (p) + || MPLIST_MTEXT_P (p))) + continue; + } + tail = mplist_add (tail, Mplist, pl); } - if (MPLIST_TAIL_P (plist)) - { - M17N_OBJECT_UNREF (plist); - return NULL; - } - return plist; } static MPlist * -get_candidate_list (MInputContextInfo *ic_info, MPlist *args) +config_variable (MPlist *plist, MPlist *global_vars, MPlist *custom_vars, + MPlist *config_vars) { - 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); + MPlist *global = NULL, *custom = NULL, *config = NULL; + MSymbol name = MPLIST_SYMBOL (plist); + MText *description = NULL; + MSymbol status; + MPlist *value, *valids; - plist = MPLIST_PLIST (args); - if (charset) + if (global_vars) { - if (! (plist = adjust_candidates (plist, charset))) - return NULL; + global = mplist__assq (global_vars, name); + if (global) + global = MPLIST_NEXT (MPLIST_PLIST (global)); /* (DESC VALUE ...) */ } - else - M17N_OBJECT_REF (plist); - if (column > 0) + plist = MPLIST_NEXT (plist); + if (MPLIST_MTEXT_P (plist)) + description = MPLIST_MTEXT (plist); + else if (global && MPLIST_MTEXT (global)) + description = MPLIST_MTEXT (global); + if (global) + global = MPLIST_NEXT (global); /* (VALUE VALIDS ...) */ + + if (MPLIST_TAIL_P (plist)) { - if (MPLIST_MTEXT_P (plist)) + /* Inherit from global (if any). */ + if (global) { - 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); - } - } - 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); + value = global; + if (MPLIST_KEY (value) == Mt) + value = NULL; + valids = MPLIST_NEXT (global); + status = Minherited; } - else /* MPLIST_PLIST_P (plist) */ + else { - MPlist *pl = MPLIST_PLIST (plist), *p; - MPlist *next = MPLIST_NEXT (plist); - int j; - - if (MPLIST_TAIL_P (next)) - M17N_OBJECT_REF (pl); - else - { - pl = mplist_copy (pl); - while (! MPLIST_TAIL_P (next)) - { - p = mplist_copy (MPLIST_PLIST (next)); - pl = mplist__conc (pl, p); - M17N_OBJECT_UNREF (p); - next = MPLIST_NEXT (next); - } - } - M17N_OBJECT_UNREF (plist); - plist = mplist (); - len = mplist_length (pl); - if (len <= column) - mplist_add (plist, Mplist, pl); - else - { - MPlist *p0 = pl; - - for (i = 0; i < len; i += column) - { - p = mplist (); - mplist_add (plist, Mplist, p); - M17N_OBJECT_UNREF (p); - for (j = 0; j < column && i + j < len; j++) - { - p = mplist_add (p, Mtext, MPLIST_VAL (p0)); - p0 = MPLIST_NEXT (p0); - } - } - } - M17N_OBJECT_UNREF (pl); + value = NULL; + valids = NULL; + status = Mnil; + plist = NULL; } } + else + { + value = plist = MPLIST_NEXT (plist); + valids = MPLIST_NEXT (value); + if (MPLIST_KEY (value) == Mt) + value = NULL; + if (! MPLIST_TAIL_P (valids)) + global = NULL; + else if (global) + valids = MPLIST_NEXT (global); + status = Mnil; + } + if (config_vars && (config = mplist__assq (config_vars, name))) + { + config = MPLIST_NEXT (MPLIST_PLIST (config)); + if (! MPLIST_TAIL_P (config)) + { + value = MPLIST_NEXT (config); + if (MFAILP (check_variable_value (value, global ? global : plist))) + value = NULL; + status = Mconfigured; + } + } + else if (custom_vars && (custom = mplist__assq (custom_vars, name))) + { + custom = MPLIST_NEXT (MPLIST_PLIST (custom)); + if (! MPLIST_TAIL_P (custom)) + { + value = MPLIST_NEXT (custom); + if (MFAILP (check_variable_value (value, global ? global : plist))) + value = NULL; + status = Mcustomized; + } + } + + plist = mplist (); + mplist_add (plist, Msymbol, name); + if (description) + mplist_add (plist, Mtext, description); + else + mplist_add (plist, Msymbol, Mnil); + mplist_add (plist, Msymbol, status); + if (value) + mplist_add (plist, MPLIST_KEY (value), MPLIST_VAL (value)); + else + mplist_add (plist, Mt, NULL); + if (valids && ! MPLIST_TAIL_P (valids)) + mplist__conc (plist, valids); return plist; } +/* Return a configured variable definition list based on + IM_INFO->vars. If a variable in it doesn't contain a value, try to + get it from global_info->vars. */ -static MPlist * -regularize_action (MPlist *action_list) +static void +config_all_variables (MInputMethodInfo *im_info) { - MPlist *action = NULL; - MSymbol name; - MPlist *args; + MPlist *global_vars, *custom_vars, *config_vars; + MInputMethodInfo *temp; + MPlist *tail, *plist; - if (MPLIST_PLIST_P (action_list)) + M17N_OBJECT_UNREF (im_info->configured_vars); + + if (MPLIST_TAIL_P (im_info->vars) + || ! im_info->mdb) + return; + + global_vars = im_info != global_info ? global_info->vars : NULL; + custom_vars = ((temp = get_custom_info (im_info)) ? temp->vars : NULL); + config_vars = ((temp = get_config_info (im_info)) ? temp->vars : NULL); + + im_info->configured_vars = tail = mplist (); + MPLIST_DO (plist, im_info->vars) { - 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); - } + MPlist *pl = config_variable (MPLIST_PLIST (plist), + global_vars, custom_vars, config_vars); + if (pl) + tail = mplist_add (tail, Mplist, pl); } - else if (MPLIST_MTEXT_P (action_list) || MPLIST_INTEGER_P (action_list)) +} + +/* Load an input method (LANGUAGE NAME) from PLIST into IM_INFO. + CONFIG contains configuration information of the input method. */ + +static void +load_im_info (MPlist *plist, MInputMethodInfo *im_info) +{ + MPlist *pl, *p; + + if (! im_info->cmds && (pl = mplist__assq (plist, Mcommand))) { - 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); + load_commands (im_info, MPLIST_PLIST (pl)); + config_all_commands (im_info); + pl = mplist_pop (pl); + M17N_OBJECT_UNREF (pl); } - return action; + + if (! im_info->vars && (pl = mplist__assq (plist, Mvariable))) + { + load_variables (im_info, MPLIST_PLIST (pl)); + config_all_variables (im_info); + pl = mplist_pop (pl); + M17N_OBJECT_UNREF (pl); + } + + MPLIST_DO (plist, plist) + if (MPLIST_PLIST_P (plist)) + { + MPlist *elt = MPLIST_PLIST (plist); + MSymbol key; + + if (MFAILP (MPLIST_SYMBOL_P (elt))) + continue; + key = MPLIST_SYMBOL (elt); + if (key == Mtitle) + { + if (im_info->title) + continue; + elt = MPLIST_NEXT (elt); + if (MFAILP (MPLIST_MTEXT_P (elt))) + continue; + im_info->title = MPLIST_MTEXT (elt); + M17N_OBJECT_REF (im_info->title); + } + else if (key == Mmap) + { + pl = mplist__from_alist (MPLIST_NEXT (elt)); + if (MFAILP (pl)) + continue; + if (! im_info->maps) + im_info->maps = pl; + else + { + mplist__conc (im_info->maps, pl); + M17N_OBJECT_UNREF (pl); + } + } + else if (key == Mmacro) + { + if (! im_info->macros) + im_info->macros = mplist (); + MPLIST_DO (elt, MPLIST_NEXT (elt)) + { + if (MFAILP (MPLIST_PLIST_P (elt))) + continue; + load_macros (im_info, MPLIST_PLIST (elt)); + } + } + else if (key == Mmodule) + { + if (! im_info->externals) + im_info->externals = mplist (); + MPLIST_DO (elt, MPLIST_NEXT (elt)) + { + if (MFAILP (MPLIST_PLIST_P (elt))) + continue; + load_external_module (im_info, MPLIST_PLIST (elt)); + } + } + else if (key == Mstate) + { + MPLIST_DO (elt, MPLIST_NEXT (elt)) + { + MIMState *state; + + if (MFAILP (MPLIST_PLIST_P (elt))) + continue; + pl = MPLIST_PLIST (elt); + if (! im_info->states) + im_info->states = mplist (); + state = load_state (im_info, MPLIST_PLIST (elt)); + if (MFAILP (state)) + continue; + mplist_put (im_info->states, state->name, state); + } + } + else if (key == Minclude) + { + /* elt ::= include (tag1 tag2 ...) key item ... */ + MSymbol key; + MInputMethodInfo *temp; + + elt = MPLIST_NEXT (elt); + if (MFAILP (MPLIST_PLIST_P (elt))) + continue; + temp = get_im_info_by_tags (MPLIST_PLIST (elt)); + if (MFAILP (temp)) + continue; + elt = MPLIST_NEXT (elt); + if (MFAILP (MPLIST_SYMBOL_P (elt))) + continue; + key = MPLIST_SYMBOL (elt); + elt = MPLIST_NEXT (elt); + if (key == Mmap) + { + if (! temp->maps || MPLIST_TAIL_P (temp->maps)) + continue; + if (! im_info->maps) + im_info->maps = mplist (); + MPLIST_DO (pl, temp->maps) + { + p = MPLIST_VAL (pl); + MPLIST_ADD_PLIST (im_info->maps, MPLIST_KEY (pl), p); + M17N_OBJECT_REF (p); + } + } + else if (key == Mmacro) + { + if (! temp->macros || MPLIST_TAIL_P (temp->macros)) + continue; + if (! im_info->macros) + im_info->macros = mplist (); + MPLIST_DO (pl, temp->macros) + { + p = MPLIST_VAL (pl); + MPLIST_ADD_PLIST (im_info->macros, MPLIST_KEY (pl), p); + M17N_OBJECT_REF (p); + } + } + else if (key == Mstate) + { + if (! temp->states || MPLIST_TAIL_P (temp->states)) + continue; + if (! im_info->states) + im_info->states = mplist (); + MPLIST_DO (pl, temp->states) + { + MIMState *state = MPLIST_VAL (pl); + + mplist_add (im_info->states, MPLIST_KEY (pl), state); + M17N_OBJECT_REF (state); + } + } + } + else if (key == Mdescription) + { + if (im_info->description) + continue; + elt = MPLIST_NEXT (elt); + if (MFAILP (MPLIST_MTEXT_P (elt))) + continue; + im_info->description = MPLIST_MTEXT (elt); + M17N_OBJECT_REF (im_info->description); + + } + } + im_info->tick = time (NULL); } -static int -take_action_list (MInputContext *ic, MPlist *action_list) + + +static int take_action_list (MInputContext *ic, MPlist *action_list); +static void preedit_commit (MInputContext *ic); + +static void +shift_state (MInputContext *ic, MSymbol state_name) { + MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info; 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; + MIMState *orig_state = ic_info->state, *state; - MPLIST_DO (action_list, action_list) + /* Find a state to shift to. If not found, shift to the initial + state. */ + if (state_name == Mt) { - MPlist *action = regularize_action (action_list); - MSymbol name; - MPlist *args; + if (! ic_info->prev_state) + return; + state = ic_info->prev_state; + } + else if (state_name == Mnil) + { + state = (MIMState *) MPLIST_VAL (im_info->states); + } + else + { + state = (MIMState *) mplist_get (im_info->states, state_name); + if (! state) + state = (MIMState *) MPLIST_VAL (im_info->states); + } - if (! action) - continue; - name = MPLIST_SYMBOL (action); - args = MPLIST_NEXT (action); + MDEBUG_PRINT1 ("\n [IM] (shift %s)", MSYMBOL_NAME (state->name)); - MDEBUG_PRINT1 (" %s", MSYMBOL_NAME (name)); - if (name == Minsert) + /* Enter the new state. */ + ic_info->state = state; + ic_info->map = state->map; + ic_info->state_key_head = ic_info->key_head; + if (state == (MIMState *) MPLIST_VAL (im_info->states) + && orig_state) + /* We have shifted to the initial state. */ + preedit_commit (ic); + mtext_cpy (ic_info->preedit_saved, ic->preedit); + ic_info->state_pos = ic->cursor_pos; + if (state != orig_state) + { + if (state == (MIMState *) MPLIST_VAL (im_info->states)) + ic_info->prev_state = NULL; + else + ic_info->prev_state = orig_state; + + if (state->title) + ic->status = state->title; + else + ic->status = im_info->title; + ic->status_changed = 1; + if (ic_info->map == ic_info->state->map + && ic_info->map->map_actions) { - 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)); + MDEBUG_PRINT (" init-actions:"); + take_action_list (ic, ic_info->map->map_actions); } - else if (name == M_candidates) - { - MPlist *plist = get_candidate_list (ic_info, args); - int len; + } +} - if (! plist) - continue; - if (MPLIST_MTEXT_P (plist)) - { - preedit_insert (ic, ic->cursor_pos, NULL, - mtext_ref_char (MPLIST_MTEXT (plist), 0)); - len = 1; - } - else - { - MText * mt = MPLIST_MTEXT (MPLIST_PLIST (plist)); +/* Find a candidate group that contains a candidate number INDEX from + PLIST. Set START_INDEX to the first candidate number of the group, + END_INDEX to the last candidate number plus 1, GROUP_INDEX to the + candidate group number if they are non-NULL. If INDEX is -1, find + the last candidate group. */ - 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); - M17N_OBJECT_UNREF (plist); +static MPlist * +find_candidates_group (MPlist *plist, int index, + int *start_index, int *end_index, int *group_index) +{ + int i = 0, gidx = 0, len; + + MPLIST_DO (plist, plist) + { + if (MPLIST_MTEXT_P (plist)) + len = mtext_nchars (MPLIST_MTEXT (plist)); + else + len = mplist_length (MPLIST_PLIST (plist)); + if (index < 0 ? MPLIST_TAIL_P (MPLIST_NEXT (plist)) + : i + len > index) + { + if (start_index) + *start_index = i; + if (end_index) + *end_index = i + len; + if (group_index) + *group_index = gidx; + return plist; + } + i += len; + gidx++; + } + return NULL; +} + +static void +preedit_insert (MInputContext *ic, int pos, MText *mt, int c) +{ + MInputContextInfo *ic_info = ((MInputContext *) ic)->info; + MPlist *markers; + int nchars = mt ? mtext_nchars (mt) : 1; + + if (mt) + mtext_ins (ic->preedit, pos, mt); + else + mtext_ins_char (ic->preedit, pos, c, 1); + MPLIST_DO (markers, ic_info->markers) + if (MPLIST_INTEGER (markers) > pos) + MPLIST_VAL (markers) = (void *) (MPLIST_INTEGER (markers) + nchars); + if (ic->cursor_pos >= pos) + ic->cursor_pos += nchars; + ic->preedit_changed = 1; +} + + +static void +preedit_delete (MInputContext *ic, int from, int to) +{ + MInputContextInfo *ic_info = ((MInputContext *) ic)->info; + MPlist *markers; + + mtext_del (ic->preedit, from, to); + MPLIST_DO (markers, ic_info->markers) + { + if (MPLIST_INTEGER (markers) > to) + MPLIST_VAL (markers) + = (void *) (MPLIST_INTEGER (markers) - (to - from)); + else if (MPLIST_INTEGER (markers) > from); + MPLIST_VAL (markers) = (void *) from; + } + if (ic->cursor_pos >= to) + ic->cursor_pos -= to - from; + else if (ic->cursor_pos > from) + ic->cursor_pos = from; + ic->preedit_changed = 1; +} + +static void +preedit_commit (MInputContext *ic) +{ + MInputContextInfo *ic_info = (MInputContextInfo *) ic->info; + int preedit_len = mtext_nchars (ic->preedit); + + if (preedit_len > 0) + { + MPlist *p; + + mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit), + Mcandidate_list, NULL, 0); + mtext_put_prop_values (ic->preedit, 0, mtext_nchars (ic->preedit), + Mcandidate_index, NULL, 0); + mtext_cat (ic->produced, ic->preedit); + if ((mdebug__flag & mdebug_mask) + && mtext_nchars (ic->preedit) > 0) + { + int i; + + MDEBUG_PRINT (" (produced"); + for (i = 0; i < mtext_nchars (ic->preedit); i++) + MDEBUG_PRINT1 (" U+%04X", mtext_ref_char (ic->preedit, i)); + MDEBUG_PRINT (")"); + } + mtext_reset (ic->preedit); + mtext_reset (ic_info->preedit_saved); + MPLIST_DO (p, ic_info->markers) + MPLIST_VAL (p) = 0; + ic->cursor_pos = ic_info->state_pos = 0; + ic->preedit_changed = 1; + } + if (ic->candidate_list) + { + M17N_OBJECT_UNREF (ic->candidate_list); + ic->candidate_list = NULL; + ic->candidates_changed = MINPUT_CANDIDATES_LIST_CHANGED; + if (ic->candidate_show) + { + ic->candidate_show = 0; + ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED; + } + } + memmove (ic_info->keys, ic_info->keys + ic_info->key_head, + sizeof (int) * (ic_info->used - ic_info->key_head)); + ic_info->used -= ic_info->key_head; + ic_info->state_key_head = ic_info->key_head = 0; +} + +static int +new_index (MInputContext *ic, int current, int limit, MSymbol sym, MText *mt) +{ + int code = marker_code (sym); + + if (mt && (code == '[' || code == ']')) + { + int pos = current; + + if (code == '[' && current > 0) + { + if (mtext_prop_range (mt, Mcandidate_list, pos - 1, &pos, NULL, 1) + && pos > 0) + current = pos; + } + else if (code == ']' && current < mtext_nchars (mt)) + { + if (mtext_prop_range (mt, Mcandidate_list, pos, NULL, &pos, 1)) + current = pos; + } + return current; + } + if (code >= 0) + return (code == '<' ? 0 + : code == '>' ? limit + : code == '-' ? current - 1 + : code == '+' ? current + 1 + : code == '=' ? current + : code - '0' > limit ? limit + : code - '0'); + if (! ic) + return 0; + return (int) mplist_get (((MInputContextInfo *) ic->info)->markers, sym); +} + +static void +update_candidate (MInputContext *ic, MTextProperty *prop, int idx) +{ + 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; + + preedit_delete (ic, from, to); + if (MPLIST_MTEXT_P (group)) + { + mt = MPLIST_MTEXT (group); + preedit_insert (ic, from, 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_insert (ic, from, 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) + { + if (! (plist = adjust_candidates (plist, charset))) + return NULL; + } + else + M17N_OBJECT_REF (plist); + + if (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); + } + } + 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 /* MPLIST_PLIST_P (plist) */ + { + MPlist *pl = MPLIST_PLIST (plist), *p; + MPlist *next = MPLIST_NEXT (plist); + int j; + + if (MPLIST_TAIL_P (next)) + M17N_OBJECT_REF (pl); + else + { + pl = mplist_copy (pl); + while (! MPLIST_TAIL_P (next)) + { + p = mplist_copy (MPLIST_PLIST (next)); + pl = mplist__conc (pl, p); + M17N_OBJECT_UNREF (p); + next = MPLIST_NEXT (next); + } + } + M17N_OBJECT_UNREF (plist); + plist = mplist (); + len = mplist_length (pl); + if (len <= column) + mplist_add (plist, Mplist, pl); + else + { + MPlist *p0 = pl; + + for (i = 0; i < len; i += column) + { + p = mplist (); + mplist_add (plist, Mplist, p); + M17N_OBJECT_UNREF (p); + for (j = 0; j < column && i + j < len; j++) + { + p = mplist_add (p, Mtext, MPLIST_VAL (p0)); + p0 = MPLIST_NEXT (p0); + } + } + } + M17N_OBJECT_UNREF (pl); + } + } + + 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 all actions are performed without error, 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) + continue; + if (MPLIST_MTEXT_P (plist)) + { + preedit_insert (ic, ic->cursor_pos, NULL, + mtext_ref_char (MPLIST_MTEXT (plist), 0)); + len = 1; + } + 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); + M17N_OBJECT_UNREF (plist); + } + else if (name == Mselect) + { + int start, end; + int code, idx, gindex; + int pos = ic->cursor_pos; + MPlist *group; + + if (pos == 0 + || ! (prop = mtext_get_property (ic->preedit, pos - 1, + Mcandidate_list))) + continue; + if (MPLIST_SYMBOL_P (args)) + { + code = marker_code (MPLIST_SYMBOL (args)); + if (code < 0) + continue; + } + else + code = -1; + idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index); + group = find_candidates_group (mtext_property_value (prop), idx, + &start, &end, &gindex); + + if (code != '[' && code != ']') + { + 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); + } + 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) + { + delete_surrounding_text (ic, pos); + } + 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; + } + } + else if (name == Mmark) + { + int code = marker_code (MPLIST_SYMBOL (args)); + + if (code < 0) + mplist_put (ic_info->markers, MPLIST_SYMBOL (args), + (void *) ic->cursor_pos); + } + else if (name == Mpushback) + { + if (MPLIST_INTEGER_P (args)) + { + int num = MPLIST_INTEGER (args); + + if (num > 0) + ic_info->key_head -= num; + 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 == 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 (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) + { + 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); + ic->cursor_pos = ic_info->state_pos = 0; + ic_info->state_key_head = ic_info->key_head = 0; + + if (intarg < 0) + ic_info->used += intarg; + else + ic_info->used = intarg; + shift_state (ic, Mnil); + 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; + }; + } + } + + M17N_OBJECT_UNREF (ic->candidate_list); + 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. */ + + /* If MAP is the root map of the initial state, it means that + the current input method can not handle KEY. */ + if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map) + { + MDEBUG_PRINT (" unhandled\n"); + return -1; + } + + if (map != ic_info->state->map) + { + /* If MAP is not the root map... */ + /* If MAP has branch actions, perform them. */ + 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 is the root map, perform branch actions (if any) or + shift to the initial state. */ + if (map->branch_actions) + { + MDEBUG_PRINT (" branch-actions:"); + if (take_action_list (ic, map->branch_actions) < 0) + { + MDEBUG_PRINT ("\n"); + return -1; + } + } + else + 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 (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)); + } + } + + 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 (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 (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->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); + } + 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); + 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--; + } + /* 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 + && mtext_nchars (ic->preedit) > 0) + shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name); + + if (mtext_nchars (ic->produced) > 0) + { + MSymbol lang = msymbol_get (ic->im->language, Mlanguage); + + if (lang != Mnil) + mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced), + Mlanguage, ic->im->language); + } + + 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); +} + + +/* 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 ...)) */ + + +/* 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); } - else if (name == Mselect) + } + 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) { - int start, end; - int code, idx, gindex; - int pos = ic->cursor_pos; - MPlist *group; + fprintf (stderr, "\n%s ", prefix); + dump_im_map (map_list, indent + 2); + } + } + fprintf (stderr, ")"); +} + + + +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 (minput_default_driver.callback_list, Minput_reset, + (void *) 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); + +} + +int +minput__callback (MInputContext *ic, MSymbol command) +{ + MInputCallbackFunc func; + + if (! ic->im->driver.callback_list) + return -1; + func = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list, + command); + if (! func) + return -1; + (func) (ic, command); + return 0; +} + +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 */ + + +/* 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 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's 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 »²¾È)¡£ + */ +/*** @{ */ +/*=*/ + +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. - if (pos == 0 - || ! (prop = mtext_get_property (ic->preedit, pos - 1, - Mcandidate_list))) - continue; - if (MPLIST_SYMBOL_P (args)) - { - code = marker_code (MPLIST_SYMBOL (args)); - if (code < 0) - continue; - } - else - code = -1; - idx = (int) mtext_get_prop (ic->preedit, pos - 1, Mcandidate_index); - group = find_candidates_group (mtext_property_value (prop), idx, - &start, &end, &gindex); + These are the predefined symbols that are used as the @c KEY + argument of minput_filter (). */ - if (code != '[' && code != ']') - { - 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); - } - 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; +MSymbol Minput_focus_out; +MSymbol Minput_focus_in; +MSymbol Minput_focus_move; - if (MPLIST_SYMBOL_P (args) - && (pos = surrounding_pos (MPLIST_SYMBOL (args))) != 0) - { - delete_surrounding_text (ic, pos); - } - 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; - } - } - else if (name == Mmark) - { - int code = marker_code (MPLIST_SYMBOL (args)); +/*=*/ +/***en + @name Variables: Predefined symbols used in input method information. - if (code < 0) - mplist_put (ic_info->markers, MPLIST_SYMBOL (args), - (void *) ic->cursor_pos); - } - else if (name == Mpushback) - { - if (MPLIST_INTEGER_P (args)) - { - int num = MPLIST_INTEGER (args); + 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 (). */ +/*** @{ */ +/*=*/ +MSymbol Minherited; +MSymbol Mcustomized; +MSymbol Mconfigured; +/*** @} */ - if (num > 0) - ic_info->key_head -= num; - 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; +/***en + @brief The default driver for internal input methods. - ic_info->key_head--; + The variable #minput_default_driver is the default driver for + internal input methods. - 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 == Mcall) - { - MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info; - MIMExternalFunc func = NULL; - MSymbol module, func_name; - MPlist *func_args, *val; - int ret = 0; + The member MInputDriver::open_im () searches the m17n database for + an input method that matches the tag \< #Minput_method, $LANGUAGE, + $NAME\> and loads it. - module = MPLIST_SYMBOL (args); - args = MPLIST_NEXT (args); - func_name = MPLIST_SYMBOL (args); + 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. - if (im_info->externals) - { - MIMExternalModule *external - = (MIMExternalModule *) mplist_get (im_info->externals, - module); - if (external) - func = (MIMExternalFunc) mplist_get (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; + The macro M17N_INIT () sets the variable #minput_driver to the + pointer to this driver so that all internal input methods use it. - if (MPLIST_KEY (args) == Msymbol - && MPLIST_KEY (args) != Mnil - && (code = marker_code (MPLIST_SYMBOL (args))) >= 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)); + 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\> + ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£ - mtext_reset (ic->preedit); - mtext_reset (ic_info->preedit_saved); - ic->cursor_pos = ic_info->state_pos = 0; - ic_info->state_key_head = ic_info->key_head = 0; + ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ç¤¢¤ê¡¢ + ¤·¤¿¤¬¤Ã¤Æ¡¢¥×¥í¥°¥é¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ ŬÀڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist + ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit + ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊ󤬥桼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£ - if (intarg < 0) - ic_info->used += intarg; - else - ic_info->used = intarg; - shift_state (ic, Mnil); - 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; + ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver + ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£ - 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; + ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ + ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£ */ - 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; +MInputDriver minput_default_driver; +/*=*/ - MPLIST_DO (args, args) - { - MPlist *cond; +/***en + @brief The driver for internal input methods. - 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; + 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 .h> is included. */ +/***ja + @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð. - if (im_info->macros - && (actions = mplist_get (im_info->macros, name))) - { - if (take_action_list (ic, actions) < 0) - return -1; - }; - } - } + ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á + ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥í M17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó + ¥¿¤ò#minput_default_driver (.h> ¤¬ include ¤µ¤ì¤Æ¤¤¤ë + »þ) ¤Ë½é´ü²½¤¹¤ë¡£ */ - prop = NULL; - 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); - } +MInputDriver *minput_driver; - 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; -} +MSymbol Minput_driver; +/*=*/ -/* 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. */ +/***en + @brief Open an input method. -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; + 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. - MDEBUG_PRINT2 (" [IM] handle `%s' in state %s", - msymbol_name (key), MSYMBOL_NAME (ic_info->state->name)); + This function at first decides a driver for the input method as + described below. - if (map->submaps) - { - submap = mplist_get (map->submaps, key); - if (! submap && (alias = msymbol_get (key, M_key_alias)) != Mnil) - submap = mplist_get (map->submaps, alias); - } + If $LANGUAGE is not #Mnil, the driver pointed by the variable + #minput_driver is used. - if (submap) - { - if (alias == Mnil) - 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 $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. - if (! name[0] || ! name[1]) - mtext_ins_char (ic->preedit, ic->cursor_pos++, name[0], 1); - } - } + Then, the member MInputDriver::open_im () of the driver is + called. - /* 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. */ + $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 + ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£ + + ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£ - /* If MAP is the root map of the initial state, it means that - the current input method can not handle KEY. */ - if (map == ((MIMState *) MPLIST_VAL (im_info->states))->map) - { - MDEBUG_PRINT (" unhandled\n"); - return -1; - } + $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver + ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£ - if (map != ic_info->state->map) - { - /* If MAP is not the root map... */ - /* If MAP has branch actions, perform them. */ - 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 is the root map, perform branch actions (if any) or - shift to the initial state. */ - if (map->branch_actions) - { - MDEBUG_PRINT (" branch-actions:"); - if (take_action_list (ic, map->branch_actions) < 0) - { - MDEBUG_PRINT ("\n"); - return -1; - } - } - else - shift_state (ic, Mnil); - } - } - MDEBUG_PRINT ("\n"); - return 0; -} + $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver + ¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£ + $NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ -static void -reset_ic (MInputContext *ic, MSymbol ignore) -{ - MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info; - MInputContextInfo *ic_info = (MInputContextInfo *) ic->info; - MText *status; - MPlist *plist; + ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£ - MDEBUG_PRINT ("\n [IM] reset\n"); + $ARG ¤Ï¹½Â¤ÂÎ MInputMethod ¤Î¥á¥ó¥Ð @c arg ¤ËÀßÄꤵ¤ì¡¢¥É¥é¥¤¥Ð¤«¤é»²¾È¤Ç¤­¤ë¡£ - ic_info->state = (MIMState *) MPLIST_VAL (im_info->states); - ic_info->prev_state = NULL; - ic_info->map = ic_info->state->map; - ic_info->state_key_head = ic_info->key_head = 0; - MLIST_RESET (ic_info); - ic_info->key_unhandled = 0; + @latexonly \IPAlabel{minput_open} @endlatexonly - if (mtext_nchars (ic->produced) > 0) - mtext_reset (ic->produced); - if (mtext_nchars (ic->preedit) > 0) - { - mtext_reset (ic->preedit); - ic->preedit_changed = ic->cursor_pos_changed = 1; - } - MPLIST_DO (plist, ic_info->markers) - MPLIST_VAL (plist) = 0; +*/ - M17N_OBJECT_UNREF (ic_info->vars); - ic_info->vars = mplist (); - plist = get_nested_list (ic->im->language, ic->im->name, Mnil, M_variable); - MPLIST_DO (plist, plist) - { - MSymbol var = MPLIST_SYMBOL (plist); - MPlist *pl; +MInputMethod * +minput_open_im (MSymbol language, MSymbol name, void *arg) +{ + MInputMethod *im; + MInputDriver *driver; - plist = MPLIST_NEXT (plist); - pl = MPLIST_PLIST (plist); - pl = MPLIST_NEXT (pl); /* Skip description. */ - mplist_push (ic_info->vars, MPLIST_KEY (pl), MPLIST_VAL (pl)); - mplist_push (ic_info->vars, Msymbol, var); - } + MINPUT__INIT (); - if (ic->candidate_list) - { - M17N_OBJECT_UNREF (ic->candidate_list); - ic->candidate_list = NULL; - ic->candidates_changed |= MINPUT_CANDIDATES_LIST_CHANGED; - } - if (ic->candidate_show) - { - ic->candidate_show = 0; - ic->candidates_changed |= MINPUT_CANDIDATES_SHOW_CHANGED; - } - if (ic->candidate_index > 0) + MDEBUG_PRINT2 (" [IM] opening (%s %s) ... ", + msymbol_name (language), msymbol_name (name)); + if (language) + driver = minput_driver; + else { - ic->candidate_index = 0; - ic->candidates_changed |= MINPUT_CANDIDATES_INDEX_CHANGED; + driver = (MInputDriver *) msymbol_get (name, Minput_driver); + if (! driver) + MERROR (MERROR_IM, NULL); } - mtext_reset (ic_info->preedit_saved); - ic_info->state_pos = ic->cursor_pos = 0; - - status = ic_info->state->title ? ic_info->state->title : im_info->title; - if (ic->status != status) + MSTRUCT_CALLOC (im, MERROR_IM); + im->language = language; + im->name = name; + im->arg = arg; + im->driver = *driver; + if ((*im->driver.open_im) (im) < 0) { - ic->status = status; - ic->status_changed = 1; + MDEBUG_PRINT (" failed\n"); + free (im); + return NULL; } + MDEBUG_PRINT (" ok\n"); + return im; } -static int -open_im (MInputMethod *im) -{ - MInputMethodInfo *im_info = get_im_info (im->language, im->name, Mnil); +/*=*/ - if (! im_info) - MERROR (MERROR_IM, -1); - im->info = im_info; - im_info->im = im; - return 0; -} +/***en + @brief Close an input method. -static void -close_im (MInputMethod *im) + 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) { - im->info = NULL; + 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"); } -static int -create_ic (MInputContext *ic) -{ - MInputMethod *im = ic->im; - MInputMethodInfo *im_info = (MInputMethodInfo *) im->info; - MInputContextInfo *ic_info; - MPlist *plist; +/*=*/ - if (ic->info) - ic_info = (MInputContextInfo *) ic->info; - else - { - MSTRUCT_CALLOC (ic_info, MERROR_IM); - ic->info = ic_info; - } - MLIST_INIT1 (ic_info, keys, 8); - ic_info->markers = mplist (); - ic_info->vars = mplist (); - plist = get_nested_list (im->language, im->name, Mnil, M_variable); - MPLIST_DO (plist, plist) - { - MSymbol var = MPLIST_SYMBOL (plist); - MPlist *pl; +/***en + @brief Create an input context. - plist = MPLIST_NEXT (plist); - pl = MPLIST_PLIST (plist); - pl = MPLIST_NEXT (pl); /* Skip description. */ - mplist_push (ic_info->vars, MPLIST_KEY (pl), MPLIST_VAL (pl)); - mplist_push (ic_info->vars, Msymbol, var); - } + 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. - ic_info->preedit_saved = mtext (); - if (im_info->externals) - { - MPlist *func_args = mplist (), *plist; + @return + If an input context is successfully created, minput_create_ic () + returns a pointer to it. Otherwise it returns @c NULL. */ - mplist_add (func_args, Mt, ic); - MPLIST_DO (plist, im_info->externals) - { - MIMExternalModule *external = MPLIST_VAL (plist); - MIMExternalFunc func - = (MIMExternalFunc) mplist_get (external->func_list, Minit); +/***ja + @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë. - if (func) - (func) (func_args); - } - M17N_OBJECT_UNREF (func_args); - } - reset_ic (ic, Mnil); - return 0; -} + ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM + ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢ + #Minput_preedit_start, #Minput_status_start, #Minput_status_draw + ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£ -static void -destroy_ic (MInputContext *ic) + @return + ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () + ¤Ï¤½¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ + */ + +MInputContext * +minput_create_ic (MInputMethod *im, void *arg) { - MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info; - MInputContextInfo *ic_info = (MInputContextInfo *) ic->info; + MInputContext *ic; - if (im_info->externals) + 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) { - 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 (external->func_list, Mfini); + MDEBUG_PRINT (" failed\n"); + M17N_OBJECT_UNREF (ic->preedit); + M17N_OBJECT_UNREF (ic->produced); + M17N_OBJECT_UNREF (ic->plist); + free (ic); + return NULL; + }; - if (func) - (func) (func_args); - } - M17N_OBJECT_UNREF (func_args); + if (im->driver.callback_list) + { + minput__callback (ic, Minput_preedit_start); + minput__callback (ic, Minput_status_start); + minput__callback (ic, Minput_status_draw); } - 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->preceding_text); - M17N_OBJECT_UNREF (ic_info->following_text); - free (ic->info); + + 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. */ -/** 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. +/***ja + @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë. - Ignore ARG. */ + ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£ + ¤³¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () + ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï + #Minput_preedit_done, #Minput_status_done, #Minput_candidates_done + ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£ + */ -static int -filter (MInputContext *ic, MSymbol key, void *arg) +void +minput_destroy_ic (MInputContext *ic) { - MInputMethodInfo *im_info = (MInputMethodInfo *) ic->im->info; - MInputContextInfo *ic_info = (MInputContextInfo *) ic->info; - int i = 0; - - if (! ic_info->state) + MDEBUG_PRINT2 (" [IM] destroying context (%s %s) ... ", + msymbol_name (ic->im->name), msymbol_name (ic->im->language)); + if (ic->im->driver.callback_list) { - ic_info->key_unhandled = 1; - return 0; + minput__callback (ic, Minput_preedit_done); + minput__callback (ic, Minput_status_done); + minput__callback (ic, Minput_candidates_done); } - 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); - MLIST_APPEND1 (ic_info, keys, key, MERROR_IM); - ic_info->key_unhandled = 0; - - /* If KEY has Meta or Alt modifier, put M_key_alias property. */ - if (key != Mnil) - { - if (! msymbol_get (key, M_key_alias) - && (strchr (MSYMBOL_NAME (key), 'M') - || strchr (MSYMBOL_NAME (key), 'A'))) - { - char *name = MSYMBOL_NAME (key); - char *meta_or_alt; + (*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); +} - while (name[0] && name[1] == '-' - && (name[0] != 'M' && name[0] != 'A')) - name += 2; - if ((name[0] == 'M' || name[0] == 'A') && name[1] == '-') - { - MSymbol alias; - - meta_or_alt = name; - name = alloca (MSYMBOL_NAMELEN (key) + 1); - memcpy (name, MSYMBOL_NAME (key), MSYMBOL_NAMELEN (key) + 1); - name[meta_or_alt - MSYMBOL_NAME (key)] - = *meta_or_alt == 'M' ? 'A' : 'M'; - alias = msymbol (name); - msymbol_put (key, M_key_alias, alias); - } - } - else if (MSYMBOL_NAMELEN (key) == 3 - && MSYMBOL_NAME (key)[0] == 'S' - && MSYMBOL_NAME (key)[1] == '-' - && MSYMBOL_NAME (key)[2] >= 'A' && MSYMBOL_NAME (key)[2] <= 'Z') - msymbol_put (key, M_key_alias, one_char_symbol[(int)MSYMBOL_NAME (key)[2]]); - } +/*=*/ - 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--; - } - /* 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); +/***en + @brief Filter an input key. - /* 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 - && mtext_nchars (ic->preedit) > 0) - shift_state (ic, ((MIMState *) MPLIST_VAL (im_info->states))->name); + 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. - if (mtext_nchars (ic->produced) > 0) - { - MSymbol lang = msymbol_get (ic->im->language, Mlanguage); + 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. - if (lang != Mnil) - mtext_put_prop (ic->produced, 0, mtext_nchars (ic->produced), - Mlanguage, ic->im->language); - } + To inform the input method about the focus-out event, call this + function with #Minput_focus_out as $KEY. - return (! ic_info->key_unhandled && mtext_nchars (ic->produced) == 0); -} + 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 1 if the last event or key was not handled, otherwise - return 0. + @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. */ - There is no need of looking up because ic->produced should already - contain the produced text (if any). +/***ja + @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë. - Ignore KEY. */ + ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC + ¤Ë±þ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½¤·¤¿»þÅÀ¤Ç¡¢¤½¤ì¤¾¤ì + #Minput_preedit_draw, #Minput_status_draw, + #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£ -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); -} + @return + $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£ + ¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£ + ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup () + ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£ -static MPlist *load_im_info_keys; + @latexonly \IPAlabel{minput_filter} @endlatexonly +*/ -static MPlist * -load_partial_im_info (MSymbol language, MSymbol name, - MSymbol extra, MSymbol key) +int +minput_filter (MInputContext *ic, MSymbol key, void *arg) { - MDatabase *mdb; - MPlist *plist; + int ret; - if (language == Mnil) - MERROR (MERROR_IM, NULL); - mdb = mdatabase_find (Minput_method, language, name, extra); - if (! mdb) - MERROR (MERROR_IM, NULL); + if (! ic + || ! ic->active) + return 0; + ret = (*ic->im->driver.filter) (ic, key, arg); - mplist_push (load_im_info_keys, key, Mt); - plist = mdatabase__load_for_keys (mdb, load_im_info_keys); - mplist_pop (load_im_info_keys); - return plist; + 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; } +/*=*/ -static MInputMethodInfo * -get_im_info (MSymbol language, MSymbol name, MSymbol extra) -{ - MDatabase *mdb; - MPlist *plist; - MInputMethodInfo *im_info = NULL; +/***en + @brief Look up a text produced in the input context. - if (language == Mnil) - MERROR (MERROR_IM, NULL); - mdb = mdatabase_find (Minput_method, language, name, extra); - if (! mdb) - MERROR (MERROR_IM, NULL); + 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 (! im_info_list) - im_info_list = mplist (); - else if ((plist = mplist_find_by_value (im_info_list, mdb))) - { - if (mdatabase__check (mdb)) - { - plist = MPLIST_NEXT (plist); - im_info = MPLIST_VAL (plist); - return im_info; - } - mplist_pop (plist); - free_im_info (MPLIST_VAL (plist)); - mplist_pop (plist); - } + If a text was produced by the input method, it is concatenated + to M-text $MT. - plist = mdatabase_load (mdb); - if (! plist) - MERROR (MERROR_IM, NULL); - im_info = load_im_info (language, name, plist); - M17N_OBJECT_UNREF (plist); - if (! im_info) - MERROR (MERROR_IM, NULL); - mplist_push (im_info_list, Mt, im_info); - mplist_push (im_info_list, Mt, mdb); - return im_info; -} + This function calls #MInputDriver::lookup . - -/* Input method command handler. */ + @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. */ -/* 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 ...)) */ +/***ja + @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹. -/* Check if PLIST is a valid command key sequence. - PLIST must be NULL or: - [ symbol:KEY | integer:KEY ] ... */ + ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹¡£ + $KEY ¤Ï´Ø¿ô minput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ -static int -check_command_keyseq (MPlist *plist) -{ - if (! plist) - return 0; - MPLIST_DO (plist, plist) - { - if (MPLIST_SYMBOL_P (plist)) - continue; - else if (MPLIST_INTEGER_P (plist)) - { - int n = MPLIST_INTEGER (plist); + ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text + $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£ - if (n < 0 || n > 9) - return -1; - MPLIST_KEY (plist) = Msymbol; - MPLIST_VAL (plist) = one_char_symbol['0' + 9]; - } - else - return -1; - } - return 0; -} + ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£ -/* Check if PLIST has this form: - ([ plist:([ symbol:KEY | integer:KEY ]) | mtext:KEYSEQ ] - ...) - If the form of PLIST matches, return 0, otherwise return -1. */ + @return + $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£ + ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£ + ¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£ -static int -check_command_list (MPlist *plist) -{ - MPLIST_DO (plist, plist) - { - if (MPLIST_PLIST_P (plist)) - { - MPlist *pl = MPLIST_PLIST (plist); + @latexonly \IPAlabel{minput_lookup} @endlatexonly */ - MPLIST_DO (pl, pl) - if (! MPLIST_SYMBOL_P (pl) && ! MPLIST_INTEGER_P (pl)) - return -1; - } - else if (! MPLIST_MTEXT_P (plist)) - return -1; - } - return 0; +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. - -/* Input method variable handler. */ + 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. -/* Check if PLIST has this form: - (TYPE:VAL ;; TYPE ::= integer | mtext | symbol - VALID-VALUE - ...) - If the form of PLIST matches, return 0, otherwise return -1. */ + 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 ). -static int -check_variable_list (MPlist *plist) -{ - MSymbol type = MPLIST_KEY (plist); - MPlist *p; + $FONTSIZE specifies the fontsize of preedit text in 1/10 point. - if (type != Minteger && type != Mtext && type != Msymbol) - return -1; - MPLIST_DO (plist, MPLIST_NEXT (plist)) - { - if (type == Minteger && MPLIST_PLIST_P (plist)) - { - MPLIST_DO (p, MPLIST_PLIST (plist)) - if (! MPLIST_INTEGER_P (p)) - return -1; - } - else if (type != MPLIST_KEY (plist)) - return -1; - } - return 0; -} + $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. */ -/* Support functions for mdebug_dump_im. */ +/***ja + @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë. -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); + ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂɸ ($X, $Y ) + ¤Î°ÌÃÖ¤Ë ¡¢¹â¤µ $ASCENT¡¢ $DESCENT + ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤΰÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£ - prefix = (char *) alloca (indent + 1); - memset (prefix, 32, indent); - prefix[indent] = '\0'; + ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y + ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT + ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï + $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢ + $ASCENT ¤È $DESCENT ¤ò ($X . $Y ) + ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£ - 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, ")"); -} + $FONTSIZE ¤Ë¤Ï preedit ¥Æ¥­¥¹¥È¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£ + $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c + NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£ + */ -static void -dump_im_state (MIMState *state, int indent) +void +minput_set_spot (MInputContext *ic, int x, int y, + int ascent, int descent, int fontsize, + MText *mt, int pos) { - char *prefix; - MPlist *map_list; + 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); +} +/*=*/ - prefix = (char *) alloca (indent + 1); - memset (prefix, 32, indent); - prefix[indent] = '\0'; +/***en + @brief Toggle input method. - 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, ")"); -} + The minput_toggle () function toggles the input method associated + with input context $IC. */ +/***ja + @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë. - + ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC + ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£ + */ -int -minput__init () +void +minput_toggle (MInputContext *ic) { - char *key_names[32] - = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "BackSpace", "Tab", "Linefeed", "Clear", NULL, "Return", NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, "Escape", NULL, NULL, NULL, NULL }; - char buf[6], buf2[256]; - int i; + if (ic->im->driver.callback_list) + minput__callback (ic, Minput_toggle); + ic->active = ! ic->active; +} - Minput_method = msymbol ("input-method"); - Minput_driver = msymbol ("input-driver"); - Mtitle = msymbol ("title"); - Mmacro = msymbol ("macro"); - Mmodule = msymbol ("module"); - Mmap = msymbol ("map"); - Mstate = msymbol ("state"); - Minclude = msymbol ("include"); - Minsert = msymbol ("insert"); - M_candidates = msymbol (" candidates"); - Mdelete = msymbol ("delete"); - Mmove = msymbol ("move"); - Mmark = msymbol ("mark"); - Mpushback = msymbol ("pushback"); - Mundo = msymbol ("undo"); - Mcall = msymbol ("call"); - Mshift = msymbol ("shift"); - Mselect = msymbol ("select"); - Mshow = msymbol ("show"); - Mhide = msymbol ("hide"); - Mcommit = msymbol ("commit"); - Munhandle = msymbol ("unhandle"); - Mset = msymbol ("set"); - Madd = msymbol ("add"); - Msub = msymbol ("sub"); - Mmul = msymbol ("mul"); - Mdiv = msymbol ("div"); - Mequal = msymbol ("="); - Mless = msymbol ("<"); - Mgreater = msymbol (">"); - Mless_equal = msymbol ("<="); - Mgreater_equal = msymbol (">="); - Mcond = msymbol ("cond"); - Mplus = msymbol ("+"); - Mminus = msymbol ("-"); - Mstar = msymbol ("*"); - Mslush = msymbol ("/"); - Mand = msymbol ("&"); - Mor = msymbol ("|"); - Mnot = msymbol ("!"); +/*=*/ - Mcandidates_group_size = msymbol ("candidates-group-size"); - Mcandidates_charset = msymbol ("candidates-charset"); +/***en + @brief Reset an input context. - 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"); + 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. */ - Mcandidate_list = msymbol_as_managing_key (" candidate-list"); - Mcandidate_index = msymbol (" candidate-index"); +/***ja + @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë. - Minit = msymbol ("init"); - Mfini = msymbol ("fini"); + ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô + ¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¥ê¥»¥Ã¥È¤È¤Ï¡¢ + ¼ÂºÝ¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˰ܤ¹¤³¤È¤Ç¤¢¤ë¡£¸½ºßÆþÎÏÃæ¤Î¥Æ¥­¥¹ + ¥È¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¤³¤È¤Ê¤¯ºï½ü¤µ¤ì¤ë¤Î¤Ç¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é + ¥à¤Ï¡¢É¬Íפʤé¤Ðͽ¤á minput_filter () ¤ò°ú¿ô @r key #Mnil ¤Ç¸Æ¤ó¤Ç + ¶¯À©Åª¤Ë¥×¥ê¥¨¥Ç¥£¥Ã¥È¥Æ¥­¥¹¥È¤ò¥³¥ß¥Ã¥È¤µ¤»¤ë¤³¤È¡£ */ - M_key_alias = msymbol (" key-alias"); - M_description = msymbol ("description"); - M_command = msymbol ("command"); - M_variable = msymbol ("variable"); +void +minput_reset_ic (MInputContext *ic) +{ + if (ic->im->driver.callback_list) + minput__callback (ic, Minput_reset); +} - load_im_info_keys = mplist (); - mplist_add (load_im_info_keys, Mstate, Mnil); - mplist_push (load_im_info_keys, Mmap, Mnil); +/*=*/ - buf[0] = 'C'; - buf[1] = '-'; - buf[3] = '\0'; - for (i = 0, buf[2] = '@'; i < ' '; i++, buf[2]++) - { - MSymbol alias; +/***en + @brief Get title and icon filename of an input method. - one_char_symbol[i] = msymbol (buf); - if (key_names[i]) - { - alias = msymbol (key_names[i]); - msymbol_put (one_char_symbol[i], M_key_alias, alias); - } - else - alias = one_char_symbol[i]; - buf[2] += (i == 0) ? -32 : 32; - msymbol_put (alias, M_key_alias, msymbol (buf)); - buf[2] -= (i == 0) ? -32 : 32; - } - for (buf[2] = i; i < 127; i++, buf[2]++) - one_char_symbol[i] = msymbol (buf + 2); - one_char_symbol[i++] = msymbol ("Delete"); - buf[2] = 'M'; - buf[3] = '-'; - buf[5] = '\0'; - buf2[0] = 'M'; - buf2[1] = '-'; - for (buf[4] = '@'; i < 160; i++, buf[4]++) - { - one_char_symbol[i] = msymbol (buf); - if (key_names[i - 128]) - { - strcpy (buf2 + 2, key_names[i - 128]); - msymbol_put (one_char_symbol[i], M_key_alias, msymbol (buf2)); - } - } - for (buf[4] = i - 128; i < 255; i++, buf[4]++) - one_char_symbol[i] = msymbol (buf + 2); - one_char_symbol[i] = msymbol ("M-Delete"); + 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. - command_list = variable_list = NULL; + 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. - 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 (minput_default_driver.callback_list, Minput_reset, - (void *) reset_ic); - minput_driver = &minput_default_driver; - return 0; -} + @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 (). */ -void -minput__fini () +MPlist * +minput_get_title_icon (MSymbol language, MSymbol name) { - if (command_list) - { - M17N_OBJECT_UNREF (command_list); - command_list = NULL; - } - if (variable_list) - { - M17N_OBJECT_UNREF (variable_list); - variable_list = NULL; - } + MInputMethodInfo *im_info; + MPlist *plist; + char *file = NULL; + MText *mt; - if (minput_default_driver.callback_list) - { - M17N_OBJECT_UNREF (minput_default_driver.callback_list); - minput_default_driver.callback_list = NULL; - } - if (minput_driver->callback_list) + MINPUT__INIT (); + + im_info = get_im_info (language, name, Mnil, Mtitle); + if (! im_info || !im_info->title) + return NULL; + mt = mtext_get_prop (im_info->title, 0, Mtext); + if (mt) + file = mdatabase__find_file ((char *) MTEXT_DATA (mt)); + else { - M17N_OBJECT_UNREF (minput_driver->callback_list); - minput_driver->callback_list = NULL; - } + char *buf = alloca (MSYMBOL_NAMELEN (language) + MSYMBOL_NAMELEN (name) + + 12); - if (im_info_list) - { - while (! MPLIST_TAIL_P (im_info_list)) + sprintf (buf, "icons/%s-%s.png", (char *) MSYMBOL_NAME (language), + (char *) MSYMBOL_NAME (name)); + file = mdatabase__find_file (buf); + if (! file && language == Mt) { - /* Pop (t . mdb) */ - mplist_pop (im_info_list); - free_im_info ((MInputMethodInfo *) MPLIST_VAL (im_info_list)); - /* Pop (t . im_info) */ - mplist_pop (im_info_list); + sprintf (buf, "icons/%s.png", (char *) MSYMBOL_NAME (name)); + file = mdatabase__find_file (buf); } - M17N_OBJECT_UNREF (im_info_list); - im_info_list = NULL; } - - M17N_OBJECT_UNREF (load_im_info_keys); -} -void -minput__callback (MInputContext *ic, MSymbol command) -{ - if (ic->im->driver.callback_list) + plist = mplist (); + mplist_add (plist, Mtext, im_info->title); + if (file) { - MInputCallbackFunc func - = (MInputCallbackFunc) mplist_get (ic->im->driver.callback_list, - command); - - if (func) - (func) (ic, command); + mt = mtext__from_data (file, strlen (file), MTEXT_FORMAT_UTF_8, 1); + free (file); + mplist_add (plist, Mtext, mt); + M17N_OBJECT_UNREF (mt); } + return plist; } -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 */ - - -/* External API */ - -/*** @addtogroup m17nInputMethod */ -/*** @{ */ /*=*/ /***en - @name Variables: Predefined symbols for callback commands. + @brief Get description text of an input method. - 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 ). + The minput_get_description () function returns an M-text that + describes the input method specified by $LANGUAGE and $NAME. - Most of them don't require extra argument nor return any value; - exceptions are these: + @return + If the specified input method has a description text, a pointer to + #MText is returned. The caller has to free it by m17n_object_unref (). + If the input method does not have a description text, @c NULL is + returned. */ +/***ja + @brief ÆþÎϥ᥽¥Ã¥É¤ÎÀâÌÀ¥Æ¥­¥¹¥È¤òÆÀ¤ë. - Minput_get_surrounding_text: When a callback function assigned for - this command is called, the first element of #MInputContext::plist - has key #Msymbol 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. - The callback function must set the key of this element to #Mtext - and the value to the retrieved M-text (whose length may be shorter - than the requested number of characters if the available text is - not that long, or it may be longer if an application thinks it's - more efficient to return that length). + ´Ø¿ô minput_get_description () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄê + ¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤òÀâÌÀ¤¹¤ë M-text ¤òÊÖ¤¹¡£ - Minput_delete_surrounding_text: When a callback function assigned - for this command is called, the first element of - #MInputContext::plist has key #Msymbol 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. */ + @return »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢ + #MText ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤½¤ì¤ò m17n_object_unref + () ¤òÍѤ¤¤Æ²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ÆþÎϥ᥽¥Ã¥É¤ËÀâÌÀ¥Æ¥­¥¹¥È¤¬Ìµ¤± + ¤ì¤Ð@c NULL ¤òÊÖ¤¹¡£ */ -/***ja - @name ÊÑ¿ô¡§ ¥³¡¼¥ë¥Ð¥Ã¥¯¥³¥Þ¥ó¥ÉÍÑÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë. +MText * +minput_get_description (MSymbol language, MSymbol name) +{ + MInputMethodInfo *im_info; - ÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Î¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Ë¤ª¤¤¤Æ @c COMMAND - °ú¿ô¤È¤·¤ÆÍѤ¤¤é¤ì¤ëÄêµÁºÑ¤ß¥·¥ó¥Ü¥ë (#MInputDriver::callback_list »²¾È)¡£ - */ -/*** @{ */ -/*=*/ + MINPUT__INIT (); -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; -/*** @} */ + im_info = get_im_info (language, name, Mnil, Mdescription); + if (! im_info || ! im_info->description) + return NULL; + M17N_OBJECT_REF (im_info->description); + return im_info->description; +} /*=*/ /***en - @name Variables: Predefined symbols for special input events. + @brief Get information about input method command(s). - These are the predefined symbols that are used as the @c KEY - argument of minput_filter (). */ + The minput_get_command () function returns information about + the command $COMMAND of the input method specified by $LANGUAGE and + $NAME. An input method command is a pseudo key event to which one + or more actual input key sequences are assigned. -/*** @{ */ -/*=*/ + There are two kinds of commands, global and local. A global + command has a global definition, and the description and the key + assignment may be inherited by a local command. Each input method + defines a local command which has a local key assignment. It may + also declare a local command that inherits the definition of a + global command of the same name. -MSymbol Minput_focus_out; -MSymbol Minput_focus_in; -MSymbol Minput_focus_move; + If $LANGUAGE is #Mt and $NAME is #Mnil, this function returns + information about a global command. Otherwise information about a + local command is returned. -/*** @} */ + If $COMMAND is #Mnil, information about all commands is returned. -/*=*/ + The return value is a @e well-formed plist (#m17nPlist) of this + format: +@verbatim + ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...) +@endverbatim + @c NAME is a symbol representing the command name. -/***en - @brief The default driver for internal input methods. + @c DESCRIPTION is an M-text describing the command, or #Mnil if the + command has no description. - The variable #minput_default_driver is the default driver for - internal input methods. + @c STATUS is a symbol representing how the key assignment is decided. + The value is #Mnil (the default key assignment), #Mcustomized (the + key assignment is customized by per-user configuration file), or + #Mconfigured (the key assignment is set by the call of + minput_config_command ()). For a local command only, it may also + be #Minherited (the key assignment is inherited from the + corresponding global command). - The member MInputDriver::open_im () searches the m17n database for - an input method that matches the tag \< #Minput_method, $LANGUAGE, - $NAME\> and loads it. + @c KEYSEQ is a plist of one or more symbols representing a key + sequence assigned to the command. If there's no KEYSEQ, the + command is currently disabled (i.e. no key sequence can trigger + actions of the command). - 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. + If $COMMAND is not #Mnil, the first element of the returned plist + contains the information about $COMMAND. - The macro M17N_INIT () sets the variable #minput_driver to the - pointer to this driver so that all internal input methods use it. + @return - Therefore, unless @c minput_driver is set differently, the driver - dependent arguments $ARG of the functions whose name begins with - "minput_" are all ignored. */ + If the requested information was found, a pointer to a non-empty + plist is returned. As the plist is kept in the library, the + caller must not modify nor free it. + Otherwise (the specified input method or the specified command + does not exist), @c NULL is returned. */ /***ja - @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥǥե©¥ë¥È¥É¥é¥¤¥Ð. + @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë. - ÊÑ¿ô #minput_default_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѤΥǥե©¥ë¥È¤Î¥É¥é¥¤¥Ð¤òɽ¤¹¡£ + ´Ø¿ô minput_get_command () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ + ¥á¥½¥Ã¥É¤Î¥³¥Þ¥ó¥É $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ + ¥ó¥É¤È¤Ï¡¢µ¿»÷¥­¡¼¥¤¥Ù¥ó¥È¤Ç¤¢¤ê¡¢£±¤Ä°Ê¾å¤Î¼ÂºÝ¤ÎÆþÎÏ¥­¡¼¥·¡¼¥¯¥¨ + ¥ó¥¹¤¬³ä¤êÅö¤Æ¤é¤ì¤ë¡£ - ¥á¥ó¥Ð MInputDriver::open_im () ¤Ï m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹Ã椫¤é¥¿¥° - \< #Minput_method, $LANGUAGE, $NAME\> - ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤òõ¤·¡¢¤½¤ì¤ò¥í¡¼¥É¤¹¤ë¡£ + ¥³¥Þ¥ó¥É¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤Ê¥³¥Þ¥ó¥É + ¤Ï¥°¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤Ê¥³¥Þ¥ó¥É¤Ï¤½¤ÎÀâÌÀ¤È¥­¡¼³ä¤êÅö¤Æ + ¤ò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤Ê¥­¡¼³äÅö¤ò»ý¤Ä¥í¡¼ + ¥«¥ë¤Ê¥³¥Þ¥ó¥É¤òÄêµÁ¤¹¤ë¡£¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤Ê¥³¥Þ¥ó¥É¤ÎÄêµÁ¤ò·Ñ + ¾µ¤¹¤ë¥í¡¼¥«¥ë¤Ê¥³¥Þ¥ó¥É¤òÀë¸À¤¹¤ë¤³¤È¤â¤Ç¤­¤ë¡£ - ¥á¥ó¥Ð MInputDriver::callback_list () ¤Ï @c NULL ¤Ç¤¢¤ê¡¢ - ¤·¤¿¤¬¤Ã¤Æ¡¢¥×¥í¥°¥é¥Þ¦¤ÇÀÕǤ¤ò»ý¤Ã¤Æ ŬÀڤʥ³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤Î plist - ¤ËÀßÄꤷ¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤µ¤â¤Ê¤¤¤È¡¢preedit - ¥Æ¥­¥¹¥È¤Ê¤É¤Î¥Õ¥£¡¼¥É¥Ð¥Ã¥¯¾ðÊ󤬥桼¥¶¤Ëɽ¼¨¤µ¤ì¤Ê¤¤¡£ + $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ë¥³ + ¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¤â + ¤Î¤òÊÖ¤¹¡£ - ¥Þ¥¯¥í M17N_INIT () ¤ÏÊÑ¿ô #minput_driver - ¤ò¤³¤Î¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤ËÀßÄꤷ¡¢Á´¤Æ¤ÎÆâÉôÆþÎϥ᥽¥Ã¥É¤¬¤³¤Î¥É¥é¥¤¥Ð¤ò»È¤¦¤è¤¦¤Ë¤¹¤ë¡£ + $COMMAND ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ - ¤·¤¿¤¬¤Ã¤Æ¡¢@c minput_driver ¤¬¥Ç¥Õ¥©¥ë¥ÈÃͤΤޤޤǤ¢¤ì¤Ð¡¢minput_ - ¤Ç»Ï¤Þ¤ë´Ø¿ô¤Î¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë°ú¿ô $ARG ¤Ï¤¹¤Ù¤Æ̵»ë¤µ¤ì¤ë¡£ */ + Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (#m17nPlist) ¤Ç¤¢¤ë¡£ -MInputDriver minput_default_driver; -/*=*/ +@verbatim + ((NAME DESCRIPTION STATUS [KEYSEQ ...]) ...) +@endverbatim + @c NAME ¤Ï¥³¥Þ¥ó¥É̾¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£ -/***en - @brief The driver for internal input methods. + @c DESCRIPTION ¤Ï¥³¥Þ¥ó¥É¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë + ¤Ï #Mnil ¤Ç¤¢¤ë¡£ - 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 .h> is included. */ -/***ja - @brief ÆâÉôÆþÎϥ᥽¥Ã¥ÉÍѥɥ饤¥Ð. + @c STATUS ¤Ï¥­¡¼³ä¤êÅö¤Æ¤¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë¤Ç¤¢ + ¤ê¡¢¤½¤ÎÃÍ¤Ï #Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤Î³ä¤êÅö¤Æ¡Ë, #Mcustomized ¡Ê¥æ¡¼¥¶ + Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿³ä¤êÅö¤Æ¡Ë, #Mconfigured + ¡Êminput_config_command ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ë³ä¤êÅö¤Æ¡Ë¤Î + ¤¤¤º¤ì¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ë¥³¥Þ¥ó¥É¤Î¾ì¹ç¤Ë¤Ï¡¢#Minherited ¡ÊÂбþ¤¹¤ë + ¥°¥í¡¼¥Ð¥ë¥³¥Þ¥ó¥É¤«¤é¤Î·Ñ¾µ¤Ë¤è¤ë³ä¤êÅö¤Æ¡Ë¤Ç¤â¤è¤¤¡£ - ÊÑ¿ô #minput_driver ¤ÏÆâÉôÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤Æ»ÈÍѤµ¤ì¤Æ¤¤¤ëÆþÎÏ¥á - ¥½¥Ã¥É¥É¥é¥¤¥Ð¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¡£¥Þ¥¯¥í M17N_INIT () ¤Ï¤³¤Î¥Ý¥¤¥ó - ¥¿¤ò#minput_default_driver (.h> ¤¬ include ¤µ¤ì¤Æ¤¤¤ë - »þ) ¤Ë½é´ü²½¤¹¤ë¡£ */ + @c KEYSEQ ¤Ï£±¤Ä°Ê¾å¤Î¥·¥ó¥Ü¥ë¤«¤é¤Ê¤ë plist ¤Ç¤¢¤ê¡¢³Æ¥·¥ó¥Ü¥ë¤Ï¥³¥Þ + ¥ó¥É¤Ë³ä¤êÅö¤Æ¤é¤ì¤Æ¤¤¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òɽ¤¹¡£KEYSEQ ¤¬Ìµ¤¤¾ì¹ç¤Ï¡¢ + ¤½¤Î¥³¥Þ¥ó¥É¤Ï¸½¾õ¤Ç»ÈÍÑÉÔǽ¤Ç¤¢¤ë¡£¡Ê¤¹¤Ê¤ï¤Á¥³¥Þ¥ó¥É¤ÎÆ°ºî¤òµ¯ + Æ°¤Ç¤­¤ë¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Ìµ¤¤¡£¡Ë -MInputDriver *minput_driver; + $COMMAND ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁǤϡ¢ + $COMMAND ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£ -MSymbol Minput_driver; + @return + + µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹ + ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë + ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£ + + ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ä¥³¥Þ¥ó¥É¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð + @c NULL ¤òÊÖ¤¹¡£ */ + +#if EXAMPLE_CODE +MText * +get_im_command_description (MSymbol language, MSymbol name, MSymbol command) +{ + /* Return a description of the command COMMAND of the input method */ + /* specified by LANGUAGE and NAME. */ + MPlist *cmd = minput_get_command (langauge, name, command); + MPlist *plist; + + if (! cmds) + return NULL; + plist = mplist_value (cmds); /* (NAME DESCRIPTION KEY-SEQ ...) */ + plist = mplist_next (plist); /* (DESCRIPTION KEY-SEQ ...) */ + return (mplist_key (plist) == Mtext + ? (MText *) mplist_value (plist) + : NULL); +} +#endif + +MPlist * +minput_get_command (MSymbol language, MSymbol name, MSymbol command) +{ + MInputMethodInfo *im_info; + + MINPUT__INIT (); + + im_info = get_im_info (language, name, Mnil, Mcommand); + if (! im_info + || ! im_info->configured_cmds + || MPLIST_TAIL_P (im_info->configured_cmds)) + return NULL; + if (command == Mnil) + return im_info->configured_cmds; + return mplist__assq (im_info->configured_cmds, command); +} /*=*/ /***en - @brief Open an input method. + @brief Configure the key sequence of an input method command. - 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. + The minput_config_command () function assigns a list of key + sequences $KEYSEQLIST to the command $COMMAND of the input method + specified by $LANGUAGE and $NAME. - This function at first decides a driver for the input method as - described below. + If $KEYSEQLIST is a non-empty plist, it must be a list of key + sequences, and each key sequence must be a plist of symbols. - If $LANGUAGE is not #Mnil, the driver pointed by the variable - #minput_driver is used. + If $KEYSEQLIST is an empty plist, the command becomes unusable. - 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. + If $KEYSEQLIST is NULL, the configuration of the command for the + input method is canceled, and the default key sequences become + effective. In such case, if $COMMAND is #Mnil, configurations for + all commands of the input method are canceled. - Then, the member MInputDriver::open_im () of the driver is - called. + If $NAME is #Mnil, this function configures the key assignment of a + global command, not that of a specific input method. - $ARG is set in the member @c arg of the structure MInputMethod so - that the driver can refer to it. */ + The configuration takes effect for input methods opened or + re-opened later in the current session. In order to make the + configuration take effect for the future session, it must be saved + in a per-user configuration file by the function + minput_save_config (). + + @return + If the operation was successful, this function returns 0, + otherwise returns -1. The operation fails in these cases: +
    +
  • $KEYSEQLIST is not in a valid form. +
  • $COMMAND is not available for the input method. +
  • $LANGUAGE and $NAME do not specify an existing input method. +
+ + @seealso + minput_get_commands (), minput_save_config (). +*/ /***ja - @brief ÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë. + @brief ÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤òÀßÄꤹ¤ë. - ´Ø¿ô minput_open_im () ¤Ï¸À¸ì $LANGUAGE ¤È̾Á° $NAME - ¤Ë¹çÃפ¹¤ëÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤·¡¢¿·¤¿¤Ë³ä¤êÅö¤Æ¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£ - - ¤³¤Î´Ø¿ô¤Ï¡¢¤Þ¤ºÆþÎϥ᥽¥Ã¥ÉÍѤΥɥ饤¥Ð¤ò°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ·èÄꤹ¤ë¡£ + ´Ø¿ô minput_config_command () ¤Ï¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È + $KEYSEQLIST ¤ò¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤Î + ¥³¥Þ¥ó¥É $COMMAND ¤Ë³ä¤êÅö¤Æ¤ë¡£ - $LANGUAGE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô #minput_driver - ¤Ç»Ø¤µ¤ì¤Æ¤¤¤ë¥É¥é¥¤¥Ð¤òÍѤ¤¤ë¡£ + $KEYSEQLIST ¤¬¶õ¥ê¥¹¥È¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Î¥ê¥¹¥È¤Ç¤¢¤ê¡¢ + ³Æ¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤Ï¥·¥ó¥Ü¥ë¤Î plist ¤Ç¤¢¤ë¡£ - $LANGUAGE ¤¬ #Mnil ¤Ç¤¢¤ê¡¢$NAME ¤¬ #Minput_driver - ¥×¥í¥Ñ¥Æ¥£¤ò»ý¤Ä¾ì¹ç¤Ë¤Ï¡¢¤½¤Î¥×¥í¥Ñ¥Æ¥£¤ÎÃͤǻؤµ¤ì¤Æ¤¤¤ëÆþÎϥɥ饤¥Ð¤òÍѤ¤¤ÆÆþÎϥ᥽¥Ã¥É¤ò¥ª¡¼¥×¥ó¤¹¤ë¡£ - $NAME ¤Ë¤½¤Î¤è¤¦¤Ê¥×¥í¥Ñ¥Æ¥£¤¬Ìµ¤«¤Ã¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ + $KEYSEQLIST ¤¬¶õ¤Î plist ¤Ê¤é¤Ð¡¢¥³¥Þ¥ó¥É¤Ï»ÈÍѤǤ­¤Ê¤¯¤Ê¤ë¡£ - ¼¡¤¤¤Ç¡¢¥É¥é¥¤¥Ð¤Î¥á¥ó¥Ð MInputDriver::open_im () ¤¬¸Æ¤Ð¤ì¤ë¡£ + $KEYSEQLIST ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤Î¥³¥Þ¥ó¥É¤ÎÀßÄê¤Ï + ¥­¥ã¥ó¥»¥ë¤µ¤ì¡¢¥Ç¥Õ¥©¥ë¥È¤Î¥­¡¼¥·¡¼¥¯¥¨¥ó¥¹¤¬Í­¸ú¤Ë¤Ê¤ë¡£¤³¤Î¾ì¹ç¡¢ + $COMMAND ¤¬ #Mnil ¤Ê¤é¤Ð»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤Î¥³¥Þ¥ó¥É¤ÎÀßÄ꤬ + ¥­¥ã¥ó¥»¥ë¤µ¤ì¤ë¡£ - $ARG ¤Ï¹½Â¤ÂÎ MInputMethod ¤Î¥á¥ó¥Ð @c arg ¤ËÀßÄꤵ¤ì¡¢¥É¥é¥¤¥Ð¤«¤é»²¾È¤Ç¤­¤ë¡£ + $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð + ¥ë¤Ê¥³¥Þ¥ó¥É¤Î¥­¡¼³ä¤êÅö¤Æ¤òÀßÄꤹ¤ë¡£ - @latexonly \IPAlabel{minput_open} @endlatexonly + ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï + ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹ + ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤ + ¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ + + @return + + ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£ +
    +
  • $KEYSEQLIST ¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£ +
  • $COMMAND ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£ +
  • $LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£ +
+ @seealso + minput_get_commands (), minput_save_config (). */ -MInputMethod * -minput_open_im (MSymbol language, MSymbol name, void *arg) +#if EXAMPLE_CODE +/* Add "C-x u" to the "start" command of Unicode input method. */ { - MInputMethod *im; - MInputDriver *driver; + MSymbol start_command = msymbol ("start"); + MSymbol unicode = msymbol ("unicode"); + MPlist *cmd, *plist, *key_seq_list, *key_seq; - MDEBUG_PRINT2 (" [IM] opening (%s %s) ... ", - msymbol_name (language), msymbol_name (name)); - if (language) - driver = minput_driver; - else + /* At first get the current key-sequence assignment. */ + cmd = mplist_get_command (Mt, unicode, start_command); + if (! cmd) { - driver = (MInputDriver *) msymbol_get (name, Minput_driver); - if (! driver) - MERROR (MERROR_IM, NULL); + /* The input method does not have the command "start". Here */ + /* should come some error handling code. */ + } + /* Now CMD == ((start DESCRIPTION KEY-SEQUENCE ...) ...). Extract */ + /* the part (KEY-SEQUENCE ...). */ + plist = mplist_next (mplist_next (mplist_value (cmd))); + /* Copy it because we should not modify it directly. */ + key_seq_list = mplist_copy (plist); + m17n_object_unref (cmds); + + key_seq = mplist (); + mplist_add (key_seq, Msymbol, msymbol ("C-x")); + mplist_add (key_seq, Msymbo, msymbol ("u")); + mplist_add (key_seq_list, Mplist, key_seq); + m17n_object_unref (key_seq); + + minput_config_command (Mt, unicode, start_command, key_seq_list); + m17n_object_unref (key_seq_list); +} +#endif + +int +minput_config_command (MSymbol language, MSymbol name, MSymbol command, + MPlist *keyseqlist) +{ + MInputMethodInfo *im_info, *config; + MPlist *plist; + + MINPUT__INIT (); + + if (keyseqlist) + { + if (command == Mnil) + MERROR (MERROR_IM, -1); + MPLIST_DO (plist, keyseqlist) + if (! MPLIST_PLIST_P (plist) + || ! check_command_keyseq (plist)) + MERROR (MERROR_IM, -1); + } + + im_info = get_im_info (language, name, Mnil, Mcommand); + if (! im_info) + MERROR (MERROR_IM, -1); + if (command != Mnil + && (! im_info->cmds + || ! mplist__assq (im_info->cmds, command))) + MERROR (MERROR_IM, -1); + + config = get_config_info (im_info); + if (! config) + { + if (! im_config_list) + im_config_list = mplist (); + config = new_im_info (NULL, language, name, Mnil, im_config_list); + config->cmds = mplist (); + config->vars = mplist (); + } + + if (command == Mnil) + { + MInputMethodInfo *custom = get_custom_info (im_info); + + mplist_set (config->cmds, Mnil, NULL); + if (custom && custom->cmds) + { + MPLIST_DO (plist, custom->cmds) + { + command = MPLIST_SYMBOL (MPLIST_PLIST (plist)); + plist = mplist (); + mplist_add (plist, Msymbol, command); + mplist_push (config->cmds, Mplist, plist); + M17N_OBJECT_UNREF (plist); + } + } } - - MSTRUCT_CALLOC (im, MERROR_IM); - im->language = language; - im->name = name; - im->arg = arg; - im->driver = *driver; - if ((*im->driver.open_im) (im) < 0) + else { - MDEBUG_PRINT (" failed\n"); - free (im); - return NULL; + plist = mplist__assq (config->cmds, command); + if (plist) + { + plist = MPLIST_PLIST (plist); /* (NAME [nil KEY-SEQUENCE ...]) */ + plist = MPLIST_NEXT (plist); /* ([nil ...]) */ + if (! MPLIST_TAIL_P (plist)) + mplist_set (plist, Mnil, NULL); /* () */ + } + else + { + plist = mplist (); + mplist_add (config->cmds, Mplist, plist); + M17N_OBJECT_UNREF (plist); + plist = mplist_add (plist, Msymbol, command); + plist = MPLIST_NEXT (plist); + } + if (keyseqlist) + { + MPlist *pl; + + plist = mplist_add (plist, Msymbol, Mnil); + MPLIST_DO (keyseqlist, keyseqlist) + { + pl = mplist_copy (MPLIST_VAL (keyseqlist)); + plist = mplist_add (plist, Mplist, pl); + M17N_OBJECT_UNREF (pl); + } + } } - MDEBUG_PRINT (" ok\n"); - return im; + config_all_commands (im_info); + im_info->tick = time (NULL); + return 0; } /*=*/ /***en - @brief Close an input method. + @brief Get information about input method variable(s). - The minput_close_im () function closes the input method $IM, which - must have been created by minput_open_im (). */ + The minput_get_variable () function returns information about + the variable $VARIABLE of the input method specified by $LANGUAGE and $NAME. + An input method variable controls behavior of an input method. -/***ja - @brief ÆþÎϥ᥽¥Ã¥É¤ò¥¯¥í¡¼¥º¤¹¤ë. + There are two kinds of variables, global and local. A global + variable has a global definition, and the description and the value + may be inherited by a local variable. Each input method defines a + local variable which has local value. It may also declare a + local variable that inherits definition of a global variable of + the same name. - ´Ø¿ô minput_close_im () ¤Ï¡¢ÆþÎϥ᥽¥Ã¥É $IM ¤ò¥¯¥í¡¼¥º¤¹¤ë¡£ - ¤³¤ÎÆþÎϥ᥽¥Ã¥É $IM ¤Ï minput_open_im () ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£ */ + If $LANGUAGE is #Mt and $NAME is #Mnil, information about a global + variable is returned. Otherwise information about a local variable + is returned. -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"); -} + If $VARIABLE is #Mnil, information about all variables is + returned. -/*=*/ + The return value is a @e well-formed plist (#m17nPlist) of this + format: +@verbatim + ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...) +@endverbatim + @c NAME is a symbol representing the variable name. + + @c DESCRIPTION is an M-text describing the variable, or #Mnil if the + variable has no description. + + @c STATUS is a symbol representing how the value is decided. The + value is #Mnil (the default value), #Mcustomized (the value is + customized by per-user configuration file), or #Mconfigured (the + value is set by the call of minput_config_variable ()). For a + local variable only, it may also be #Minherited (the value is + inherited from the corresponding global variable). + + @c VALUE is the initial value of the variable. If the key of this + element is #Mt, the variable has no initial value. Otherwise, the + key is #Minteger, #Msymbol, or #Mtext and the value is of the + corresponding type. + + @c VALID-VALUEs (if any) specify which values the variable can have. + They have the same type (i.e. having the same key) as @c VALUE except + for the case that VALUE is an integer. In that case, @c VALID-VALUE + may be a plist of two integers specifying the range of possible + values. -/***en - @brief Create an input context. + If there no @c VALID-VALUE, the variable can have any value as long + as the type is the same as @c VALUE. - 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. + If $VARIABLE is not #Mnil, the first element of the returned plist + contains the information about $VARIABLE. @return - If an input context is successfully created, minput_create_ic () - returns a pointer to it. Otherwise it returns @c NULL. */ + If the requested information was found, a pointer to a non-empty + plist is returned. As the plist is kept in the library, the + caller must not modify nor free it. + + Otherwise (the specified input method or the specified variable + does not exist), @c NULL is returned. */ /***ja - @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÀ¸À®¤¹¤ë. + @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë. - ´Ø¿ô minput_create_ic () ¤ÏÆþÎϥ᥽¥Ã¥É $IM - ¤ËÂбþ¤¹¤ëÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¡¢ - #Minput_preedit_start, #Minput_status_start, #Minput_status_draw - ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£ + ´Ø¿ô minput_get_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎÏ + ¥á¥½¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤È¤Ï¡¢ + ÆþÎϥ᥽¥Ã¥É¤Î¿¶Éñ¤òÀ©¸æ¤¹¤ë¤â¤Î¤Ç¤¢¤ë¡£ - @return - ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤¬À¸À®¤µ¤ì¤¿¾ì¹ç¡¢minput_create_ic () - ¤Ï¤½¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ - */ + ÊÑ¿ô¤Ë¤Ï¡¢¥°¥í¡¼¥Ð¥ë¤È¥í¡¼¥«¥ë¤Î£²¼ïÎब¤¢¤ë¡£¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤Ï¥° + ¥í¡¼¥Ð¥ë¤ËÄêµÁ¤µ¤ì¡¢¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤Ï¤½¤ÎÀâÌÀ¤ÈÃͤò·Ñ¾µ¤¹¤ë¤³¤È¤¬¤Ç + ¤­¤ë¡£³ÆÆþÎϥ᥽¥Ã¥É¤Ï¥í¡¼¥«¥ë¤ÊÃͤò»ý¤Ä¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÄêµÁ¤¹¤ë¡£ + ¤Þ¤¿Æ±Ì¾¤Î¥°¥í¡¼¥Ð¥ë¤ÊÊÑ¿ô¤ÎÄêµÁ¤ò·Ñ¾µ¤¹¤ë¥í¡¼¥«¥ë¤ÊÊÑ¿ô¤òÀë¸À¤¹¤ë + ¤³¤È¤â¤Ç¤­¤ë¡£ -MInputContext * -minput_create_ic (MInputMethod *im, void *arg) -{ - MInputContext *ic; + $LANGUAGE ¤¬ #Mt ¤Ç $NAME ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤³¤Î´Ø¿ô¤Ï¥°¥í¡¼¥Ð¥ëÊÑ + ¿ô¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¥í¡¼¥«¥ëÊÑ¿ô¤Ë´Ø¤¹¤ë¤â¤Î¤òÊÖ¤¹¡£ - 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; - }; + $VARIABLE ¤¬ #Mnil ¤Î¾ì¹ç¤Ï¡¢¤¹¤Ù¤Æ¤Î¥³¥Þ¥ó¥É¤Ë´Ø¤¹¤ë¾ðÊó¤òÊÖ¤¹¡£ - if (im->driver.callback_list) - { - minput__callback (ic, Minput_preedit_start); - minput__callback (ic, Minput_status_start); - minput__callback (ic, Minput_status_draw); - } + Ìá¤êÃͤϰʲ¼¤Î·Á¼°¤Î @e well-formed plist (#m17nPlist) ¤Ç¤¢¤ë¡£ +@verbatim + ((NAME DESCRIPTION STATUS VALUE [VALID-VALUE ...]) ...) +@endverbatim - MDEBUG_PRINT (" ok\n"); - return ic; -} + @c NAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£ -/*=*/ + @c DESCRIPTION ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¤«¡¢ÀâÌÀ¤¬Ìµ¤¤¾ì¹ç¤Ë¤Ï + #Mnil ¤Ç¤¢¤ë¡£ -/***en - @brief Destroy an input context. + @c STATUS ¤ÏÃͤ¬¤É¤Î¤è¤¦¤ËÄê¤á¤é¤ì¤ë¤«¤ò¤¢¤é¤ï¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢ + @c STATUS ¤ÎÃÍ¤Ï #Mnil ¡Ê¥Ç¥Õ¥©¥ë¥È¤ÎÃÍ¡Ë, #Mcustomized ¡Ê¥æ¡¼¥¶Ëè¤ÎÀß + Äê¥Õ¥¡¥¤¥ë¤Ë¤è¤Ã¤Æ¥«¥¹¥¿¥Þ¥¤¥º¤µ¤ì¤¿ÃÍ¡Ë, #Mconfigured + ¡Êminput_config_variable ()¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÀßÄꤵ¤ì¤ëÃ͡ˤΤ¤¤º¤ì + ¤«¤Ç¤¢¤ë¡£¥í¡¼¥«¥ëÊÑ¿ô¤Î¾ì¹ç¤Ë¤Ï¡¢#Minherited ¡ÊÂбþ¤¹¤ë¥°¥í¡¼¥Ð¥ë + ÊÑ¿ô¤«¤é·Ñ¾µ¤·¤¿Ã͡ˤǤâ¤è¤¤¡£ - 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. */ + @c VALUE ¤ÏÊÑ¿ô¤Î½é´üÃͤǤ¢¤ë¡£¤³¤ÎÍ×ÁǤΥ­¡¼¤¬#Mt ¤Ç¤¢¤ì¤Ð½é´üÃͤò»ý + ¤¿¤Ê¤¤¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¥­¡¼¤Ï #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì + ¤«¤Ç¤¢¤ê¡¢ÃͤϤ½¤ì¤¾¤ìÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£ -/***ja - @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤òÇ˲õ¤¹¤ë. + @c VALID-VALUE ¤Ï¤â¤·¤¢¤ì¤Ð¡¢ÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò»ØÄꤹ¤ë¡£¤³¤ì¤Ï @c VALUE + ¤ÈƱ¤¸·¿(¤¹¤Ê¤ï¤ÁƱ¤¸¥­¡¼¤ò»ý¤Ä) ¤Ç¤¢¤ë¤¬¡¢Îã³°¤È¤·¤Æ @c VALUE ¤¬ + integer ¤Î¾ì¹ç¤Ï @c VALID-VALUE ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹Æó¤Ä¤ÎÀ°¿ô¤«¤é + ¤Ê¤ë plist ¤È¤Ê¤ë¤³¤È¤¬¤Ç¤­¤ë¡£ - ´Ø¿ô minput_destroy_ic () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤òÇ˲õ¤¹¤ë¡£ - ¤³¤ÎÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Ï minput_create_ic () - ¤Ë¤è¤Ã¤Æºî¤é¤ì¤¿¤â¤Î¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡£¤³¤Î´Ø¿ô¤Ï - #Minput_preedit_done, #Minput_status_done, #Minput_candidates_done - ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¤³¤Î½ç¤Ë¸Æ¤Ö¡£ - */ + @c VALID-VALUE ¤¬¤Ê¤±¤ì¤Ð¡¢ÊÑ¿ô¤Ï @c VALUE ¤ÈƱ¤¸·¿¤Ç¤¢¤ë¸Â¤ê¤¤¤«¤Ê¤ëÃͤâ + ¤È¤ë¤³¤È¤¬¤Ç¤­¤ë¡£ -void -minput_destroy_ic (MInputContext *ic) + $VARIABLE ¤¬ #Mnil ¤Ç¤Ê¤±¤ì¤Ð¡¢ÊÖ¤µ¤ì¤ë plist ¤ÎºÇ½é¤ÎÍ×ÁÇ¤Ï + $VARIABLE ¤Ë´Ø¤¹¤ë¾ðÊó¤ò´Þ¤à¡£ + + @return + + µá¤á¤é¤ì¤¿¾ðÊ󤬸«¤Ä¤«¤ì¤Ð¡¢¶õ¤Ç¤Ê¤¤ plist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¥ê¥¹ + ¥È¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð¦¤¬Êѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë + ¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£ + + ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢¤¹¤Ê¤ï¤Á»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤äÊÑ¿ô¤¬Â¸ºß¤·¤Ê¤±¤ì¤Ð + @c NULL ¤òÊÖ¤¹¡£ */ + +MPlist * +minput_get_variable (MSymbol language, MSymbol name, MSymbol variable) { - 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); + MInputMethodInfo *im_info; + + MINPUT__INIT (); + + im_info = get_im_info (language, name, Mnil, Mvariable); + if (! im_info || ! im_info->configured_vars) + return NULL; + if (variable == Mnil) + return im_info->configured_vars; + return mplist__assq (im_info->configured_vars, variable); } /*=*/ /***en - @brief Filter an input key. + @brief Configure the value of an input method variable. - 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. + The minput_config_variable () function assigns $VALUE to the + variable $VARIABLE of the input method specified by $LANGUAGE and + $NAME. - 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. + If $VALUE is not NULL, it must be a plist of one element whose key + is #Minteger, #Msymbol, or #Mtext, and the value is of the + corresponding type. - To inform the input method about the focus-out event, call this - function with #Minput_focus_out as $KEY. + If $VALUE is NULL, a configuration for the variable for the input + method is canceled, and the variable is initialized to the default + value. In that case, if $VARIABLE is #Mnil, configurations for + all variables of the input method are canceled. - To inform the input method about the focus-in event, call this - function with #Minput_focus_in as $KEY. + If $NAME is #Mnil, this function configure the value of global + variable, not that of a specific input method. - 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. + The configuration takes effect for input methods opened or + re-opened later in the current session. To make the configuration + take effect for the future session, it must be saved in a per-user + configuration file by the function minput_save_config (). @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. */ + If the operation was successful, this function returns 0, + otherwise returns -1. The operation fails in these cases: +
    +
  • $VALUE is not in a valid form, the type does not match the + definition, or the value is our of range. +
  • $VARIABLE is not available for the input method. +
  • $LANGUAGE and $NAME do not specify an existing input method. +
+ + @seealso + minput_get_variable (), minput_save_config (). */ /***ja - @brief ÆþÎÏ¥­¡¼¤ò¥Õ¥£¥ë¥¿¤¹¤ë. + @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë. - ´Ø¿ô minput_filter () ¤ÏÆþÎÏ¥­¡¼ $KEY ¤òÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC - ¤Ë±þ¤¸¤Æ¥Õ¥£¥ë¥¿¤·¡¢preedit ¥Æ¥­¥¹¥È¡¢¥¹¥Æ¡¼¥¿¥¹¡¢¸½»þÅÀ¤Ç¤Î¸õÊ䤬ÊѲ½¤·¤¿»þÅÀ¤Ç¡¢¤½¤ì¤¾¤ì - #Minput_preedit_draw, #Minput_status_draw, - #Minput_candidates_draw ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¡£ + ´Ø¿ô minput_config_variable () ¤ÏÃÍ $VALUE ¤ò¡¢$LANGUAGE ¤È $NAME + ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô $VARIABLE ¤Ë³ä¤êÅö¤Æ¤ë¡£ - @return - $KEY ¤¬¥Õ¥£¥ë¥¿¤µ¤ì¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 1 ¤òÊÖ¤¹¡£ - ¤³¤Î¾ì¹ç¸Æ¤Ó½Ð¤·Â¦¤Ï¤³¤Î¥­¡¼¤ò¼Î¤Æ¤ë¤Ù¤­¤Ç¤¢¤ë¡£ - ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð 0 ¤òÊÖ¤·¡¢¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤¿¤È¤¨¤ÐƱ¤¸¥­¡¼¤Ç´Ø¿ô minput_lookup () - ¤ò¸Æ¤Ö¤Ê¤É¤·¤Æ¡¢¤³¤Î¥­¡¼¤ò½èÍý¤¹¤ë¡£ + $VALUE ¤¬ NULL¤Ç¤Ê¤±¤ì¤Ð¡¢£±Í×ÁǤΠplist ¤Ç¤¢¤ê¡¢¤½¤Î¥­¡¼¤Ï + #Minteger, #Msymbol, #Mtext ¤Î¤¤¤º¤ì¤«¡¢ÃͤÏÂбþ¤¹¤ë·¿¤Î¤â¤Î¤Ç¤¢¤ë¡£ - @latexonly \IPAlabel{minput_filter} @endlatexonly -*/ + $VALUE ¤¬ NULL ¤Ç¤¢¤ì¤Ð¡¢»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¤ÎÀßÄê¤Ï¥­¥ã¥ó¥»¥ë + ¤µ¤ì¡¢ÊÑ¿ô¤Ï¥Ç¥Õ¥©¥ë¥ÈÃͤ˽é´ü²½¤µ¤ì¤ë¡£¤³¤Î¾ì¹ç¡¢$VARIABLE ¤¬ + #Mnil ¤Ê¤é¤Ð»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÎÁ´¤Æ¤ÎÊÑ¿ô¤ÎÀßÄ꤬¥­¥ã¥ó¥»¥ë¤µ¤ì¤ë¡£ + + $NAME ¤¬ #Mnil ¤Ê¤é¤Ð¡¢¤³¤Î´Ø¿ô¤Ï¸Ä¡¹¤ÎÆþÎϥ᥽¥Ã¥É¤Ç¤Ï¤Ê¤¯¥°¥í¡¼¥Ð + ¥ë¤ÊÊÑ¿ô¤ÎÃͤòÀßÄꤹ¤ë¡£ + + ¤³¤ì¤é¤ÎÀßÄê¤Ï¡¢¸½¹Ô¤Î¥»¥Ã¥·¥ç¥óÃæ¤ÇÆþÎϥ᥽¥Ã¥É¤¬¥ª¡¼¥×¥ó¡Ê¤Þ¤¿¤Ï + ºÆ¥ª¡¼¥×¥ó¡Ë¤µ¤ì¤¿»þÅÀ¤ÇÍ­¸ú¤Ë¤Ê¤ë¡£¾­Íè¤Î¥»¥Ã¥·¥ç¥óÃæ¤Ç¤âÍ­¸ú¤Ë¤¹ + ¤ë¤¿¤á¤Ë¤Ï¡¢´Ø¿ô minput_save_config () ¤òÍѤ¤¤Æ¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤ + ¥ë¤ËÊݸ¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ + + @return + + ¤³¤Î´Ø¿ô¤Ï¡¢½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤ò¡¢¼ºÇÔ¤¹¤ì¤Ð -1 ¤òÊÖ¤¹¡£¼ºÇԤȤϰʲ¼¤Î¾ì¹ç¤Ç¤¢¤ë¡£ +
    +
  • $VALUE¤¬Í­¸ú¤Ê·Á¼°¤Ç¤Ê¤¤¡£·¿¤¬ÄêµÁ¤Ë¹ç¤ï¤Ê¤¤¡¢¤Þ¤¿¤ÏÃͤ¬Èϰϳ°¤Ç¤¢¤ë¡£ +
  • $VARIABLE ¤¬»ØÄê¤ÎÆþÎϥ᥽¥Ã¥É¤ÇÍøÍѤǤ­¤Ê¤¤¡£ +
  • $LANGUAGE ¤È $NAME ¤Ç»ØÄꤵ¤ì¤ëÆþÎϥ᥽¥Ã¥É¤¬Â¸ºß¤·¤Ê¤¤¡£ +
+ @seealso + minput_get_commands (), minput_save_config (). +*/ int -minput_filter (MInputContext *ic, MSymbol key, void *arg) +minput_config_variable (MSymbol language, MSymbol name, MSymbol variable, + MPlist *value) { - int ret; + MInputMethodInfo *im_info, *config; + MPlist *plist; - if (! ic - || ! ic->active) - return 0; - ret = (*ic->im->driver.filter) (ic, key, arg); + MINPUT__INIT (); - if (ic->im->driver.callback_list) + im_info = get_im_info (language, name, Mnil, Mvariable); + if (! im_info) + MERROR (MERROR_IM, -1); + if (variable == Mnil) { - 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); + if (value) + MERROR (MERROR_IM, -1); } + else if (! im_info->vars + || ! (plist = mplist__assq (im_info->configured_vars, variable))) + MERROR (MERROR_IM, -1); - return ret; + if (variable != Mnil && value) + { + plist = MPLIST_PLIST (plist); + plist = MPLIST_NEXT (plist); /* (DESC STATUS VALUE VALIDS ...) */ + plist = MPLIST_NEXT (plist); /* (STATUS VALUE VALIDS ...) */ + plist = MPLIST_NEXT (plist); /* (VALUE VALIDS ...) */ + if (MPLIST_KEY (plist) != Mt + && ! check_variable_value (value, plist)) + MERROR (MERROR_IM, -1); + } + + config = get_config_info (im_info); + if (! config) + { + if (! im_config_list) + im_config_list = mplist (); + config = new_im_info (NULL, language, name, Mnil, im_config_list); + config->cmds = mplist (); + config->vars = mplist (); + } + + if (variable == Mnil) + { + MInputMethodInfo *custom = get_custom_info (im_info); + + mplist_set (config->vars, Mnil, NULL); + if (custom && custom->cmds) + { + MPLIST_DO (plist, custom->vars) + { + variable = MPLIST_SYMBOL (MPLIST_PLIST (plist)); + plist = mplist (); + mplist_add (plist, Msymbol, variable); + mplist_push (config->vars, Mplist, plist); + M17N_OBJECT_UNREF (plist); + } + } + } + else + { + plist = mplist__assq (config->vars, variable); + if (plist) + { + plist = MPLIST_PLIST (plist); /* (NAME nil VALUE) */ + plist = MPLIST_NEXT (plist); /* ([nil VALUE]) */ + if (! MPLIST_TAIL_P (plist)) + mplist_set (plist, Mnil ,NULL); /* () */ + } + else + { + plist = mplist (); + mplist_add (config->vars, Mplist, plist); + M17N_OBJECT_UNREF (plist); + plist = mplist_add (plist, Msymbol, variable); + plist = MPLIST_NEXT (plist); + } + if (value) + { + plist = mplist_add (plist, Msymbol, Mnil); + mplist_add (plist, MPLIST_KEY (value), MPLIST_VAL (value)); + } + } + config_all_variables (im_info); + im_info->tick = time (NULL); + return 0; } /*=*/ /***en - @brief Look up a text produced in the input context. + @brief Get the name of per-user configuration file. + + The minput_config_file () function returns the absolute path name + of per-user configuration file into which minput_save_config () + save configurations. It is usually @c "config.mic" under the + directory @c ".m17n.d" of user's home directory. It is not assured + that the file of the returned name exists nor is + readable/writable. If minput_save_config () fails and returns -1, + an application program might check the file, make it + writable (if possible), and try minput_save_config () again. + + @return + + This function returns a string. As the string is kept in the + library, the caller must not modify nor free it. + + @seealso + minput_save_config () +*/ +/***ja + @brief ¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤Î̾Á°¤òÆÀ¤ë. + + ´Ø¿ô minput_config_file () ¤Ï¡¢´Ø¿ô minput_save_config () ¤¬ÀßÄê¤ò + Êݸ¤¹¤ë¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤Ø¤ÎÀäÂХѥ¹Ì¾¤òÊÖ¤¹¡£Ä̾ï¤Ï¡¢¥æ¡¼¥¶ + ¤Î¥Û¡¼¥à¥Ç¥£¥ì¥¯¥È¥ê¤Î²¼¤Î¥Ç¥£¥ì¥¯¥È¥ê @c ".m17n.d" ¤Ë¤¢¤ë@c + "config.mic" ¤È¤Ê¤ë¡£ÊÖ¤µ¤ì¤¿Ì¾Á°¤Î¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤¹¤ë¤«¡¢Æɤ߽ñ¤­¤Ç + ¤­¤ë¤«¤ÏÊݾڤµ¤ì¤Ê¤¤¡£´Ø¿ôminput_save_config () ¤¬¼ºÇÔ¤·¤Æ -1 ¤òÊÖ + ¤·¤¿¾ì¹ç¤Ë¤Ï¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï¥Õ¥¡¥¤¥ë¤Î¸ºß¤ò³Îǧ¤·¡¢ + ¡Ê¤Ç¤­¤ì¤Ð¡Ë½ñ¤­¹þ¤ß²Äǽ¤Ë¤·ºÆÅÙminput_save_config () ¤ò»î¤¹¤³¤È¤¬ + ¤Ç¤­¤ë¡£ + + @return + + ¤³¤Î´Ø¿ô¤Ïʸ»úÎó¤òÊÖ¤¹¡£Ê¸»úÎó¤Ï¥é¥¤¥Ö¥é¥ê¤¬´ÉÍý¤·¤Æ¤¤¤ë¤Î¤Ç¡¢¸Æ½Ð + ¦¤¬½¤Àµ¤·¤¿¤ê²òÊü¤·¤¿¤ê¤¹¤ë¤³¤È¤Ï¤Ç¤­¤Ê¤¤¡£ + + @seealso + minput_save_config () +*/ + +char * +minput_config_file () +{ + MINPUT__INIT (); + + return mdatabase__file (im_custom_mdb); +} - 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. +/***en + @brief Save configurations in per-user configuration file. - This function calls #MInputDriver::lookup . + The minput_save_config () functions saves the configurations done + so far in the current session into the per-user configuration + file. @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 ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥ÈÃæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹. + If the operation was successful, 1 is returned. If the per-user + configuration file is currently locked, 0 is returned. In that + case, the caller may wait for a while and try again. If the + configuration file is not writable, -1 is returned. In that case, + the caller may check the name of the file by calling + minput_config_file (), make it writable if possible, and try + again. - ´Ø¿ô minput_lookup () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC Ãæ¤Î¥Æ¥­¥¹¥È¤òõ¤¹¡£ - $KEY ¤Ï´Ø¿ô minput_filter () ¤Ø¤ÎľÁ°¤Î¸Æ¤Ó½Ð¤·¤ËÍѤ¤¤é¤ì¤¿¤â¤Î¤ÈƱ¤¸¤Ç¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ + @seealso + minput_config_file () */ +/***ja + @brief ÀßÄê¤ò¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë. - ¥Æ¥­¥¹¥È¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆÀ¸À®¤µ¤ì¤Æ¤¤¤ì¤Ð¡¢¥Æ¥­¥¹¥È¤Ï M-text - $MT ¤ËÏ¢·ë¤µ¤ì¤ë¡£ + ´Ø¿ô minput_save_config () ¤Ï¸½¹Ô¤Î¥»¥Ã¥·¥ç¥ó¤Ç¤³¤ì¤Þ¤Ç¤Ë¹Ô¤Ã¤¿ÀßÄê + ¤ò¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤ËÊݸ¤¹¤ë¡£ - ¤³¤Î´Ø¿ô¤Ï¡¢#MInputDriver::lookup ¤ò¸Æ¤Ö¡£ + @return - @return - $KEY ¤¬ÆþÎϥ᥽¥Ã¥É¤Ë¤è¤Ã¤ÆŬÀڤ˽èÍý¤Ç¤­¤ì¤Ð¡¢¤³¤Î´Ø¿ô¤Ï 0 ¤òÊÖ¤¹¡£ - ¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤¹¡£ - ¤³¤Î¾ì¹ç¤Ç¤â $MT ¤Ë²¿¤é¤«¤Î¥Æ¥­¥¹¥È¤¬À¸À®¤µ¤ì¤Æ¤¤¤ë¤³¤È¤¬¤¢¤ë¡£ + À®¸ù¤¹¤ì¤Ð 1 ¤òÊÖ¤¹¡£¥æ¡¼¥¶Ëè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤¬¥í¥Ã¥¯¤µ¤ì¤Æ¤¤¤ì¤Ð 0 + ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢¸Æ½Ð¦¤Ï¤·¤Ð¤é¤¯ÂԤäƺƻî¹Ô¤Ç¤­¤ë¡£ÀßÄê¥Õ¥¡¥¤¥ë + ¤¬½ñ¤­¹þ¤ßÉԲĤξì¹ç¡¢-1 ¤òÊÖ¤¹¡£¤³¤Î¾ì¹ç¡¢minput_config_file () ¤ò + ¸Æ¤ó¤Ç¥Õ¥¡¥¤¥ë̾¤ò¥Á¥§¥Ã¥¯¤·¡¢¤Ç¤­¤ì¤Ð½ñ¤­¹þ¤ß²Äǽ¤Ë¤·¡¢ºÆ»î¹Ô¤Ç¤­ + ¤ë¡£ - @latexonly \IPAlabel{minput_lookup} @endlatexonly */ + @seealso + minput_config_file () */ int -minput_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt) +minput_save_config (void) { - return (ic ? (*ic->im->driver.lookup) (ic, key, arg, mt) : -1); + MPlist *data, *tail, *plist, *p, *elt; + int ret; + + MINPUT__INIT (); + ret = mdatabase__lock (im_custom_mdb); + if (ret <= 0) + return ret; + if (! im_config_list) + return 1; + update_custom_info (); + if (! im_custom_list) + im_custom_list = mplist (); + data = tail = mplist (); + + MPLIST_DO (plist, im_config_list) + { + MPlist *pl = MPLIST_PLIST (plist); + MSymbol language, name, extra, command, variable; + MInputMethodInfo *custom, *config; + + language = MPLIST_SYMBOL (pl); + pl = MPLIST_NEXT (pl); + name = MPLIST_SYMBOL (pl); + pl = MPLIST_NEXT (pl); + extra = MPLIST_SYMBOL (pl); + pl = MPLIST_NEXT (pl); + config = MPLIST_VAL (pl); + custom = get_custom_info (config); + if (! custom) + custom = new_im_info (NULL, language, name, extra, im_custom_list); + if (config->cmds) + MPLIST_DO (pl, config->cmds) + { + elt = MPLIST_PLIST (pl); + command = MPLIST_SYMBOL (elt); + if (custom->cmds) + p = mplist__assq (custom->cmds, command); + else + custom->cmds = mplist (), p = NULL; + elt = MPLIST_NEXT (elt); + if (MPLIST_TAIL_P (elt)) + { + if (p) + mplist__pop_unref (p); + } + else + { + elt = MPLIST_NEXT (elt); + if (p) + { + p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p))); + mplist_set (p, Mnil, NULL); + mplist__conc (p, elt); + } + else + { + p = MPLIST_PLIST (pl); + mplist_add (custom->cmds, Mplist, p); + } + } + } + if (config->vars) + MPLIST_DO (pl, config->vars) + { + elt = MPLIST_PLIST (pl); + variable = MPLIST_SYMBOL (elt); + if (custom->vars) + p = mplist__assq (custom->vars, variable); + else + custom->vars = mplist (), p = NULL; + elt = MPLIST_NEXT (elt); + if (MPLIST_TAIL_P (elt)) + { + if (p) + mplist__pop_unref (p); + } + else + { + elt = MPLIST_NEXT (elt); + if (p) + { + p = MPLIST_NEXT (MPLIST_NEXT (MPLIST_PLIST (p))); + mplist_set (p, Mnil, NULL); + mplist__conc (p, elt); + } + else + { + p = MPLIST_PLIST (pl); + mplist_add (custom->vars, Mplist, p); + } + } + } + } + M17N_OBJECT_UNREF (im_config_list); + + MPLIST_DO (plist, im_custom_list) + { + MPlist *pl = MPLIST_PLIST (plist); + MSymbol language, name, extra; + MInputMethodInfo *custom, *im_info; + + language = MPLIST_SYMBOL (pl); + pl = MPLIST_NEXT (pl); + name = MPLIST_SYMBOL (pl); + pl = MPLIST_NEXT (pl); + extra = MPLIST_SYMBOL (pl); + pl = MPLIST_NEXT (pl); + custom = MPLIST_VAL (pl); + im_info = lookup_im_info (im_info_list, language, name, extra); + if (im_info) + { + if (im_info->cmds) + config_all_commands (im_info); + if (im_info->vars) + config_all_variables (im_info); + } + + elt = mplist (); + tail = mplist_add (tail, Mplist, elt); + M17N_OBJECT_UNREF (elt); + pl = mplist (); + elt = mplist_add (elt, Mplist, pl); + M17N_OBJECT_UNREF (pl); + pl = mplist_add (pl, Msymbol, Minput_method); + pl = mplist_add (pl, Msymbol, language); + pl = mplist_add (pl, Msymbol, name); + if (extra != Mnil) + pl = mplist_add (pl, Msymbol, extra); + if (custom->cmds && ! MPLIST_TAIL_P (custom->cmds)) + { + pl = mplist (); + elt = mplist_add (elt, Mplist, pl); + M17N_OBJECT_UNREF (pl); + pl = mplist_add (pl, Msymbol, Mcommand); + MPLIST_DO (p, custom->cmds) + pl = mplist_add (pl, Mplist, MPLIST_PLIST (p)); + } + if (custom->vars && ! MPLIST_TAIL_P (custom->vars)) + { + pl = mplist (); + elt = mplist_add (elt, Mplist, pl); + M17N_OBJECT_UNREF (pl); + pl = mplist_add (pl, Msymbol, Mvariable); + MPLIST_DO (p, custom->vars) + pl = mplist_add (pl, Mplist, MPLIST_PLIST (p)); + } + } + + mplist_push (data, Mstring, ";; -*- mode:lisp; coding:utf-8 -*-"); + ret = mdatabase__save (im_custom_mdb, data); + mdatabase__unlock (im_custom_mdb); + M17N_OBJECT_UNREF (data); + return (ret < 0 ? -1 : 1); } + /*=*/ /***en - @brief Set the spot of the input context. + @name Obsolete functions +*/ +/*** @{ */ - 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. +/*=*/ +/***en + @brief Get a list of variables of an input method (obsolete). - 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 ). + This function is obsolete. Use minput_get_variable () instead. - $FONTSIZE specifies the fontsize of preedit text in 1/10 point. + The minput_get_variables () function returns a plist (#MPlist) of + variables used to control the behavior of the input method + specified by $LANGUAGE and $NAME. The plist is @e well-formed + (#m17nPlist) of the following format: - $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. */ +@verbatim + (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] ) + VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] ) + ...) +@endverbatim -/***ja - @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤Î¥¹¥Ý¥Ã¥È¤òÀßÄꤹ¤ë. + @c VARNAME is a symbol representing the variable name. - ´Ø¿ô minput_set_spot () ¤Ï¡¢ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC ¤Î¥¹¥Ý¥Ã¥È¤ò¡¢ºÂɸ ($X, $Y ) - ¤Î°ÌÃÖ¤Ë ¡¢¹â¤µ $ASCENT¡¢ $DESCENT - ¤ÇÀßÄꤹ¤ë¡£ ¤³¤ì¤é¤ÎÃͤΰÕÌ£¤ÏÆþÎϥ᥽¥Ã¥É¥É¥é¥¤¥Ð¤Ë°Í¸¤¹¤ë¡£ + @c DOC-MTEXT is an M-text describing the variable. - ¤¿¤È¤¨¤Ð CUI ´Ä¶­¤ÇÆ°ºî¤¹¤ë¥É¥é¥¤¥Ð¤Ï $X ¤È $Y - ¤ò¤½¤ì¤¾¤ìÎó¤È¹Ô¤ÎÈÖ¹æ¤È¤·¤ÆÍѤ¤¡¢$ASCENT ¤È $DESCENT - ¤ò̵»ë¤¹¤ë¤«¤â¤·¤ì¤Ê¤¤¡£ ¤Þ¤¿¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥àÍѤΥɥ饤¥Ð¤Ï - $X ¤È $Y ¤ò¥¯¥é¥¤¥¢¥ó¥È¥¦¥£¥ó¥É¥¦¤Î¸¶ÅÀ¤«¤é¤Î¥ª¥Õ¥»¥Ã¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¤¡¢ - $ASCENT ¤È $DESCENT ¤ò ($X . $Y ) - ¤ÎÎó¤Î¥¢¥»¥ó¥È¤È¥Ç¥£¥»¥ó¥È¤ò¥Ô¥¯¥»¥ëñ°Ì¤Çɽ¤·¤¿¤â¤Î¤È¤·¤Æ°·¤¦¤«¤â¤·¤ì¤Ê¤¤¡£ + @c DEFAULT-VALUE is the default value of the variable. It is a + symbol, integer, or M-text. - $FONTSIZE ¤Ë¤Ï preedit ¥Æ¥­¥¹¥È¤Î¥Õ¥©¥ó¥È¥µ¥¤¥º¤ò 1/10 ¥Ý¥¤¥ó¥Èñ°Ì¤Ç»ØÄꤹ¤ë¡£ + @c VALUEs (if any) specifies the possible values of the variable. + If @c DEFAULT-VALUE is an integer, @c VALUE may be a plist (@c FROM + @c TO), where @c FROM and @c TO specifies a range of possible + values. - $MT ¤È $POS ¤Ï¤½¤Î¥¹¥Ý¥Ã¥È¤Î M-text ¤Èʸ»ú°ÌÃ֤Ǥ¢¤ë¡£$MT ¤Ï @c - NULL ¤Ç¤â¤è¤¯¡¢¤½¤Î¾ì¹ç¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤Ï¥¹¥Ý¥Ã¥È¼þÊդΥƥ­¥¹¥È¤Ë´Ø¤¹¤ë¾ðÊó¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¡£ - */ + For instance, suppose an input method has the variables: -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); -} -/*=*/ + @li name:intvar, description:"value is an integer", + initial value:0, value-range:0..3,10,20 -/***en - @brief Toggle input method. + @li name:symvar, description:"value is a symbol", + initial value:nil, value-range:a, b, c, nil - The minput_toggle () function toggles the input method associated - with input context $IC. */ + @li name:txtvar, description:"value is an M-text", + initial value:empty text, no value-range (i.e. any text) + + Then, the returned plist is as follows. + +@verbatim + (intvar ("value is an integer" 0 (0 3) 10 20) + symvar ("value is a symbol" nil a b c nil) + txtvar ("value is an M-text" "")) +@endverbatim + + @return + If the input method uses any variables, a pointer to #MPlist is + returned. As the plist is kept in the library, the caller must not + modify nor free it. If the input method does not use any + variable, @c NULL is returned. */ /***ja - @brief ÆþÎϥ᥽¥Ã¥É¤òÀÚÂؤ¨¤ë. + @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë. - ´Ø¿ô minput_toggle () ¤ÏÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC - ¤ËÂбþÉÕ¤±¤é¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ò¥È¥°¥ë¤¹¤ë¡£ - */ + ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ + ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È + (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(#m17nPlist) °Ê + ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£ -void -minput_toggle (MInputContext *ic) -{ - if (ic->im->driver.callback_list) - minput__callback (ic, Minput_toggle); - ic->active = ! ic->active; -} +@verbatim + (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] ) + VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] ) + ...) +@endverbatim -/*=*/ + @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£ -/***en - @brief Reset an input context. + @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£ - 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. */ + @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï + M-text ¤Ç¤¢¤ë¡£ -/***ja - @brief ÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È¤ò¥ê¥»¥Ã¥È¤¹¤ë. + @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤· + @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á + ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£ - ´Ø¿ô minput_reset_ic () ¤Ï #Minput_reset - ¤ËÂбþ¤¹¤ë¥³¡¼¥ë¥Ð¥Ã¥¯´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤Ë¤è¤Ã¤ÆÆþÎÏ¥³¥ó¥Æ¥¯¥¹¥È $IC - ¤ò¥ê¥»¥Ã¥È¤¹¤ë¡£¥ê¥»¥Ã¥È¤È¤Ï¡¢¼ÂºÝ¤Ë¤ÏÆþÎϥ᥽¥Ã¥É¤ò½é´ü¾õÂ֤˰ܤ¹¤³¤È¤Ç¤¢¤ê¡¢¤·¤¿¤¬¤Ã¤Æ¡¢¤â¤·¸½ºßÆþÎÏÃæ¤Î¥Æ¥­¥¹¥È¤¬¤¢¤ì¤Ð¡¢¤½¤ì¤Ï¥³¥ß¥Ã¥È¤µ¤ì¤ë¡£ - ɬÍפʤé¤Ð¡¢¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï minput_lookup () - ¤òÆɤó¤Ç¤½¤Î¥³¥ß¥Ã¥È¤µ¤ì¤¿¥Æ¥­¥¹¥È¤ò¼è¤ê½Ð¤¹¤³¤È¤¬¤Ç¤­¡¢¤½¤ÎºÝ¡¢ - minput_lookup () ¤Î°ú¿ô @c KEY ¤È @c ARG - ¤Ï̵»ë¤µ¤ì¤ë¡£ */ -void -minput_reset_ic (MInputContext *ic) -{ - if (ic->im->driver.callback_list) - minput__callback (ic, Minput_reset); -} + Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£ -/*=*/ + @li name:intvar, ÀâÌÀ:"value is an integer", + ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20 -/***en - @brief Get title and icon filename of an input method. + @li name:symvar, ÀâÌÀ:"value is a symbol", + ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil - The minput_get_title_icon () function returns a plist containing a - title and icon filename (if any) of the input method specifies by - $LANGUAGE and $NAME. + @li name:txtvar, ÀâÌÀ:"value is an M-text", + ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä) - 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 M-text and the value is an M-text of the - icon image (absolute) filename for the same purpose. + ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£ - @return - If there exists the 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 (). -*/ +@verbatim + (intvar ("value is an integer" 0 (0 3) 10 20) + symvar ("value is a symbol" nil a b c nil) + txtvar ("value is an M-text" "")) +@endverbatim + + @return + ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£ + ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ + ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£ */ MPlist * -minput_get_title_icon (MSymbol language, MSymbol name) +minput_get_variables (MSymbol language, MSymbol name) { - MPlist *plist = load_partial_im_info (language, name, Mnil, Mtitle); - MPlist *pl; - char *file = NULL; - MText *mt; - - if (! plist) - return NULL; - if (MPLIST_TAIL_P (plist)) - goto no_title; - pl = MPLIST_PLIST (plist); - pl = MPLIST_NEXT (pl); - if (! MPLIST_MTEXT_P (pl)) - goto no_title; - M17N_OBJECT_REF (pl); - M17N_OBJECT_UNREF (plist); - plist = pl; - pl = MPLIST_NEXT (pl); - if (MPLIST_MTEXT_P (pl)) - { - if (mtext_nchars (MPLIST_MTEXT (pl)) > 0) - { - mt = MPLIST_MTEXT (pl); - file = mdatabase__find_file ((char *) MTEXT_DATA (mt)); - } - } - else if (language != Mnil && name != Mnil) - - { - char *buf = alloca (MSYMBOL_NAMELEN (language) + MSYMBOL_NAMELEN (name) - + 12); + MInputMethodInfo *im_info; + MPlist *vars; - sprintf (buf, "icons/%s-%s.png", (char *) MSYMBOL_NAME (language), - (char *) MSYMBOL_NAME (name)); - file = mdatabase__find_file (buf); - if (! file && language == Mt) - { - sprintf (buf, "icons/%s.png", (char *) MSYMBOL_NAME (name)); - file = mdatabase__find_file (buf); - } - } + MINPUT__INIT (); - if (file) - { - mt = mtext__from_data (file, strlen (file), MTEXT_FORMAT_UTF_8, 1); - free (file); - mplist_set (pl, Mtext, mt); - M17N_OBJECT_UNREF (mt); - } - else - mplist_set (pl, Mnil, NULL); - return plist; + im_info = get_im_info (language, name, Mnil, Mvariable); + if (! im_info || ! im_info->configured_vars) + return NULL; - no_title: - M17N_OBJECT_UNREF (plist); - return NULL; + M17N_OBJECT_UNREF (im_info->bc_vars); + im_info->bc_vars = mplist (); + MPLIST_DO (vars, im_info->configured_vars) + { + MPlist *plist = MPLIST_PLIST (vars); + MPlist *elt = mplist (); + + mplist_push (im_info->bc_vars, Mplist, elt); + mplist_add (elt, Msymbol, MPLIST_SYMBOL (plist)); + elt = MPLIST_NEXT (elt); + mplist_set (elt, Mplist, mplist_copy (MPLIST_NEXT (plist))); + M17N_OBJECT_UNREF (elt); + } + return im_info->bc_vars; } /*=*/ /***en - @brief Get description text of an input method. + @brief Set the initial value of an input method variable. - The minput_get_description () function returns an M-text that - describes the input method specified by $LANGUAGE and $NAME. + The minput_set_variable () function sets the initial value of + input method variable $VARIABLE to $VALUE for the input method + specified by $LANGUAGE and $NAME. + + By default, the initial value is 0. + + This setting gets effective in a newly opened input method. @return - If the specified input method has a description text, a pointer to - #MText is returned. The caller has to free it by m17n_object_unref (). - If the input method does not have a description text, @c NULL is - returned. */ + If the operation was successful, 0 is returned. Otherwise -1 is + returned, and #merror_code is set to #MERROR_IM. */ /***ja - @brief ÆþÎϥ᥽¥Ã¥É¤ÎÀâÌÀ¥Æ¥­¥¹¥È¤òÆÀ¤ë. + @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë. - ´Ø¿ô minput_get_description () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄê - ¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤òÀâÌÀ¤¹¤ë M-text ¤òÊÖ¤¹¡£ + ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME + ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE + ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£ - @return »ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤¬ÀâÌÀ¤¹¤ë¥Æ¥­¥¹¥È¤ò»ý¤Ã¤Æ¤¤¤ì¤Ð¡¢ - #MText ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤½¤ì¤ò m17n_object_unref - () ¤òÍѤ¤¤Æ²òÊü¤·¤Ê¤¯¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ÆþÎϥ᥽¥Ã¥É¤ËÀâÌÀ¥Æ¥­¥¹¥È¤¬Ìµ¤± - ¤ì¤Ð@c NULL ¤òÊÖ¤¹¡£ */ + ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃÍ¤Ï 0 ¤Ç¤¢¤ë¡£ -MText * -minput_get_description (MSymbol language, MSymbol name) + ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£ + + @return + ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢ + #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£ */ + +int +minput_set_variable (MSymbol language, MSymbol name, + MSymbol variable, void *value) { - MPlist *plist = load_partial_im_info (language, name, Mnil, M_description); - MPlist *pl; - MText *mt = NULL; + MPlist *plist, *pl; + MInputMethodInfo *im_info; + int ret; - if (! plist) - return NULL; - if (MPLIST_TAIL_P (plist)) - { - M17N_OBJECT_UNREF (plist); - return NULL; - } - pl = MPLIST_PLIST (plist); - pl = MPLIST_NEXT (pl); - if (MPLIST_MTEXT_P (pl)) + MINPUT__INIT (); + + if (variable == Mnil) + MERROR (MERROR_IM, -1); + plist = minput_get_variable (language, name, variable); + plist = MPLIST_PLIST (plist); + plist = MPLIST_NEXT (plist); + pl = mplist (); + mplist_add (pl, MPLIST_KEY (plist), value); + ret = minput_config_variable (language, name, variable, pl); + M17N_OBJECT_UNREF (pl); + if (ret == 0) { - mt = MPLIST_MTEXT (pl); - M17N_OBJECT_REF (mt); + im_info = get_im_info (language, name, Mnil, Mvariable); + im_info->tick = 0; } - M17N_OBJECT_UNREF (plist); - return mt; + return ret; } +/*=*/ + /***en @brief Get information about input method commands. @@ -4005,13 +5675,35 @@ minput_get_description (MSymbol language, MSymbol name) MPlist * minput_get_commands (MSymbol language, MSymbol name) { - MPlist *plist = get_nested_list (language, name, Mnil, M_command); + MInputMethodInfo *im_info; + MPlist *cmds; + + MINPUT__INIT (); + + im_info = get_im_info (language, name, Mnil, Mcommand); + if (! im_info || ! im_info->configured_vars) + return NULL; + M17N_OBJECT_UNREF (im_info->bc_cmds); + im_info->bc_cmds = mplist (); + MPLIST_DO (cmds, im_info->configured_cmds) + { + MPlist *plist = MPLIST_PLIST (cmds); + MPlist *elt = mplist (); - return (MPLIST_TAIL_P (plist) ? NULL : plist); + mplist_push (im_info->bc_cmds, Mplist, elt); + mplist_add (elt, MPLIST_SYMBOL (plist), + mplist_copy (MPLIST_NEXT (plist))); + M17N_OBJECT_UNREF (elt); + } + return im_info->bc_cmds; } +/*=*/ + /***en - @brief Assign a key sequence to an input method command. + @brief Assign a key sequence to an input method command (obsolete). + + This function is obsolete. Use minput_config_command () instead. The minput_assign_command_keys () function assigns input key sequence $KEYSEQ to input method command $COMMAND for the input @@ -4055,249 +5747,30 @@ int minput_assign_command_keys (MSymbol language, MSymbol name, MSymbol command, MPlist *keyseq) { - MPlist *plist, *pl, *p; - - if (check_command_keyseq (keyseq) < 0 - || ! (plist = get_nested_list (language, name, Mnil, M_command))) - MERROR (MERROR_IM, -1); - pl = mplist_get (plist, command); - if (pl) - { - pl = MPLIST_NEXT (pl); - if (! keyseq) - while ((p = mplist_pop (pl))) - M17N_OBJECT_UNREF (p); - else - { - keyseq = mplist_copy (keyseq); - mplist_push (pl, Mplist, keyseq); - M17N_OBJECT_UNREF (keyseq); - } - } - else - { - if (name == Mnil) - MERROR (MERROR_IM, -1); - if (! keyseq) - return 0; - /* Get global commands. */ - pl = get_nested_list (Mnil, Mnil, Mnil, M_command); - pl = mplist_get (pl, command); - if (! pl) - MERROR (MERROR_IM, -1); - p = mplist (); - mplist_add (p, Mtext, mplist_value (pl)); - keyseq = mplist_copy (keyseq); - mplist_add (p, Mplist, keyseq); - M17N_OBJECT_UNREF (keyseq); - mplist_push (plist, command, p); - } - return 0; -} - -/***en - @brief Get a list of variables of an input method. - - The minput_get_variables () function returns a plist (#MPlist) of - variables used to control the behavior of the input method - specified by $LANGUAGE and $NAME. The plist is @e well-formed - (#m17nPlist) of the following format: - -@verbatim - (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] ) - VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] ) - ...) -@endverbatim - - @c VARNAME is a symbol representing the variable name. - - @c DOC-MTEXT is an M-text describing the variable. - - @c DEFAULT-VALUE is the default value of the variable. It is a - symbol, integer, or M-text. - - @c VALUEs (if any) specifies the possible values of the variable. - If @c DEFAULT-VALUE is an integer, @c VALUE may be a plist (@c FROM - @c TO), where @c FROM and @c TO specifies a range of possible - values. - - For instance, suppose an input method has the variables: - - @li name:intvar, description:"value is an integer", - initial value:0, value-range:0..3,10,20 - - @li name:symvar, description:"value is a symbol", - initial value:nil, value-range:a, b, c, nil - - @li name:txtvar, description:"value is an M-text", - initial value:empty text, no value-range (i.e. any text) - - Then, the returned plist is as follows. - -@verbatim - (intvar ("value is an integer" 0 (0 3) 10 20) - symvar ("value is a symbol" nil a b c nil) - txtvar ("value is an M-text" "")) -@endverbatim - - @return - If the input method uses any variables, a pointer to #MPlist is - returned. As the plist is kept in the library, the caller must not - modify nor free it. If the input method does not use any - variable, @c NULL is returned. */ -/***ja - @brief ÆþÎϥ᥽¥Ã¥É¤ÎÊÑ¿ô¥ê¥¹¥È¤òÆÀ¤ë. - - ´Ø¿ô minput_get_variables () ¤Ï¡¢$LANGUAGE ¤È $NAME ¤Ë¤è¤Ã¤Æ»ØÄꤵ - ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤Î¿¶¤ëÉñ¤¤¤òÀ©¸æ¤¹¤ëÊÑ¿ô¤Î¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È - (#MPlist) ¤òÊÖ¤¹¡£¤³¤Î¥ê¥¹¥È¤Ï @e well-formed ¤Ç¤¢¤ê(#m17nPlist) °Ê - ²¼¤Î·Á¼°¤Ç¤¢¤ë¡£ - -@verbatim - (VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] ) - VARNAME (DOC-MTEXT DEFAULT-VALUE [ VALUE ... ] ) - ...) -@endverbatim - - @c VARNAME ¤ÏÊÑ¿ô¤Î̾Á°¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£ - - @c DOC-MTEXT ¤ÏÊÑ¿ô¤òÀâÌÀ¤¹¤ë M-text ¤Ç¤¢¤ë¡£ - - @c DEFAULT-VALUE ¤ÏÊÑ¿ô¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤǤ¢¤ê¡¢¥·¥ó¥Ü¥ë¡¢À°¿ô¤â¤·¤¯¤Ï - M-text ¤Ç¤¢¤ë¡£ - - @c VALUE ¤Ï¡¢¤â¤·»ØÄꤵ¤ì¤Æ¤¤¤ì¤ÐÊÑ¿ô¤Î¼è¤êÆÀ¤ëÃͤò¼¨¤¹¡£¤â¤· - @c DEFAULT-VALUE ¤¬À°¿ô¤Ê¤é¡¢ @c VALUE ¤Ï (@c FROM @c TO) ¤È¤¤¤¦·Á - ¤Î¥ê¥¹¥È¤Ç¤âÎɤ¤¡£¤³¤Î¾ì¹ç @c FROM ¤È @c TO ¤Ï²Äǽ¤ÊÃͤÎÈϰϤò¼¨¤¹¡£ - - Îã¤È¤·¤Æ¡¢¤¢¤ëÆþÎϥ᥽¥Ã¥É¤¬¼¡¤Î¤è¤¦¤ÊÊÑ¿ô¤ò»ý¤Ä¾ì¹ç¤ò¹Í¤¨¤è¤¦¡£ - - @li name:intvar, ÀâÌÀ:"value is an integer", - ½é´üÃÍ:0, ÃͤÎÈÏ°Ï:0..3,10,20 - - @li name:symvar, ÀâÌÀ:"value is a symbol", - ½é´üÃÍ:nil, ÃͤÎÈÏ°Ï:a, b, c, nil - - @li name:txtvar, ÀâÌÀ:"value is an M-text", - ½é´üÃÍ:empty text, ÃͤÎÈϰϤʤ·(¤É¤ó¤Ê M-text ¤Ç¤â²Ä) - - ¤³¤Î¾ì¹ç¡¢ÊÖ¤µ¤ì¤ë¥ê¥¹¥È¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë¡£ - -@verbatim - (intvar ("value is an integer" 0 (0 3) 10 20) - symvar ("value is a symbol" nil a b c nil) - txtvar ("value is an M-text" "")) -@endverbatim - - @return - ÆþÎϥ᥽¥Ã¥É¤¬²¿¤é¤«¤ÎÊÑ¿ô¤ò»ÈÍѤ·¤Æ¤¤¤ì¤Ð #MPlist ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£ - ÊÖ¤µ¤ì¤ë¥×¥í¥Ñ¥Æ¥£¥ê¥¹¥È¤Ï¥é¥¤¥Ö¥é¥ê¤Ë¤è¤Ã¤Æ´ÉÍý¤µ¤ì¤Æ¤ª¤ê¡¢¸Æ¤Ó½Ð¤·Â¦¤ÇÊѹ¹¤·¤¿¤ê²òÊü¤·¤¿¤ê¤·¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£ - ÆþÎϥ᥽¥Ã¥É¤¬ÊÑ¿ô¤ò°ìÀÚ»ÈÍѤ·¤Æ¤Ê¤±¤ì¤Ð¡¢@c NULL ¤òÊÖ¤¹¡£ */ - -MPlist * -minput_get_variables (MSymbol language, MSymbol name) -{ - MPlist *plist = get_nested_list (language, name, Mnil, M_variable); - - return (MPLIST_TAIL_P (plist) ? NULL : plist); -} - -/***en - @brief Set the initial value of an input method variable. - - The minput_set_variable () function sets the initial value of - input method variable $VARIABLE to $VALUE for the input method - specified by $LANGUAGE and $NAME. - - By default, the initial value is 0. - - This setting gets effective in a newly opened input method. - - @return - If the operation was successful, 0 is returned. Otherwise -1 is - returned, and #merror_code is set to #MERROR_IM. */ -/***ja - @brief ÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô¤Î½é´üÃͤòÀßÄꤹ¤ë. - - ´Ø¿ô minput_set_variable () ¤Ï¡¢$LANGUAGE ¤È $NAME - ¤Ë¤è¤Ã¤Æ»ØÄꤵ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤ÎÆþÎϥ᥽¥Ã¥ÉÊÑ¿ô $VARIABLE - ¤Î½é´üÃͤò¡¢ $VALUE ¤ËÀßÄꤹ¤ë¡£ - - ¥Ç¥Õ¥©¥ë¥È¤Î½é´üÃÍ¤Ï 0 ¤Ç¤¢¤ë¡£ - - ¤³¤ÎÀßÄê¤Ï¡¢¿·¤·¤¯¥ª¡¼¥×¥ó¤µ¤ì¤¿ÆþÎϥ᥽¥Ã¥É¤«¤éÍ­¸ú¤È¤Ê¤ë¡£ - - @return - ½èÍý¤¬À®¸ù¤¹¤ì¤Ð 0 ¤òÊÖ¤¹¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð -1 ¤òÊÖ¤·¡¢ - #merror_code ¤ò #MERROR_IM ¤ËÀßÄꤹ¤ë¡£ */ + int ret; -int -minput_set_variable (MSymbol language, MSymbol name, - MSymbol variable, void *value) -{ - MPlist *plist, *val_element, *range_element; - MSymbol type; + MINPUT__INIT (); - plist = get_nested_list (language, name, Mnil, M_variable); - if (! plist) - MERROR (MERROR_IM, -1); - plist = mplist_find_by_value (plist, variable); - if (! plist) + if (command == Mnil) MERROR (MERROR_IM, -1); - plist = MPLIST_PLIST (MPLIST_NEXT (plist)); - val_element = MPLIST_NEXT (plist); - type = MPLIST_KEY (val_element); - range_element = MPLIST_NEXT (val_element); - - if (! MPLIST_TAIL_P (range_element)) + if (keyseq) { - if (type == Minteger) - { - int val = (int) value, this_val; - - MPLIST_DO (plist, range_element) - { - this_val = (int) MPLIST_VAL (plist); - if (MPLIST_PLIST_P (plist)) - { - int min_bound, max_bound; - MPlist *pl = MPLIST_PLIST (plist); - - min_bound = (int) MPLIST_VAL (pl); - pl = MPLIST_NEXT (pl); - max_bound = (int) MPLIST_VAL (pl); - if (val >= min_bound && val <= max_bound) - break; - } - else if (val == this_val) - break; - } - if (MPLIST_TAIL_P (plist)) - MERROR (MERROR_IM, -1); - } - else if (type == Msymbol) - { - MPLIST_DO (plist, range_element) - if (MPLIST_SYMBOL (plist) == (MSymbol) value) - break; - if (MPLIST_TAIL_P (plist)) - MERROR (MERROR_IM, -1); - } - else /* type == Mtext */ - { - MPLIST_DO (plist, range_element) - if (mtext_cmp (MPLIST_MTEXT (plist), (MText *) value) == 0) - break; - if (MPLIST_TAIL_P (plist)) - MERROR (MERROR_IM, -1); - M17N_OBJECT_REF (value); - } - } + MPlist *plist; - mplist_set (val_element, type, value); - return 0; + if (! check_command_keyseq (keyseq)) + MERROR (MERROR_IM, -1); + plist = mplist (); + mplist_add (plist, Mplist, keyseq); + keyseq = plist; + } + else + keyseq = mplist (); + ret = minput_config_command (language, name, command, keyseq); + M17N_OBJECT_UNREF (keyseq); + return ret; } +/*** @} */ /*** @} */ /*=*/ /*** @addtogroup m17nDebug */