Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

855 lines
22 KiB

/*++
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;
}