#include "hwxobj.h" #include "memmgr.h" #include "hwxfe.h" //980803:ToshiaK #include "dbg.h" #include "cmnhdr.h" #ifdef UNDER_CE // Windows CE Stub for unsupported APIs #include "stub_ce.h" #endif // UNDER_CE // implementation of CHwxThread, CHwxThreadMB, and CHwxThreadCAC //---------------------------------------------------------------- //971217:ToshiaK: comment outed. changed to m_hHwxjpn as non static //---------------------------------------------------------------- //HINSTANCE CHwxThread::m_hHwxjpn = NULL; PHWXCONFIG CHwxThread::lpHwxConfig = NULL; PHWXCREATE CHwxThread::lpHwxCreate = NULL; PHWXSETCONTEXT CHwxThread::lpHwxSetContext = NULL; PHWXSETGUIDE CHwxThread::lpHwxSetGuide = NULL; PHWXALCVALID CHwxThread::lpHwxAlcValid = NULL; PHWXSETPARTIAL CHwxThread::lpHwxSetPartial = NULL; PHWXSETABORT CHwxThread::lpHwxSetAbort = NULL; PHWXINPUT CHwxThread::lpHwxInput = NULL; PHWXENDINPUT CHwxThread::lpHwxEndInput = NULL; PHWXPROCESS CHwxThread::lpHwxProcess = NULL; PHWXRESULTSAVAILABLE CHwxThread::lpHwxResultsAvailable = NULL; PHWXGETRESULTS CHwxThread::lpHwxGetResults = NULL; PHWXDESTROY CHwxThread::lpHwxDestroy = NULL; CHwxThread::CHwxThread():CHwxObject(NULL) { m_thrdID = 0 ; m_hThread = NULL ; m_thrdArg = HWX_PARTIAL_ALL; m_hStopEvent = NULL; //---------------------------------------------------------------- //971217:ToshiaK changed m_hHwxjpn to non static data. //so, Initialize it in Constructor. //---------------------------------------------------------------- m_hHwxjpn = NULL; } CHwxThread::~CHwxThread() { Dbg(("CHwxThread::~CHwxThread START\n")); // if ( IsThreadStarted() ) // { //---------------------------------------------------------------- //970729: ToshiaK temporary, comment out. //---------------------------------------------------------------- // StopThread(); // } if ( m_hHwxjpn ) { // decreament library ref count until it is equal to zero FreeLibrary(m_hHwxjpn); m_hHwxjpn = NULL; } if (m_hStopEvent) { CloseHandle(m_hStopEvent); m_hStopEvent = NULL; } } BOOL CHwxThread::Initialize(TCHAR * pClsName) { BOOL bRet = CHwxObject::Initialize(pClsName); if ( bRet ) { TCHAR tchPath[MAX_PATH]; //TCHAR tchMod[32]; //---------------------------------------------------------------- //980803:ToshiaK. Fareast merge. //---------------------------------------------------------------- CHwxFE::GetRecognizerFileName(m_hInstance, tchPath, sizeof(tchPath)/sizeof(tchPath[0])); //OutputDebugString("hwxthd\n"); //OutputDebugString(tchPath); //OutputDebugString("\n"); //lstrcat(tchPath, tchMod); if ( !m_hHwxjpn ) { // first time load //OutputDebugString(tchPath); m_hHwxjpn = LoadLibrary(tchPath); //m_hHwxjpn = LoadLibrary(TEXT("hwxjpn.dll")); if ( m_hHwxjpn ) { // get HwxXXXXX() API address from hwxjpn.dll #ifndef UNDER_CE lpHwxConfig =(PHWXCONFIG)GetProcAddress(m_hHwxjpn,"HwxConfig"); lpHwxCreate= (PHWXCREATE)GetProcAddress(m_hHwxjpn,"HwxCreate"); lpHwxSetContext= (PHWXSETCONTEXT)GetProcAddress(m_hHwxjpn,"HwxSetContext"); lpHwxSetGuide= (PHWXSETGUIDE)GetProcAddress(m_hHwxjpn,"HwxSetGuide"); lpHwxAlcValid= (PHWXALCVALID)GetProcAddress(m_hHwxjpn,"HwxALCValid"); lpHwxSetPartial= (PHWXSETPARTIAL)GetProcAddress(m_hHwxjpn,"HwxSetPartial"); lpHwxSetAbort= (PHWXSETABORT)GetProcAddress(m_hHwxjpn,"HwxSetAbort"); lpHwxInput= (PHWXINPUT)GetProcAddress(m_hHwxjpn,"HwxInput"); lpHwxEndInput= (PHWXENDINPUT)GetProcAddress(m_hHwxjpn,"HwxEndInput"); lpHwxProcess= (PHWXPROCESS)GetProcAddress(m_hHwxjpn,"HwxProcess"); lpHwxResultsAvailable= (PHWXRESULTSAVAILABLE)GetProcAddress(m_hHwxjpn,"HwxResultsAvailable"); lpHwxGetResults= (PHWXGETRESULTS)GetProcAddress(m_hHwxjpn,"HwxGetResults"); lpHwxDestroy= (PHWXDESTROY)GetProcAddress(m_hHwxjpn,"HwxDestroy"); #else // UNDER_CE lpHwxConfig =(PHWXCONFIG)GetProcAddress(m_hHwxjpn,TEXT("HwxConfig")); lpHwxCreate= (PHWXCREATE)GetProcAddress(m_hHwxjpn,TEXT("HwxCreate")); lpHwxSetContext= (PHWXSETCONTEXT)GetProcAddress(m_hHwxjpn,TEXT("HwxSetContext")); lpHwxSetGuide= (PHWXSETGUIDE)GetProcAddress(m_hHwxjpn,TEXT("HwxSetGuide")); lpHwxAlcValid= (PHWXALCVALID)GetProcAddress(m_hHwxjpn,TEXT("HwxALCValid")); lpHwxSetPartial= (PHWXSETPARTIAL)GetProcAddress(m_hHwxjpn,TEXT("HwxSetPartial")); lpHwxSetAbort= (PHWXSETABORT)GetProcAddress(m_hHwxjpn,TEXT("HwxSetAbort")); lpHwxInput= (PHWXINPUT)GetProcAddress(m_hHwxjpn,TEXT("HwxInput")); lpHwxEndInput= (PHWXENDINPUT)GetProcAddress(m_hHwxjpn,TEXT("HwxEndInput")); lpHwxProcess= (PHWXPROCESS)GetProcAddress(m_hHwxjpn,TEXT("HwxProcess")); lpHwxResultsAvailable= (PHWXRESULTSAVAILABLE)GetProcAddress(m_hHwxjpn,TEXT("HwxResultsAvailable")); lpHwxGetResults= (PHWXGETRESULTS)GetProcAddress(m_hHwxjpn,TEXT("HwxGetResults")); lpHwxDestroy= (PHWXDESTROY)GetProcAddress(m_hHwxjpn,TEXT("HwxDestroy")); #endif // UNDER_CE if ( !lpHwxConfig || !lpHwxCreate || !lpHwxSetContext || !lpHwxSetGuide || !lpHwxAlcValid || !lpHwxSetPartial || !lpHwxSetAbort || !lpHwxInput || !lpHwxEndInput || !lpHwxProcess || !lpHwxResultsAvailable || !lpHwxGetResults || !lpHwxDestroy ) { FreeLibrary(m_hHwxjpn); m_hHwxjpn = NULL; bRet = FALSE; } else { (*lpHwxConfig)(); } } else { bRet = FALSE; } } } if ( bRet && m_hHwxjpn && !IsThreadStarted() ) { bRet = StartThread(); } return bRet; } BOOL CHwxThread::StartThread() { BOOL bRet = FALSE; if ( !(m_hStopEvent = CreateEvent(NULL,FALSE,FALSE,NULL)) ) return bRet; m_Quit = FALSE; #ifndef UNDER_CE // Windows CE does not support THREAD_QUERY_INFORMATION m_hThread = CreateThread(NULL, 0, RealThreadProc, (void *)this, THREAD_QUERY_INFORMATION, &m_thrdID); #else // UNDER_CE m_hThread = CreateThread(NULL, 0, RealThreadProc, (void *)this, 0, &m_thrdID); #endif // UNDER_CE if ( m_hThread ) { if ( IsMyHwxCls(TEXT("CHwxThreadCAC")) ) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); // SetThreadPriority(m_hThread, THREAD_PRIORITY_BELOW_NORMAL); SetThreadPriority(m_hThread, THREAD_PRIORITY_LOWEST); } bRet = TRUE; } return bRet; } void CHwxThread::StopThread() { Dbg(("StopThread START\n")); DWORD dwReturn = 0; if ( m_hThread && IsMyHwxCls(TEXT("CHwxThreadCAC")) ) { //---------------------------------------------------------------- //980817:ToshiaK.Removed SetPriorityClass() line. //This is very dangerous code, because we don't know what applicatin //does about Priority. //In KK's case, In WordPerfect, if we use SetPriorityClass(), //WordPerfect never quit. I don't know why Li-zhang wrote this line. //Anyway, it should be removed. //---------------------------------------------------------------- //SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS); SetThreadPriority(m_hThread, THREAD_PRIORITY_HIGHEST); } if (m_hThread && GetExitCodeThread(m_hThread,&dwReturn) && STILL_ACTIVE == dwReturn ) { INT ret, i; ret = PostThreadMessage(m_thrdID, THRDMSG_EXIT, 0, 0); for(i = 0; i < 100; i++) { Sleep(100); if(m_Quit) { //OutputDebugString("Thread END\n"); Dbg(("Thread Quit\n")); break; } } m_hThread = NULL; //---------------------------------------------------------------- //971202:By Toshiak. Do not use WaitForSigleObject() to syncronize //---------------------------------------------------------------- #ifdef RAID_2926 PostThreadMessage(m_thrdID, THRDMSG_EXIT, 0,0); WaitForSingleObject(m_hStopEvent,INFINITE); m_hThread = NULL ; #endif } Dbg(("StopThread End\n")); } DWORD WINAPI CHwxThread::RealThreadProc(void * pv) { CHwxThread * pCHwxThread = reinterpret_cast(pv); return pCHwxThread->ClassThreadProc() ; } DWORD CHwxThread::ClassThreadProc() { return RecognizeThread(m_thrdArg); } CHwxThreadMB::CHwxThreadMB(CHwxMB * pMB,int nSize) { m_pMB = pMB; #ifdef FE_CHINESE_SIMPLIFIED m_recogMask = ALC_CHS_EXTENDED; #elif FE_KOREAN m_recogMask = ALC_KOR_EXTENDED; #else m_recogMask = ALC_JPN_EXTENDED; #endif m_prevChar = INVALID_CHAR; m_hrcActive = NULL; m_giSent = 0; m_bDirty = FALSE; m_guide.xOrigin = 0; m_guide.yOrigin = 0; m_guide.cxBox = nSize << 3; m_guide.cyBox = nSize << 3; // m_guide.cxBase = 0; m_guide.cyBase = nSize << 3; m_guide.cHorzBox = 256; m_guide.cVertBox = 1; m_guide.cyMid = nSize << 3; m_guide.cxOffset = 0; m_guide.cyOffset = 0; m_guide.cxWriting = nSize << 3; m_guide.cyWriting = nSize << 3; m_guide.nDir = HWX_HORIZONTAL; } CHwxThreadMB::~CHwxThreadMB() { m_pMB = NULL; } BOOL CHwxThreadMB::Initialize(TCHAR * pClsName) { return CHwxThread::Initialize(pClsName); } DWORD CHwxThreadMB::RecognizeThread(DWORD dummy) { MSG msg; int count; // Now we are sitting in our message loop to wait for // the message sent by the main thread while (1) { if (!m_bDirty) { GetMessage(&msg, NULL, 0, 0); } else { if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { m_bDirty = FALSE; (*lpHwxProcess)(m_hrcActive); count = (*lpHwxResultsAvailable)(m_hrcActive); if (count > m_giSent) { GetCharacters(m_giSent, count); m_giSent = count; } continue; } } if (!HandleThreadMsg(&msg)) { //SetEvent(m_hStopEvent); m_Quit = TRUE; return 0; } } m_Quit = TRUE; Unref(dummy); } void CHwxThreadMB::GetCharacters(int iSentAlready, int iReady) { HWXRESULTPRI *pResult, *pHead; HWXRESULTS *pBox; int iIndex; int count = iReady - iSentAlready; pBox = (HWXRESULTS *)MemAlloc(count * (sizeof(HWXRESULTS) + (MB_NUM_CANDIDATES - 1)*sizeof(WCHAR))); if (pBox) { iIndex = (*lpHwxGetResults)(m_hrcActive, MB_NUM_CANDIDATES, iSentAlready, count, pBox); pHead = NULL; for (iIndex = count - 1; iIndex >= 0; iIndex--) { // Index to the correct box results structure. HWXRESULTS *pBoxCur = (HWXRESULTS *) (((char *) pBox) + (iIndex * (sizeof(HWXRESULTS) + (MB_NUM_CANDIDATES - 1) * sizeof(WCHAR)))); pResult = GetCandidates(pBoxCur); if (pResult == NULL) { break; } pResult->pNext = pHead; pHead = pResult; } MemFree((void *)pBox); // Call back to the main thread to dispatch the BOXRESULTS if (pHead) { PostMessage(m_pMB->GetMBWindow(), MB_WM_HWXCHAR, (WPARAM)pHead, 0); } } } ////////////////////////////////////////////////////////////////// // Function : CHwxThreadMB::HandleThreadMsg // Type : BOOL // Purpose : // Args : // : MSG * pMsg // Return : // DATE : Fri Oct 06 20:45:37 2000 // Histroy : 00/10/07: for Satori #2471. // It's very difficult bug. // Old code are following.. // // switch(pMsg->message){ // : // case THRDMSG_EXIT: // default: // return FALSE; // } // if HandlThreadMsg() receive unknown message, // it always return False, then Thread quits!!!!. // In Cicero environment, somebody post unkonwn message, // to this Thread ID, when IMM IME is switched to Another IMM IME. // IMEPad uses AttachThreadInput() attached application process's thread ID, // Message is duplicated and HW thread receive this illegal // message ID. // So, I changed to return TRUE if HW thread receive unkonwn message // // switch(pMsg->message){ // : // case THRDMSG_EXIT: // return FALSE; // default: // return TRUE; // } // ////////////////////////////////////////////////////////////////// BOOL CHwxThreadMB::HandleThreadMsg(MSG *pMsg) { PSTROKE pstr; int iIndex; int count; switch (pMsg->message) { case THRDMSG_ADDINK: pstr = (PSTROKE) pMsg->lParam; if (!pstr) return TRUE; if (m_hrcActive == NULL) { m_giSent = 0; m_hrcActive = (*lpHwxCreate)((HRC)NULL); if (m_hrcActive == NULL) return TRUE; m_guide.cxBox = m_guide.cyBox = m_guide.cyBase = pMsg->wParam << 3; m_guide.cyMid = m_guide.cxWriting = m_guide.cyWriting = pMsg->wParam << 3; (*lpHwxSetGuide)(m_hrcActive, &m_guide); // Setup the ALC mask everytime we do recognization (*lpHwxAlcValid)(m_hrcActive, m_recogMask); // Setup the context information if we have a valid prevChar if (m_prevChar != INVALID_CHAR) { WCHAR ctxtChar; // Get the correct context if( FoldStringW(MAP_FOLDCZONE, &m_prevChar, 1, &ctxtChar, 1) ) { (*lpHwxSetContext)(m_hrcActive, ctxtChar); } } } count = (pstr->iBox * pMsg->wParam) << 3; // Compute the offset for the box logically. for (iIndex = 0; iIndex < pstr->cpt; iIndex++) { pstr->apt[iIndex].x = ((pstr->apt[iIndex].x - pstr->xLeft) << 3) + count; pstr->apt[iIndex].y = (pstr->apt[iIndex].y << 3); } (*lpHwxInput)(m_hrcActive, pstr->apt,pstr->cpt,0); MemFree((void *)pstr); m_bDirty = TRUE; return TRUE; case THRDMSG_RECOGNIZE: if (m_hrcActive == NULL) { return(TRUE); } (*lpHwxEndInput)(m_hrcActive); (*lpHwxProcess)(m_hrcActive); // // We only get back the top 6 candidates. // count = pMsg->wParam; // # of boxes written in is sent here. if (count > m_giSent) { GetCharacters(m_giSent, count); m_giSent = count; } (*lpHwxDestroy)(m_hrcActive); m_bDirty = FALSE; m_hrcActive = NULL; return TRUE; // case THRDMSG_CHAR: // PostMessage(m_pMB->GetMBWindow(), MB_WM_COMCHAR, pMsg->wParam, 0); // return TRUE; case THRDMSG_SETMASK: m_recogMask = pMsg->wParam; return TRUE; case THRDMSG_SETCONTEXT: m_prevChar = (WCHAR) pMsg->wParam; return TRUE; case THRDMSG_EXIT: default: //---------------------------------------------------------------- //Satori #2471:return TRUE not to quit thread accicentaly. //---------------------------------------------------------------- return TRUE; } } HWXRESULTPRI * CHwxThreadMB::GetCandidates(HWXRESULTS *pbox) { HWXRESULTPRI *pResult; int i; pResult = (HWXRESULTPRI *)MemAlloc(sizeof(HWXRESULTPRI)); if (!pResult) return NULL; pResult->pNext = NULL; for ( i=0; ichCandidate[i] = pbox->rgChar[i]; if ( !pbox->rgChar[i] ) break; } pResult->cbCount = (USHORT)i; pResult->iSelection = 0; return pResult; } CHwxThreadCAC::CHwxThreadCAC(CHwxCAC * pCAC) { m_pCAC = pCAC; } CHwxThreadCAC::~CHwxThreadCAC() { m_pCAC = NULL; } BOOL CHwxThreadCAC::Initialize(TCHAR * pClsName) { return CHwxThread::Initialize(pClsName); } DWORD CHwxThreadCAC::RecognizeThread(DWORD dwPart) { MSG msg; //UINT nPartial = dwPart; HRC hrc; HWXGUIDE guide; BOOL bRecog; DWORD cstr; STROKE *pstr; // Create the initial hrc for this thread, set the recognition paramters. hrc = (*lpHwxCreate)((HRC) NULL); if ( !hrc ) return 0; guide.xOrigin = 0; guide.yOrigin = 0; guide.cxBox = 1000; guide.cyBox = 1000; // guide.cxBase = 0; guide.cyBase = 1000; guide.cHorzBox = 1; guide.cVertBox = 1; guide.cyMid = 1000; guide.cxOffset = 0; guide.cyOffset = 0; guide.cxWriting = 1000; guide.cyWriting = 1000; guide.nDir = HWX_HORIZONTAL; (*lpHwxSetGuide)(hrc, &guide); // Set the guide // (*lpHwxSetPartial)(hrc, nPartial); // Set the recognition type (*lpHwxSetAbort)(hrc,(UINT *)m_pCAC->GetStrokeCountAddress()); // Set the abort address // Begin the message loop while (TRUE) { bRecog = FALSE; // Wait until we're told to recognize. if(GetMessage(&msg, NULL, 0, 0) == FALSE) { if ( hrc ) (*lpHwxDestroy)(hrc); hrc = NULL; //971202: removed by Toshiak //SetEvent(m_hStopEvent); m_Quit = TRUE; Dbg(("Recognize Thread END\n")); return 0; } // We'll eat all the incoming messages do { switch (msg.message) { case THRDMSG_SETGUIDE: guide.cxBox = msg.wParam; guide.cyBox = msg.wParam; guide.cyBase = msg.wParam; guide.cyMid = msg.wParam; guide.cxWriting = msg.wParam; guide.cyWriting = msg.wParam; (*lpHwxSetGuide)(hrc, &guide); // Set the guide break; case THRDMSG_RECOGNIZE: bRecog = TRUE; break; case THRDMSG_EXIT: if ( hrc ) (*lpHwxDestroy)(hrc); hrc = NULL; //971202: removed by ToshiaK //SetEvent(m_hStopEvent); m_Quit = TRUE; Dbg(("Recognize Thread END\n")); return 0; default: break; } } while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)); // Was there a message to recognize? if (!bRecog) continue; bRecog = FALSE; // Count the number of valid strokes cstr = 0; pstr = m_pCAC->GetStrokePointer(); while (pstr) { cstr++; pstr = pstr->pNext; } // If the available stroke count doesn't match the actual stroke count, exit if ((cstr != (DWORD)m_pCAC->GetStrokeCount()) || (!cstr)) { continue; } recoghelper(hrc,HWX_PARTIAL_ALL,cstr); recoghelper(hrc,HWX_PARTIAL_ORDER,cstr); recoghelper(hrc,HWX_PARTIAL_FREE,cstr); } m_Quit = TRUE; Unref(dwPart); } void CHwxThreadCAC::recoghelper(HRC hrc,DWORD dwPart,DWORD cstr) { UINT nPartial = dwPart; HRC hrcTmp; DWORD dwTick; HWXRESULTS *pbox; int ires; STROKE *pstr; int nSize = dwPart != HWX_PARTIAL_ALL ? PREFIXLIST : FULLLIST; pbox = (HWXRESULTS *)MemAlloc(sizeof(HWXRESULTS) + nSize * sizeof(WCHAR)); if ( !pbox ) { return; } hrcTmp = (*lpHwxCreate)(hrc); (*lpHwxSetPartial)(hrcTmp, nPartial); // Set the recognition type // (*lpHwxSetAbort)(hrcTmp,(UINT *)m_pCAC->GetStrokeCountAddress()); // Set the abort address pstr = m_pCAC->GetStrokePointer(); dwTick = 0; while (pstr) { dwTick +=3641L; (*lpHwxInput)(hrcTmp, pstr->apt,pstr->cpt, dwTick); pstr = pstr->pNext; } memset(pbox, '\0', sizeof(HWXRESULTS) + nSize * sizeof(WCHAR)); // Call the recognizer for results (*lpHwxEndInput)(hrcTmp); (*lpHwxProcess)(hrcTmp); (*lpHwxGetResults)(hrcTmp, nSize, 0, 1, pbox); (*lpHwxDestroy)(hrcTmp); // Return the results ires = 0; while (pbox->rgChar[ires]) { if (cstr != (DWORD)m_pCAC->GetStrokeCount()) break; SendMessage(m_pCAC->GetCACWindow(), CAC_WM_RESULT, (nPartial << 8) | cstr, MAKELPARAM((pbox->rgChar[ires]), ires)); ires++; } MemFree((void *)pbox); if ( ires ) { SendMessage(m_pCAC->GetCACWindow(), CAC_WM_SHOWRESULT,0,0); } } void CHwxThreadCAC::RecognizeNoThread(int nSize) { HRC hrc; HWXGUIDE guide; STROKE *pstr; long numstrk = 0; if (( pstr = m_pCAC->GetStrokePointer()) == (STROKE *) NULL) return; // Create the initial hrc for this thread, set the recognition paramters. hrc = (*lpHwxCreate)((HRC) NULL); if ( !hrc ) return; guide.xOrigin = 0; guide.yOrigin = 0; guide.cxBox = nSize; guide.cyBox = nSize; // guide.cxBase = 0; guide.cyBase = nSize; guide.cHorzBox = 1; guide.cVertBox = 1; guide.cyMid = 0; guide.cxOffset = 0; guide.cyOffset = 0; guide.cxWriting = nSize; guide.cyWriting = nSize; guide.nDir = HWX_HORIZONTAL; (*lpHwxSetGuide)(hrc, &guide); // Set the guide // (*lpHwxSetPartial)(hrc,HWX_PARTIAL_ALL); // Set the recognition type (*lpHwxSetAbort)(hrc,(UINT *)m_pCAC->GetStrokeCountAddress()); numstrk = m_pCAC->GetStrokeCount(); recoghelper(hrc,HWX_PARTIAL_ALL,numstrk); recoghelper(hrc,HWX_PARTIAL_ORDER,numstrk); // recoghelper(hrc,HWX_PARTIAL_FREE,numstrk); (*lpHwxDestroy)(hrc); }