/**************************************************************************** APIENTRY.CPP Owner: cslim Copyright (c) 1997-1999 Microsoft Corporation API entries between IMM32 and IME History: 14-JUL-1999 cslim Copied from IME98 source tree *****************************************************************************/ #include "precomp.h" #include "apientry.h" #include "common.h" #include "ui.h" #include "hauto.h" #include "dllmain.h" #include "hanja.h" #include "escape.h" #include "config.h" #include "names.h" #include "winex.h" #include "hanja.h" #include "cpadsvr.h" #include "debug.h" /////////////////////////////////////////////////////////////////////////////// // ImeMenu Define #define NUM_ROOT_MENU_L 4 #define NUM_ROOT_MENU_R 1 #define NUM_SUB_MENU_L 0 #define NUM_SUB_MENU_R 0 #define IDIM_ROOT_ML_1 0x10 #define IDIM_ROOT_ML_2 0x11 #define IDIM_ROOT_ML_3 0x12 #define IDIM_ROOT_ML_4 0x13 #define IDIM_ROOT_MR_1 0x30 /////////////////////////////////////////////////////////////////////////////// // Private function Declarations PRIVATE BOOL IsInSystemSetupMode(); PRIVATE BOOL IsRunningAsLocalSystem(); PRIVATE BOOL IsRunningInOOBE(); PRIVATE BOOL PASCAL Select(HIMC hImc, BOOL fSelect); PRIVATE VOID PASCAL UpdateOpenCloseState(PCIMECtx pImeCtx); PRIVATE VOID PASCAL ToAsciiExHangulMode(PCIMECtx pImeCtx, UINT uVirKey, UINT uScanCode, CONST LPBYTE lpbKeyState); PRIVATE BOOL PASCAL ToAsciiExHanja(PCIMECtx pImeCtx, UINT uVirKey, CONST LPBYTE lpbKeyState); PRIVATE WCHAR PASCAL Banja2Junja(WCHAR bChar); PRIVATE BOOL PASCAL IsKSC5601(WCHAR wcCur); /*---------------------------------------------------------------------------- ImeInquire This function handle initialization of IME. It also returns IMEINFO structure and UI class name of IME ----------------------------------------------------------------------------*/ BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPTSTR lpszWndClass, DWORD dwSystemInfoFlags) { BOOL fRet = fFalse; Dbg(DBGID_API, TEXT("ImeInquire():lpIMEInfo = 0x%08lX, dwSystemInfoFlags = 0x%08lX"), lpIMEInfo, dwSystemInfoFlags); if (lpIMEInfo) { lpIMEInfo->dwPrivateDataSize = sizeof(IMCPRIVATE); // The private data in an IME context. lpIMEInfo->fdwProperty = IME_PROP_AT_CARET // IME conversion window is at caret position. | IME_PROP_NEED_ALTKEY // ALT key pass into ImeProcessKey | IME_PROP_CANDLIST_START_FROM_1 // Candidate list start from 1 | IME_PROP_END_UNLOAD; if (IsMemphis() || IsWinNT5orUpper()) lpIMEInfo->fdwProperty |= IME_PROP_COMPLETE_ON_UNSELECT; // Complete when IME unselected. lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE // IMEs in NATIVE mode else ALPHANUMERIC mode | IME_CMODE_FULLSHAPE // else in SBCS mode | IME_CMODE_HANJACONVERT;// Hangul hanja conversion lpIMEInfo->fdwSentenceCaps = 0; // IME sentence mode capability lpIMEInfo->fdwUICaps = 0; lpIMEInfo->fdwSCSCaps = SCS_CAP_COMPSTR; // IME can generate the composition string by SCS_SETSTR lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION; // ImeSetCompositionString capability // Set Unicode flag if system support it if (vfUnicode == fTrue) lpIMEInfo->fdwProperty |= IME_PROP_UNICODE; // String content of the Input Context will be UNICODE // NT5 Unicode injection through VK_PACKET if (IsWinNT5orUpper()) lpIMEInfo->fdwProperty |= IME_PROP_ACCEPT_WIDE_VKEY; // Return Unicode string for Unicode environment #ifndef UNDER_CE // Windows CE always Unicode if (vfUnicode == fTrue) StrCopyW((LPWSTR)lpszWndClass, wszUIClassName); else lstrcpyA(lpszWndClass, szUIClassName); #else // UNDER_CE lstrcpyW(lpszWndClass, wszUIClassName); #endif // UNDER_CE fRet = fTrue; } ////////////////////////////////////////////////////////////////////////// // 16 bit application check // If client is 16 bit Apps, only allow KS C-5601 chars. if (IsWinNT()) { // Win98 does not pass dwSystemInfoFlags; vpInstData->dwSystemInfoFlags = dwSystemInfoFlags; if (dwSystemInfoFlags & IME_SYSINFO_WOW16) vpInstData->f16BitApps = fTrue; // If in MT setup mode(system setup, upgrading and OOBE), display IME status window. if (IsInSystemSetupMode()) vpInstData->dwSystemInfoFlags |= IME_SYSINFO_WINLOGON; } else { // user GetProcessVersion DWORD dwVersion = GetProcessVersion(GetCurrentProcessId()); // Windowss 3.x if (HIWORD(dwVersion) <= 3) { vpInstData->f16BitApps = fTrue; #ifdef DEBUG DebugOutT(TEXT("!!! 16bit Apps running under Win9x !!!\r\n")); #endif } } // If 16bit apps, always disable ISO10646(full range Hangul) if (vpInstData->f16BitApps == fTrue) vpInstData->fISO10646 = fFalse; return fRet; } /*---------------------------------------------------------------------------- ImeConversionList obtain the list of candidate list from one character ----------------------------------------------------------------------------*/ DWORD WINAPI ImeConversionList(HIMC hIMC, LPCTSTR lpSource, LPCANDIDATELIST lpDest, DWORD dwBufLen, UINT uFlag) { WCHAR wchHanja; Dbg(DBGID_API, TEXT("ImeConversionList():hIMC = 0x%08lX, *lpSource = %04X, dwBufLen =%08lX"), hIMC, *(LPWSTR)lpSource, dwBufLen); if (hIMC == NULL) return 0; if (lpSource == NULL || *(LPWSTR)lpSource == 0) return 0; // If dwBufLen==0 then should return buffer size if (dwBufLen && lpDest == NULL) return 0; // // Code Conversion // // CONFIRM: Win98 send Unicode or not? if (IsMemphis() || IsWinNT()) wchHanja = *(LPWSTR)lpSource; else { if (MultiByteToWideChar(CP_KOREA, MB_PRECOMPOSED, lpSource, 2, &wchHanja, 1) == 0) return 0; } switch (uFlag) { case GCL_CONVERSION: return GetConversionList(wchHanja, lpDest, dwBufLen); break; case GCL_REVERSECONVERSION: case GCL_REVERSE_LENGTH: break; default: DbgAssert(0); } return (0); } /*---------------------------------------------------------------------------- ImeConfigure Open IME configuration DLG ----------------------------------------------------------------------------*/ BOOL WINAPI ImeConfigure(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) { BOOL fRet = fFalse; Dbg (DBGID_API, TEXT("ImeConfigure():hKL = 0x%08lX, dwMode = 0x%08lX"), hKL, dwMode); switch (dwMode) { case IME_CONFIG_GENERAL: if (ConfigDLG(hWnd)) fRet = fTrue; break; default: break; } return fRet; } /*---------------------------------------------------------------------------- ImeDestroy ----------------------------------------------------------------------------*/ BOOL WINAPI ImeDestroy(UINT uReserved) { Dbg(DBGID_API, TEXT("ImeDestroy(): Bye *-<\r\nSee Again !")); if (uReserved) return (fFalse); else return (fTrue); } /*---------------------------------------------------------------------------- ImeEscape Support Korean IME escape functions ----------------------------------------------------------------------------*/ LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData) { PCIMECtx pImeCtx = GetIMECtx(hIMC); LRESULT lRet; if (lpData == NULL || pImeCtx == NULL) return 0; Dbg(DBGID_API, TEXT("ImeEscape():hIMC = 0x%08lX, uSubFunc = 0x%08lX"), hIMC, uSubFunc); switch (uSubFunc) { case IME_ESC_AUTOMATA: lRet = EscAutomata(pImeCtx, (LPIMESTRUCT32)lpData, fTrue); break; case IME_AUTOMATA: lRet = EscAutomata(pImeCtx, (LPIMESTRUCT32)lpData, fFalse); break; case IME_GETOPEN: lRet = EscGetOpen(pImeCtx, (LPIMESTRUCT32)lpData); break; // Popup Hanja candidate window case IME_ESC_HANJA_MODE: if (lRet = EscHanjaMode(pImeCtx, (LPSTR)lpData, fTrue)) { pImeCtx->SetCandidateMsg(CIMECtx::MSG_OPENCAND); pImeCtx->GenerateMessage(); } break; // 16bit apps(Win 3.1) compatibility case IME_HANJAMODE: if (lRet = EscHanjaMode(pImeCtx, (LPSTR)lpData, fFalse)) { pImeCtx->SetCandidateMsg(CIMECtx::MSG_OPENCAND); pImeCtx->GenerateMessage(); } break; case IME_SETOPEN: lRet = EscSetOpen(pImeCtx, (LPIMESTRUCT32)lpData); break; case IME_MOVEIMEWINDOW: lRet = EscMoveIMEWindow(pImeCtx, (LPIMESTRUCT32)lpData); break; case 0x1100: lRet = EscGetIMEKeyLayout(pImeCtx, (LPIMESTRUCT32)lpData); break; default: Dbg(DBGID_Misc, TEXT("Unknown ImeEscape() subfunc(#0x%X) is called."), uSubFunc); return (0); } return (lRet); } /*---------------------------------------------------------------------------- ImeSetActiveContext ----------------------------------------------------------------------------*/ BOOL WINAPI ImeSetActiveContext(HIMC hIMC, BOOL fActive) { Dbg(DBGID_API, TEXT("ImeSetActiveContext():hIMC = 0x%08lX, fActive = 0x%d"), hIMC, fActive); // Initialize composition context. For Korean IME, don't need to kee composition str, // when context changed. //if (pImeCtx) //{ //pImeCtx->ClearCompositionStrBuffer(); //pImeCtx->GetAutomata()->InitState(); //pImeCtx->ResetComposition(); //} // CONFIRM: Is this really safe to disable? #if 0 LPINPUTCONTEXT lpIMC; LPCOMPOSITIONSTRING lpCompStr; Dbg(DBGID_API, _T("ImeSetActiveContext():hIMC = 0x%08lX, fActive = 0x%d"), hIMC, fActive); if (!hIMC) return fFalse; lpIMC = ImmLockIMC(hIMC); if (!lpIMC) return fFalse; if (fActive) { if (lpCompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr)) { if (lpCompStr->dwCompStrLen) { CIMEData ImeData; // if composition character mismatched with Automata object's reset with lpCompStr // I'm really suspicious when this situation occurs. I think never occur... -cslim if (pInstData->pMachine->GetCompositionChar() != *(LPWSTR)((LPBYTE)lpCompStr + lpCompStr->dwCompStrOffset)) { pInstData->pMachine->InitState(); pInstData->pMachine-> SetCompositionChar(*(LPWSTR)((LPBYTE)lpCompStr + lpCompStr->dwCompStrOffset)); } } ImmUnlockIMCC(lpIMC->hCompStr); } } ImmUnlockIMC(hIMC); #endif return fTrue; } /*---------------------------------------------------------------------------- ImeProcessKey Return fTrue if IME should process the key ----------------------------------------------------------------------------*/ BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT uVirKey, LPARAM lParam, CONST LPBYTE lpbKeyState) { PCIMECtx pImeCtx; WORD uScanCode; BOOL fRet = fFalse; Dbg(DBGID_API, TEXT("ImeProcessKey():hIMC=0x%08lX, uVKey=0x%04X, lParam=0x%08lX"), hIMC, uVirKey, lParam); if (lpbKeyState == NULL) return fFalse; // NT5 Unicode injection uVirKey = (UINT)LOWORD(uVirKey); uScanCode = HIWORD(lParam); if (uVirKey == VK_PROCESSKEY) // Mouse button clicked { Dbg(DBGID_Key, TEXT("ImeProcessKey : return fTrue - Mouse Button Pressed")); return fTrue; } else if (uScanCode & KF_UP) { Dbg(DBGID_Key, TEXT("ImeProcessKey : return fFalse - KF_UP")); return (fFalse); } else if (uVirKey == VK_SHIFT) // no SHIFT key { Dbg(DBGID_Key, TEXT("ImeProcessKey : return fFalse - VK_SHIFT")); return (fFalse); } else if (uVirKey == VK_CONTROL) // no CTRL key { Dbg(DBGID_Key, TEXT("ImeProcessKey : return fFalse - VK_CONTROL")); return (fFalse); } else if (uVirKey == VK_HANGUL || uVirKey == VK_JUNJA || uVirKey == VK_HANJA) { Dbg(DBGID_Key, TEXT("ImeProcessKey : return fTrue - VK_HANGUL, VK_JUNJA, VK_HANJA")); return (fTrue); } else { // need more check } if ((pImeCtx = GetIMECtx(hIMC)) == NULL) return fFalse; // If IME close, return with no action. if (pImeCtx->IsOpen() == fFalse) { Dbg(DBGID_Key, TEXT("ImeProcessKey : return fFalse - IME closed")); return fFalse; } // If Hanja conv mode return fTrue. ImeToAsciiEx will handle. if (pImeCtx->GetConversionMode() & IME_CMODE_HANJACONVERT) { return fTrue; } // If interim state if (pImeCtx->GetCompBufLen()) { // If ALT key down and in composition process, finalize it. if (uVirKey == VK_MENU) { Dbg(DBGID_Key, TEXT("ImeProcessKey : Finalize and return fFalse - VK_MENU")); pImeCtx->FinalizeCurCompositionChar(); pImeCtx->GenerateMessage(); } else { Dbg(DBGID_Key, TEXT("ImeProcessKey : Interim state. Key pressed except ALT")); fRet = fTrue; } } else // If composition string does not exist, { // if Ctrl+xx key, do not process in non-interim mode if (IsControlKeyPushed(lpbKeyState) == fFalse) { // If Hangul mode if (pImeCtx->GetConversionMode() & IME_CMODE_HANGUL) { // Start of hangul composition WORD wcCur = 0; if (pImeCtx->GetAutomata() != NULL) { wcCur = pImeCtx->GetAutomata()->GetKeyMap(uVirKey, IsShiftKeyPushed(lpbKeyState) ? 1 : 0 ); } // 2beolsik Alphanumeric keys have same layout as English key // So we don't need process when user pressed Alphanumeric key under 2beolsik if ( (wcCur && pImeCtx->GetGData() && pImeCtx->GetGData()->GetCurrentBeolsik() != KL_2BEOLSIK) || (wcCur & H_HANGUL) ) fRet = fTrue; } // if IME_CMODE_FULLSHAPE if (pImeCtx->GetConversionMode() & IME_CMODE_FULLSHAPE) { if (CHangulAutomata::GetEnglishKeyMap(uVirKey, IsShiftKeyPushed(lpbKeyState) ? 1 : 0)) fRet = fTrue; } } } // NT 5 Unicode injection if (uVirKey == VK_PACKET) { Dbg(DBGID_Key, TEXT("ImeProcessKey : VK_PACKET")); fRet = fTrue; } Dbg(DBGID_Key, TEXT("ImeProcessKey : return value = %d"), fRet); return fRet; } /*---------------------------------------------------------------------------- NotifyIME Change the status of IME according to the given parameter ----------------------------------------------------------------------------*/ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { PCIMECtx pImeCtx; BOOL fRet = fFalse; Dbg(DBGID_API, TEXT("NotifyIME():hIMC = 0x%08lX, dwAction = 0x%08lX, dwIndex = 0x%08lX, dwValue = 0x%08lX"), hIMC, dwAction, dwIndex, dwValue); if ((pImeCtx = GetIMECtx(hIMC)) == NULL) return fFalse; switch (dwAction) { case NI_COMPOSITIONSTR: switch (dwIndex) { ////////////////////////////////////////////////////////// case CPS_COMPLETE: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): NI_COMPOSITIONSTR-CPS_COMPLETE")); // If composition state if (pImeCtx->GetCompBufLen()) { // For ESC_HANJAMODE call this, we should reset comp str. pImeCtx->ResetComposition(); pImeCtx->SetResultStr(pImeCtx->GetCompBufStr()); pImeCtx->SetEndComposition(fTrue); pImeCtx->StoreComposition(); // Raid #104 if (pImeCtx->GetConversionMode() & IME_CMODE_HANJACONVERT) { // Cancel Hanja change mode pImeCtx->SetConversionMode(pImeCtx->GetConversionMode() & ~IME_CMODE_HANJACONVERT); pImeCtx->SetCandidateMsg(CIMECtx::MSG_CLOSECAND); } // Clear all automata states pImeCtx->GetAutomata()->InitState(); pImeCtx->GenerateMessage(); fRet = fTrue; } break; ////////////////////////////////////////////////////////// case CPS_CANCEL: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): NI_COMPOSITIONSTR-CPS_CANCEL")); // if composition string exist, remove it and send WM_IME_ENDCOMPOSITION if (pImeCtx->GetCompBufLen()) { pImeCtx->SetEndComposition(fTrue); pImeCtx->GenerateMessage(); pImeCtx->ClearCompositionStrBuffer(); fRet = fTrue; } break; ////////////////////////////////////////////////////////// case CPS_CONVERT: case CPS_REVERT: default: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): NI_COMPOSITIONSTR-CPS_CONVERT or CPS_REVERT !!! NOT IMPMLEMENTED !!!")); break; } // switch (dwIndex) break; case NI_OPENCANDIDATE: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): NI_OPENCANDIDATE")); // if not Hanja mocde if (!(pImeCtx->GetConversionMode() & IME_CMODE_HANJACONVERT)) { if (pImeCtx->GetCompBufLen() && GenerateHanjaCandList(pImeCtx)) { pImeCtx->SetCandidateMsg(CIMECtx::MSG_OPENCAND); // Set Hanja conv mode pImeCtx->SetConversionMode(pImeCtx->GetConversionMode() | IME_CMODE_HANJACONVERT); OurSendMessage(pImeCtx->GetAppWnd(), WM_IME_NOTIFY, IMN_SETCONVERSIONMODE, 0L); pImeCtx->GenerateMessage(); fRet = fTrue; } } break; case NI_CLOSECANDIDATE: if (pImeCtx->GetConversionMode() & IME_CMODE_HANJACONVERT) { pImeCtx->SetCandidateMsg(CIMECtx::MSG_CLOSECAND); // Set clear Hanja conv mode pImeCtx->SetConversionMode(pImeCtx->GetConversionMode() & ~IME_CMODE_HANJACONVERT); // To Notify to UI wnd OurSendMessage(pImeCtx->GetAppWnd(), WM_IME_NOTIFY, IMN_SETCONVERSIONMODE, 0L); pImeCtx->GenerateMessage(); fRet = fTrue; } break; case NI_SELECTCANDIDATESTR: case NI_SETCANDIDATE_PAGESTART: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): NI_SETCANDIDATE_PAGESTART")); if (pImeCtx->GetConversionMode() & IME_CMODE_HANJACONVERT) { pImeCtx->SetCandStrSelection(dwValue); pImeCtx->SetCandidateMsg(CIMECtx::MSG_CHANGECAND); pImeCtx->GenerateMessage(); fRet = fTrue; } break; case NI_CONTEXTUPDATED: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): NI_CONTEXTUPDATED")); switch (dwValue) { case IMC_SETOPENSTATUS: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): NI_CONTEXTUPDATED - IMC_SETOPENSTATUS")); Dbg(DBGID_IMENotify, TEXT("pImeCtx->GetConversionMode() = 0x%08lX"), pImeCtx->GetConversionMode()); UpdateOpenCloseState(pImeCtx); fRet = fTrue; break; case IMC_SETCONVERSIONMODE: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): NI_CONTEXTUPDATED - IMC_SETCONVERSIONMODE")); Dbg(DBGID_IMENotify, TEXT("pImeCtx->GetConversionMode() = 0x%08lX"), pImeCtx->GetConversionMode()); UpdateOpenCloseState(pImeCtx); fRet = fTrue; break; //case IMC_SETSTATUSWINDOWPOS: case IMC_SETCANDIDATEPOS: case IMC_SETCOMPOSITIONFONT: case IMC_SETCOMPOSITIONWINDOW: //DbgAssert(0); fRet = fTrue; break; default: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): NI_CONTEXTUPDATED - Unhandeled IMC value = 0x%08lX"), dwValue); break; } // switch (dwValue) break; case NI_IMEMENUSELECTED: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): NI_IMEMENUSELECTED")); switch (dwIndex) { case IDIM_ROOT_MR_1: // BUGBUG: NT Bug #379149 // Because Internat uses SendMessage, If user does not cancel the DLG, Deadlock occurs. // ImeConfigure(GetKeyboardLayout(NULL), pImeCtx->GetAppWnd(), IME_CONFIG_GENERAL, NULL); OurPostMessage(GetActiveUIWnd(), WM_MSIME_PROPERTY, 0L, IME_CONFIG_GENERAL); break; case IDIM_ROOT_ML_4: fRet = OurImmSetConversionStatus(hIMC, (pImeCtx->GetConversionMode() & ~IME_CMODE_HANGUL) | IME_CMODE_FULLSHAPE, pImeCtx->GetSentenceMode()); break; case IDIM_ROOT_ML_3: fRet = OurImmSetConversionStatus(hIMC, pImeCtx->GetConversionMode() & ~(IME_CMODE_HANGUL | IME_CMODE_FULLSHAPE), pImeCtx->GetSentenceMode()); break; case IDIM_ROOT_ML_2: fRet = OurImmSetConversionStatus(hIMC, pImeCtx->GetConversionMode() | IME_CMODE_HANGUL | IME_CMODE_FULLSHAPE, pImeCtx->GetSentenceMode()); break; case IDIM_ROOT_ML_1: fRet = OurImmSetConversionStatus(hIMC, (pImeCtx->GetConversionMode() | IME_CMODE_HANGUL) & ~IME_CMODE_FULLSHAPE, pImeCtx->GetSentenceMode()); break; } // switch (dwIndex) break; case NI_CHANGECANDIDATELIST: case NI_FINALIZECONVERSIONRESULT: case NI_SETCANDIDATE_PAGESIZE: default: Dbg(DBGID_IMENotify, TEXT("NotifyIME(): Unhandeled NI_ value = 0x%08lX"), dwAction); break; } // switch (dwAction) return fRet; } /*---------------------------------------------------------------------------- ImeSelect Initialize/Uninitialize IME private context ----------------------------------------------------------------------------*/ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) // fTrue-initialize, fFalse-uninitialize(free resource) { BOOL fRet = fFalse; Dbg(DBGID_API, TEXT("ImeSelect():hIMC = 0x%08lX, fSelect = 0x%d"), hIMC, fSelect); if (!hIMC) // if invalid input context handle { DbgAssert(0); return fFalse; } // If DLL_PROCESS_DETACH already called once. if (vfDllDetachCalled) { return fFalse; } fRet = Select(hIMC, fSelect); return fRet; } /*---------------------------------------------------------------------------- ImeSetCompositionString ----------------------------------------------------------------------------*/ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPVOID lpComp, DWORD dwCompLen, LPVOID lpRead, DWORD dwReadLen) { PCIMECtx pImeCtx; WCHAR wcComp; BOOL fSendStart, fRet = fFalse; Dbg(DBGID_API|DBGID_SetComp, TEXT("ImeSetCompositionString():hIMC = 0x%08lX, dwIndex = 0x%08lX, lpComp = 0x%04X"), hIMC, dwIndex, *(LPWSTR)lpComp); if ((pImeCtx = GetIMECtx(hIMC)) == NULL) return fFalse; if (dwIndex == SCS_SETSTR) { // Conv mode check if ((pImeCtx->GetConversionMode() & IME_CMODE_HANGUL)==0) { Dbg(DBGID_API|DBGID_SetComp, TEXT("!!! WARNING !!!: ImeSetCompositionString(): English mode")); return fFalse; } // Send WM_IME_STARTCOMPOSITION if not interim state. fSendStart = pImeCtx->GetCompBufLen() ? fFalse : fTrue; wcComp = L'\0'; // Parameter check if (lpComp != NULL && *(LPWSTR)lpComp != L'\0' && dwCompLen != 0) { if (pImeCtx->IsUnicodeEnv()) wcComp = *(LPWSTR)lpComp; else if (MultiByteToWideChar(CP_KOREA, MB_PRECOMPOSED, (LPSTR)lpComp, 2, &wcComp, 1) == 0) { DbgAssert(0); wcComp = 0; } // Hangul range check if ( (wcComp > 0x3130 && wcComp < 0x3164) || (wcComp >= 0xAC00 && wcComp < 0xD7A4) ) { pImeCtx->SetCompositionStr(wcComp); pImeCtx->StoreComposition(); } else { Dbg(DBGID_SetComp, TEXT("!!! WARNING !!!: lpComp is null or Input character is not Hangul")); DbgAssert(0); wcComp = 0; } } // Send WM_IME_STARTCOMPOSITION if (fSendStart) pImeCtx->SetStartComposition(fTrue); // REVIEW: Even if wcComp ==0, Should send WM_IME_COMPOSITION // Send composition char //SetTransBuffer(lpTransMsg, WM_IME_COMPOSITION, // (WPARAM)wcComp, (GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET)); // Set Automata state if non-null comp char if (wcComp) pImeCtx->GetAutomata()->SetCompositionChar(wcComp); else { // REVIEW: Even if wcComp ==0, Should send WM_IME_COMPOSITION pImeCtx->ClearCompositionStrBuffer(); pImeCtx->AddMessage(WM_IME_COMPOSITION, 0, (GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET)); pImeCtx->SetEndComposition(fTrue); pImeCtx->GetAutomata()->InitState(); } // Generate IME message pImeCtx->GenerateMessage(); fRet = fTrue; } return fRet; } /*---------------------------------------------------------------------------- ImeToAsciiEx ----------------------------------------------------------------------------*/ UINT WINAPI ImeToAsciiEx(UINT uVirKey, UINT uScanCode, CONST LPBYTE lpbKeyState, LPTRANSMSGLIST lpTransBuf, UINT fuState, HIMC hIMC) { PCIMECtx pImeCtx; UINT uNumMsg=0; WORD bKeyCode; Dbg(DBGID_API, TEXT("ImeToAsciiEx(): hIMC = 0x%08lX, uVirKey = 0x%04X, uScanCode = 0x%04X"), hIMC, uVirKey, uScanCode); Dbg(DBGID_Key, TEXT("lpbKeyState = 0x%08lX, lpdwTransBuf = 0x%08lX, fuState = 0x%04X"), lpbKeyState, lpTransBuf, fuState); if ((pImeCtx = GetIMECtx(hIMC)) == NULL) return 0; // Start process key pImeCtx->SetProcessKeyStatus(fTrue); // special message buffer for ToAsciiEx() pImeCtx->SetTransMessage(lpTransBuf); /////////////////////////////////////////////////////////////////////////// // If Hanja conv mode if (pImeCtx->GetConversionMode() & IME_CMODE_HANJACONVERT) { if (ToAsciiExHanja(pImeCtx, uVirKey, lpbKeyState) == fFalse) goto ToAsciiExExit_NoMsg; } else { /////////////////////////////////////////////////////////////////////////// // W2K specific - Unicode injection if (LOWORD(uVirKey) == VK_PACKET) { WCHAR wch = HIWORD(uVirKey); Dbg(DBGID_Key, TEXT("ImeToAsciiEx: VK_PACKET arrived(NonHanja conv mode)")); // If composition char exist, first finalize and append injection char, then send all. if (pImeCtx->GetCompBufLen()) { pImeCtx->FinalizeCurCompositionChar(); pImeCtx->AppendResultStr(wch); } else // If no composition char exist, just insert injection char as finalized char. pImeCtx->SetResultStr(wch); goto ToAsciiExExit; } /////////////////////////////////////////////////////////////////////////// // If Non-Hanja conv mode switch (uVirKey) { case VK_PROCESSKEY: // if mouse button clicked Dbg(DBGID_Key, TEXT("ImeToAsciiEx : VK_PROCESSKEY")); if (pImeCtx->GetCompBufLen()) pImeCtx->FinalizeCurCompositionChar(); break; case VK_HANGUL : Dbg(DBGID_Key, " - VK_HANGUL"); if (pImeCtx->GetCompBufLen()) pImeCtx->FinalizeCurCompositionChar(); OurImmSetConversionStatus(hIMC, pImeCtx->GetConversionMode()^IME_CMODE_HANGUL, pImeCtx->GetSentenceMode()); UpdateOpenCloseState(pImeCtx); break; case VK_JUNJA : Dbg(DBGID_Key, TEXT(" - VK_JUNJA")); if (pImeCtx->GetCompBufLen()) pImeCtx->FinalizeCurCompositionChar(); pImeCtx->AddKeyDownMessage(uVirKey, uScanCode); OurImmSetConversionStatus(hIMC, pImeCtx->GetConversionMode()^IME_CMODE_FULLSHAPE, pImeCtx->GetSentenceMode()); UpdateOpenCloseState(pImeCtx); break; case VK_HANJA : Dbg(DBGID_Key, TEXT(" - VK_HANJA")); if (pImeCtx->GetCompBufLen()) { // Keep current composition str pImeCtx->SetCompositionStr(pImeCtx->GetCompBufStr()); if (GenerateHanjaCandList(pImeCtx)) { pImeCtx->SetCandidateMsg(CIMECtx::MSG_OPENCAND); OurImmSetConversionStatus(hIMC, pImeCtx->GetConversionMode() | IME_CMODE_HANJACONVERT, pImeCtx->GetSentenceMode()); } } else pImeCtx->AddKeyDownMessage(uVirKey, uScanCode); break; default : // if hangul mode if (pImeCtx->GetConversionMode() & IME_CMODE_HANGUL) ToAsciiExHangulMode(pImeCtx, uVirKey, uScanCode, lpbKeyState); else // if junja mode if ( (pImeCtx->GetConversionMode() & IME_CMODE_FULLSHAPE) && (bKeyCode = CHangulAutomata::GetEnglishKeyMap(uVirKey, (IsShiftKeyPushed(lpbKeyState) ? 1 : 0))) ) { if (uVirKey >= 'A' && uVirKey <= 'Z') { bKeyCode = CHangulAutomata::GetEnglishKeyMap(uVirKey, (IsShiftKeyPushed(lpbKeyState) ? 1 : 0) ^ ((lpbKeyState[VK_CAPITAL] & 0x01) ? 1: 0)); } bKeyCode = Banja2Junja(bKeyCode); pImeCtx->SetResultStr(bKeyCode); } // Unknown mode else { DbgAssert(0); pImeCtx->AddKeyDownMessage(uVirKey, uScanCode); } } // switch (uVirKey) } ToAsciiExExit: pImeCtx->StoreComposition(); //pImeCtx->StoreCandidate(); pImeCtx->FinalizeMessage(); // final setup for IME Messages ToAsciiExExit_NoMsg: uNumMsg = pImeCtx->GetMessageCount(); pImeCtx->ResetMessage(); // reset pImeCtx->SetTransMessage((LPTRANSMSGLIST)NULL);// start process key pImeCtx->SetProcessKeyStatus(fFalse); return (uNumMsg); } /*---------------------------------------------------------------------------- ToAsciiExHangulMode Subroutine used by ImeToAsciiEx. ----------------------------------------------------------------------------*/ VOID PASCAL ToAsciiExHangulMode(PCIMECtx pImeCtx, UINT uVirKey, UINT uScanCode, CONST LPBYTE lpbKeyState) { CHangulAutomata* pAutomata; WCHAR wcCur; UINT uNumMsg=0; Dbg(DBGID_API, TEXT("ToAsciiExHangulMode()")); pAutomata = pImeCtx->GetAutomata(); DbgAssert(pAutomata != NULL); switch (uVirKey) { /////////////////////////////////////////////////////////// // Back space processing case VK_BACK : Dbg(DBGID_Key, TEXT("ImeToAsciiEx : VK_BACK")); if (pAutomata->BackSpace()) { wcCur = pAutomata->GetCompositionChar(); if (pImeCtx->GetGData() && pImeCtx->GetGData()->GetJasoDel() == fFalse) { pAutomata->InitState(); wcCur = 0; } if (wcCur) { pImeCtx->SetCompositionStr(wcCur); break; } else { Dbg(DBGID_Key, TEXT("ImeToAsciiEx : VK_BACK - Empty char")); // Send Empty Composition stringto clear message pImeCtx->AddMessage(WM_IME_COMPOSITION, 0, (GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET)); // Send Close composition window message pImeCtx->SetEndComposition(fTrue); break; } } else { // BUG : DbgAssert(0); // Put the Backspace message into return buffer. pImeCtx->AddMessage(WM_CHAR, (WPARAM)VK_BACK, (LPARAM)0x000E0001L); //(uScanCode << 16) | 1UL } break; default : // Ctrl+xx processing bug #60 if (IsControlKeyPushed(lpbKeyState)) { pImeCtx->FinalizeCurCompositionChar(); pImeCtx->AddKeyDownMessage(uVirKey, uScanCode); } else switch (pAutomata->Machine(uVirKey, IsShiftKeyPushed(lpbKeyState) ? 1 : 0 )) { case HAUTO_COMPOSITION: // Send start composition msg. if no composition exist. if (pImeCtx->GetCompBufLen() == 0) pImeCtx->SetStartComposition(fTrue); // Get Current composition char wcCur = pAutomata->GetCompositionChar(); // if ISO10646 flag disabled, should permit only KSC5601 chars if (vpInstData->fISO10646== fFalse) { Dbg(DBGID_API, TEXT("ToAsciiExHangulMode - ISO10646 Off")); if (IsKSC5601(wcCur) == fFalse) { Dbg(DBGID_API, TEXT("ToAsciiExHangulMode - Non KSC5601 char")); // To cancel last Jaso pAutomata->BackSpace(); // Complete pAutomata->MakeComplete(); pImeCtx->SetResultStr(pAutomata->GetCompleteChar()); // Run Automata again pAutomata->Machine(uVirKey, IsShiftKeyPushed(lpbKeyState) ? 1 : 0 ); wcCur = pAutomata->GetCompositionChar(); } } pImeCtx->SetCompositionStr(wcCur); break; case HAUTO_COMPLETE: pImeCtx->SetResultStr(pAutomata->GetCompleteChar()); pImeCtx->SetCompositionStr(pAutomata->GetCompositionChar()); break; //////////////////////////////////////////////////////// // User pressed Alphanumeric key. // When user type alphanumeric char in interim state. // ImeProcessKey should guarantee return fTrue only if // hangul key pressed or alphanumeric key(including special keys) // pressed in interim state or Fullshape mode. case HAUTO_NONHANGULKEY: wcCur = pAutomata->GetKeyMap(uVirKey, IsShiftKeyPushed(lpbKeyState) ? 1 : 0); if (wcCur && (pImeCtx->GetConversionMode() & IME_CMODE_FULLSHAPE)) wcCur = Banja2Junja(wcCur); // if interim state if (pImeCtx->GetCompBufLen()) { //DbgAssert(lpImcP->fdwImeMsg & MSG_ALREADY_START); pImeCtx->FinalizeCurCompositionChar(); if (wcCur) pImeCtx->AppendResultStr(wcCur); else pImeCtx->AddKeyDownMessage(uVirKey, uScanCode); } else // Not interim state { if (wcCur) pImeCtx->SetResultStr(wcCur); else // if not alphanumeric key(special key), just send it to App pImeCtx->AddKeyDownMessage(uVirKey, uScanCode); } break; default : DbgAssert(0); } // switch (pAutomata->Machine(uVirKey, (lpbKeyState[VK_SHIFT] & 0x80) ? 1 : 0 ) ) } // switch (uVirKey) return; } /*---------------------------------------------------------------------------- ToAsciiExHanja Subroutine used by ImeToAsciiEx. Handle key code in Hanja conversion mode on Returns True only if there is message need to generated. ----------------------------------------------------------------------------*/ BOOL PASCAL ToAsciiExHanja(PCIMECtx pImeCtx, UINT uVirKey, CONST LPBYTE lpbKeyState) { UINT uNumMsg = 0; DWORD iStart; WORD bKeyCode; LPCANDIDATELIST lpCandList; WCHAR wcHanja, wchInject; Dbg(DBGID_Hanja, TEXT("ToAsciiExHanja(): IME_CMODE_HANJACONVERT")); // if Left Alt key or Ctrl+xx down or no cand info. if (pImeCtx->GetPCandInfo() == NULL || pImeCtx->GetPCandInfo()->dwCount == 0) { Dbg(DBGID_Hanja, TEXT("ToAsciiExHanja(): WARNING no cand info. send MSG_CLOSE_CANDIDATE")); pImeCtx->SetCandidateMsg(CIMECtx::MSG_CLOSECAND); // Cancel Hanja conversion mode OurImmSetConversionStatus(pImeCtx->GetHIMC(), pImeCtx->GetConversionMode() & ~IME_CMODE_HANJACONVERT, pImeCtx->GetSentenceMode()); return fTrue; } wchInject = HIWORD(uVirKey); uVirKey = LOWORD(uVirKey); lpCandList = (LPCANDIDATELIST)((LPBYTE)pImeCtx->GetPCandInfo() + sizeof(CANDIDATEINFO)); iStart = (lpCandList->dwSelection / lpCandList->dwPageSize) * lpCandList->dwPageSize; // FIXED : In Hanja conversion mode, for selection candidate, use english keymap bKeyCode = CHangulAutomata::GetEnglishKeyMap(uVirKey, IsShiftKeyPushed(lpbKeyState) ? 1 : 0 ); if (bKeyCode && (uVirKey != VK_PACKET)) { if (bKeyCode >= '1' && bKeyCode <= '9' && iStart + bKeyCode - '1' < lpCandList->dwCount) { wcHanja = pImeCtx->GetCandidateStr(iStart + bKeyCode - '1'); Dbg(DBGID_Hanja, TEXT("ImeToAsciiEx-HANJACONVERT : wcHanja = 0x%04X"), wcHanja); pImeCtx->SetEndComposition(fTrue); pImeCtx->SetCandidateMsg(CIMECtx::MSG_CLOSECAND); pImeCtx->SetResultStr(wcHanja); OurImmSetConversionStatus(pImeCtx->GetHIMC(), pImeCtx->GetConversionMode() & ~IME_CMODE_HANJACONVERT, pImeCtx->GetSentenceMode()); // pImeCtx->ClearCompositionStrBuffer(); } else goto Exit_NoHandledKey; } else { switch (uVirKey) { case VK_HANJA : case VK_ESCAPE : case VK_PROCESSKEY : case VK_HANGUL : // Added for left and right Window buttons case VK_LWIN : case VK_RWIN : case VK_APPS : case VK_MENU : case VK_PACKET : // FIXED : Bug #27 // Word notify CPS_COMPLETE when user ALT down in hanja conv mode // then send double finalize char // check if composition char exist DbgAssert(pImeCtx->GetCompBufLen()); // Comp string should be exist in Hanja conv mode. if (pImeCtx->GetCompBufLen()) { // FIXED : if ESC_HANJA called, MSG_ALREADY_START is not set // This prevent MSG_END_COMPOSITION. pImeCtx->SetEndComposition(fTrue); pImeCtx->SetResultStr(pImeCtx->GetCompBufStr()); // Unicode injection if (uVirKey == VK_PACKET) { Dbg(DBGID_Key|DBGID_Hanja, TEXT("ImeToAsciiEx: VK_PACKET arrived(Hanja conv mode Comp char exist) - Append 0x%x"), wchInject); pImeCtx->AppendResultStr(wchInject); } } pImeCtx->SetCandidateMsg(CIMECtx::MSG_CLOSECAND); // Cancel Hanja conversion mode OurImmSetConversionStatus(pImeCtx->GetHIMC(), pImeCtx->GetConversionMode() & ~IME_CMODE_HANJACONVERT, pImeCtx->GetSentenceMode()); break; case VK_LEFT : if (iStart) { lpCandList->dwPageStart -= CAND_PAGE_SIZE; lpCandList->dwSelection -= CAND_PAGE_SIZE; pImeCtx->SetCandidateMsg(CIMECtx::MSG_CHANGECAND); } else goto Exit_NoHandledKey; // Keep current composition str pImeCtx->SetCompositionStr(pImeCtx->GetCompBufStr()); break; case VK_RIGHT : if (iStart + CAND_PAGE_SIZE < lpCandList->dwCount) { lpCandList->dwPageStart += CAND_PAGE_SIZE; lpCandList->dwSelection += CAND_PAGE_SIZE; pImeCtx->SetCandidateMsg(CIMECtx::MSG_CHANGECAND); } else goto Exit_NoHandledKey; // Keep current composition str pImeCtx->SetCompositionStr(pImeCtx->GetCompBufStr()); break; default : // Keep current composition str // pImeCtx->SetCompositionStr(pImeCtx->GetCompBufStr()); goto Exit_NoHandledKey; } } return fTrue; Exit_NoHandledKey: MessageBeep(MB_ICONEXCLAMATION); return fFalse; } /*---------------------------------------------------------------------------- ImeRegisterWord NOT USED ----------------------------------------------------------------------------*/ BOOL WINAPI ImeRegisterWord(LPCTSTR lpszReading, DWORD dwStyle, LPCTSTR lpszString) { Dbg(DBGID_API, TEXT("ImeRegisterWord() : NOT IMPLEMENTED")); return fFalse; } /*---------------------------------------------------------------------------- ImeUnregisterWord NOT USED ----------------------------------------------------------------------------*/ BOOL WINAPI ImeUnregisterWord(LPCTSTR lpszReading, DWORD dwStyle, LPCTSTR lpszString) { Dbg(DBGID_API, TEXT("ImeUnregisterWord() : NOT IMPLEMENTED")); return fFalse; } /*---------------------------------------------------------------------------- ImeGetRegisterWordStyle NOT USED ----------------------------------------------------------------------------*/ UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUF lpStyleBuf) { Dbg(DBGID_API, TEXT("ImeGetRegisterWordStyle() : NOT IMPLEMENTED")); return (0); } /*---------------------------------------------------------------------------- ImeEnumRegisterWord NOT USED ----------------------------------------------------------------------------*/ UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROC lpfnRegisterWordEnumProc, LPCTSTR lpszReading, DWORD dwStyle, LPCTSTR lpszString, LPVOID lpData) { Dbg(DBGID_API, TEXT("ImeEnumRegisterWord() : NOT IMPLEMENTED")); return (0); } /*---------------------------------------------------------------------------- ImeGetImeMenuItems ----------------------------------------------------------------------------*/ DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize) { PCIMECtx pImeCtx; DWORD dwNumOfItems=0; Dbg(DBGID_API, TEXT("ImeGetImeMenuItems() : ")); if ((pImeCtx = GetIMECtx(hIMC)) == NULL) return 0; if (!lpImeMenu) { if (!lpImeParentMenu) { if (dwFlags & IGIMIF_RIGHTMENU) dwNumOfItems = NUM_ROOT_MENU_R; else dwNumOfItems = NUM_ROOT_MENU_L; goto ImeGetImeMenuItemsExit; } else { if (dwFlags & IGIMIF_RIGHTMENU) dwNumOfItems = NUM_SUB_MENU_R; else dwNumOfItems = NUM_SUB_MENU_L; goto ImeGetImeMenuItemsExit; } return 0; } if (!lpImeParentMenu) { if (dwFlags & IGIMIF_RIGHTMENU) { lpImeMenu->cbSize = sizeof(IMEMENUITEMINFOW); lpImeMenu->fType = 0; lpImeMenu->fState = 0; lpImeMenu->wID = IDIM_ROOT_MR_1; lpImeMenu->hbmpChecked = 0; lpImeMenu->hbmpUnchecked = 0; OurLoadStringW(vpInstData->hInst, IDS_CONFIG, lpImeMenu->szString, IMEMENUITEM_STRING_SIZE); lpImeMenu->hbmpItem = 0; dwNumOfItems = NUM_ROOT_MENU_R; } else // Left Menu { // 1. Hangul Halfshape menu lpImeMenu->cbSize = sizeof(IMEMENUITEMINFOW); lpImeMenu->fType = IMFT_RADIOCHECK; if ((pImeCtx->GetConversionMode() & IME_CMODE_HANGUL) && !(pImeCtx->GetConversionMode() & IME_CMODE_FULLSHAPE)) lpImeMenu->fState = IMFS_CHECKED; else lpImeMenu->fState = 0; lpImeMenu->wID = IDIM_ROOT_ML_1; lpImeMenu->hbmpChecked = 0; lpImeMenu->hbmpUnchecked = 0; OurLoadStringW(vpInstData->hInst, IDS_IME_HANGUL_HALF, lpImeMenu->szString, IMEMENUITEM_STRING_SIZE); lpImeMenu->hbmpItem = 0; // 2. Hangul Fullshape menu lpImeMenu++; lpImeMenu->cbSize = sizeof(IMEMENUITEMINFOW); lpImeMenu->fType = IMFT_RADIOCHECK; if ((pImeCtx->GetConversionMode() & IME_CMODE_HANGUL) && (pImeCtx->GetConversionMode()& IME_CMODE_FULLSHAPE)) lpImeMenu->fState = IMFS_CHECKED; else lpImeMenu->fState = 0; lpImeMenu->wID = IDIM_ROOT_ML_2; lpImeMenu->hbmpChecked = 0; lpImeMenu->hbmpUnchecked = 0; OurLoadStringW(vpInstData->hInst, IDS_IME_HANGUL_FULL, lpImeMenu->szString, IMEMENUITEM_STRING_SIZE); lpImeMenu->hbmpItem = 0; // 3. English Halfshape menu lpImeMenu++; lpImeMenu->cbSize = sizeof(IMEMENUITEMINFOW); lpImeMenu->fType = IMFT_RADIOCHECK; if (!(pImeCtx->GetConversionMode() & IME_CMODE_HANGUL) && !(pImeCtx->GetConversionMode() & IME_CMODE_FULLSHAPE)) lpImeMenu->fState = IMFS_CHECKED; else lpImeMenu->fState = 0; lpImeMenu->wID = IDIM_ROOT_ML_3; lpImeMenu->hbmpChecked = 0; lpImeMenu->hbmpUnchecked = 0; OurLoadStringW(vpInstData->hInst, IDS_IME_ENG_HALF, lpImeMenu->szString, IMEMENUITEM_STRING_SIZE); lpImeMenu->hbmpItem = 0; // 4. English Fullshape menu lpImeMenu++; lpImeMenu->cbSize = sizeof(IMEMENUITEMINFOW); lpImeMenu->fType = IMFT_RADIOCHECK; if ( !(pImeCtx->GetConversionMode() & IME_CMODE_HANGUL) && (pImeCtx->GetConversionMode() & IME_CMODE_FULLSHAPE)) lpImeMenu->fState = IMFS_CHECKED; else lpImeMenu->fState = 0; lpImeMenu->wID = IDIM_ROOT_ML_4; lpImeMenu->hbmpChecked = 0; lpImeMenu->hbmpUnchecked = 0; OurLoadStringW(vpInstData->hInst, IDS_IME_ENG_FULL, lpImeMenu->szString, IMEMENUITEM_STRING_SIZE); lpImeMenu->hbmpItem = 0; // return total number of menu list dwNumOfItems = NUM_ROOT_MENU_L; } } ImeGetImeMenuItemsExit: return dwNumOfItems; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Private Helper Functions // // // OS setup (Whistler,Win2K) sets this flag // BOOL IsInSystemSetupMode() { LPCSTR szKeyName = "SYSTEM\\Setup"; DWORD dwType, dwSize; HKEY hKeySetup; DWORD dwSystemSetupInProgress = 0; DWORD dwUpgradeInProcess = 0; DWORD dwOOBEInProcess = 0; LONG lResult; if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKeySetup) == ERROR_SUCCESS) { dwSize = sizeof(DWORD); lResult = RegQueryValueEx(hKeySetup, TEXT("SystemSetupInProgress"), NULL, &dwType, (LPBYTE) &dwSystemSetupInProgress, &dwSize); dwSize = sizeof(DWORD); lResult = RegQueryValueEx(hKeySetup, TEXT("UpgradeInProgress"), NULL, &dwType, (LPBYTE) &dwUpgradeInProcess, &dwSize); dwSize = sizeof(DWORD); lResult = RegQueryValueEx(hKeySetup, TEXT("OobeInProgress"), NULL, &dwType, (LPBYTE) &dwOOBEInProcess, &dwSize); if (dwSystemSetupInProgress == 1 || dwUpgradeInProcess == 1 || dwOOBEInProcess == 1) { RegCloseKey (hKeySetup); return TRUE; } RegCloseKey (hKeySetup); } if (IsWinNT5orUpper() && (IsRunningAsLocalSystem() || IsRunningInOOBE())) return TRUE; return FALSE ; } //+---------------------------------------------------------------------------- // // Function: RunningAsLocalSystem // // Synopsis: Detects whether we're running in the System account. // // Arguments: None // // Returns: TRUE if the service is running as LocalSystem // FALSE if it is not or if any errors were encountered // //----------------------------------------------------------------------------- BOOL IsRunningAsLocalSystem() { SID LocalSystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID }; BOOL fCheckSucceeded; BOOL fIsLocalSystem = FALSE; fCheckSucceeded = CheckTokenMembership(NULL, &LocalSystemSid, &fIsLocalSystem); return (fCheckSucceeded && fIsLocalSystem); } /*---------------------------------------------------------------------------- IsRunningInOOBE Bug #401732:IME Status window does not come up on the registration page of WPA in the windows starting mode ----------------------------------------------------------------------------*/ BOOL IsRunningInOOBE() { TCHAR achModule[MAX_PATH]; TCHAR ch; LPTSTR pch; LPTSTR pchFileName; if (GetModuleFileName(NULL, achModule, ARRAYSIZE(achModule)) == 0) return FALSE; pch = pchFileName = achModule; while ((ch = *pch) != 0) { pch = CharNext(pch); if (ch == '\\') pchFileName = pch; } if (lstrcmpi(pchFileName, TEXT("msoobe.exe")) == 0) return TRUE; return FALSE; } BOOL PASCAL Select(HIMC hIMC, BOOL fSelect) { PCIMECtx pImeCtx = NULL; BOOL fRet = fTrue; // If IME select On if (fSelect) { IMCPRIVATE imcPriv; IImeIPoint1* pIP = NULL; LPCImeIPoint pCIImeIPoint = NULL; DWORD dwInitStatus = 0; // Clear all private buffer ZeroMemory(&imcPriv, sizeof(IMCPRIVATE)); ////////////////////////////////////////////////////////////////////// // Create IImeIPoint1 instance ////////////////////////////////////////////////////////////////////// if ((pCIImeIPoint = new CIImeIPoint)==NULL) return fFalse; // This increments the reference count if (FAILED(pCIImeIPoint->QueryInterface(IID_IImeIPoint1, (VOID **)&pIP))) return fFalse; AST(pIP != NULL); imcPriv.pIPoint = pIP; // initialize IImeIPoint interface. This will create CImeCtx object Dbg(DBGID_API, "ImeSelect - init IP"); pCIImeIPoint->Initialize(hIMC); ////////////////////////////////////////////////////////////////////// // Get CImeCtx object from IImeIPoint1 ////////////////////////////////////////////////////////////////////// pCIImeIPoint->GetImeCtx((VOID**)&pImeCtx); AST(pImeCtx != NULL); if (pImeCtx == NULL) { Dbg( DBGID_API, "ImeSelect - pImeCtx == NULL" ); return fFalse; } // Set pImeCtx imcPriv.pImeCtx = pImeCtx; // Set hIMC for compare imcPriv.hIMC = hIMC; ////////////////////////////////////////////////////////////////////// // Set IMC private buffer ////////////////////////////////////////////////////////////////////// Dbg(DBGID_API, TEXT("ImeSelect - set priv buf")); SetPrivateBuffer(hIMC, &imcPriv, sizeof(IMCPRIVATE)); // Set Unicode flag pImeCtx->SetUnicode(vfUnicode); ////////////////////////////////////////////////////////////////////// // Set initial IMC states if not already set ////////////////////////////////////////////////////////////////////// pImeCtx->GetInitStatus(&dwInitStatus); // if INPUTCONTEXT member are not initialized, initialize it. if (!(dwInitStatus & INIT_CONVERSION)) { pImeCtx->SetOpen(fFalse); // Initial IME close status == Alphanumeric mode pImeCtx->SetConversionMode(IME_CMODE_ALPHANUMERIC); // Set initial conversion mode. dwInitStatus |= INIT_CONVERSION; } #if 0 // !!! We don't need this code NT5 IMM does it !!! else { // When IME switched from other IME, for example KKIME, // status window sometimes not updated to correct info because KKIME maintains // conversion mode independetly from Open/Close status and they uses non-Korean // conversion mode like IME_CMODE_KATAKANA or IME_CMODE_ROMAN. // So need to adjust conversion mode according to Open/Clos Status and current // conversion mode. if (pImeCtx->IsOpen() == fFalse && pImeCtx->GetConversionMode() != IME_CMODE_ALPHANUMERIC) pImeCtx->SetConversionMode(IME_CMODE_ALPHANUMERIC); else if (pImeCtx->IsOpen() && (pImeCtx->GetConversionMode() & (IME_CMODE_HANGUL|IME_CMODE_FULLSHAPE)) == fFalse) pImeCtx->SetConversionMode(IME_CMODE_HANGUL); } #endif if (!(dwInitStatus & INIT_LOGFONT)) { LOGFONT* pLf = pImeCtx->GetLogFont(); ////////////////////////////////////////////////////////////////// // Note: Win98 does not support CreateFontW(). // But, imc->logfont->lfFaceName is UNICODE! if (IsMemphis() || IsWinNT()) StrCopyW((LPWSTR)pLf->lfFaceName, wzIMECompFont); else lstrcpyA(pLf->lfFaceName, szIMECompFont); // Gulim 9pt pLf->lfHeight = 16; pLf->lfEscapement = 0; pLf->lfOrientation = 0; pLf->lfWeight = FW_NORMAL; pLf->lfItalic = fFalse; pLf->lfUnderline = fFalse; pLf->lfStrikeOut = fFalse; pLf->lfCharSet = HANGUL_CHARSET; pLf->lfOutPrecision = OUT_DEFAULT_PRECIS; pLf->lfClipPrecision = CLIP_DEFAULT_PRECIS; pLf->lfQuality = DEFAULT_QUALITY; pLf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; dwInitStatus |= INIT_LOGFONT; } if (!(dwInitStatus & INIT_STATUSWNDPOS)) { if (pImeCtx->GetGDataRaw()) { pImeCtx->SetStatusWndPos((pImeCtx->GetGDataRaw())->ptStatusPos); } dwInitStatus |= INIT_STATUSWNDPOS; } if (!(dwInitStatus & INIT_COMPFORM)) { pImeCtx->SetCompositionFormStyle(CFS_DEFAULT); dwInitStatus |= INIT_COMPFORM; } // Set New initialization status pImeCtx->SetInitStatus(dwInitStatus); } else // fSelect { IImeIPoint1* pIP = GetImeIPoint(hIMC); LPCImePadSvr lpCImePadSvr; CIMCPriv ImcPriv; LPIMCPRIVATE pImcPriv; // Cleanup Private buffer and release IImeIPoint1 // Always OnImeSelect already cleanup. if (pIP) pIP->Release(); lpCImePadSvr = CImePadSvr::GetCImePadSvr(); if(lpCImePadSvr) lpCImePadSvr->SetIUnkIImeIPoint((IUnknown *)NULL); if (ImcPriv.LockIMC(hIMC)) { ImcPriv->pIPoint = (IImeIPoint1*)NULL; ImcPriv->pImeCtx = NULL; ImcPriv.ResetPrivateBuffer(); } } Dbg(DBGID_API, "Select() exit hIMC=%x, fSelect=%d", hIMC, fSelect); return (fTrue); } ////////////////////////////////////////////////////////////////////////////// // Conversion mode and Open/Close Helper functions // In Kor IME, Open status equal to Han mode and Close status equal to Eng mode // So, we change pair open status with conversion mode, and vice versa. ////////////////////////////////////////////////////////////////////////////// // UpdateOpenCloseState() // Purpose : // Set Open/Close state according to conversion mode // if Eng mode - set Close // if Han mode - Set Open VOID PASCAL UpdateOpenCloseState(PCIMECtx pImeCtx) { if ( (pImeCtx->GetConversionMode() & IME_CMODE_HANGUL) || (pImeCtx->GetConversionMode() & IME_CMODE_FULLSHAPE) || (pImeCtx->GetConversionMode() & IME_CMODE_HANJACONVERT) ) { if (pImeCtx->IsOpen() == fFalse) OurImmSetOpenStatus(pImeCtx->GetHIMC(), fTrue); } else { if (pImeCtx->IsOpen()) OurImmSetOpenStatus(pImeCtx->GetHIMC(), fFalse); } } #if NOTUSED ////////////////////////////////////////////////////////////////////////////// // UpdateConversionState() // Purpose : // Set Conversion state according to Open/Close status // if Open - Set Han mode // if Close - Set Eng mode VOID PASCAL UpdateConversionState(HIMC hIMC) { LPINPUTCONTEXT lpIMC; if (lpIMC = OurImmLockIMC(hIMC)) { if (OurImmGetOpenStatus(hIMC)) { if ( !(lpIMC->fdwConversion & (IME_CMODE_HANGUL|IME_CMODE_FULLSHAPE)) ) { OurImmSetConversionStatus(hIMC, lpIMC->fdwConversion | IME_CMODE_HANGUL, lpIMC->fdwSentence); } DbgAssert(lpIMC->fdwConversion & (IME_CMODE_HANGUL|IME_CMODE_FULLSHAPE)); } else { // BUG: IME_CMODE_HANJACONVERT ???? if (lpIMC->fdwConversion & (IME_CMODE_HANGUL|IME_CMODE_FULLSHAPE)) OurImmSetConversionStatus(hIMC, lpIMC->fdwConversion & ~(IME_CMODE_HANGUL|IME_CMODE_FULLSHAPE), lpIMC->fdwSentence); DbgAssert(!(lpIMC->fdwConversion & IME_CMODE_HANGUL)); } OurImmUnlockIMC(hIMC); } } #endif /*---------------------------------------------------------------------------- Banja2Junja Convert Ascii Half shape to Full shape character ----------------------------------------------------------------------------*/ WCHAR PASCAL Banja2Junja(WCHAR bChar) //, LPDWORD lpTransBuf, LPCOMPOSITIONSTRING lpCompStr) { WCHAR wcJunja; if (bChar == L' ') wcJunja = 0x3000; // FullWidth space else if (bChar == L'~') wcJunja = 0xFF5E; else if (bChar == L'\\') wcJunja = 0xFFE6; // FullWidth WON sign else wcJunja = 0xFF00 + (WORD)(bChar - (BYTE)0x20); Dbg(DBGID_Misc, TEXT("Banja2Junja: wcJunja = 0x%04X"), wcJunja); return wcJunja; } /*---------------------------------------------------------------------------- IsKSC5601 Test if character within the KSC 5601 Return True if input Unicode chracter has correspoding KSC 5601 code ----------------------------------------------------------------------------*/ BOOL PASCAL IsKSC5601(WCHAR wcCur) { WCHAR wcUni[2]; BYTE szWansung[4]; wcUni[0] = wcCur; wcUni[1] = 0; // check if compatibility Hangul jamo if (wcCur >= 0x3131 && wcCur <= 0x3163) return fTrue; // Convert to ANSI if (WideCharToMultiByte(CP_KOREA, 0, wcUni, 1, (LPSTR)szWansung, sizeof(szWansung), NULL, NULL)==0) { DbgAssert(0); return fFalse; } else { // KSC 5601 Area in 949 cp if ( (szWansung[0]>=0xB0 && szWansung[0]<=0xC8) && (szWansung[1]>=0xA1 && szWansung[1]<=0xFE) ) return fTrue; else return fFalse; } }