///////////////////////////////////////////////////////////////////////////////
//
// 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 .
*
* 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
* .
*/
/*
** $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
#include
#include
#include
#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[] =
"¡¡£¡¡±££¡ç£¥£¦¡¯£¨£©£ª£«£¬££®£¯£°£±£²£³£´£µ£¶£·£¸£¹£º£»£¼£½£¾£¿"
"£À£Á£Â£Ã£Ä£Å£Æ£Ç£È£É£Ê£Ë£Ì£Í£Î£Ï£Ð£Ñ£Ò£Ó£Ô£Õ£Ö£×£Ø£Ù£Ú¡²£Ü¡³£Þ¡õ"
"¡®£á£â£ã£ä£å£æ£ç£è£é£ê£ë£ì£í£î£ï£ð£ñ£ò£ó£ô£õ£ö£÷£ø£ù£ú£û£ü£ý¡« ";
#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 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