Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1062 lines
27 KiB

/**************************************************************************\
* Module Name: imectl.c
*
* Copyright (c) Microsoft Corp. 1995 All Rights Reserved
*
* IME Window Handling Routines
*
* History:
* 20-Dec-1995 wkwok
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
BOOL gfShowIMEStatus = TRUE;
/*
* Local Routines.
*/
LONG ImeWndCreateHandler(PIMEUI, LPCREATESTRUCT);
LONG ImeSystemHandler(PIMEUI, UINT, WPARAM, LPARAM);
LONG ImeSelectHandler(PIMEUI, UINT, WPARAM, LPARAM);
LONG ImeControlHandler(PIMEUI, UINT, WPARAM, LPARAM, BOOL);
LONG ImeSetContextHandler(PIMEUI, UINT, WPARAM, LPARAM);
LONG ImeNotifyHandler(PIMEUI, UINT, WPARAM, LPARAM);
HWND CreateIMEUI(PIMEUI, HKL);
VOID DestroyIMEUI(PIMEUI);
LONG SendMessageToUI(PIMEUI, UINT, WPARAM, LPARAM, BOOL);
VOID SendOpenStatusNotify(PIMEUI, HWND, BOOL);
VOID ImeSetImc(PIMEUI, HIMC);
VOID FocusSetIMCContext(HWND, BOOL);
BOOL ImeBroadCastMsg(PIMEUI, UINT, WPARAM, LPARAM);
VOID ImeMarkUsedContext(HWND, HIMC);
BOOL ImeIsUsableContext(HWND, HIMC);
/*
* Common macros for IME UI, HKL and IMC handlings
*/
#define GETHKL(pimeui) (pimeui->hKL)
#define SETHKL(pimeui, hkl) (pimeui->hKL=(hkl))
#define GETIMC(pimeui) (pimeui->hIMC)
#define SETIMC(pimeui, himc) (ImeSetImc(pimeui, himc))
#define GETUI(pimeui) (pimeui->hwndUI)
#define SETUI(pimeui, hwndui) (pimeui->hwndUI=(hwndui))
LOOKASIDE ImeUILookaside;
/***************************************************************************\
* ImeWndProc
*
* WndProc for IME class
*
* History:
\***************************************************************************/
LONG APIENTRY ImeWndProcWorker(
PWND pwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
DWORD fAnsi)
{
HWND hwnd = HWq(pwnd);
PIMEUI pimeui;
static BOOL fInit = TRUE;
CheckLock(pwnd);
VALIDATECLASSANDSIZE(pwnd, FNID_IME);
INITCONTROLLOOKASIDE(&ImeUILookaside, IMEUI, spwnd, 8);
/*
* If the control is not interested in this message,
* pass it to DefWindowProc.
*/
if (!FWINDOWMSG(message, FNID_IME))
return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
/*
* Get the pimeui for the given window now since we will use it a lot in
* various handlers. This was stored using SetWindowLong(hwnd,0,pimeui) when
* we initially created the IME control.
*/
pimeui = ((PIMEWND)pwnd)->pimeui;
/*
* This is necessary to avoid recursion call from IME UI.
*/
if (pimeui != NULL) {
UserAssert(pimeui->nCntInIMEProc >= 0);
if (pimeui->nCntInIMEProc > 0) {
switch (message) {
case WM_IME_SYSTEM:
switch (wParam)
{
case IMS_ISACTIVATED:
case IMS_SETOPENSTATUS:
/*
* Because these will not be pass to UI.
* We can do it.
*/
break;
default:
return 0L;
}
break;
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:
return 0L;
default:
return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
}
}
}
switch (message) {
case WM_ERASEBKGND:
return (LONG)TRUE;
case WM_PAINT:
break;
case WM_CREATE:
return ImeWndCreateHandler(pimeui, (LPCREATESTRUCT)lParam);
case WM_DESTROY:
/*
* We are destroying the IME window, destroy
* any UI window that it owns.
*/
DestroyIMEUI(pimeui);
break;
case WM_NCDESTROY:
case WM_FINALDESTROY:
if (pimeui) {
Unlock(&pimeui->spwnd);
FreeLookasideEntry(&ImeUILookaside, pimeui);
}
NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT);
goto CallDWP;
case WM_IME_SYSTEM:
return ImeSystemHandler(pimeui, message, wParam, lParam);
case WM_IME_SELECT:
return ImeSelectHandler(pimeui, message, wParam, lParam);
case WM_IME_CONTROL:
return ImeControlHandler(pimeui, message, wParam, lParam, fAnsi);
case WM_IME_SETCONTEXT:
return ImeSetContextHandler(pimeui, message, wParam, lParam);
case WM_IME_NOTIFY:
return ImeNotifyHandler(pimeui, message, wParam, lParam);
case WM_IME_COMPOSITION:
case WM_IME_ENDCOMPOSITION:
case WM_IME_STARTCOMPOSITION:
return SendMessageToUI(pimeui, message, wParam, lParam, fAnsi);
default:
CallDWP:
return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
}
return 0L;
}
LONG WINAPI ImeWndProcA(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
PWND pwnd;
if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
return (0L);
}
return ImeWndProcWorker(pwnd, message, wParam, lParam, TRUE);
}
LONG WINAPI ImeWndProcW(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
PWND pwnd;
if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
return (0L);
}
return ImeWndProcWorker(pwnd, message, wParam, lParam, FALSE);
}
LONG ImeWndCreateHandler(
PIMEUI pimeui,
LPCREATESTRUCT lpcs)
{
HWND hwndParent;
HIMC hImc;
PWND pImeWnd = pimeui->spwnd;
if (!TestWF(pImeWnd, WFPOPUP) || !TestWF(pImeWnd, WFDISABLED)) {
RIPMSG0(RIP_WARNING, "IME window should have WS_POPUP and WS_DISABLE!!");
return -1L;
}
/*
* Check with parent window, if exists, try to get IMC.
* If this is top level window, wait for first WM_IME_SETCONTEXT.
*/
if ((hwndParent = lpcs->hwndParent) != NULL) {
hImc = ImmGetContext(hwndParent);
if (hImc != NULL_HIMC && ImeIsUsableContext(HWq(pImeWnd), hImc)) {
/*
* Store it for later use.
*/
SETIMC(pimeui, hImc);
}
else {
SETIMC(pimeui, NULL_HIMC);
}
ImmReleaseContext(hwndParent, hImc);
}
else {
SETIMC(pimeui, NULL_HIMC);
}
/*
* Initialize status window show state
* The status window is not open yet.
*/
pimeui->fShowStatus = 0;
pimeui->nCntInIMEProc = 0;
pimeui->fActivate = 0;
pimeui->fDestroy = 0;
pimeui->hwndIMC = NULL;
pimeui->hKL = GetKeyboardLayout(0);
#ifdef LATE_CREATEUI
SETUI(pimeui, NULL);
#else
SETUI(pimeui, CreateIMEUI(pimeui, pimeui->hKL));
#endif
return 0L;
}
LONG ImeSystemHandler(
PIMEUI pimeui,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
PINPUTCONTEXT pInputContext;
HWND hwndOwner;
HIMC hImc = GETIMC(pimeui);
switch (wParam) {
case IMS_SETOPENSTATUS:
if ((pInputContext = ImmLockIMC(hImc)) != NULL) {
BOOL fOpen;
UINT ustat;
hwndOwner = pInputContext->hWnd;
fOpen = pInputContext->fOpen;
ImmUnlockIMC(hImc);
/*
* MSB will have context availablity bit.
* LSB will have open / close status bit.
*/
ustat = 0x8000 | (fOpen ? 0x0001 : 0x0000);
#ifdef LATER
NtUserSendNotifyToShell(hwndOwner, GETHKL(pimeui), ustat);
#endif
}
break;
case IMS_SETOPENCLOSE:
if (hImc != NULL_HIMC)
ImmSetOpenStatus(hImc, (BOOL)lParam);
break;
#ifdef LATER
case IMS_WINDOWPOS:
if (hImc != NULL_HIMC) {
INT i;
BOOL f31Hidden = FALSE:
if ((pInputContext = ImmLockIMC(hImc)) != NULL) {
f31Hidden = (pInputContext & F31COMPAT_MCWHIDDEN) ? TRUE : FALSE;
ImmUnlockIMC(hImc);
}
if (IsWindow(pimeui->hwndIMC)) {
if (!f31Hidden) {
}
}
#endif
case IMS_ACTIVATECONTEXT:
FocusSetIMCContext((HWND)(lParam), TRUE);
break;
case IMS_DEACTIVATECONTEXT:
FocusSetIMCContext((HWND)(lParam), FALSE);
break;
#ifdef LATER
case IMS_UNLOADTHREADLAYOUT:
/*
* Unload only if the specified HKL is not current active.
*/
if (GetKeyboardLayout(0) == (HKL)lParam)
break;
return (LONG)(ImmUnloadLayout((HKL)lParam));
#endif
case IMS_ACTIVATETHREADLAYOUT:
/*
* Activate only if the specified HKL is not current active.
*/
if (GetKeyboardLayout(0) == (HKL)lParam)
break;
return (LONG)(ImmActivateLayout((HKL)lParam));
default:
break;
}
return 0L;
}
LONG ImeSelectHandler(
PIMEUI pimeui,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
HWND hwndUI;
/*
* Deliver this message to other IME windows in this thread.
*/
if (pimeui->fDefault)
ImeBroadCastMsg(pimeui, message, wParam, lParam);
/*
* We must re-create UI window of newly selected IME.
*/
if ((BOOL)wParam == TRUE) {
UserAssert(!IsWindow(GETUI(pimeui)));
#ifdef LATE_CREATEUI
if (!pimeui->fActivate)
return 0L;
#endif
SETHKL(pimeui, (HKL)lParam);
hwndUI = CreateIMEUI(pimeui, (HKL)lParam);
SETUI(pimeui, hwndUI);
SetWindowLong(hwndUI, IMMGWL_IMC, GETIMC(pimeui));
SendMessageToUI(pimeui, message, wParam, lParam, FALSE);
if (pimeui->fShowStatus && pimeui->fActivate &&
IsWindow(pimeui->hwndIMC)) {
/*
* This must be sent to an application as an app may want
* to hook this message to do its own UI.
*/
SendOpenStatusNotify(pimeui, pimeui->hwndIMC, TRUE);
}
}
else {
if (pimeui->fShowStatus && pimeui->fActivate &&
IsWindow(pimeui->hwndIMC)) {
/*
* This must be sent to an application as an app may want
* to hook this message to do its own UI.
*/
SendOpenStatusNotify(pimeui, pimeui->hwndIMC, FALSE);
}
SendMessageToUI(pimeui, message, wParam, lParam, FALSE);
DestroyIMEUI(pimeui);
}
return 0L;
}
LONG ImeControlHandler(
PIMEUI pimeui,
UINT message,
WPARAM wParam,
LPARAM lParam,
BOOL fAnsi)
{
HIMC hImc;
DWORD dwConversion, dwSentence;
/*
* Do nothing with NULL hImc.
*/
if ((hImc = GETIMC(pimeui)) == NULL_HIMC)
return 0L;
switch (wParam) {
case IMC_OPENSTATUSWINDOW:
if (gfShowIMEStatus && !pimeui->fShowStatus) {
pimeui->fShowStatus = TRUE;
SendMessageToUI(pimeui, WM_IME_NOTIFY,
IMN_OPENSTATUSWINDOW, 0L, FALSE);
}
break;
case IMC_CLOSESTATUSWINDOW:
if (gfShowIMEStatus && pimeui->fShowStatus) {
pimeui->fShowStatus = FALSE;
SendMessageToUI(pimeui, WM_IME_NOTIFY,
IMN_CLOSESTATUSWINDOW, 0L, FALSE);
}
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 (fAnsi) {
if (!ImmSetCompositionFontA(hImc, (LPLOGFONTA)lParam))
return 1L;
}
else {
if (!ImmSetCompositionFontW(hImc, (LPLOGFONTW)lParam))
return 1L;
}
break;
case IMC_SETCONVERSIONMODE:
ImmGetConversionStatus(hImc, &dwConversion, &dwSentence);
if (!ImmSetConversionStatus(hImc, (DWORD)lParam, dwSentence))
return 1L;
break;
case IMC_SETSENTENCEMODE:
ImmGetConversionStatus(hImc, &dwConversion, &dwSentence);
if (!ImmSetConversionStatus(hImc, dwConversion, (DWORD)lParam))
return 1L;
break;
case IMC_SETOPENSTATUS:
if (!ImmSetOpenStatus(hImc, (BOOL)lParam))
return 1L;
break;
case IMC_GETCONVERSIONMODE:
ImmGetConversionStatus(hImc,&dwConversion, &dwSentence);
return (LONG)dwConversion;
case IMC_GETSENTENCEMODE:
ImmGetConversionStatus(hImc,&dwConversion, &dwSentence);
return (LONG)dwSentence;
case IMC_GETOPENSTATUS:
return (LONG)ImmGetOpenStatus(hImc);
case IMC_GETCOMPOSITIONFONT:
if (fAnsi) {
if (!ImmGetCompositionFontA(hImc, (LPLOGFONTA)lParam))
return 1L;
}
else {
if (!ImmGetCompositionFontW(hImc, (LPLOGFONTW)lParam))
return 1L;
}
break;
case IMC_SETCOMPOSITIONWINDOW:
if (!ImmSetCompositionWindow(hImc, (LPCOMPOSITIONFORM)lParam))
return 1L;
break;
case IMC_SETSTATUSWINDOWPOS:
{
POINT ppt;
ppt.x = (LONG)((LPPOINTS)&lParam)->x;
ppt.y = (LONG)((LPPOINTS)&lParam)->y;
if (!ImmSetStatusWindowPos(hImc, &ppt))
return 1L;
}
break;
case IMC_SETCANDIDATEPOS:
if (!ImmSetCandidateWindow(hImc, (LPCANDIDATEFORM)lParam))
return 1;
break;
/*
* Followings are the messsages to be sent to UI.
*/
case IMC_GETCANDIDATEPOS:
case IMC_GETSTATUSWINDOWPOS:
case IMC_GETCOMPOSITIONWINDOW:
case IMC_GETSOFTKBDPOS:
case IMC_SETSOFTKBDPOS:
return SendMessageToUI(pimeui, message, wParam, lParam, fAnsi);
default:
break;
}
return 0L;
}
LONG ImeSetContextHandler(
PIMEUI pimeui,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
PWND pwndIme;
HWND hwndPrevIMC, hwndFocus;
HIMC hFocusImc;
UINT uStat;
LONG lRet;
pimeui->fActivate = (BOOL)wParam ? 1 : 0;
pwndIme = pimeui->spwnd;
hwndPrevIMC = pimeui->hwndIMC;
if ((BOOL)wParam == TRUE) {
#ifdef LATE_CREATEUI
if (!GETUI(pimeui))
SETUI(pimeui, CreateIMEUI(pimeui, GETHKL(pimeui)));
#endif
hwndFocus = NtUserQueryWindow(HWq(pwndIme), WindowFocusWindow);
hFocusImc = ImmGetContext(hwndFocus);
/*
* Cannot share input context with other IME window.
*/
if (hFocusImc != NULL_HIMC &&
!ImeIsUsableContext(HWq(pwndIme), hFocusImc)) {
SETIMC(pimeui, NULL_HIMC);
return 0L;
}
SETIMC(pimeui, hFocusImc);
/*
* Store it to the window memory.
*/
SetWindowLong(GETUI(pimeui), IMMGWL_IMC, hFocusImc);
/*
* When we're receiving context,
* it is necessary to set the owner to this window.
* This is for:
* Give the UI moving information.
* Give the UI automatic Z-ordering.
* Hide the UI when the owner is minimized.
*/
if (hFocusImc != NULL_HIMC) {
PINPUTCONTEXT pInputContext;
/*
* Get the window who's given the context.
*/
if ((pInputContext = ImmLockIMC(hFocusImc)) != NULL)
UserAssert(hwndFocus == pInputContext->hWnd);
else
return 0L; // the context was broken
if ((pInputContext->fdw31Compat & F31COMPAT_ECSETCFS) &&
hwndPrevIMC != hwndFocus) {
COMPOSITIONFORM cf;
/*
* Set CFS_DEFAULT....
*/
RtlZeroMemory(&cf, sizeof(cf));
ImmSetCompositionWindow(hFocusImc, &cf);
pInputContext->fdw31Compat &= ~F31COMPAT_ECSETCFS;
}
#ifdef LATER
// Get the status for shell notify
uStat = 0x8000|(lpIMC->fOpen?0x0001:0x0000);
// Currently, only Korean version has an interest in this info.
if ((GETHKL(hwnd) & 0xF000FFFL) == 0xE0000412L)
{
if (lpIMC->fdwConversion & IME_CMODE_NATIVE)
uStat |= 0x0002;
if (lpIMC->fdwConversion & IME_CMODE_FULLSHAPE)
uStat |= 0x0004;
}
#endif
ImmUnlockIMC(hFocusImc);
if (NtUserSetImeOwnerWindow(HWq(pwndIme), hwndFocus))
pimeui->hwndIMC = hwndFocus;
}
else {
/*
* NULL IMC is getting activated
*/
pimeui->hwndIMC = hwndFocus;
NtUserSetImeOwnerWindow(HWq(pwndIme), NULL);
/*
* Get the status for shell notify
*/
uStat = 0x0000;
}
#ifdef LATER
/*
* Possible update to open/close/disable status.
*/
if (uStat != IMEStatSentToShell)
SendNotifyToShell(((PIMEUI)hwnd)->hwndIMC, GETHKL(hwnd), uStat);
#endif
}
lRet = SendMessageToUI(pimeui, message, wParam, lParam, FALSE);
if (gfShowIMEStatus) {
PWND pwndFocus, pwndIMC, pwndPrevIMC;
HWND hwndActive;
hwndFocus = NtUserQueryWindow(HWq(pwndIme), WindowFocusWindow);
pwndFocus = ValidateHwndNoRip(hwndFocus);
if ((BOOL)wParam == TRUE) {
/*
* BOGUS BOGUS
* The following if statement is still insufficient
* it needs to think what WM_IME_SETCONTEXT:TRUE should do
* in the case of WINNLSEnableIME(true) - ref.win95c B#8548.
*/
if (pwndFocus != NULL && GETPTI(pwndIme) == GETPTI(pwndFocus)) {
if (!pimeui->fShowStatus) {
/*
* We have never sent IMN_OPENSTATUSWINDOW yet....
*/
if (ValidateHwndNoRip(pimeui->hwndIMC)) {
pimeui->fShowStatus = TRUE;
SendOpenStatusNotify(pimeui, pimeui->hwndIMC, TRUE);
}
}
else if ((pwndIMC = ValidateHwndNoRip(pimeui->hwndIMC)) != NULL &&
(pwndPrevIMC = ValidateHwndNoRip(hwndPrevIMC)) != NULL &&
GetTopLevelWindow(pwndIMC) != GetTopLevelWindow(pwndPrevIMC)) {
/*
* Because the top level window of IME Wnd was changed.
*/
pimeui->fShowStatus = FALSE;
SendOpenStatusNotify(pimeui, hwndPrevIMC, FALSE);
pimeui->fShowStatus = TRUE;
SendOpenStatusNotify(pimeui, pimeui->hwndIMC, TRUE);
}
}
#ifdef LATER
/*
* There may have other IME windows that have fSowStatus.
* We need to check the fShowStatus in the window list.
*/
NtUserImeCheckShowStatus(HWq(pwndIme));
#endif
}
else {
/*
* When focus was removed from this thread, we close the
* status window.
* Because focus was already removed from whndPrevIMC,
* hwndPrevIMC may be destroyed but we need to close the
* status window.
*/
hwndActive = NtUserQueryWindow(HWq(pwndIme), WindowActiveWindow);
if (pwndFocus == NULL || GETPTI(pwndIme) != GETPTI(pwndFocus) ||
hwndActive == NULL) {
pimeui->fShowStatus = FALSE;
if (IsWindow(hwndPrevIMC))
SendOpenStatusNotify(pimeui, hwndPrevIMC, FALSE);
else
SendMessageToUI(pimeui, WM_IME_NOTIFY,
IMN_CLOSESTATUSWINDOW, 0L, FALSE);
}
}
}
return lRet;
}
LONG ImeNotifyHandler(
PIMEUI pimeui,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
HWND hwndUI;
LONG lRet = 0L;
switch (wParam) {
case IMN_PRIVATE:
hwndUI = GETUI(pimeui);
if (IsWindow(hwndUI))
lRet = SendMessage(hwndUI, message, wParam, lParam);
break;
default:
lRet = SendMessageToUI(pimeui, message, wParam, lParam, FALSE);
}
return lRet;
}
HWND CreateIMEUI(
PIMEUI pimeui,
HKL hKL)
{
PWND pwndIme = pimeui->spwnd;
HWND hwndUI;
IMEINFOEX iiex;
PIMEDPI pimedpi;
WNDCLASS wndcls;
if (!ImmGetImeInfoEx(&iiex, ImeInfoExKeyboardLayout, &hKL))
return (HWND)NULL;
if ((pimedpi = ImmLockImeDpi(hKL)) == NULL) {
RIPMSG1(RIP_WARNING, "CreateIMEUI: ImmLockImeDpi(%lx) failed.", hKL);
return (HWND)NULL;
}
if (!GetClassInfoW(pimedpi->hInst, iiex.wszUIClass, &wndcls)) {
RIPMSG1(RIP_WARNING, "CreateIMEUI: GetClassInfoW(%ws) failed\n", iiex.wszUIClass);
ImmUnlockImeDpi(pimedpi);
return (HWND)NULL;
}
if (iiex.ImeInfo.fdwProperty & IME_PROP_UNICODE) {
/*
* For Unicode IME, we create an Unicode IME UI window.
*/
hwndUI = CreateWindowExW(0L,
iiex.wszUIClass,
iiex.wszUIClass,
WS_POPUP|WS_DISABLED,
0, 0, 0, 0,
HWq(pwndIme), 0, wndcls.hInstance, NULL);
}
else {
/*
* For ANSI IME, we create an ANSI IME UI window.
*/
LPSTR pszClass;
int i, cchBufSize;
BOOL bUDC;
cchBufSize = wcslen(iiex.wszUIClass) * sizeof(WCHAR);
pszClass = (LPSTR)LocalAlloc(LPTR, cchBufSize+1);
if (!pszClass)
return (HWND)NULL;
i = WideCharToMultiByte(CP_ACP,
(DWORD)0,
iiex.wszUIClass, // src
wcslen(iiex.wszUIClass),
pszClass, // dest
cchBufSize,
(LPSTR)NULL,
(LPBOOL)&bUDC);
pszClass[i] = '\0';
hwndUI = CreateWindowExA(0L,
pszClass,
pszClass,
WS_POPUP|WS_DISABLED,
0, 0, 0, 0,
HWq(pwndIme), 0, wndcls.hInstance, NULL);
LocalFree(pszClass);
}
if (hwndUI)
NtUserSetWindowLong(hwndUI, IMMGWL_IMC, (LONG)GETIMC(pimeui), FALSE);
return hwndUI;
}
VOID DestroyIMEUI(
PIMEUI pimeui)
{
// This has currently nothing to do except for destroying the UI.
// Review: Need to notify the UI with WM_IME_SETCONTEXT ?
// Review: This doesn't support Multiple IME install yet.
HWND hwndUI = GETUI(pimeui);
if (IsWindow(hwndUI)) {
pimeui->fDestroy = TRUE;
/*
* We need this verify because the owner might have already
* killed it during its termination.
*/
NtUserDestroyWindow(hwndUI);
}
pimeui->fDestroy = FALSE;
SETUI(pimeui, NULL);
return;
}
/***************************************************************************\
* SendMessageToUI
*
* History:
* 09-Apr-1996 wkwok Created
\***************************************************************************/
LONG SendMessageToUI(
PIMEUI pimeui,
UINT message,
WPARAM wParam,
LPARAM lParam,
BOOL fAnsi)
{
PWND pwndUI;
LONG lRet;
pwndUI = ValidateHwndNoRip(GETUI(pimeui));
if (pwndUI == NULL)
return 0L;
pimeui->nCntInIMEProc++; // Mark to avoid recursion.
lRet = SendMessageWorker(pwndUI, message, wParam, lParam, fAnsi);
pimeui->nCntInIMEProc--; // Mark to avoid recursion.
return lRet;
}
/***************************************************************************\
* SendOpenStatusNotify
*
* History:
* 09-Apr-1996 wkwok Created
\***************************************************************************/
VOID SendOpenStatusNotify(
PIMEUI pimeui,
HWND hwndApp,
BOOL fOpen)
{
WPARAM wParam = fOpen ? IMN_OPENSTATUSWINDOW : IMN_CLOSESTATUSWINDOW;
if (GetClientInfo()->dwExpWinVer >= VER40)
SendMessage(hwndApp, WM_IME_NOTIFY, wParam, 0L);
else
SendMessageToUI(pimeui, WM_IME_NOTIFY, wParam, 0L, FALSE);
return;
}
VOID ImeSetImc(
PIMEUI pimeui,
HIMC hImc)
{
HWND hImeWnd = HWq(pimeui->spwnd);
HIMC hOldImc = GETIMC(pimeui);
/*
* return if nothing to change.
*/
if (hImc == hOldImc)
return;
/*
* Unmark the old input context.
*/
if (hOldImc != NULL_HIMC)
ImeMarkUsedContext(NULL, hOldImc);
/*
* Update the in use input context for this IME window.
*/
pimeui->hIMC = hImc;
/*
* Mark the new input context.
*/
if (hImc != NULL_HIMC)
ImeMarkUsedContext(hImeWnd, hImc);
return;
}
/***************************************************************************\
* FocusSetIMCContext()
*
* History:
* 21-Mar-1996 wkwok Created
\***************************************************************************/
VOID FocusSetIMCContext(
HWND hWnd,
BOOL fActivate)
{
HIMC hImc;
if (IsWindow(hWnd)) {
hImc = ImmGetContext(hWnd);
ImmSetActiveContext(hWnd, hImc, fActivate);
ImmReleaseContext(hWnd, hImc);
}
else {
ImmSetActiveContext(NULL, NULL_HIMC, fActivate);
}
return;
}
BOOL ImeBroadCastMsg(
PIMEUI pimeui,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
return TRUE;
}
/***************************************************************************\
* ImeMarkUsedContext()
*
* Some IME windows can not share the same input context. This function
* marks the specified hImc to be in used by the specified IME window.
*
* History:
* 12-Mar-1996 wkwok Created
\***************************************************************************/
VOID ImeMarkUsedContext(
HWND hImeWnd,
HIMC hImc)
{
PIMC pImc;
pImc = HMValidateHandle((HANDLE)hImc, TYPE_INPUTCONTEXT);
if (pImc == NULL) {
RIPMSG1(RIP_WARNING, "ImeMarkUsedContext: Invalid hImc (=%lx).", hImc);
return;
}
UserAssert(pImc->hImeWnd == NULL || hImeWnd == NULL);
/*
* Nothing to change?
*/
if (pImc->hImeWnd == hImeWnd)
return;
NtUserUpdateInputContext(hImc, UpdateInUseImeWindow, (DWORD)hImeWnd);
return;
}
/***************************************************************************\
* ImeIsUsableContext()
*
* 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.
*
* History:
* 12-Mar-1996 wkwok Created
\***************************************************************************/
BOOL ImeIsUsableContext(
HWND hImeWnd,
HIMC hImc)
{
PIMC pImc;
UserAssert(hImeWnd != NULL);
pImc = HMValidateHandle((HANDLE)hImc, TYPE_INPUTCONTEXT);
if (pImc == NULL) {
RIPMSG1(RIP_WARNING, "ImeIsUsableContext: Invalid hImc (=%lx).", hImc);
return FALSE;
}
if (pImc->hImeWnd == NULL || pImc->hImeWnd == hImeWnd)
return TRUE;
return FALSE;
}