mirror of
https://github.com/VincentWei/MiniGUI.git
synced 2026-02-08 11:52:02 +08:00
1841 lines
49 KiB
C
1841 lines
49 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// IMPORTANT NOTICE
|
||
//
|
||
// The following open source license statement does not apply to any
|
||
// entity in the Exception List published by FMSoft.
|
||
//
|
||
// For more information, please visit:
|
||
//
|
||
// https://www.fmsoft.cn/exception-list
|
||
//
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
/*
|
||
* This file is part of MiniGUI, a mature cross-platform windowing
|
||
* and Graphics User Interface (GUI) support system for embedded systems
|
||
* and smart IoT devices.
|
||
*
|
||
* Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd.
|
||
* Copyright (C) 1998~2002, WEI Yongming
|
||
*
|
||
* This program is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation, either version 3 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
*
|
||
* Or,
|
||
*
|
||
* As this program is a library, any link to this program must follow
|
||
* GNU General Public License version 3 (GPLv3). If you cannot accept
|
||
* GPLv3, you need to be licensed from FMSoft.
|
||
*
|
||
* If you have got a commercial license of this program, please use it
|
||
* under the terms and conditions of the commercial license.
|
||
*
|
||
* For more information about the commercial license, please refer to
|
||
* <http://www.minigui.com/blog/minigui-licensing-policy/>.
|
||
*/
|
||
/*
|
||
** $Id: hzinput.c 8944 2007-12-29 08:29:16Z xwyan $
|
||
**
|
||
** hzinput.c: The GB2312 IME window.
|
||
**
|
||
** Orignally by KANG Xiaoning, some code from cce by He Rui.
|
||
**
|
||
** Copyright (C) 1998, 1999 He Rui (herui@cs.duke.edu)
|
||
** Copyright (C) 1999 Kang Xiaoning.
|
||
** Copyright (C) 2000 Zheng Xiang.
|
||
** Copyright (C) 2000, 2001, 2002 Wei Yongming.
|
||
** Copyright (C) 2003 ~ 2007 Feynman Software.
|
||
**
|
||
** Current maintainer: Wei Yongming
|
||
** Create date: 1999/04/01
|
||
**
|
||
** Used abbreviations:
|
||
** ime: input method
|
||
** punc: punctuate mark
|
||
**
|
||
*/
|
||
|
||
/*
|
||
** This program is free software; you can redistribute it and/or modify
|
||
** it under the terms of the GNU General Public License as published by
|
||
** the Free Software Foundation; either version 2 of the License, or
|
||
** (at your option) any later version.
|
||
**
|
||
** This program is distributed in the hope that it will be useful,
|
||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
** GNU General Public License for more details.
|
||
**
|
||
** You should have received a copy of the GNU General Public License
|
||
** along with this program; if not, write to the Free Software
|
||
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
*/
|
||
|
||
/*
|
||
** Modify records:
|
||
**
|
||
** Who When Where For What
|
||
**-----------------------------------------------------------------------------
|
||
** WEI Yongming 1999/06/14 Tsinghua Message dispatching
|
||
** GONG Xiaorui 1999/07/01 HongShiFang Soft keyboard
|
||
** WEI Yongming 1999/07/17 Tsinghua Add some local functions
|
||
** WEI Yongming 1999/08/24 Tsinghua Remove soft keyboard.
|
||
** WEI Yongming 1999/08/29 Tsinghua Handle some special keys.
|
||
** Wei Yongming 1999/09/01 Tsinghua Translat punc marks.
|
||
** Wei Yongming 1999/09/01 Tsinghua Translat punc marks.
|
||
** Wei Yongming 2000/11/06 BluePoint Merge pinyin module by Zheng Xiang.
|
||
**
|
||
** TODO:
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
|
||
#include "common.h"
|
||
#include "minigui.h"
|
||
#include "gdi.h"
|
||
#include "window.h"
|
||
#include "control.h"
|
||
#include "endianrw.h"
|
||
#include "misc.h"
|
||
|
||
#include "hzinput.h"
|
||
#include "pinyin.h"
|
||
|
||
/************ private functions *******************/
|
||
static BOOL hz_input_init(void);
|
||
static void hz_input_done(void);
|
||
static void unload_input_table(int i);
|
||
static BOOL hz_filter(unsigned char key, LPARAM lParam);
|
||
static int toggle_input_method(void);
|
||
static void toggle_half_full(void);
|
||
static void set_active_input_method(int);
|
||
static void refresh_input_method_area(HWND hwnd, HDC hDC);
|
||
static void DispSelection(HDC hDC);
|
||
|
||
static void FindMatchKey(void);
|
||
static void FillMatchChars(int j);
|
||
static void FillAssociateChars(int index);
|
||
static void FindAssociateKey(int index);
|
||
|
||
static hz_input_table* IntCode_Init(void);
|
||
static void IntCode_FindMatchKey(void);
|
||
static void IntCode_FillMatchChars(int index);
|
||
static void intcode_hz_filter(unsigned char key,LPARAM lParam);
|
||
|
||
/***************************************************************************
|
||
* variable defines *
|
||
***************************************************************************/
|
||
|
||
#define VERSION_STRING "Chinese Input"
|
||
static BOOL bTwoLines;
|
||
static char ime_tab_path [MAX_PATH + 1];
|
||
|
||
static const unsigned char fullchar[] =
|
||
" !”#$%&’()*+,-./0123456789:;<=>?"
|
||
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ〔\〕^□"
|
||
"‘abcdefghijklmnopqrstuvwxyz{|}~ ";
|
||
|
||
#define CPUNCTYPE_1TO1 0
|
||
#define CPUNCTYPE_1TO2 1
|
||
#define CPUNCTYPE_CYCLE 2
|
||
|
||
#define CTRLBTN_WIDTH 16
|
||
#define CTRLBTN_HEIGHT 16
|
||
|
||
typedef struct PuncMark
|
||
{
|
||
unsigned char epunc;
|
||
int type;
|
||
int currone; // only for cycle
|
||
unsigned char* cpunc;
|
||
}PUNCMARK;
|
||
|
||
static PUNCMARK puncmark[] =
|
||
{
|
||
{'`', 0, 0, "·"},
|
||
{'~', 0, 0, "~"},
|
||
{'!', 0, 0, "!"},
|
||
{'@', 0, 0, "℃"},
|
||
{'#', 0, 0, "#"},
|
||
{'$', 0, 0, "¥"},
|
||
{'%', 0, 0, "%"},
|
||
{'^', CPUNCTYPE_1TO2, 0, "……"},
|
||
{'&', 0, 0, "§"},
|
||
{'*', 0, 0, "×"},
|
||
{'_', CPUNCTYPE_1TO2, 0, "——"},
|
||
{'(', CPUNCTYPE_CYCLE, 0, "()"},
|
||
{')', CPUNCTYPE_CYCLE, 0, "〔〕"},
|
||
{'{', CPUNCTYPE_CYCLE, 0, "《》"},
|
||
{'}', CPUNCTYPE_CYCLE, 0, "〈〉"},
|
||
{'[', CPUNCTYPE_CYCLE, 0, "〖〗"},
|
||
{']', CPUNCTYPE_CYCLE, 0, "【】"},
|
||
{'\\', 0, 0, "÷"},
|
||
{'|', 0, 0, "※"},
|
||
{';', 0, 0, ";"},
|
||
{':', 0, 0, ":"},
|
||
{'\'', CPUNCTYPE_CYCLE, 0, "‘’"},
|
||
{'\"', CPUNCTYPE_CYCLE, 0, "“”"},
|
||
{',', 0, 0, ","},
|
||
{'.', 0, 0, "。"},
|
||
{'<', CPUNCTYPE_CYCLE, 0, "「」"},
|
||
{'>', CPUNCTYPE_CYCLE, 0, "『』"},
|
||
{'?', 0, 0, "?"},
|
||
{'/', 0, 0, "、"}
|
||
};
|
||
|
||
static int IsOpened; /* 1 for opened, 0 for closed */
|
||
static int IsHanziInput; /* 0 for ascii, 1 for hanzi input */
|
||
static int IsFullChar; /* 0 for half char, 1 for full char */
|
||
static int IsFullPunc; /* 0 for half punctuate marks, 1 for full marks */
|
||
|
||
static int CurIME;
|
||
static int nIMENr; /* effetive IME method number */
|
||
|
||
static HWND sg_hTargetWnd = 0; // target window of ime.
|
||
|
||
static hz_input_table *input_table[NR_INPUTMETHOD],*cur_table = NULL;
|
||
static char seltab[16][MAX_PHRASE_LENGTH];
|
||
|
||
static int CurSelNum=0; /* Current Total Selection Number */
|
||
static unsigned long InpKey[MAX_INPUT_LENGTH],save_InpKey[MAX_INPUT_LENGTH];
|
||
/* Input key buffer */
|
||
static int InputCount,InputMatch, StartKey,EndKey;
|
||
static int save_StartKey,save_EndKey, save_MultiPageMode,
|
||
save_NextPageIndex, save_CurrentPageIndex;
|
||
static int NextPageIndex,CurrentPageIndex,MultiPageMode;
|
||
/* When enter MultiPageMode:
|
||
StartKey .... CurrentPageIndex .... NextPageIndex .... EndKey
|
||
*/
|
||
static unsigned long val1, val2,key1,key2;
|
||
static int IsAssociateMode;
|
||
static int CharIndex[15]; // starting index of matched char/phrases
|
||
|
||
static const BITMAP* sg_bmpIME; // the bmp of the IME control button
|
||
|
||
static int UseAssociateMode = 0;
|
||
|
||
/* 6 bit a key mask */
|
||
static const unsigned long mask[]=
|
||
{
|
||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||
0x3F000000, 0x3FFC0000, 0x3FFFF000, 0x3FFFFFC0, 0x3FFFFFFF, 0x3FFFFFFF,
|
||
0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF
|
||
};
|
||
|
||
/***************************************************************************
|
||
* some local functions *
|
||
***************************************************************************/
|
||
|
||
static hz_input_table* load_input_method(char *filename)
|
||
{
|
||
#if MGUI_BYTEORDER == MGUI_BIG_ENDIAN
|
||
int i;
|
||
#endif
|
||
|
||
int nread;
|
||
FILE *fd;
|
||
char phrase_filename[100],assoc_filename[100];
|
||
hz_input_table *table;
|
||
|
||
table = calloc (1, sizeof(hz_input_table));
|
||
if (table == NULL)
|
||
return NULL;
|
||
|
||
fd = fopen(filename, "rb");
|
||
if (fd == NULL) {
|
||
free (table);
|
||
return NULL;
|
||
}
|
||
|
||
nread = fread(table, sizeof(hz_input_table),1,fd);
|
||
if (nread != 1) {
|
||
goto fail;
|
||
}
|
||
#if MGUI_BYTEORDER == MGUI_BIG_ENDIAN
|
||
table->TotalKey = ArchSwap32(table->TotalKey);
|
||
table->MaxPress = ArchSwap32(table->MaxPress);
|
||
table->MaxDupSel= ArchSwap32(table->MaxDupSel);
|
||
table->TotalChar= ArchSwap32(table->TotalChar);
|
||
table->PhraseNum= ArchSwap32(table->PhraseNum);
|
||
for (i = 0; i < 64; i++) {
|
||
table->KeyIndex [i] = ArchSwap16(table->KeyIndex[i]);
|
||
}
|
||
#endif
|
||
|
||
if( strcmp(MAGIC_NUMBER, table->magic_number) ) {
|
||
goto fail;
|
||
}
|
||
|
||
table->item = (ITEM *)malloc (sizeof(ITEM) * table->TotalChar);
|
||
if ( table->item == NULL ) {
|
||
goto fail;
|
||
}
|
||
|
||
if (fread (table->item, sizeof(ITEM), table->TotalChar, fd) < table->TotalChar)
|
||
goto fail;
|
||
|
||
#if MGUI_BYTEORDER == MGUI_BIG_ENDIAN
|
||
for (i = 0; i < table->TotalChar; i++) {
|
||
table->item[i].key1 = ArchSwap32(table->item[i].key1);
|
||
table->item[i].key2 = ArchSwap32(table->item[i].key2);
|
||
table->item[i].frequency = ArchSwap16(table->item[i].frequency);
|
||
}
|
||
#endif
|
||
|
||
fclose (fd);
|
||
|
||
if (table->PhraseNum > 0) {
|
||
strcpy( phrase_filename, filename );
|
||
strcat( phrase_filename, ".phr" );
|
||
strcpy( assoc_filename, filename );
|
||
strcat( assoc_filename, ".lx");
|
||
|
||
table->PhraseFile = fopen( phrase_filename, "rb" );
|
||
table->AssocFile = fopen( assoc_filename, "rb");
|
||
|
||
if (table->PhraseFile == NULL || table->AssocFile == NULL) {
|
||
printf("Load Phrase/Assoc File error!\n");
|
||
free(table->item);
|
||
free(table);
|
||
return NULL;
|
||
}
|
||
}
|
||
else {
|
||
table->PhraseFile = table->AssocFile = NULL;
|
||
}
|
||
|
||
return table;
|
||
|
||
fail:
|
||
free (table->item);
|
||
free (table);
|
||
fclose (fd);
|
||
return NULL;
|
||
}
|
||
|
||
static void free_input_method(hz_input_table *table)
|
||
{
|
||
free(table->item);
|
||
free(table);
|
||
}
|
||
|
||
static void ClrIn(void)
|
||
{
|
||
memset(InpKey, 0, sizeof( InpKey));
|
||
memset( seltab, 0, sizeof( seltab));
|
||
|
||
MultiPageMode = NextPageIndex = CurrentPageIndex = 0;
|
||
CurSelNum = InputCount = InputMatch = 0;
|
||
IsAssociateMode = 0; /* lian xiang */
|
||
}
|
||
|
||
static void FindAssociateKey(int index)
|
||
{
|
||
FILE *fp = cur_table->AssocFile;
|
||
int ofs[2],offset;
|
||
|
||
if (index < 0xB0A1)
|
||
{
|
||
StartKey = EndKey = 0;
|
||
return; /* no match */
|
||
}
|
||
|
||
offset = (index / 256 - 0xB0) * 94 + index % 256 - 0xA1;
|
||
fseek(fp, offset * sizeof(int), SEEK_SET);
|
||
fread(ofs,sizeof(int),2,fp);
|
||
#if MGUI_BYTEORDER == MGUI_BIG_ENDIAN
|
||
ofs[0] = ArchSwap32(ofs[0]);
|
||
ofs[1] = ArchSwap32(ofs[1]);
|
||
#endif
|
||
StartKey = 72 * 94 + 1 + ofs[0];
|
||
EndKey = 72 * 94 + 1 + ofs[1];
|
||
}
|
||
|
||
static void load_phrase( int phrno, char *tt )
|
||
{
|
||
FILE *fp = cur_table->PhraseFile;
|
||
int ofs[2], len;
|
||
|
||
fseek( fp, ( phrno + 1 ) << 2, SEEK_SET );
|
||
fread( ofs, sizeof(int), 2, fp );
|
||
#if MGUI_BYTEORDER == MGUI_BIG_ENDIAN
|
||
ofs[0] = ArchSwap32(ofs[0]);
|
||
ofs[1] = ArchSwap32(ofs[1]);
|
||
#endif
|
||
len = ofs[1] - ofs[0];
|
||
|
||
if ( len > 128 || len <= 0 ) {
|
||
strcpy( tt, "error" );
|
||
return;
|
||
}
|
||
|
||
ofs[0] += ( cur_table->PhraseNum + 1 ) << 2;
|
||
/* Add the index area length */
|
||
fseek( fp, ofs[0], SEEK_SET );
|
||
fread( tt, 1, len, fp );
|
||
tt[len] = 0;
|
||
}
|
||
|
||
static void putstr (unsigned char *p ,LPARAM lParam)
|
||
{
|
||
int index,len = strlen(p);
|
||
__mg_ime_writemsg(p, len, lParam, TRUE);
|
||
if (InputCount <= InputMatch) /* All Match */
|
||
{
|
||
index = (int)p[len-2] * 256 + p[len-1];
|
||
ClrIn();
|
||
if (UseAssociateMode)
|
||
{
|
||
FindAssociateKey(index);
|
||
CurrentPageIndex = StartKey;
|
||
MultiPageMode = 0;
|
||
FillAssociateChars(StartKey);
|
||
if (CurSelNum > 0)
|
||
{
|
||
IsAssociateMode = 1;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int nCount = InputCount - InputMatch,nMatch = InputMatch,i;
|
||
MultiPageMode = NextPageIndex = CurrentPageIndex = 0;
|
||
InputCount = InputMatch = 0;
|
||
|
||
for(i = 0; i < nCount; i++)
|
||
save_InpKey[i] = InpKey[nMatch+i];
|
||
|
||
memset(InpKey, 0, sizeof(InpKey));
|
||
for(i = 1; i <= nCount; i++) /* feed the additional keys */
|
||
{
|
||
InpKey[InputCount] = save_InpKey[InputCount];
|
||
InputCount++;
|
||
if (InputCount <= InputMatch+1)
|
||
{
|
||
FindMatchKey();
|
||
MultiPageMode = 0;
|
||
CurrentPageIndex = StartKey;
|
||
FillMatchChars(StartKey);
|
||
}
|
||
}
|
||
if (InputMatch == 0) /* left key has no match, delete */
|
||
{
|
||
ClrIn();
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
static int epunc2cpunc (unsigned char epunc, unsigned char* cpunc)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < 29; i++) {
|
||
if (puncmark [i].epunc == epunc) {
|
||
switch (puncmark [i].type)
|
||
{
|
||
case CPUNCTYPE_1TO1:
|
||
memcpy (cpunc, puncmark [i].cpunc, 2);
|
||
return 2;
|
||
case CPUNCTYPE_1TO2:
|
||
memcpy (cpunc, puncmark [i].cpunc, 4);
|
||
return 4;
|
||
case CPUNCTYPE_CYCLE:
|
||
memcpy (cpunc, puncmark[i].cpunc + puncmark[i].currone, 2);
|
||
if (puncmark[i].currone == 0)
|
||
puncmark[i].currone = 2;
|
||
else
|
||
puncmark[i].currone = 0;
|
||
return 2;
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* After add/delete a char, search the matched char/phrase, update the
|
||
StartKey/EndKey key, save the related keys at first, if no match
|
||
is found, we may restore its original value
|
||
*/
|
||
static void FindMatchKey(void)
|
||
{
|
||
save_StartKey = StartKey;
|
||
save_EndKey = EndKey;
|
||
save_MultiPageMode = MultiPageMode;
|
||
save_NextPageIndex = NextPageIndex;
|
||
save_CurrentPageIndex = CurrentPageIndex;
|
||
|
||
val1 = InpKey[4] | (InpKey[3]<<6) | (InpKey[2]<<12) | (InpKey[1]<<18) |
|
||
(InpKey[0]<<24);
|
||
val2 = InpKey[9] | (InpKey[8]<<6) | (InpKey[7]<<12) | (InpKey[6]<<18) |
|
||
(InpKey[5]<<24);
|
||
|
||
if (InputCount == 1)
|
||
StartKey = cur_table->KeyIndex[InpKey[0]];
|
||
else
|
||
StartKey = CharIndex[InputCount-1];
|
||
|
||
EndKey = cur_table->KeyIndex[InpKey[0]+1];
|
||
|
||
for (; StartKey < EndKey; StartKey++)
|
||
{
|
||
key1 = (cur_table->item[StartKey].key1 & mask[InputCount+5]);
|
||
key2 = (cur_table->item[StartKey].key2 & mask[InputCount]);
|
||
|
||
if (key1 > val1) break;
|
||
if (key1 < val1) continue;
|
||
if (key2 < val2) continue;
|
||
break;
|
||
}
|
||
CharIndex[InputCount] = StartKey;
|
||
}
|
||
|
||
/* Find the matched chars/phrases and fill it into SelTab
|
||
The starting checked index is j
|
||
|
||
The Selection Line 1xxx 2xxx, 80-20=60 60/2=30 chinese chars only
|
||
0-9 Selection can contain only 30 chinese chars
|
||
*/
|
||
|
||
static void FillAssociateChars(int index)
|
||
{
|
||
unsigned char str[25];
|
||
int PhraseNo, CurLen = 0;
|
||
|
||
CurSelNum = 0;
|
||
while( CurSelNum < cur_table->MaxDupSel && index < EndKey &&
|
||
CurLen < MAX_SEL_LENGTH)
|
||
{
|
||
fseek( cur_table->AssocFile, index << 2, SEEK_SET );
|
||
fread( &PhraseNo, sizeof(int), 1, cur_table->AssocFile );
|
||
#if MGUI_BYTEORDER == MGUI_BIG_ENDIAN
|
||
PhraseNo = ArchSwap32(PhraseNo);
|
||
#endif
|
||
load_phrase( PhraseNo, str );
|
||
strcpy(seltab[CurSelNum],str+2);
|
||
CurLen += strlen(seltab[CurSelNum++]);
|
||
index++;
|
||
}
|
||
|
||
/* check if more than one page */
|
||
if ( index < EndKey && CurSelNum == cur_table->MaxDupSel )
|
||
{
|
||
/* has another matched key, so enter MultiPageMode, has more pages */
|
||
NextPageIndex = index;
|
||
MultiPageMode = 1;
|
||
}
|
||
else if (MultiPageMode)
|
||
{
|
||
NextPageIndex = StartKey; /* rotate selection */
|
||
}
|
||
else MultiPageMode = 0;
|
||
}
|
||
|
||
static void FillMatchChars(int j)
|
||
{
|
||
int SelNum = 0, CurLen = 0;
|
||
//bzero( seltab, sizeof( seltab ) );
|
||
|
||
while( ( cur_table->item[j].key1 & mask[InputCount+5] ) == val1 &&
|
||
( cur_table->item[j].key2 & mask[InputCount] ) == val2 &&
|
||
SelNum < cur_table->MaxDupSel && j < EndKey &&
|
||
CurLen < MAX_SEL_LENGTH)
|
||
{
|
||
unsigned short ch = cur_table->item[j].ch;
|
||
#if MGUI_BYTEORDER == MGUI_BIG_ENDIAN
|
||
ch = ArchSwap16 (ch);
|
||
#endif
|
||
|
||
if (ch < 0xA1A1)
|
||
load_phrase (ch, seltab[SelNum]);
|
||
else
|
||
{
|
||
memcpy (&seltab[SelNum], &(cur_table->item[j].ch), 2);
|
||
seltab [SelNum][2] = '\0';
|
||
}
|
||
CurLen += strlen(seltab[SelNum++]);
|
||
j++;
|
||
}
|
||
|
||
if (SelNum == 0) /* some match found */
|
||
{
|
||
StartKey = save_StartKey;
|
||
EndKey = save_EndKey;
|
||
MultiPageMode = save_MultiPageMode;
|
||
NextPageIndex = save_NextPageIndex;
|
||
CurrentPageIndex = save_CurrentPageIndex;
|
||
return; /* keep the original selection */
|
||
}
|
||
|
||
CurSelNum = SelNum;
|
||
|
||
for(SelNum = CurSelNum; SelNum < 16; SelNum++)
|
||
seltab[SelNum][0] = '\0'; /* zero out the unused area */
|
||
InputMatch = InputCount; /* until now we have some matches */
|
||
|
||
/* check if more than one page */
|
||
if ( j < EndKey && (cur_table->item[j].key1 & mask[InputCount+5]) == val1 &&
|
||
( cur_table->item[j].key2 & mask[InputCount] ) == val2 &&
|
||
CurSelNum == cur_table->MaxDupSel )
|
||
{
|
||
/* has another matched key, so enter MultiPageMode, has more pages */
|
||
NextPageIndex = j;
|
||
MultiPageMode = 1;
|
||
}
|
||
else if (MultiPageMode)
|
||
{
|
||
NextPageIndex = StartKey; /* rotate selection */
|
||
}
|
||
else MultiPageMode = 0;
|
||
}
|
||
|
||
/* return value: Has output? */
|
||
static BOOL hz_filter(unsigned char key, LPARAM lParam)
|
||
{
|
||
int inkey = 0,vv;
|
||
char *is_sel_key = (char*)0;
|
||
|
||
if (IsHanziInput) {
|
||
unsigned char cc [2];
|
||
|
||
if (IsFullPunc) {
|
||
unsigned char cpunc[4];
|
||
int len;
|
||
|
||
len = epunc2cpunc (key, cpunc);
|
||
|
||
if (len != 0) {
|
||
__mg_ime_writemsg(cpunc, len, lParam, TRUE);
|
||
ClrIn();
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
if (IsFullChar && key >= ' ' && key <= 127) {
|
||
key = (key - ' ') << 1;
|
||
cc[0] = (unsigned char)(fullchar[key]);
|
||
cc[1] = (unsigned char)(fullchar[key+1]);
|
||
|
||
__mg_ime_writemsg(cc, 2, lParam, TRUE);
|
||
return FALSE;
|
||
}
|
||
}
|
||
else {
|
||
__mg_ime_outchar (key, lParam);
|
||
return FALSE;
|
||
}
|
||
|
||
if (CurIME == 0) {
|
||
intcode_hz_filter(key, lParam);
|
||
return TRUE;
|
||
}
|
||
|
||
#ifdef _IME_GB2312_PINYIN
|
||
if (CurIME == 1) {
|
||
Pinyin_HZFilter (&Pinyin_Module, key, lParam);
|
||
return TRUE;
|
||
}
|
||
#endif
|
||
|
||
switch ( key ) {
|
||
case '\010': /* BackSpace Ctrl+H */
|
||
case '\177': /* BackSpace */
|
||
if ( InputCount > 0 )
|
||
{
|
||
InpKey[--InputCount]=0;
|
||
if (InputCount == 0)
|
||
{
|
||
ClrIn();
|
||
|
||
}
|
||
else if (InputCount < InputMatch)
|
||
{
|
||
FindMatchKey();
|
||
MultiPageMode = 0;
|
||
CurrentPageIndex = StartKey;
|
||
FillMatchChars(StartKey);
|
||
}
|
||
|
||
}
|
||
else __mg_ime_outchar(key,lParam);
|
||
break;
|
||
|
||
case '\033': /* ESCAPE */
|
||
if (InputCount > 0)
|
||
{
|
||
ClrIn();
|
||
|
||
}
|
||
else __mg_ime_outchar(key,lParam);
|
||
break;
|
||
|
||
case '-':
|
||
if ( MultiPageMode )
|
||
{
|
||
if ( CurrentPageIndex > StartKey)
|
||
CurrentPageIndex = CurrentPageIndex - cur_table->MaxDupSel;
|
||
else CurrentPageIndex = StartKey;
|
||
if (IsAssociateMode)
|
||
FillAssociateChars(CurrentPageIndex);
|
||
else FillMatchChars(CurrentPageIndex);
|
||
|
||
}
|
||
else __mg_ime_outchar(key,lParam);
|
||
break;
|
||
|
||
case '=':
|
||
if ( MultiPageMode )
|
||
{
|
||
CurrentPageIndex = NextPageIndex;
|
||
if (IsAssociateMode)
|
||
FillAssociateChars(CurrentPageIndex);
|
||
else FillMatchChars(CurrentPageIndex);
|
||
|
||
}
|
||
else __mg_ime_outchar(key,lParam);
|
||
break;
|
||
|
||
case ' ':
|
||
if ( CurSelNum == 0 )
|
||
__mg_ime_outchar(key,lParam);
|
||
if ( seltab[0][0] )
|
||
putstr(seltab[0],lParam);
|
||
break;
|
||
|
||
default:
|
||
|
||
inkey = cur_table->KeyMap[key];
|
||
is_sel_key = strchr( cur_table->selkey, key);
|
||
vv = is_sel_key - cur_table->selkey;
|
||
/* selkey index, strchr may return NULL */
|
||
|
||
/* if a key is simultaneously inkey & is_sel_key, then selkey first?*/
|
||
if ( (!inkey && !is_sel_key) ||
|
||
(!inkey && is_sel_key && (CurSelNum == 0 || seltab[vv][0] == 0)) )
|
||
{
|
||
IsAssociateMode = 0;
|
||
ClrIn();
|
||
__mg_ime_outchar(key,lParam);
|
||
break;
|
||
}
|
||
|
||
if (is_sel_key && CurSelNum > 0 && seltab[vv][0])
|
||
{
|
||
putstr(seltab[vv],lParam);
|
||
break;
|
||
}
|
||
|
||
/* now it must be inkey? */
|
||
IsAssociateMode = 0;
|
||
if ( inkey >= 1 && InputCount < MAX_INPUT_LENGTH )
|
||
InpKey[InputCount++] = inkey;
|
||
|
||
if (InputCount <= InputMatch+1)
|
||
{
|
||
FindMatchKey();
|
||
CurrentPageIndex = StartKey;
|
||
MultiPageMode = 0;
|
||
FillMatchChars(StartKey);
|
||
if (InputCount >= cur_table->MaxPress && CurSelNum == 1 &&
|
||
cur_table->last_full)
|
||
{
|
||
// left only one selection
|
||
putstr(seltab[0],lParam);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
} /* switch */
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
static void DispSelection(HDC hDC)
|
||
{
|
||
int i, pos = 1;
|
||
|
||
char str[100];
|
||
char minibuf[2];
|
||
minibuf[1]=0;
|
||
str[0]=0;
|
||
if (MultiPageMode && CurrentPageIndex != StartKey)
|
||
{
|
||
strcat(str,"< ");
|
||
pos += 2;
|
||
}
|
||
|
||
for( i = 0; i < CurSelNum; i++ )
|
||
{
|
||
if ( !seltab[i][0] ) {
|
||
if (CurIME == 0 && i == 0)
|
||
continue;
|
||
else
|
||
break;
|
||
}
|
||
|
||
minibuf[0]= input_table[CurIME]->selkey[i];
|
||
strcat(str,minibuf);
|
||
strcat(str,seltab[i]);
|
||
strcat(str," ");
|
||
}
|
||
|
||
if ( MultiPageMode && NextPageIndex != StartKey)
|
||
{
|
||
strcat (str,"> ");
|
||
}
|
||
|
||
if (bTwoLines)
|
||
TextOut (hDC, 2, 18, str);
|
||
else
|
||
TextOut (hDC, 150, 2, str);
|
||
}
|
||
|
||
static void unload_input_table(int i)
|
||
{
|
||
if (((i >= 0) && (i < 10)) && input_table[i])
|
||
{
|
||
if (i == CurIME)
|
||
{
|
||
if (IsHanziInput)
|
||
toggle_input_method();
|
||
CurIME = 0;
|
||
}
|
||
|
||
if (input_table[i]->PhraseFile)
|
||
fclose(input_table[i]->PhraseFile);
|
||
if (input_table[i]->AssocFile)
|
||
fclose(input_table[i]->AssocFile);
|
||
|
||
free_input_method(input_table[i]);
|
||
input_table[i] = NULL;
|
||
}
|
||
}
|
||
|
||
static int toggle_input_method(void)
|
||
{
|
||
if (input_table[CurIME] || CurIME == 1)
|
||
{
|
||
IsHanziInput ^= 1;
|
||
|
||
cur_table = input_table[CurIME];
|
||
ClrIn();
|
||
}
|
||
|
||
return IsHanziInput;
|
||
}
|
||
|
||
static void toggle_half_full(void)
|
||
{
|
||
IsFullChar ^= 1;
|
||
ClrIn();
|
||
}
|
||
|
||
static void toggle_punc (void)
|
||
{
|
||
IsFullPunc ^= 1;
|
||
|
||
ClrIn();
|
||
}
|
||
|
||
static BOOL hz_input_init(void)
|
||
{
|
||
char szFileName[MAX_PATH + 1];
|
||
char szKey[10];
|
||
char szValue[MAX_NAME + 1];
|
||
int number;
|
||
int i;
|
||
|
||
if( GetMgEtcValue ("imeinfo", "imetabpath",
|
||
ime_tab_path, MAX_PATH) < 0 ) {
|
||
fprintf (stderr, "IME: Get imetab file path error!\n");
|
||
return FALSE;
|
||
}
|
||
|
||
IsOpened = 1;
|
||
IsHanziInput = 1; // default is hanzi input
|
||
IsFullChar = 0;
|
||
IsFullPunc = 0;
|
||
CurIME = 0;
|
||
input_table[0] = IntCode_Init();
|
||
if (input_table[0] == NULL)
|
||
return FALSE;
|
||
|
||
#ifdef _IME_GB2312_PINYIN
|
||
if (!InitPinyinInput (ime_tab_path, &Pinyin_Module)) {
|
||
fprintf (stderr, "IME: Init Pinyin module failure!\n");
|
||
unload_input_table (0);
|
||
return FALSE;
|
||
}
|
||
nIMENr = 2;
|
||
#else
|
||
nIMENr = 1;
|
||
#endif
|
||
|
||
if ((sg_bmpIME = GetSystemBitmap (HWND_DESKTOP, SYSBMP_IMECTRLBTN))
|
||
== NULL) {
|
||
fprintf (stderr, "IME: Load the control button failure!\n");
|
||
return FALSE;
|
||
}
|
||
|
||
if( GetMgEtcValue ("imeinfo", "imenumber",
|
||
szValue, 10) < 0 )
|
||
goto error;
|
||
|
||
number = atoi (szValue);
|
||
if(number <= 0)
|
||
goto error;
|
||
|
||
number = (number < NR_INPUTMETHOD) ? number : NR_INPUTMETHOD;
|
||
|
||
for (i = 0; i < number; i++) {
|
||
sprintf(szKey, "ime%d", i);
|
||
if( GetMgEtcValue ("imeinfo",
|
||
szKey, szValue, MAX_NAME) < 0 )
|
||
goto error;
|
||
|
||
#ifdef _DEBUG
|
||
fprintf (stderr, "IME: Loading Input Method %d: %s\n",i, szValue);
|
||
#endif
|
||
|
||
strcpy(szFileName, ime_tab_path);
|
||
strcat(szFileName, szValue);
|
||
strcat(szFileName, ".tab");
|
||
input_table [i + nIMENr] = load_input_method(szFileName);
|
||
|
||
if (!input_table [i + nIMENr])
|
||
goto error;
|
||
}
|
||
|
||
nIMENr += number;
|
||
|
||
if (nIMENr > 1)
|
||
CurIME = 1;
|
||
cur_table = input_table [CurIME];
|
||
|
||
return TRUE;
|
||
|
||
error:
|
||
#ifdef _IME_GB2312_PINYIN
|
||
for (i = 0; i < nIMENr; i++) {
|
||
if (i != 1)
|
||
unload_input_table (i);
|
||
}
|
||
PinyinInputCleanup (ime_tab_path, &Pinyin_Module);
|
||
#else
|
||
for (i = 0; i < nIMENr; i++)
|
||
unload_input_table (i);
|
||
#endif
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static void hz_input_done(void)
|
||
{
|
||
int i;
|
||
|
||
for (i = 0; i < NR_INPUTMETHOD; i++)
|
||
if (input_table[i]) {
|
||
if (input_table[i]->PhraseFile)
|
||
fclose(input_table[i]->PhraseFile);
|
||
if (input_table[i]->AssocFile)
|
||
fclose(input_table[i]->AssocFile);
|
||
|
||
free_input_method(input_table[i]);
|
||
}
|
||
|
||
#ifdef _IME_GB2312_PINYIN
|
||
PinyinInputCleanup (ime_tab_path, &Pinyin_Module);
|
||
#endif
|
||
}
|
||
|
||
static void set_active_input_method(int active)
|
||
{
|
||
#if _IME_GB2312_PINYIN
|
||
if (input_table[active] || active == 1)
|
||
#else
|
||
if (input_table[active])
|
||
#endif
|
||
{
|
||
CurIME = active;
|
||
cur_table = input_table[active];
|
||
ClrIn();
|
||
#if _IME_GB2312_PINYIN
|
||
if (CurIME == 1 || CurIME == 0)
|
||
#else
|
||
if (CurIME == 0)
|
||
#endif
|
||
UseAssociateMode = 0;
|
||
else
|
||
UseAssociateMode = 1;
|
||
}
|
||
}
|
||
|
||
static void refresh_input_method_area(HWND hwnd, HDC hDC)
|
||
{
|
||
RECT rc;
|
||
char str[100];
|
||
int i;
|
||
char minibuf[2];
|
||
WINDOWINFO *info;
|
||
|
||
GetClientRect (hwnd, &rc);
|
||
FillBoxWithBitmapPart (hDC, rc.right - 4 - 32, 2,
|
||
CTRLBTN_WIDTH, CTRLBTN_HEIGHT,
|
||
0, 0,
|
||
sg_bmpIME,
|
||
0, (IsFullChar*CTRLBTN_HEIGHT));
|
||
|
||
FillBoxWithBitmapPart (hDC, rc.right - 4 - 16, 2,
|
||
CTRLBTN_WIDTH, CTRLBTN_HEIGHT,
|
||
0, 0,
|
||
sg_bmpIME,
|
||
CTRLBTN_WIDTH, (IsFullPunc*CTRLBTN_HEIGHT));
|
||
|
||
if (!IsHanziInput) {
|
||
rc.left += 2;
|
||
rc.top += 2;
|
||
info = (WINDOWINFO*)GetWindowInfo (hwnd);
|
||
info->we_rdr->disabled_text_out (hwnd, hDC, "【 En 】", &rc, DT_SINGLELINE);
|
||
}
|
||
#ifdef _IME_GB2312_PINYIN
|
||
else if (CurIME != 1)
|
||
#else
|
||
else
|
||
#endif
|
||
{
|
||
minibuf[1] = 0;
|
||
strcpy (str, input_table[CurIME]->cname);
|
||
|
||
for( i = 0; i <= MAX_INPUT_LENGTH ; i++)
|
||
{
|
||
if (i < InputCount)
|
||
minibuf[0] = input_table[CurIME]->KeyName[InpKey[i]];
|
||
else
|
||
minibuf[0]=' ';
|
||
|
||
if (i == InputMatch && InputCount > InputMatch && i != 0)
|
||
strcat (str,"-");
|
||
|
||
strcat (str,minibuf);
|
||
}
|
||
|
||
TextOut (hDC, 2, 2, str);
|
||
DispSelection (hDC);
|
||
}
|
||
#ifdef _IME_GB2312_PINYIN
|
||
else
|
||
RefreshPYInputArea (&Pinyin_Module, hDC, bTwoLines);
|
||
#endif
|
||
}
|
||
|
||
/*************************************************************************
|
||
* Internal Code Input Method *
|
||
*************************************************************************/
|
||
|
||
static hz_input_table *IntCode_Init(void)
|
||
{
|
||
hz_input_table *table;
|
||
int i,index;
|
||
|
||
UseAssociateMode = 1; /* force to no associate */
|
||
table = malloc(sizeof(hz_input_table));
|
||
if (table == NULL)
|
||
{
|
||
#ifdef _DEBUG
|
||
fprintf(stderr, "IME: load_input_method");
|
||
#endif
|
||
return NULL;
|
||
}
|
||
|
||
/* reset to zero. */
|
||
memset (table, 0, sizeof (hz_input_table));
|
||
|
||
strcpy(table->magic_number,MAGIC_NUMBER);
|
||
strcpy(table->ename, "IntCode");
|
||
strcpy(table->cname, "【内码】");
|
||
strcpy(table->selkey, "0123456789abcdef");
|
||
|
||
table->last_full = 1;
|
||
for(i = 0; i < 128; i++)
|
||
{
|
||
table->KeyMap[i] = 0;
|
||
if ((i >= '0' && i <= '9') || (i >= 'a' && i <= 'f'))
|
||
{
|
||
if (i >= '0' && i <= '9')
|
||
index = i - '0';
|
||
else index = i -'a' + 10;
|
||
table->KeyMap[i] = index;
|
||
table->KeyName[index] = toupper(i);
|
||
}
|
||
}
|
||
return table;
|
||
}
|
||
|
||
/* StartKey <= index < EndKey is valid */
|
||
static void IntCode_FindMatchKey(void)
|
||
{
|
||
unsigned long Key = (InpKey[0] << 12) | (InpKey[1] << 8);
|
||
switch(InputCount)
|
||
{
|
||
case 0:
|
||
case 1:
|
||
StartKey = EndKey = 0; /* not display selection */
|
||
break;
|
||
case 2:
|
||
StartKey = Key + 0xA1;
|
||
EndKey = Key + 0xFF; /* A1-A9,B0-F7 A1-FE */
|
||
break;
|
||
case 3:
|
||
StartKey = Key + (InpKey[2] << 4);
|
||
if (InpKey[2] == 10) StartKey++; /* A1 */
|
||
EndKey = StartKey + 0x10;
|
||
if (InpKey[2] == 15) EndKey--; /* FE */
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* ABCD AB then C=a..f, Sel=0-9 begin display selection
|
||
ABC then D=0-f, Sel=0-f
|
||
*/
|
||
static void IntCode_FillMatchChars(int index)
|
||
{
|
||
int MaxSel,i;
|
||
|
||
CurSelNum = 0;
|
||
if (InputCount < 2) return;
|
||
if (InputCount == 2) MaxSel = 10; else MaxSel = 16;
|
||
|
||
if (index % 256 == 0xA1 && InputCount == 3)
|
||
{
|
||
seltab[0][0] = '\0';
|
||
CurSelNum++;
|
||
}
|
||
|
||
while( CurSelNum < MaxSel && index < EndKey)
|
||
{
|
||
seltab[CurSelNum][0] = index / 256;
|
||
seltab[CurSelNum][1] = index % 256;
|
||
seltab[CurSelNum][2] = '\0';
|
||
CurSelNum++;
|
||
index++;
|
||
}
|
||
|
||
for(i = CurSelNum; i < 16; i++)
|
||
seltab[i][0] = '\0'; /* zero out the unused area */
|
||
|
||
InputMatch = InputCount;
|
||
|
||
/* check if more than one page */
|
||
if ( index < EndKey && CurSelNum == MaxSel && MaxSel == 10)
|
||
{
|
||
/* has another matched key, so enter MultiPageMode, has more pages */
|
||
NextPageIndex = index;
|
||
MultiPageMode = 1;
|
||
}
|
||
else if (MultiPageMode)
|
||
{
|
||
NextPageIndex = StartKey; /* rotate selection */
|
||
}
|
||
else MultiPageMode = 0;
|
||
}
|
||
|
||
static void intcode_hz_filter(unsigned char key,LPARAM lParam)
|
||
{
|
||
int inkey = 0;
|
||
|
||
switch ( key )
|
||
{
|
||
case '\010': /* BackSpace Ctrl+H */
|
||
case '\177': /* BackSpace */
|
||
if ( InputCount > 0 )
|
||
{
|
||
InpKey[--InputCount]=0;
|
||
if (InputCount == 0)
|
||
{
|
||
ClrIn();
|
||
}
|
||
else if (InputCount >= 2)
|
||
{
|
||
IntCode_FindMatchKey();
|
||
MultiPageMode = 0;
|
||
CurrentPageIndex = StartKey;
|
||
IntCode_FillMatchChars(StartKey);
|
||
|
||
}
|
||
}
|
||
else __mg_ime_outchar(key,lParam);
|
||
break;
|
||
|
||
case '\033': /* ESCAPE */
|
||
if (InputCount > 0)
|
||
{
|
||
ClrIn();
|
||
}
|
||
else __mg_ime_outchar(key,lParam);
|
||
break;
|
||
|
||
case '-':
|
||
if ( MultiPageMode )
|
||
{
|
||
if ( CurrentPageIndex > StartKey)
|
||
CurrentPageIndex = CurrentPageIndex - 10;
|
||
else CurrentPageIndex = StartKey;
|
||
IntCode_FillMatchChars(CurrentPageIndex);
|
||
|
||
}
|
||
else __mg_ime_outchar(key,lParam);
|
||
break;
|
||
|
||
case '=':
|
||
if ( MultiPageMode )
|
||
{
|
||
CurrentPageIndex = NextPageIndex;
|
||
IntCode_FillMatchChars(CurrentPageIndex);
|
||
|
||
}
|
||
else __mg_ime_outchar(key,lParam);
|
||
break;
|
||
|
||
case ' ':
|
||
if ( CurSelNum == 0 )
|
||
__mg_ime_outchar(key,lParam);
|
||
if ( seltab[0][0] )
|
||
putstr(seltab[0],lParam);
|
||
break;
|
||
|
||
default:
|
||
inkey = cur_table->KeyMap[key];
|
||
switch(InputCount)
|
||
{
|
||
case 0: /* A-F */
|
||
case 1: /* 0-F */
|
||
case 2: /* A-F */
|
||
if (inkey >=0 && !(InputCount != 1 && inkey < 10) &&
|
||
!(InputCount == 1 &&
|
||
( (InpKey[0]==10 && inkey>9) || //A1-A9
|
||
(InpKey[0]==10 && inkey==0) ||
|
||
(InpKey[0]==15 && inkey>7)) ) ) //B0-F7
|
||
{
|
||
InpKey[InputCount++] = inkey;
|
||
|
||
if (InputCount >=2)
|
||
{
|
||
IntCode_FindMatchKey();
|
||
MultiPageMode = 0;
|
||
CurrentPageIndex = StartKey;
|
||
IntCode_FillMatchChars(StartKey);
|
||
|
||
}
|
||
|
||
}
|
||
else if (InputCount == 2 && inkey >= 0 && inkey < CurSelNum &&
|
||
seltab[inkey][0])
|
||
{
|
||
putstr(seltab[inkey],lParam);
|
||
}
|
||
else /* not select key or input key */
|
||
{
|
||
ClrIn();
|
||
__mg_ime_outchar(key,lParam);
|
||
return;
|
||
}
|
||
break;
|
||
case 3: /* output char */
|
||
if (inkey >=1 && !(InpKey[2] == 10 && inkey == 0) &&
|
||
!(InpKey[2] == 15 && inkey == 15))
|
||
{
|
||
seltab[0][0] = (InpKey[0] << 4) | InpKey[1];
|
||
seltab[0][1] = (InpKey[2] << 4) | inkey ;
|
||
seltab[0][2] = '\0';
|
||
putstr(seltab[0],lParam);
|
||
}
|
||
else
|
||
{
|
||
ClrIn();
|
||
__mg_ime_outchar(key,lParam);
|
||
return;
|
||
}
|
||
break;
|
||
}
|
||
} /* switch */
|
||
}
|
||
|
||
/*************** below are interface to other modules **************/
|
||
/* use these functions in other modules only */
|
||
|
||
/* set current active input method */
|
||
/* this function sets the active input method to ime */
|
||
/* ime value can be: 0 for internal code */
|
||
/* 1 for pinyin */
|
||
/* 2 for wubi */
|
||
static void imeSetStatus(int iStatusCode, int Value)
|
||
{
|
||
switch (iStatusCode) {
|
||
case IS_ENABLE:
|
||
if (Value && !IsHanziInput)
|
||
toggle_input_method ();
|
||
else if (!Value && IsHanziInput)
|
||
toggle_input_method ();
|
||
break;
|
||
|
||
case IS_FULLCHAR:
|
||
if (Value && !IsFullChar)
|
||
toggle_half_full ();
|
||
else if (!Value && IsFullChar)
|
||
toggle_half_full ();
|
||
break;
|
||
|
||
case IS_FULLPUNC:
|
||
if (Value && !IsFullPunc)
|
||
toggle_punc ();
|
||
else if (!Value && IsFullPunc)
|
||
toggle_punc ();
|
||
break;
|
||
|
||
case IS_METHOD:
|
||
if (Value < 0) {
|
||
Value = (CurIME + 1) % nIMENr;
|
||
set_active_input_method (Value);
|
||
}
|
||
else {
|
||
if (Value >= nIMENr)
|
||
Value = nIMENr - 1;
|
||
|
||
if (Value != CurIME)
|
||
set_active_input_method (Value);
|
||
else
|
||
return;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
static int imeGetStatus(int iStatusCode)
|
||
{
|
||
switch (iStatusCode) {
|
||
case IS_ENABLE:
|
||
return IsHanziInput;
|
||
break;
|
||
|
||
case IS_FULLCHAR:
|
||
return IsFullChar;
|
||
break;
|
||
|
||
case IS_FULLPUNC:
|
||
return IsFullPunc;
|
||
break;
|
||
|
||
case IS_METHOD:
|
||
return CurIME;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static inline BOOL imeIsSpecialChar (int chr)
|
||
{
|
||
if (chr == '\t' || chr == '\n' || chr == '\r')
|
||
return TRUE;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static inline BOOL imeIsSpecialKey (int scancode)
|
||
{
|
||
if (scancode == SCANCODE_TAB
|
||
|| scancode == SCANCODE_ENTER
|
||
|| scancode > SCANCODE_F1)
|
||
return TRUE;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static inline BOOL imeIsEffectiveIME (void)
|
||
{
|
||
return IsHanziInput || IsFullChar || IsFullPunc;
|
||
}
|
||
|
||
static int clean_left_ctrl = 1;
|
||
|
||
|
||
/*************************************************************************
|
||
* extern function *
|
||
*************************************************************************/
|
||
void __mg_ime_writemsg (BYTE *buffer, int len, LPARAM lParam, BOOL bDByte)
|
||
{
|
||
WORD wDByte;
|
||
int i;
|
||
|
||
if (bDByte) {
|
||
for (i=0; i<len; i+=2) {
|
||
wDByte = MAKEWORD16 (buffer[i], buffer[i+1]);
|
||
if (sg_hTargetWnd)
|
||
PostMessage (sg_hTargetWnd, MSG_CHAR, wDByte, 0);
|
||
#if defined(_LITE_VERSION) && !defined(_STAND_ALONE)
|
||
else
|
||
Send2ActiveWindow (mgTopmostLayer, MSG_CHAR, wDByte, 0);
|
||
#endif
|
||
}
|
||
}
|
||
else {
|
||
for (i=0; i<len; i++) {
|
||
if (sg_hTargetWnd)
|
||
PostMessage (sg_hTargetWnd, MSG_CHAR, buffer[i], 0);
|
||
#if defined(_LITE_VERSION) && !defined(_STAND_ALONE)
|
||
else
|
||
Send2ActiveWindow (mgTopmostLayer, MSG_CHAR, buffer[i], 0);
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
void __mg_ime_outchar (unsigned char c, LPARAM lParam)
|
||
{
|
||
int scancode = 0;
|
||
|
||
switch (c) {
|
||
case '\010':
|
||
case '\177': /* BackSpace */
|
||
scancode = SCANCODE_BACKSPACE;
|
||
break;
|
||
case '\033':
|
||
scancode = SCANCODE_ESCAPE;
|
||
break;
|
||
case '\t':
|
||
scancode = SCANCODE_TAB;
|
||
break;
|
||
}
|
||
|
||
if (scancode) {
|
||
#if defined(_LITE_VERSION) && !defined(_STAND_ALONE)
|
||
if (!sg_hTargetWnd) {
|
||
Send2ActiveWindow (mgTopmostLayer, MSG_KEYDOWN, scancode, (LPARAM)KS_IMEPOST);
|
||
Send2ActiveWindow (mgTopmostLayer, MSG_KEYUP, scancode, (LPARAM)KS_IMEPOST);
|
||
return;
|
||
}
|
||
#endif
|
||
PostMessage (sg_hTargetWnd, MSG_KEYDOWN, scancode, (LPARAM)KS_IMEPOST);
|
||
PostMessage (sg_hTargetWnd, MSG_KEYUP, scancode, (LPARAM)KS_IMEPOST);
|
||
}
|
||
else
|
||
__mg_ime_writemsg (&c, 1, lParam, FALSE);
|
||
}
|
||
|
||
/* this is the ime window proc */
|
||
int GBIMEWinProc (HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
HDC hdc;
|
||
static BOOL fCaptured = FALSE;
|
||
static int oldx, oldy;
|
||
int x, y;
|
||
int maxx, maxy;
|
||
RECT rcWindow;
|
||
RECT *prcExpect, *prcResult;
|
||
|
||
#if defined(_LITE_VERSION) && !defined(_STAND_ALONE)
|
||
if (message == MSG_KEYDOWN || message == MSG_KEYUP) {
|
||
if (wParam < SCANCODE_KEYPAD7 || wParam > SCANCODE_KEYPADPERIOD)
|
||
{
|
||
if (IsOpened && IsHanziInput) {
|
||
MSG Msg = {hWnd, message, wParam, lParam};
|
||
TranslateMessage (&Msg);
|
||
}
|
||
}
|
||
}
|
||
else if (message == MSG_SYSKEYDOWN) {
|
||
if (sg_hTargetWnd)
|
||
PostMessage (sg_hTargetWnd, message, wParam, lParam);
|
||
else
|
||
Send2ActiveWindow (mgTopmostLayer, MSG_KEYDOWN, wParam, lParam);
|
||
}
|
||
else if (message == MSG_SYSKEYUP) {
|
||
if (sg_hTargetWnd)
|
||
PostMessage (sg_hTargetWnd, message, wParam, lParam);
|
||
else
|
||
Send2ActiveWindow (mgTopmostLayer, MSG_KEYUP, wParam, lParam);
|
||
}
|
||
#endif
|
||
|
||
switch (message) {
|
||
case MSG_NCCREATE:
|
||
if (hz_input_init())
|
||
/* Register before show the window. */
|
||
SendMessage (HWND_DESKTOP, MSG_IME_REGISTER, (WPARAM)hWnd, 0);
|
||
else
|
||
return -1;
|
||
break;
|
||
|
||
case MSG_IME_OPEN:
|
||
if (!IsOpened) {
|
||
ShowWindow(hWnd, SW_SHOW);
|
||
IsOpened = 1;
|
||
}
|
||
break;
|
||
|
||
case MSG_IME_CLOSE:
|
||
if (IsOpened) {
|
||
ShowWindow(hWnd, SW_HIDE);
|
||
IsOpened = 0;
|
||
}
|
||
break;
|
||
|
||
case MSG_IME_SETSTATUS:
|
||
imeSetStatus ((int)wParam, (int)lParam);
|
||
break;
|
||
|
||
case MSG_IME_GETSTATUS:
|
||
return imeGetStatus ((int)wParam);
|
||
break;
|
||
|
||
case MSG_IME_SETTARGET:
|
||
if (sg_hTargetWnd != hWnd)
|
||
sg_hTargetWnd = (HWND)wParam;
|
||
break;
|
||
|
||
case MSG_IME_GETTARGET:
|
||
return (int)sg_hTargetWnd;
|
||
break;
|
||
|
||
case MSG_SETFOCUS:
|
||
case MSG_KILLFOCUS:
|
||
return 0;
|
||
|
||
case MSG_CHAR:
|
||
if (IsOpened && !imeIsSpecialChar (wParam)) {
|
||
if (hz_filter ((BYTE)wParam, lParam))
|
||
InvalidateRect (hWnd, NULL, TRUE);
|
||
}
|
||
return 0;
|
||
|
||
case MSG_KEYDOWN:
|
||
if (wParam != SCANCODE_LEFTCONTROL)
|
||
clean_left_ctrl = 0;
|
||
else
|
||
clean_left_ctrl = 1;
|
||
|
||
if (IsOpened) {
|
||
if (wParam == SCANCODE_SPACE && (lParam & KS_CTRL)) {
|
||
toggle_half_full ();
|
||
InvalidateRect (hWnd, NULL, TRUE);
|
||
return 0;
|
||
}
|
||
else if (wParam == SCANCODE_PERIOD && (lParam & KS_CTRL)) {
|
||
toggle_punc ();
|
||
InvalidateRect (hWnd, NULL, TRUE);
|
||
return 0;
|
||
}
|
||
else if ((wParam == SCANCODE_LEFTSHIFT) && (lParam & KS_CTRL)) {
|
||
imeSetStatus (IS_METHOD, -1);
|
||
InvalidateRect (hWnd, NULL, TRUE);
|
||
return 0;
|
||
}
|
||
|
||
#ifndef _LITE_VERSION
|
||
if (sg_hTargetWnd && imeIsEffectiveIME () && imeIsSpecialKey (wParam))
|
||
PostMessage (sg_hTargetWnd, MSG_KEYDOWN, wParam, lParam);
|
||
#else
|
||
if (!IsHanziInput || (imeIsEffectiveIME () && imeIsSpecialKey (wParam))) {
|
||
if (sg_hTargetWnd)
|
||
PostMessage (sg_hTargetWnd, MSG_KEYDOWN, wParam, lParam);
|
||
#ifndef _STAND_ALONE
|
||
else
|
||
Send2ActiveWindow (mgTopmostLayer, MSG_KEYDOWN, wParam, lParam);
|
||
#endif
|
||
}
|
||
#endif
|
||
}
|
||
#ifdef _LITE_VERSION
|
||
else {
|
||
if (sg_hTargetWnd)
|
||
PostMessage (sg_hTargetWnd, MSG_KEYDOWN, wParam, lParam);
|
||
#ifndef _STAND_ALONE
|
||
else
|
||
Send2ActiveWindow (mgTopmostLayer, MSG_KEYDOWN, wParam, lParam);
|
||
#endif
|
||
}
|
||
#endif
|
||
return 0;
|
||
|
||
case MSG_KEYUP:
|
||
if (IsOpened) {
|
||
if (wParam == SCANCODE_LEFTCONTROL && clean_left_ctrl ) {
|
||
toggle_input_method ();
|
||
InvalidateRect (hWnd, NULL, TRUE);
|
||
}
|
||
|
||
#ifndef _LITE_VERSION
|
||
if (sg_hTargetWnd && imeIsEffectiveIME () && imeIsSpecialKey (wParam))
|
||
PostMessage (sg_hTargetWnd, MSG_KEYUP, wParam, lParam);
|
||
#else
|
||
if (!IsHanziInput || (imeIsEffectiveIME () && imeIsSpecialKey (wParam))) {
|
||
if (sg_hTargetWnd)
|
||
PostMessage (sg_hTargetWnd, MSG_KEYUP, wParam, lParam);
|
||
#ifndef _STAND_ALONE
|
||
else
|
||
Send2ActiveWindow (mgTopmostLayer, MSG_KEYUP, wParam, lParam);
|
||
#endif
|
||
}
|
||
#endif
|
||
}
|
||
#ifdef _LITE_VERSION
|
||
else {
|
||
if (sg_hTargetWnd)
|
||
PostMessage (sg_hTargetWnd, MSG_KEYUP, wParam, lParam);
|
||
#ifndef _STAND_ALONE
|
||
else
|
||
Send2ActiveWindow (mgTopmostLayer, MSG_KEYUP, wParam, lParam);
|
||
#endif
|
||
}
|
||
#endif
|
||
return 0;
|
||
|
||
case MSG_PAINT:
|
||
hdc = BeginPaint (hWnd);
|
||
SetBkColor (hdc,
|
||
GetWindowElementPixelEx (hWnd, hdc, WE_MAINC_THREED_BODY));
|
||
refresh_input_method_area (hWnd, hdc);
|
||
EndPaint (hWnd, hdc);
|
||
return 0;
|
||
|
||
case MSG_LBUTTONDOWN:
|
||
{
|
||
RECT rc;
|
||
int zwidth = GetSysCCharWidth();
|
||
int zheight = GetSysCharHeight();
|
||
|
||
GetClientRect (hWnd, &rc);
|
||
|
||
oldx = LOWORD (lParam);
|
||
oldy = HIWORD (lParam);
|
||
|
||
if (IsHanziInput && oldx > 0 && oldx < 4*zwidth && oldy > 2 && oldy < zheight+2){
|
||
imeSetStatus (IS_METHOD, -1);
|
||
InvalidateRect (hWnd, NULL, TRUE);
|
||
return 0;
|
||
}
|
||
|
||
if (oldx > rc.right - 4 - 32 && oldx < rc.right - 4 - 16 && oldy > 2 && oldy < 16+2){
|
||
toggle_half_full ();
|
||
InvalidateRect (hWnd, NULL, TRUE);
|
||
return 0;
|
||
}
|
||
if (oldx > rc.right - 4 - 16 && oldx < rc.right - 4 && oldy > 2 && oldy < 16+2){
|
||
toggle_punc ();
|
||
InvalidateRect (hWnd, NULL, TRUE);
|
||
return 0;
|
||
}
|
||
|
||
SetCapture (hWnd);
|
||
ClientToScreen (hWnd, &oldx, &oldy);
|
||
fCaptured = TRUE;
|
||
}
|
||
break;
|
||
|
||
case MSG_LBUTTONUP:
|
||
ReleaseCapture ();
|
||
fCaptured = FALSE;
|
||
break;
|
||
|
||
case MSG_MOUSEMOVE:
|
||
if (fCaptured) {
|
||
GetWindowRect (hWnd, &rcWindow);
|
||
x = LOSWORD (lParam);
|
||
y = HISWORD (lParam);
|
||
OffsetRect (&rcWindow, x - oldx, y - oldy);
|
||
MoveWindow (hWnd, rcWindow.left, rcWindow.top,
|
||
RECTW (rcWindow), RECTH (rcWindow), TRUE);
|
||
oldx = x;
|
||
oldy = y;
|
||
}
|
||
break;
|
||
|
||
case MSG_SIZECHANGING:
|
||
prcExpect = (PRECT)wParam;
|
||
prcResult = (PRECT)lParam;
|
||
|
||
*prcResult = *prcExpect;
|
||
if (prcExpect->left < 0) {
|
||
prcResult->left = 0;
|
||
prcResult->right = RECTWP (prcExpect);
|
||
}
|
||
if (prcExpect->top < 0) {
|
||
prcResult->top = 0;
|
||
prcResult->bottom = RECTHP (prcExpect);
|
||
}
|
||
|
||
maxx = GetGDCapability (HDC_SCREEN, GDCAP_HPIXEL);
|
||
maxy = GetGDCapability (HDC_SCREEN, GDCAP_VPIXEL);
|
||
|
||
if (prcExpect->right > maxx) {
|
||
prcResult->right = maxx;
|
||
prcResult->left = maxx - RECTWP (prcExpect);
|
||
}
|
||
|
||
#if 0
|
||
if (prcExpect->bottom > (maxy-80)) {
|
||
prcResult->bottom = maxy-78;
|
||
prcResult->top = (maxy-78) - RECTHP (prcExpect);
|
||
}
|
||
#else
|
||
if (prcExpect->bottom > maxy) {
|
||
prcResult->bottom = maxy;
|
||
prcResult->top = maxy - RECTHP (prcExpect);
|
||
}
|
||
#endif
|
||
|
||
return 0;
|
||
|
||
case MSG_CLOSE:
|
||
SendMessage (HWND_DESKTOP, MSG_IME_UNREGISTER, (WPARAM)hWnd, 0);
|
||
hz_input_done ();
|
||
DestroyMainWindow (hWnd);
|
||
#ifndef _LITE_VERSION
|
||
PostQuitMessage (hWnd);
|
||
#endif
|
||
return 0;
|
||
}
|
||
|
||
return DefaultMainWinProc(hWnd, message, wParam, lParam);
|
||
}
|
||
|
||
static void InitIMEWinCreateInfo (PMAINWINCREATE pCreateInfo)
|
||
{
|
||
pCreateInfo->dwStyle = WS_ABSSCRPOS | WS_BORDER | WS_VISIBLE;
|
||
pCreateInfo->dwExStyle = WS_EX_TOPMOST;
|
||
pCreateInfo->spCaption = "The IME Window" ;
|
||
pCreateInfo->hMenu = 0;
|
||
pCreateInfo->hCursor = GetSystemCursor(0);
|
||
pCreateInfo->hIcon = 0;
|
||
pCreateInfo->MainWindowProc = GBIMEWinProc;
|
||
pCreateInfo->lx = GetGDCapability (HDC_SCREEN, GDCAP_MAXX) - 400;
|
||
pCreateInfo->ty = GetGDCapability (HDC_SCREEN, GDCAP_MAXY) - 80;
|
||
pCreateInfo->rx = GetGDCapability (HDC_SCREEN, GDCAP_MAXX);
|
||
pCreateInfo->by = GetGDCapability (HDC_SCREEN, GDCAP_MAXY) - 40;
|
||
pCreateInfo->iBkColor =
|
||
GetWindowElementPixelEx (HWND_NULL, HDC_SCREEN, WE_MAINC_THREED_BODY);
|
||
pCreateInfo->dwAddData = 0;
|
||
pCreateInfo->hHosting = 0;
|
||
}
|
||
|
||
#ifdef _LITE_VERSION
|
||
HWND GBIMEWindowEx (HWND hosting, int lx, int ty, int rx, int by, BOOL two_lines)
|
||
{
|
||
MAINWINCREATE CreateInfo;
|
||
HWND hMainWnd;
|
||
|
||
#ifndef _STAND_ALONE
|
||
if (!mgIsServer)
|
||
return HWND_INVALID;
|
||
#endif
|
||
|
||
InitIMEWinCreateInfo (&CreateInfo);
|
||
CreateInfo.hHosting = hosting;
|
||
if (lx != 0 || ty != 0 || rx != 0 || by != 0) {
|
||
CreateInfo.lx = lx;
|
||
CreateInfo.ty = ty;
|
||
CreateInfo.rx = rx;
|
||
CreateInfo.by = by;
|
||
bTwoLines = two_lines;
|
||
}
|
||
else
|
||
bTwoLines = TRUE;
|
||
|
||
hMainWnd = CreateMainWindow(&CreateInfo);
|
||
if (hMainWnd == HWND_INVALID)
|
||
return HWND_INVALID;
|
||
|
||
ShowWindow (hMainWnd, SW_SHOWNORMAL);
|
||
|
||
return hMainWnd;
|
||
}
|
||
#else
|
||
|
||
typedef struct ime_info
|
||
{
|
||
sem_t wait;
|
||
HWND hwnd;
|
||
} IME_INFO;
|
||
|
||
static void* start_gb_ime (void* data)
|
||
{
|
||
MSG Msg;
|
||
MAINWINCREATE CreateInfo;
|
||
IME_INFO* ime_info = (IME_INFO*) data;
|
||
HWND ime_hwnd;
|
||
|
||
InitIMEWinCreateInfo (&CreateInfo);
|
||
bTwoLines = TRUE;
|
||
|
||
ime_hwnd = ime_info->hwnd = CreateMainWindow (&CreateInfo);
|
||
sem_post (&ime_info->wait);
|
||
if (ime_hwnd == HWND_INVALID)
|
||
return NULL;
|
||
|
||
while (GetMessage (&Msg, ime_hwnd) ) {
|
||
|
||
if (Msg.message == MSG_KEYDOWN || Msg.message == MSG_KEYUP) {
|
||
if (IsOpened && IsHanziInput)
|
||
TranslateMessage (&Msg);
|
||
else if (sg_hTargetWnd) {
|
||
PostMessage (sg_hTargetWnd,
|
||
Msg.message, Msg.wParam, Msg.lParam | KS_IMEPOST);
|
||
}
|
||
}
|
||
|
||
DispatchMessage(&Msg);
|
||
}
|
||
|
||
MainWindowThreadCleanup (ime_hwnd);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
static pthread_t imethread;
|
||
|
||
/* the argument of 'hosting' is ignored. */
|
||
HWND GBIMEWindow (HWND hosting)
|
||
{
|
||
IME_INFO ime_info;
|
||
pthread_attr_t new_attr;
|
||
|
||
sem_init (&ime_info.wait, 0, 0);
|
||
|
||
pthread_attr_init (&new_attr);
|
||
pthread_attr_setdetachstate (&new_attr, PTHREAD_CREATE_DETACHED);
|
||
pthread_create (&imethread, &new_attr, start_gb_ime, &ime_info);
|
||
pthread_attr_destroy (&new_attr);
|
||
|
||
sem_wait (&ime_info.wait);
|
||
sem_destroy (&ime_info.wait);
|
||
|
||
return ime_info.hwnd;
|
||
}
|
||
|
||
#endif
|
||
|