|
|
/*++
Copyright (c) 1985 - 1999, Microsoft Corporation
Module Name:
imewndhd.cpp
Abstract:
This file implements the IME window handler Class.
Author:
Revision History:
Notes:
--*/
#include "private.h"
#include "defs.h"
#include "cdimm.h"
#include "imewndhd.h"
#include "globals.h"
LPCTSTR IMEWndHandlerName = TEXT("IMEWindowHandler");
CIMEWindowHandler::CIMEWindowHandler( HWND hwnd, BOOL fDefault ) { m_imeui.hImeWnd = hwnd; m_imeui.hIMC = NULL; m_imeui.nCntInIMEProc = 0; m_imeui.fDefault = fDefault;
CActiveIMM *_pActiveIMM = GetTLS(); if (_pActiveIMM == NULL) return;
_pActiveIMM->_GetKeyboardLayout(&m_hKL_UnSelect); }
CIMEWindowHandler::~CIMEWindowHandler( ) { }
LRESULT CIMEWindowHandler::ImeWndProcWorker( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fUnicode ) { LRESULT lr;
CActiveIMM *_pActiveIMM = GetTLS(); if (_pActiveIMM == NULL) return 0L;
lr = _ImeWndProcWorker(uMsg, wParam, lParam, fUnicode, _pActiveIMM);
return lr; }
LRESULT CIMEWindowHandler::_ImeWndProcWorker( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fUnicode, CActiveIMM* pActiveIMM )
{ /*
* This is necessary to avoid recursion call from IME UI. */ if (IsIMEHandler() > 1) { TraceMsg(TF_API, "ImeWndProcWorker: Recursive for hwnd=%08x, msg=%08x, wp=%08x, lp=%08x", m_imeui.hImeWnd, uMsg, wParam, lParam); switch (uMsg) { case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_COMPOSITION: case WM_IME_SETCONTEXT: case WM_IME_NOTIFY: case WM_IME_CONTROL: case WM_IME_COMPOSITIONFULL: case WM_IME_SELECT: case WM_IME_CHAR: case WM_IME_REQUEST: return 0L; default: return pActiveIMM->_CallWindowProc(m_imeui.hImeWnd, uMsg, wParam, lParam); } }
switch (uMsg) { case WM_CREATE: ImeWndCreateHandler((LPCREATESTRUCT)lParam); break;
case WM_DESTROY: /*
* We are destroying the IME window, * destroy any UI window that it owns. */ ImeWndDestroyHandler(); break;
case WM_NCDESTROY: /* case WM_FINALDESTROY: */ pActiveIMM->_CallWindowProc(m_imeui.hImeWnd, uMsg, wParam, lParam); ImeWndFinalDestroyHandler(); return 0L;
case WM_IME_SYSTEM: if (ImeSystemHandler(uMsg, wParam, lParam, fUnicode, pActiveIMM)) return 0L; break;
case WM_IME_SELECT: ImeSelectHandler(uMsg, wParam, lParam, fUnicode, pActiveIMM); break;
case WM_IME_CONTROL: ImeControlHandler(uMsg, wParam, lParam, fUnicode, pActiveIMM); break;
case WM_IME_SETCONTEXT: ImeSetContextHandler(uMsg, wParam, lParam, fUnicode, pActiveIMM); break;
case WM_IME_NOTIFY: ImeNotifyHandler(uMsg, wParam, lParam, fUnicode, pActiveIMM); break;
case WM_IME_REQUEST: break;
case WM_IME_COMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_STARTCOMPOSITION: { LRESULT lret; lret = SendMessageToUI(uMsg, wParam, lParam, fUnicode, pActiveIMM);
if (!pActiveIMM->_IsRealIme()) return lret;
break; }
default: if (IsMsImeMessage(uMsg)) { if (! pActiveIMM->_IsRealIme()) { return ImeMsImeHandler(uMsg, wParam, lParam, fUnicode, pActiveIMM); } } break; }
return pActiveIMM->_CallWindowProc(m_imeui.hImeWnd, uMsg, wParam, lParam); }
LRESULT CIMEWindowHandler::ImeWndCreateHandler( DWORD style, HIMC hDefIMC ) { if ( !(style & WS_POPUP) || !(style & WS_DISABLED)) { TraceMsg(TF_WARNING, "IME should have WS_POPUP and WS_DISABLED!!"); return -1L; }
CActiveIMM *_pActiveIMM = GetTLS(); if (_pActiveIMM == NULL) return 0L;
/*
*/ if (hDefIMC != NULL) { if (ImeIsUsableContext(m_imeui.hImeWnd, hDefIMC, _pActiveIMM)) { /*
* Store it for later use. */ ImeSetImc(hDefIMC, _pActiveIMM); } else { ImeSetImc(NULL, _pActiveIMM); } } else { ImeSetImc(NULL, _pActiveIMM); }
return 0L; }
LRESULT CIMEWindowHandler::ImeWndCreateHandler( LPCREATESTRUCT lpcs ) { HIMC hIMC;
if (lpcs->hwndParent != NULL) { CActiveIMM *_pActiveIMM = GetTLS(); if (_pActiveIMM == NULL) return 0L;
_pActiveIMM->GetContextInternal(lpcs->hwndParent, &hIMC, FALSE); } else if (lpcs->lpCreateParams) { hIMC = (HIMC)lpcs->lpCreateParams; } else hIMC = NULL; return ImeWndCreateHandler(lpcs->style, hIMC); }
VOID CIMEWindowHandler::ImeWndDestroyHandler( ) { }
VOID CIMEWindowHandler::ImeWndFinalDestroyHandler( ) { CActiveIMM *_pActiveIMM = GetTLS(); if (_pActiveIMM == NULL) return;
_pActiveIMM->_ImeWndFinalDestroyHandler();
SetProp(m_imeui.hImeWnd, IMEWndHandlerName, NULL); delete this; }
LRESULT CIMEWindowHandler::ImeSystemHandler( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fUnicode, CActiveIMM* pActiveIMM ) { LRESULT dwRet = 0L;
switch (wParam) { case IMS_ACTIVATETHREADLAYOUT: return ImeActivateLayout((HKL)lParam, pActiveIMM); #ifdef CICERO_3564
case IMS_FINALIZE_COMPSTR: if (! pActiveIMM->_IsRealIme()) { /*
* KOREAN: * Finalize current composition string */ HIMC hIMC = ImeGetImc(); pActiveIMM->NotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); } break; #endif // CICERO_3564
}
return dwRet; }
LRESULT CIMEWindowHandler::ImeSelectHandler( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fUnicode, CActiveIMM* pActiveIMM ) { /*
* Deliver this message to other IME windows in this thread. */ if (! pActiveIMM->_IsRealIme((HKL)lParam) && m_imeui.fDefault) ImeBroadCastMsg(uMsg, wParam, lParam, fUnicode);
/*
* We must re-create UI window of newly selected IME. */ return pActiveIMM->_ImeSelectHandler(uMsg, wParam, lParam, fUnicode, ImeGetImc()); }
LRESULT CIMEWindowHandler::ImeControlHandler( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fUnicode, CActiveIMM* pActiveIMM ) { /*
* Do nothing with NULL hIMC. */ HIMC hIMC = ImeGetImc();
switch (wParam) { case IMC_OPENSTATUSWINDOW: case IMC_CLOSESTATUSWINDOW: pActiveIMM->HideOrRestoreToolbarWnd(IMC_OPENSTATUSWINDOW == wParam); break;
/*
* ------------------------------------------------ * IMC_SETCOMPOSITIONFONT, * IMC_SETCONVERSIONMODE, * IMC_SETOPENSTATUS * ------------------------------------------------ * Don't pass these WM_IME_CONTROLs to UI window. * Call Imm in order to process these requests instead. * It makes message flows simpler. */ case IMC_SETCOMPOSITIONFONT: if (hIMC != NULL) { LOGFONTAW* lplf = (LOGFONTAW*)lParam; if (fUnicode) { if (FAILED(pActiveIMM->SetCompositionFontW(hIMC, (LOGFONTW *)lplf))) return 1L; } else { if (FAILED(pActiveIMM->SetCompositionFontA(hIMC, (LOGFONTA *)lplf))) return 1L; } } break;
case IMC_SETCONVERSIONMODE: if (hIMC != NULL) { DWORD dwConversion, dwSentence; if (FAILED(pActiveIMM->GetConversionStatus(hIMC, &dwConversion, &dwSentence)) || FAILED(pActiveIMM->SetConversionStatus(hIMC, (DWORD)lParam, dwSentence))) return 1L; } break;
case IMC_SETSENTENCEMODE: if (hIMC != NULL) { DWORD dwConversion, dwSentence; if (FAILED(pActiveIMM->GetConversionStatus(hIMC, &dwConversion, &dwSentence)) || FAILED(pActiveIMM->SetConversionStatus(hIMC, dwConversion, (DWORD)lParam))) return 1L; } break;
case IMC_SETOPENSTATUS: if (hIMC != NULL) { if (FAILED(pActiveIMM->SetOpenStatus(hIMC, (int)lParam))) return 1L; } break;
#if 0 // internal
case IMC_GETCONVERSIONMODE: if (hIMC != NULL) { DWORD dwConversion, dwSentence; if (FAILED(GetTeb()->GetConversionStatus(hIMC, &dwConversion, &dwSentence))) return 1L; return dwConversion; }
case IMC_GETSENTENCEMODE: if (hIMC != NULL) { DWORD dwConversion, dwSentence; if (FAILED(GetTeb()->GetConversionStatus(hIMC, &dwConversion, &dwSentence))) return 1L; return dwSentence; }
case IMC_GETOPENSTATUS: if (hIMC != NULL) return GetTeb()->GetOpenStatus(hIMC); #endif
case IMC_GETCOMPOSITIONFONT: if (hIMC != NULL) { LOGFONTAW* lplf = (LOGFONTAW*)lParam; if (fUnicode) { if (FAILED(pActiveIMM->GetCompositionFontW(hIMC, (LOGFONTW *)lplf))) return 1L; } else { if (FAILED(pActiveIMM->GetCompositionFontA(hIMC, (LOGFONTA *)lplf))) return 1L; } } break;
case IMC_SETCOMPOSITIONWINDOW: if (hIMC != NULL) { if (FAILED(pActiveIMM->SetCompositionWindow(hIMC, (LPCOMPOSITIONFORM)lParam))) return 1L; } break;
case IMC_SETSTATUSWINDOWPOS: if (hIMC != NULL) { POINT ppt; ppt.x = (LONG)((LPPOINTS)&lParam)->x; ppt.y = (LONG)((LPPOINTS)&lParam)->y; if (FAILED(pActiveIMM->SetStatusWindowPos(hIMC, &ppt))) return 1L; } break;
case IMC_SETCANDIDATEPOS: if (hIMC != NULL) { if (FAILED(pActiveIMM->SetCandidateWindow(hIMC, (LPCANDIDATEFORM)lParam))) return 1L; } break;
/*
* Followings are the messages to be sent to UI. */ case IMC_GETCANDIDATEPOS: case IMC_GETSTATUSWINDOWPOS: case IMC_GETCOMPOSITIONWINDOW: case IMC_GETSOFTKBDPOS: case IMC_SETSOFTKBDPOS: if (hIMC != NULL) return SendMessageToUI(uMsg, wParam, lParam, fUnicode, pActiveIMM);
default: break; }
return 0L; }
LRESULT CIMEWindowHandler::ImeSetContextHandler( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fUnicode, CActiveIMM* pActiveIMM ) { if (wParam) { /*
* if it's being activated */ if (GetWindowThreadProcessId(m_imeui.hImeWnd, NULL) != GetCurrentThreadId()) { TraceMsg(TF_WARNING, "ImeSetContextHandler: Can not access other thread's hIMC"); return 0L; }
HWND hwndFocus = GetFocus(); HIMC hFocusImc;
//
// hFocusImc always need to set some valid hIMC for SetUIWindowContext().
// When sets NULL hIMC in SetUIWindowContext(), message deliver to UI window
// has been stop.
//
if (FAILED(pActiveIMM->GetContextInternal(hwndFocus, &hFocusImc, TRUE))) { TraceMsg(TF_WARNING, "ImeSetContextHandler: No hFocusImc"); return 0L; }
/*
* Cannot share input context with other IME window. */ if (hFocusImc != NULL && ! ImeIsUsableContext(m_imeui.hImeWnd, hFocusImc, pActiveIMM)) { ImeSetImc(NULL, pActiveIMM); return 0L; }
ImeSetImc(hFocusImc, pActiveIMM);
/*
* Store it to the window memory */ pActiveIMM->SetUIWindowContext(hFocusImc); }
return SendMessageToUI(uMsg, wParam, lParam, fUnicode, pActiveIMM); }
LRESULT CIMEWindowHandler::ImeNotifyHandler( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fUnicode, CActiveIMM* pActiveIMM ) { LRESULT lRet = 0L;
switch (wParam) { case IMN_PRIVATE: break;
case IMN_SETCONVERSIONMODE: case IMN_SETOPENSTATUS: //
// notify shell and keyboard the conversion mode change
//
/*** FALL THROUGH ***/ default: lRet = SendMessageToUI(uMsg, wParam, lParam, fUnicode, pActiveIMM); }
return lRet; }
LRESULT CIMEWindowHandler::ImeMsImeHandler( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fUnicode, CActiveIMM* pActiveIMM ) { return SendMessageToUI(uMsg, wParam, lParam, fUnicode, pActiveIMM); }
LRESULT CIMEWindowHandler::SendMessageToUI( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fUnicode, CActiveIMM* pActiveIMM ) { LRESULT lRet;
InterlockedIncrement(&m_imeui.nCntInIMEProc); // Mark to avoid recursion.
lRet = pActiveIMM->_SendUIMessage(uMsg, wParam, lParam); InterlockedDecrement(&m_imeui.nCntInIMEProc); return lRet; }
LRESULT CIMEWindowHandler::ImeActivateLayout( HKL hSelKL, CActiveIMM* pActiveIMM ) { if (hSelKL == m_hKL_UnSelect) //
// Apps startup time, msctf!PostInputLangRequest may calls ActivateKeyboardLayout
// with Cicero's hKL (04110411 or 08040804).
// However, CIMEWindowHandle::m_hKL_UnSelect also have Cicero's hKL because
// this class ask to ITfInputProcessorProfile.
//
return TRUE;
HKL hUnSelKL = m_hKL_UnSelect;
/*
* Save IME_CMODE_GUID_NULL and IME_SMODE_GUID_NULL bit in the CContextList * When hSelKL is regacy IME, IMM32 SelectInputContext reset this flag. */ CContextList _hIMC_MODE_GUID_NULL;
Interface<IEnumInputContext> EnumInputContext; HRESULT hr = pActiveIMM->EnumInputContext(0, // 0 = Current Thread
EnumInputContext); if (SUCCEEDED(hr)) { CEnumrateValue<IEnumInputContext, HIMC, CContextList> Enumrate(EnumInputContext, EnumInputContextCallback, &_hIMC_MODE_GUID_NULL);
Enumrate.DoEnumrate(); }
/*
* Deactivate layout (hUnSelKL). */ pActiveIMM->_DeactivateLayout(hSelKL, hUnSelKL);
IMTLS *ptls; LANGID langid;
if ((ptls = IMTLS_GetOrAlloc()) != NULL) { ptls->pAImeProfile->GetLangId(&langid);
if (PRIMARYLANGID(langid) == LANG_KOREAN) { //
// Save open and conversion status for Korean
//
if (_hIMC_MODE_GUID_NULL.GetCount() > 0) { POSITION pos = _hIMC_MODE_GUID_NULL.GetStartPosition(); int index; for (index = 0; index < _hIMC_MODE_GUID_NULL.GetCount(); index++) { HIMC hIMC; CContextList::CLIENT_IMC_FLAG client_flag; _hIMC_MODE_GUID_NULL.GetNextHimc(pos, &hIMC, &client_flag); if (client_flag & (CContextList::IMCF_CMODE_GUID_NULL | CContextList::IMCF_SMODE_GUID_NULL )) { DIMM_IMCLock imc(hIMC); if (SUCCEEDED(imc.GetResult())) imc->fdwHangul = imc->fdwConversion; } } } } }
// /*
// * If either hKL are regacy IME, then should call IMM32's handler.
// */
// if (_pThread->IsRealIme(hSelKL) || _pThread->IsRealIme(hUnSelKL))
pActiveIMM->_CallWindowProc(m_imeui.hImeWnd, WM_IME_SYSTEM, IMS_ACTIVATETHREADLAYOUT, (LPARAM)hSelKL);
/*
* Activate layout (hSelKL). */ pActiveIMM->_ActivateLayout(hSelKL, hUnSelKL);
/*
* Restore CContextList's IME_CMODE_GUID_NULL and IME_SMODE_GUID_NULL to each hIMC */ if (_hIMC_MODE_GUID_NULL.GetCount() > 0) { POSITION pos = _hIMC_MODE_GUID_NULL.GetStartPosition(); int index; for (index = 0; index < _hIMC_MODE_GUID_NULL.GetCount(); index++) { HIMC hIMC; CContextList::CLIENT_IMC_FLAG client_flag; _hIMC_MODE_GUID_NULL.GetNextHimc(pos, &hIMC, &client_flag); if (client_flag & (CContextList::IMCF_CMODE_GUID_NULL | CContextList::IMCF_SMODE_GUID_NULL )) { DIMM_IMCLock imc(hIMC); if (SUCCEEDED(imc.GetResult())) { if (PRIMARYLANGID(langid) == LANG_KOREAN) { //
// Restore open and conversion status value by changing IMM32
//
imc->fdwConversion = imc->fdwHangul; if (imc->fdwConversion & (IME_CMODE_HANGUL | IME_CMODE_FULLSHAPE)) imc->fOpen = TRUE; else imc->fOpen = FALSE; } if (client_flag & CContextList::IMCF_CMODE_GUID_NULL) imc->fdwConversion |= IME_CMODE_GUID_NULL; if (client_flag & CContextList::IMCF_SMODE_GUID_NULL) imc->fdwSentence |= IME_SMODE_GUID_NULL; } } } }
/*
* Set unselect hKL value */ m_hKL_UnSelect = hSelKL;
return TRUE; }
VOID CIMEWindowHandler::ImeSetImc( HIMC hIMC, CActiveIMM* pActiveIMM ) { HIMC hOldImc = ImeGetImc();
/*
* return if nothing to change. */ if (hIMC == hOldImc) return;
/*
* Unmark the old input context. */ if (hOldImc != NULL) ImeMarkUsedContext(NULL, hOldImc, pActiveIMM);
/*
* Update the in use input context for this IME window. */ m_imeui.hIMC = hIMC;
/*
* Mark the new input context. */ if (hIMC != NULL) ImeMarkUsedContext(m_imeui.hImeWnd, hIMC, pActiveIMM); }
VOID CIMEWindowHandler::ImeMarkUsedContext( HWND hImeWnd, HIMC hIMC, CActiveIMM* pActiveIMM )
/*+++
Some IME windows can not share same input context. This function marks the specified hIMC to be in used by the specified IME window.
---*/
{ HWND hImcImeWnd;
if (! pActiveIMM->_ContextLookup(hIMC, &hImcImeWnd)) { TraceMsg(TF_WARNING, "ImeMarkUsedContext: Invalid hImc (=%lx).", hIMC); return; }
/*
* Nothing to change? */ if (hImcImeWnd == hImeWnd) return;
pActiveIMM->_ContextUpdate(hIMC, hImeWnd); return; }
BOOL CIMEWindowHandler::ImeIsUsableContext( HWND hImeWnd, HIMC hIMC, CActiveIMM* pActiveIMM )
/*+++
Some IME windows can not share the same input context. This function checks whether the specified hIMC can be used (means 'Set activated') by the specified IME window.
Return: TRUE - OK to use the hIMC by hImeWnd. FALSE - otherwise.
---*/
{ HWND hImcImeWnd;
if (! pActiveIMM->_ContextLookup(hIMC, &hImcImeWnd)) { TraceMsg(TF_WARNING, "ImeIsUsableContext: Invalid hIMC (=%lx).", hIMC); return FALSE; }
if (hImcImeWnd == NULL || hImcImeWnd == hImeWnd || ! IsWindow(hImcImeWnd)) return TRUE; else return FALSE; }
BOOL CIMEWindowHandler::ImeBroadCastMsg( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fUnicode ) { return TRUE; }
ENUM_RET CIMEWindowHandler::EnumInputContextCallback( HIMC hIMC, CContextList* pList ) { DIMM_IMCLock imc(hIMC); if (SUCCEEDED(imc.GetResult())) { CContextList::CLIENT_IMC_FLAG client_flag = CContextList::IMCF_NONE;
if (imc->fdwConversion & IME_CMODE_GUID_NULL) client_flag = (CContextList::CLIENT_IMC_FLAG)(client_flag | CContextList::IMCF_CMODE_GUID_NULL);
if (imc->fdwSentence & IME_SMODE_GUID_NULL) client_flag = (CContextList::CLIENT_IMC_FLAG)(client_flag | CContextList::IMCF_SMODE_GUID_NULL);
pList->SetAt(hIMC, client_flag); }
return ENUM_CONTINUE; }
CIMEWindowHandler* GetImeWndHandler( HWND hwnd, BOOL fDefault ) { CIMEWindowHandler* pimeui = static_cast<CIMEWindowHandler*>(GetProp(hwnd, IMEWndHandlerName)); if (pimeui == NULL) { pimeui = new CIMEWindowHandler(hwnd, fDefault); if (pimeui == NULL) { return NULL; } SetProp(hwnd, IMEWndHandlerName, pimeui); }
pimeui->ImeSetWnd(hwnd); return pimeui; }
|