gen-inp-v1.c

来自「linux 下的 oxim 输入法,简单易用.」· C语言 代码 · 共 1,570 行 · 第 1/3 页

C
1,570
字号
    return cmp;}static int sort_cache(const void *a, const void *b){    cache_t *aa = (cache_t *)a, *bb = (cache_t *)b;    int cmp = strcmp(aa->keystroke, bb->keystroke);    if (cmp == 0)	return 0;    else if (cmp > 0)	return 1;    else	return -1;}static int get_cache(gen_inp_conf_t *cf, char *keystroke, unsigned int *ret_start, unsigned int *ret_end){    int low, middle, high;    int cmp_value;    if (cf->n_cache)    {	low = 0;	high = cf->n_cache - 1;	while (low <= high)	{	    middle = (low+high) >> 1;	    cmp_value = strcmp(cf->cache[middle].keystroke, keystroke);	    if (cmp_value == 0)	    {		break;	    }	    else if (cmp_value > 0)	    {		high = middle - 1;	    }	    else	    {		low = middle + 1;	    }	}	if (cmp_value == 0)	{	    *ret_start = cf->cache[middle].start_idx;	    *ret_end   = cf->cache[middle].end_idx;	    return True;	}    }    return False;}static void set_cache(gen_inp_conf_t *cf, char *keystroke, unsigned int start_idx, unsigned int end_idx){    cf->n_cache ++;    unsigned int cache_pos = cf->n_cache - 1;    if (cf->n_cache == 1)    {	cf->cache = oxim_malloc(sizeof(cache_t), False);    }    else    {	cf->cache = oxim_realloc(cf->cache, sizeof(cache_t) * cf->n_cache);    }    cf->cache[cache_pos].keystroke = strdup(keystroke);    cf->cache[cache_pos].start_idx = start_idx;    cf->cache[cache_pos].end_idx = end_idx;    stable_sort(cf->cache, cf->n_cache, sizeof(cache_t), sort_cache);}static int bsearch_keystroke(gen_inp_conf_t *cf, char *keystroke, int size, int *end_idx){    int head, middle, end, start_idx, last_idx;    int ret;    /* 優先找 cache */    /* 全部存放於記憶體,就不必找 cache */    if (!cf->direct_mode)    {	unsigned int ret_start, ret_end;	if (get_cache(cf, keystroke, &ret_start, &ret_end))	{	    *end_idx = ret_end;	    return (ret_start);	}    }    head   = 0;    middle = size >> 1;    end    = size;    while ((ret=cmp_icvalue(cf, keystroke, middle, False)))    {        if (ret > 0)            end = middle;        else            head = middle + 1;        middle = (end + head) >> 1;        if (middle == head && middle == end)            break;    }    if (ret == 0)    {	start_idx = last_idx = middle;	/* 找該組字的一筆索引 */	while(start_idx > 0 &&	      ! cmp_icvalue(cf, keystroke, start_idx-1, False)) 	{	    start_idx --;	}	/* 找最後一筆索引 */	while(!cmp_icvalue(cf, keystroke, last_idx+1, False))	{	    last_idx++;	}	*end_idx = last_idx;	/* 如果直接讀取磁碟,且同字根數量超過 50,就加入 cache 列表 */	if (cf->direct_mode && (last_idx - start_idx) >= 50)	{	    set_cache(cf, keystroke, start_idx, last_idx);	}	return start_idx;    }    return -1;}static intmatch_keystroke(gen_inp_conf_t *cf, inpinfo_t *inpinfo, gen_inp_iccf_t *iccf){    int ret, start_idx, end_idx;    char *keystroke = iccf->keystroke;    inpinfo->n_mcch = 0;    if (!(iccf->mode & INPINFO_MODE_INWILD))    {	start_idx = bsearch_keystroke(cf, keystroke, cf->header.n_input_content, &end_idx);	if (start_idx < 0)	{	    return False;	}    }    else    {	int i, cmp;	/* 如果只有一個 '*' 或 '?' 沒啥意義,當作沒這回事 :-P */	if (strlen(keystroke) == 1 && (keystroke[0]=='*' || keystroke[0]=='?'))	{	    return False;	}	/* 查 cache */	int first = -1, last;	int hit_cache = get_cache(cf, keystroke, &start_idx, &end_idx);	if (!hit_cache)	{	    start_idx = 0;	    end_idx = cf->header.n_input_content - 1;	}	if (iccf->mkey_list)	{	    free(iccf->mkey_list);	    iccf->mkey_list = NULL;	}	iccf->n_mkey_list = 0;	for (i = start_idx ; i < end_idx ; i++)	{	    cmp = cmp_icvalue(cf, keystroke, i, True);	    if (cmp == 0)	    {		if (first < 0)		{		    first = i;		}		iccf->n_mkey_list ++;		if (iccf->n_mkey_list == 1)		{		    iccf->mkey_list = oxim_malloc(sizeof(unsigned int), False);		}		else		{		    iccf->mkey_list = oxim_realloc(iccf->mkey_list, sizeof(unsigned int)*iccf->n_mkey_list);		}		iccf->mkey_list[iccf->n_mkey_list -1] = i;		last = i;	    }	}	if (!iccf->n_mkey_list)	{	    return False;	}	/* 如果沒有找到 cache, 就設定 cache */	if (!hit_cache)	{	    set_cache(cf, keystroke, first, last);	}	start_idx = 0;	end_idx = iccf->n_mkey_list - 1;    }    iccf->n_record = end_idx - start_idx + 1; /* 總共幾筆紀錄 */    iccf->n_page = iccf->n_record / inpinfo->n_selkey +		   ((iccf->n_record % inpinfo->n_selkey) ? 1 : 0);    iccf->start_idx = start_idx;    iccf->end_idx = end_idx;    iccf->this_page = 0;    ret = fillpage(cf, inpinfo, iccf, 0);    if (inpinfo->n_mcch > 1 && (iccf->mode & INPINFO_MODE_SPACE))    {	iccf->mode &= ~(INPINFO_MODE_SPACE);    }    return ret;}/*------------------------------------------------------------------------*/static voidcommit_content(gen_inp_conf_t *cf, inpinfo_t *inpinfo, gen_inp_iccf_t *iccf, int idx){    static char cch_s[1024];    unsigned int n_char = inpinfo->mcch_grouping[idx+1]; /* 有幾個字? */    unsigned int mcch_idx = 0;    int i;    for (i=0 ; i < idx ; i++)    {	mcch_idx += inpinfo->mcch_grouping[i+1];    }    cch_s[0] = '\0';    while (n_char--)    {	strcat(cch_s, inpinfo->mcch[mcch_idx++].s);    }    inpinfo->cch = cch_s;    inpinfo->cch_publish.uch = 0;    /* 只有單一字元才需要提示字根 */    if (inpinfo->mcch_grouping[idx+1] == 1)    {	/* 計算真正的索引位置 */	/* idx 是目前頁的位置,所以要加上該筆劃的起始偏移值 */	unsigned int new_idx = (iccf->this_page * inpinfo->n_selkey) + idx + iccf->start_idx;	unsigned int true_idx = new_idx;	/* 有萬用字元的話要取 mkey_list[new_idx] */	if (strchr(iccf->keystroke,'*') || strchr(iccf->keystroke,'?'))	{	    true_idx = iccf->mkey_list[new_idx];	}	cintab_input_content cic;	void *icr = get_input_content(cf, true_idx);	/* 字根長度 */	memcpy(&cic.n_keystroke, icr, 1);	/* 字根內容(注意! 沒有包含 NULL 字元) */	cic.keystroke = icr+2;	/* 字元內容 */	cic.content = icr + 2 + cic.n_keystroke;	for (i = 0 ; i < cic.n_keystroke ; i++)	{	    int keycode = cic.keystroke[i];	    inpinfo->suggest_skeystroke[i].uch =		cf->header.keyname[keycode].uch;	}	oxim_ucs4_to_utf8(cic.content[0], inpinfo->cch_publish.s);	free(icr);    }    if (inpinfo->mcch)    {	free(inpinfo->mcch);	inpinfo->mcch = NULL;	inpinfo->n_mcch = 0;    }    inpinfo->keystroke_len = 0;    inpinfo->s_keystroke[0].uch = 0;    inpinfo->mcch_pgstate = MCCH_ONEPG;    iccf->mode &= ~(INPINFO_MODE_MCCH);    iccf->mode &= ~(INPINFO_MODE_INWILD);    inpinfo->guimode &= ~(GUIMOD_SELKEYSPOT);}static unsigned intcommit_keystroke(gen_inp_conf_t *cf, inpinfo_t *inpinfo, gen_inp_iccf_t *iccf)/* return: the IMKEY state */{    if (cf->n_kremap)    {	int i;	for (i=0; i<cf->n_kremap; i++)	{	    if (strcmp(iccf->keystroke, cf->kremap[i].keystroke) == 0)	    {		inpinfo->cch = cf->kremap[i].uch.s;		inpinfo->keystroke_len = 0;		inpinfo->s_keystroke[0].uch = (uchar_t)0;		inpinfo->n_mcch = 0;		inpinfo->cch_publish.uch = 0;		inpinfo->mcch_pgstate = MCCH_ONEPG;		iccf->mode &= ~(INPINFO_MODE_MCCH);		iccf->mode &= ~(INPINFO_MODE_INWILD);		inpinfo->guimode &= ~(GUIMOD_SELKEYSPOT);		return IMKEY_COMMIT;	    }	}    }    if (match_keystroke(cf, inpinfo, iccf))    {        if (inpinfo->n_mcch == 1)	{            commit_content(cf, inpinfo, iccf, 0);            return IMKEY_COMMIT;        }        else	{            iccf->mode |= INPINFO_MODE_MCCH;	    inpinfo->guimode |= GUIMOD_SELKEYSPOT;            return return_correct(cf);        }    }    else    {	if ((cf->mode & INP_MODE_AUTORESET))	{	    reset_keystroke(inpinfo, iccf);	}	else	{	    iccf->mode |= INPINFO_MODE_WRONG;	}        return return_wrong(cf);    }}/*------------------------------------------------------------------------*/static intmcch_choosech(gen_inp_conf_t *cf, 	      inpinfo_t *inpinfo, gen_inp_iccf_t *iccf, int idx){    int min;    if (inpinfo->n_mcch == 0 && ! match_keystroke(cf, inpinfo, iccf))    {        return 0;    }    if (idx < 0)		/* Always select the first. */    {	idx = 0;    }    else    {        if ((cf->mode & INP_MODE_SELKEYSHIFT))	{	    idx ++;	}        min = (inpinfo->n_selkey > inpinfo->n_mcch) ?                 inpinfo->n_mcch : inpinfo->n_selkey;        if (idx >= min)	{            return 0;	}    }    commit_content(cf, inpinfo, iccf, idx);    reset_keystroke(inpinfo, iccf);    return 1;}static intfillpage(gen_inp_conf_t *cf, inpinfo_t *inpinfo, 	 gen_inp_iccf_t *iccf, byte_t dir){    unsigned int n_pg = inpinfo->n_selkey; /* 每一頁顯示項目長度 */    cintab_input_content cic;    void *icr;    unsigned int i, j, idx, item, have_word;    switch (dir)    {	case 0:  /* 從第一頁開始 */	    iccf->this_page = 0;	    break;	case 1:  /* 下一頁 */	    if ((iccf->this_page + 1) >= iccf->n_page)	    {		return False;	    }	    iccf->this_page ++;	    break;	case -1: /* 前一頁 */	    if ((iccf->this_page - 1) < 0)	    {		return False;	    }	    iccf->this_page --;	    break;    }    /* 計算顯示頁的起始索引 */    idx = (iccf->this_page * n_pg) + iccf->start_idx;    /* 本頁筆數 */    if ((iccf->end_idx - idx + 1) < n_pg)    {	n_pg = iccf->end_idx - idx + 1;    }    if (inpinfo->mcch)    {	free(inpinfo->mcch);	inpinfo->mcch = NULL;    }    inpinfo->n_mcch = 0;    inpinfo->mcch_grouping[0] = 0; /* 預設是沒有詞 */    i = 0;    have_word = False;    for (item = 0 ; item < n_pg ; item++)    {	/* 讀取真正的輸入資料 */	icr = get_input_content(cf, ((iccf->mode & INPINFO_MODE_INWILD) ? iccf->mkey_list[idx] : idx));	/* 字根長度 */	memcpy(&cic.n_keystroke, icr, 1);	/* 字元數目 */	memcpy(&cic.n_char, icr+1, 1);	/* 字根內容(注意! 沒有包含 NULL 字元) */	cic.keystroke = icr+2;	/* 字元內容 */	cic.content = icr + 2 + cic.n_keystroke;	/* 加總字元數目 */	inpinfo->n_mcch += cic.n_char;	/* 配置所需的記憶體 */	if (inpinfo->n_mcch == cic.n_char)	{	    inpinfo->mcch = oxim_malloc(sizeof(uch_t) * cic.n_char, False);	}	else	{	    inpinfo->mcch = oxim_realloc(inpinfo->mcch, sizeof(uch_t)*inpinfo->n_mcch);	}	/* i : inpinfo->mcch 的索引	   j : 單一輸入資料字元索引 */	for (j = 0 ; j < cic.n_char; j++, i++)	{	    oxim_ucs4_to_utf8(cic.content[j], inpinfo->mcch[i].s);	}	inpinfo->mcch_grouping[item+1] = cic.n_char; 	/* 超過一個字,表示這是詞 */	if (cic.n_char > 1)	{	    have_word = True;	}	idx ++;	free(icr);    }    inpinfo->mcch_grouping[0] = have_word ? n_pg : 0;    if (iccf->n_page == 1)	inpinfo->mcch_pgstate = MCCH_ONEPG;    else if (iccf->this_page == 0)	inpinfo->mcch_pgstate = MCCH_BEGIN;    else if ((iccf->this_page + 1) == iccf->n_page)	inpinfo->mcch_pgstate = MCCH_END;    else	inpinfo->mcch_pgstate = MCCH_MIDDLE;    return True;}static intmcch_nextpage(gen_inp_conf_t *cf, 	      inpinfo_t *inpinfo, gen_inp_iccf_t *iccf, char key){    int ret=0;    switch (inpinfo->mcch_pgstate) {    case MCCH_ONEPG:	switch (key) {	case ' ':	    if ((cf->mode & INP_MODE_AUTOUPCHAR))                ret = (mcch_choosech(cf, inpinfo, iccf, -1)) ?                	IMKEY_COMMIT : return_wrong(cf);            else                ret = return_correct(cf);	    break;	case '<':	case '>':	    ret = return_correct(cf);	    break;	default:	    ret = return_wrong(cf);	    break;	}	break;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?