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.
 
 
 
 
 
 

556 lines
18 KiB

/**************************************************************************\
* Module Name: input.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* IME key input management routines for imm32 dll
*
* History:
* 01-Apr-1996 takaok split from hotkey.c
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#ifdef HIRO_DEBUG
#define D(x) x
#else
#define D(x)
#endif
/***************************************************************************\
* ImmProcessKey (Callback from Win32K.SYS)
*
* Call ImeProcessKey and IME hotkey handler
*
* History:
* 01-Mar-1996 TakaoK Created
\***************************************************************************/
DWORD WINAPI ImmProcessKey(
HWND hWnd,
HKL hkl,
UINT uVKey,
LPARAM lParam,
DWORD dwHotKeyID)
{
HIMC hIMC = ImmGetContext(hWnd);
PIMEDPI pImeDpi = ImmLockImeDpi(hkl);
DWORD dwReturn = 0;
#if DBG
if (dwHotKeyID >= IME_KHOTKEY_FIRST && dwHotKeyID <= IME_KHOTKEY_LAST) {
TAGMSG2(DBGTAG_IMM, "ImmProcessKey: Kor IME Hotkeys should not come here: dwHotKeyID=%x, uVKey=%x", dwHotKeyID, uVKey);
}
#endif
ImmAssert(dwHotKeyID != IME_KHOTKEY_ENGLISH &&
dwHotKeyID != IME_KHOTKEY_SHAPE_TOGGLE &&
dwHotKeyID != IME_KHOTKEY_HANJACONVERT);
//
// call ImeProcessKey
//
if (pImeDpi != NULL) {
PINPUTCONTEXT pInputContext = ImmLockIMC(hIMC);
if (pInputContext != NULL) {
BOOLEAN fTruncateWideVK = FALSE;
BOOLEAN fCallIme = TRUE;
BOOLEAN fSkipThisKey = FALSE;
#ifdef LATER
//
// if the current imc is not open and IME doesn't need
// keys when being closed, we don't pass any keyboard
// input to ime except hotkey and keys that change
// the keyboard status.
//
if ((pImeDpi->fdwProperty & IME_PROP_NO_KEYS_ON_CLOSE) &&
!pInputContext->fOpen &&
uVKey != VK_SHIFT &&
uVKey != VK_CONTROL &&
uVKey != VK_CAPITAL &&
uVKey != VK_KANA &&
uVKey != VK_NUMLOCK &&
uVKey != VK_SCROLL) {
// Check if Korea Hanja conversion mode
if(!(pimc->fdwConvMode & IME_CMODE_HANJACONVERT)) {
fCallIme = FALSE;
}
}
else
#endif
//
// Protect IMEs which are unaware of wide virtual keys.
//
if ((BYTE)uVKey == VK_PACKET &&
(pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY) == 0) {
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) {
//
// Since this IME is not ready to accept wide VKey, we should
// truncate it.
//
fTruncateWideVK = TRUE;
}
else {
//
// Hmm, this guy is ANSI IME, and does not declare Wide Vkey awareness.
// Let's guess this one is not ready to accept Wide Vkey, so let's not
// pass it to this guy.
// And if it is opened, we'd better skip this key for safety.
//
fCallIme = FALSE;
if (pInputContext->fOpen) {
fSkipThisKey = TRUE;
}
}
}
if (fCallIme) {
PBYTE pbKeyState = (PBYTE)ImmLocalAlloc(0, 256);
ImmAssert(fSkipThisKey == FALSE);
if (pbKeyState != NULL) {
if (GetKeyboardState(pbKeyState)) {
UINT uVKeyIme = uVKey;
if (fTruncateWideVK) {
uVKeyIme &= 0xffff;
}
if ( (*pImeDpi->pfn.ImeProcessKey)(hIMC, uVKeyIme, lParam, pbKeyState) ) {
//
// if the return value of ImeProcessKey is TRUE,
// it means the key is the one that the ime is
// waiting for.
//
pInputContext->fChgMsg = TRUE;
pInputContext->uSavedVKey = uVKey;
dwReturn |= IPHK_PROCESSBYIME;
}
}
ImmLocalFree(pbKeyState);
}
}
else if (fSkipThisKey) {
dwReturn |= IPHK_SKIPTHISKEY;
ImmAssert((dwReturn & (IPHK_PROCESSBYIME | IPHK_HOTKEY)) == 0);
}
ImmUnlockIMC(hIMC);
}
ImmUnlockImeDpi(pImeDpi);
}
//
// call hotkey handler
//
#if !defined(CUAS_ENABLE)
if (dwHotKeyID != IME_INVALID_HOTKEY && HotKeyIDDispatcher(hWnd, hIMC, hkl, dwHotKeyID)) {
// Backward compat:
// On Japanese system, some applications may want VK_KANJI.
if ((uVKey != VK_KANJI) ||
(dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN)) {
dwReturn |= IPHK_HOTKEY;
}
}
#else
//
// Check MSCTF's keyboard hook is running in this thread.
// We can use MSCTF's hotkey handler only when MSCTF's keyboard hook
// is installed and running.
//
if (CtfImmIsCiceroStartedInThread()) {
BOOL fHandled = FALSE;
if (Internal_CtfImeProcessCicHotkey(hIMC, uVKey, lParam)) {
// Backward compat:
// On Japanese system, some applications may want VK_KANJI.
if ((uVKey != VK_KANJI) ||
(dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN)) {
dwReturn |= IPHK_HOTKEY;
}
fHandled = TRUE;
}
if (!fHandled && IS_IME_KBDLAYOUT(hkl))
{
goto TryIMEHotkey;
}
} else {
TryIMEHotkey:
if (dwHotKeyID != IME_INVALID_HOTKEY) {
if (HotKeyIDDispatcher(hWnd, hIMC, hkl, dwHotKeyID)) {
// Backward compat:
// On Japanese system, some applications may want VK_KANJI.
if ((uVKey != VK_KANJI) ||
(dwHotKeyID != IME_JHOTKEY_CLOSE_OPEN)) {
dwReturn |= IPHK_HOTKEY;
}
}
}
}
#endif
//
// some 3.x application doesn't like to see
// VK_PROCESSKEY.
//
if (dwReturn & IPHK_PROCESSBYIME) {
DWORD dwImeCompat = ImmGetAppCompatFlags(hIMC);
if (dwImeCompat & IMECOMPAT_NOVKPROCESSKEY) {
// Korea 3.x application doesn't like to see dummy finalize VK_PROCESSKEY
// and IME hot key.
if ( PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) == LANG_KOREAN &&
( (uVKey == VK_PROCESSKEY) || (dwReturn & IPHK_HOTKEY) ) ) {
ImmReleaseContext(hWnd, hIMC);
return dwReturn;
}
ImmTranslateMessage(hWnd, WM_KEYDOWN, VK_PROCESSKEY, lParam);
dwReturn &= ~IPHK_PROCESSBYIME;
dwReturn |= IPHK_SKIPTHISKEY;
}
}
ImmReleaseContext(hWnd, hIMC);
return dwReturn;
}
#define TRANSMSGCOUNT 256
/***************************************************************************\
* ImmTranslateMessage (Called from user\client\ntstubs.c\TranslateMessage())
*
* Call ImeToAsciiEx()
*
* History:
* 01-Mar-1996 TakaoK Created
\***************************************************************************/
BOOL ImmTranslateMessage(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
HIMC hImc;
PINPUTCONTEXT pInputContext;
BOOL fReturn = FALSE;
HKL hkl;
PIMEDPI pImeDpi = NULL;
PBYTE pbKeyState;
PTRANSMSG pTransMsg;
PTRANSMSGLIST pTransMsgList;
DWORD dwSize;
UINT uVKey;
INT iNum;
UNREFERENCED_PARAMETER(wParam);
//
// we're interested in only those keyboard messages.
//
switch (message) {
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
break;
default:
return FALSE;
}
//
// input context is necessary for further handling
//
hImc = ImmGetContext(hwnd);
pInputContext = ImmLockIMC(hImc);
if (pInputContext == NULL) {
ImmReleaseContext(hwnd, hImc);
return FALSE;
}
//
// At first, handle VK_PROCESSKEY generated by IME.
//
if (!pInputContext->fChgMsg) {
if ((iNum=pInputContext->dwNumMsgBuf) != 0) {
pTransMsg = (PTRANSMSG)ImmLockIMCC(pInputContext->hMsgBuf);
if (pTransMsg != NULL) {
ImmPostMessages(hwnd, hImc, iNum, pTransMsg);
ImmUnlockIMCC(pInputContext->hMsgBuf);
fReturn = TRUE;
}
pInputContext->dwNumMsgBuf = 0;
}
goto ExitITM;
}
pInputContext->fChgMsg = FALSE;
//
// retrieve the keyboard layout and IME entry points
//
hkl = GetKeyboardLayout( GetWindowThreadProcessId(hwnd, NULL) );
pImeDpi = ImmLockImeDpi(hkl);
if (pImeDpi == NULL) {
RIPMSG1(RIP_WARNING, "ImmTranslateMessage pImeDpi is NULL(hkl=%x)", hkl);
goto ExitITM;
}
pbKeyState = ImmLocalAlloc(0, 256);
if ( pbKeyState == NULL ) {
RIPMSG0(RIP_WARNING, "ImmTranslateMessage out of memory" );
goto ExitITM;
}
if (!GetKeyboardState(pbKeyState)) {
RIPMSG0(RIP_WARNING, "ImmTranslateMessage GetKeyboardState() failed" );
ImmLocalFree( pbKeyState );
goto ExitITM;
}
//
// Translate the saved vkey into character code if needed
//
uVKey = pInputContext->uSavedVKey;
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) {
if (pImeDpi->ImeInfo.fdwProperty & IME_PROP_UNICODE) {
WCHAR wcTemp;
iNum = ToUnicode(pInputContext->uSavedVKey, // virtual-key code
HIWORD(lParam), // scan code
pbKeyState, // key-state array
&wcTemp, // buffer for translated key
1, // size of buffer
0);
if (iNum == 1) {
//
// hi word : unicode character code
// hi byte of lo word : zero
// lo byte of lo word : virtual key
//
uVKey = (uVKey & 0x00ff) | ((UINT)wcTemp << 16);
}
} else {
WORD wTemp = 0;
iNum = ToAsciiEx(pInputContext->uSavedVKey, // virtual-key code
HIWORD(lParam), // scan code
pbKeyState, // key-state array
&wTemp, // buffer for translated key
0, // active-menu flag
hkl);
ImmAssert(iNum <= 2);
if (iNum > 0) {
//
// hi word : should be zero
// hi byte of lo word : character code
// lo byte of lo word : virtual key
//
uVKey = (uVKey & 0x00FF) | ((UINT)wTemp << 8);
if ((BYTE)uVKey == VK_PACKET) {
//
// If ANSI IME is wide vkey aware, its ImeToAsciiEx will receive the uVKey
// as follows:
//
// 31 24 23 16 15 8 7 0
// +----------------+-----------------------------+-------------------+---------------+
// | 24~31:reserved | 16~23:trailing byte(if any) | 8~15:leading byte | 0~7:VK_PACKET |
// +----------------+-----------------------------+-------------------+---------------+
//
ImmAssert(pImeDpi->ImeInfo.fdwProperty & IME_PROP_ACCEPT_WIDE_VKEY);
}
else {
uVKey &= 0xffff;
}
}
}
}
dwSize = FIELD_OFFSET(TRANSMSGLIST, TransMsg)
+ TRANSMSGCOUNT * sizeof(TRANSMSG);
pTransMsgList = (PTRANSMSGLIST)ImmLocalAlloc(0, dwSize);
if (pTransMsgList == NULL) {
RIPMSG0(RIP_WARNING, "ImmTranslateMessage out of memory" );
ImmLocalFree(pbKeyState);
goto ExitITM;
}
pTransMsgList->uMsgCount = TRANSMSGCOUNT;
iNum = (*pImeDpi->pfn.ImeToAsciiEx)(uVKey,
HIWORD(lParam),
pbKeyState,
pTransMsgList,
0,
hImc);
if (iNum > TRANSMSGCOUNT) {
//
// The message buffer is not big enough. IME put messages
// into hMsgBuf in the input context.
//
pTransMsg = (PTRANSMSG)ImmLockIMCC(pInputContext->hMsgBuf);
if (pTransMsg != NULL) {
ImmPostMessages(hwnd, hImc, iNum, pTransMsg);
ImmUnlockIMCC(pInputContext->hMsgBuf);
}
#ifdef LATER
// Shouldn't we need this ?
fReturn = TRUE;
#endif
} else if (iNum > 0) {
ImmPostMessages(hwnd, hImc, iNum, &pTransMsgList->TransMsg[0]);
fReturn = TRUE;
}
ImmLocalFree(pbKeyState);
ImmLocalFree(pTransMsgList);
ExitITM:
ImmUnlockImeDpi(pImeDpi);
ImmUnlockIMC(hImc);
ImmReleaseContext(hwnd, hImc);
return fReturn;
}
/***************************************************************************\
* ImmPostMessages(Called from ImmTranslateMessage() )
*
* Post IME messages to application. If application is 3.x, messages
* are translated to old IME messages.
*
* History:
* 01-Mar-1996 TakaoK Created
\***************************************************************************/
VOID
ImmPostMessages(
HWND hWnd,
HIMC hImc,
INT iNum,
PTRANSMSG pTransMsg)
{
INT i;
BOOL fAnsiIME;
PCLIENTIMC pClientImc;
PTRANSMSG pTransMsgTemp, pTransMsgBuf = NULL;
//
// Check if the IME is unicode or not.
// The message buffer contains unicode messages
// if the IME is unicode.
//
pClientImc = ImmLockClientImc(hImc);
if (pClientImc == NULL) {
RIPMSG1(RIP_WARNING,
"ImmPostMessages: Invalid hImc %lx.", hImc);
return;
}
fAnsiIME = ! TestICF(pClientImc, IMCF_UNICODE);
ImmUnlockClientImc(pClientImc);
//
// translate messages to 3.x format if the App's version is 3.x.
//
pTransMsgTemp = pTransMsg;
if (GetClientInfo()->dwExpWinVer < VER40) {
DWORD dwLangId = PRIMARYLANGID(
LANGIDFROMLCID(
GetSystemDefaultLCID()));
if ( (dwLangId == LANG_KOREAN && TransGetLevel(hWnd) == 3) ||
dwLangId == LANG_JAPANESE ) {
pTransMsgBuf = ImmLocalAlloc(0, iNum * sizeof(TRANSMSG));
if (pTransMsgBuf != NULL) {
RtlCopyMemory(pTransMsgBuf, pTransMsg, iNum * sizeof(TRANSMSG));
iNum = WINNLSTranslateMessage(iNum,
pTransMsgBuf,
hImc,
fAnsiIME,
dwLangId );
pTransMsgTemp = pTransMsgBuf;
}
}
}
for (i = 0; i < iNum; i++) {
if (fAnsiIME) {
PostMessageA(hWnd,
pTransMsgTemp->message,
pTransMsgTemp->wParam,
pTransMsgTemp->lParam);
} else {
PostMessageW(hWnd,
pTransMsgTemp->message,
pTransMsgTemp->wParam,
pTransMsgTemp->lParam);
}
pTransMsgTemp++;
}
if (pTransMsgBuf != NULL) {
ImmLocalFree(pTransMsgBuf);
}
}
UINT WINNLSTranslateMessage(
INT iNum, // number of messages in the source buffer
PTRANSMSG pTransMsg, // source buffer that contains 4.0 style messages
HIMC hImc, // input context handle
BOOL fAnsi, // TRUE if pdwt contains ANSI messages
DWORD dwLangId ) // language ID ( KOREAN or JAPANESE )
{
LPINPUTCONTEXT pInputContext;
LPCOMPOSITIONSTRING pCompStr;
UINT uiRet = 0;
pInputContext = ImmLockIMC(hImc);
if (pInputContext == NULL) {
return uiRet;
}
pCompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC( pInputContext->hCompStr );
if (pCompStr != NULL) {
if (dwLangId == LANG_KOREAN) {
uiRet = WINNLSTranslateMessageK((UINT)iNum,
pTransMsg,
pInputContext,
pCompStr,
fAnsi );
} else if ( dwLangId == LANG_JAPANESE ) {
uiRet = WINNLSTranslateMessageJ((UINT)iNum,
pTransMsg,
pInputContext,
pCompStr,
fAnsi );
}
ImmUnlockIMCC(pInputContext->hCompStr);
}
ImmUnlockIMC(hImc);
return uiRet;
}