/************************************************* * toascii.c * * * * Copyright (C) 1999 Microsoft Inc. * * * *************************************************/ #include #include #include "imeattr.h" #include "imedefs.h" /**********************************************************************/ /* ProcessKey() */ /* Return Value: */ /* different state which input key will change IME to */ /**********************************************************************/ UINT PASCAL ProcessKey( // this key will cause the IME go to what state WORD wCharCode, UINT uVirtKey, UINT uScanCode, CONST LPBYTE lpbKeyState, LPINPUTCONTEXT lpIMC, LPPRIVCONTEXT lpImcP) { if (!lpIMC) { return (CST_INVALID); } if (!lpImcP) { return (CST_INVALID); } if (uVirtKey == VK_MENU) { // // no ALT key // return (CST_INVALID); } else if (uScanCode & KF_ALTDOWN) { // // no ALT-xx key // return (CST_INVALID); } else if (uVirtKey == VK_CONTROL) { // // no CTRL key // return (CST_INVALID); } else if (lpbKeyState[VK_CONTROL] & 0x80) { // // no CTRL-xx key // return (CST_INVALID); } else if (uVirtKey == VK_SHIFT) { // // no SHIFT key // return (CST_INVALID); } else if (!lpIMC->fOpen) { // // don't compose in close status // return (CST_INVALID); } else if (lpIMC->fdwConversion & IME_CMODE_NOCONVERSION) { // // don't compose in no coversion status // return (CST_INVALID); } else if (lpIMC->fdwConversion & IME_CMODE_CHARCODE) { // // not support // return (CST_INVALID); } if (uVirtKey >= VK_NUMPAD0 && uVirtKey <= VK_DIVIDE) { // // A PM decision: all numpad should be past to app // return (CST_ALPHANUMERIC); } if (!(lpIMC->fdwConversion & IME_CMODE_NATIVE)) { return (CST_INVALID); } else if (!(lpbKeyState[VK_SHIFT] & 0x80)) { // // need more check for IME_CMODE_NATIVE // } else if (wCharCode < ' ' && wCharCode > '~') { return (CST_INVALID); } // // need more check for IME_CMODE_NATIVE // if (wCharCode >= ' ' && wCharCode <= 'z') { wCharCode = bUpper[wCharCode - ' ']; } if (uVirtKey == VK_ESCAPE) { register LPGUIDELINE lpGuideLine; register UINT iImeState; if (lpImcP->fdwImeMsg & MSG_ALREADY_START) { return (CST_INPUT); } lpGuideLine = ImmLockIMCC(lpIMC->hGuideLine); if (!lpGuideLine) { return (CST_INVALID); } else if (lpGuideLine->dwLevel == GL_LEVEL_NOGUIDELINE) { iImeState = CST_INVALID; } else { // // need this key to clean information string or guideline state // iImeState = CST_INPUT; } ImmUnlockIMCC(lpIMC->hGuideLine); return (iImeState); } else if (uVirtKey == VK_BACK) { if (lpImcP->fdwImeMsg & MSG_ALREADY_START) { return (CST_INPUT); } else { return (CST_INVALID); } } // // check finalize char // if (wCharCode == ' ' && lpImcP->iImeState == CST_INIT) { return (CST_INVALID); } else if (lpImeL->fCompChar[(wCharCode - ' ') >> 4] & fMask[wCharCode & 0x000F]) { return (CST_INPUT); } else if (wCharCode >= 'G' && wCharCode <= 'Z' || wCharCode >= 'g' && wCharCode <= 'z') { // // PM decision says we should not send these letters to input // to avoid confusing users. We special handle this case by // introducing CST_BLOCKINPUT flag. // return (CST_BLOCKINPUT); } return (CST_INVALID); } /**********************************************************************/ /* ImeProcessKey() / UniImeProcessKey() */ /* Return Value: */ /* TRUE - successful, FALSE - failure */ /**********************************************************************/ // if this key is need by IME? BOOL WINAPI ImeProcessKey( HIMC hIMC, UINT uVirtKey, LPARAM lParam, CONST LPBYTE lpbKeyState) { LPINPUTCONTEXT lpIMC; LPPRIVCONTEXT lpImcP; BYTE szAscii[4]; int nChars; BOOL fRet; // // can't compose in NULL hIMC // if (!hIMC) { return (FALSE); } lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC); if (!lpIMC) { return (FALSE); } lpImcP = (LPPRIVCONTEXT)ImmLockIMCC(lpIMC->hPrivate); if (!lpImcP) { ImmUnlockIMC(hIMC); return (FALSE); } nChars = ToAscii(uVirtKey, HIWORD(lParam), lpbKeyState, (LPVOID)szAscii, 0); if (!nChars) { szAscii[0] = 0; } if (ProcessKey( (WORD)szAscii[0], uVirtKey, HIWORD(lParam), lpbKeyState, lpIMC, lpImcP) == CST_INVALID) { fRet = FALSE; } else { fRet = TRUE; } ImmUnlockIMCC(lpIMC->hPrivate); ImmUnlockIMC(hIMC); return (fRet); } /**********************************************************************/ /* TranslateToAscii() */ /* Translates the key input to WM_CHAR as keyboard drivers does */ /* */ /* Return Value: */ /* the number of translated chars */ /**********************************************************************/ UINT PASCAL TranslateToAscii( UINT uScanCode, LPTRANSMSG lpTransMsg, WORD wCharCode) { if (wCharCode) { // // one char code // lpTransMsg->message = WM_CHAR; lpTransMsg->wParam = wCharCode; lpTransMsg->lParam = (uScanCode << 16) | 1UL; return (1); } // // no char code case // return (0); } /**********************************************************************/ /* TranslateImeMessage() */ /* Return Value: */ /* the number of translated messages */ /**********************************************************************/ UINT PASCAL TranslateImeMessage( LPTRANSMSGLIST lpTransBuf, LPINPUTCONTEXT lpIMC, LPPRIVCONTEXT lpImcP) { UINT uNumMsg; UINT i; BOOL bLockMsgBuf; LPTRANSMSG lpTransMsg; uNumMsg = 0; bLockMsgBuf = FALSE; for (i = 0; i < 2; i++) { if (lpImcP->fdwImeMsg & MSG_IMN_COMPOSITIONSIZE) { if (!i) { uNumMsg++; } else { lpTransMsg->message = WM_IME_NOTIFY; lpTransMsg->wParam = IMN_PRIVATE; lpTransMsg->lParam = IMN_PRIVATE_COMPOSITION_SIZE; lpTransMsg += 1; } } if (lpImcP->fdwImeMsg & MSG_START_COMPOSITION) { if (!(lpImcP->fdwImeMsg & MSG_ALREADY_START)) { if (!i) { uNumMsg++; } else { lpTransMsg->message = WM_IME_STARTCOMPOSITION; lpTransMsg->wParam = 0; lpTransMsg->lParam = 0; lpTransMsg += 1; lpImcP->fdwImeMsg |= MSG_ALREADY_START; } } } if (lpImcP->fdwImeMsg & MSG_IMN_COMPOSITIONPOS) { if (!i) { uNumMsg++; } else { lpTransMsg->message = WM_IME_NOTIFY; lpTransMsg->wParam = IMN_SETCOMPOSITIONWINDOW; lpTransMsg->lParam = 0; lpTransMsg += 1; } } if (lpImcP->fdwImeMsg & MSG_COMPOSITION) { if (!i) { uNumMsg++; } else { lpTransMsg->message = WM_IME_COMPOSITION; lpTransMsg->wParam = lpImcP->dwCompChar; lpTransMsg->lParam = lpImcP->fdwGcsFlag; lpTransMsg += 1; } } if (lpImcP->fdwImeMsg & MSG_GUIDELINE) { if (!i) { uNumMsg++; } else { lpTransMsg->message = WM_IME_NOTIFY; lpTransMsg->wParam = IMN_GUIDELINE; lpTransMsg->lParam = 0; lpTransMsg += 1; } } if (lpImcP->fdwImeMsg & MSG_IMN_PAGEUP) { if (!i) { uNumMsg++; } else { lpTransMsg->message = WM_IME_NOTIFY; lpTransMsg->wParam = IMN_PRIVATE; lpTransMsg->lParam = IMN_PRIVATE_PAGEUP; lpTransMsg += 1; } } if (lpImcP->fdwImeMsg & MSG_END_COMPOSITION) { if (lpImcP->fdwImeMsg & MSG_ALREADY_START) { if (!i) { uNumMsg++; } else { lpTransMsg->message = WM_IME_ENDCOMPOSITION; lpTransMsg->wParam = 0; lpTransMsg->lParam = 0; lpTransMsg += 1; lpImcP->fdwImeMsg &= ~(MSG_ALREADY_START); } } } if (lpImcP->fdwImeMsg & MSG_IMN_TOGGLE_UI) { if (!i) { uNumMsg++; } else { lpTransMsg->message = WM_IME_NOTIFY; lpTransMsg->wParam = IMN_PRIVATE; lpTransMsg->lParam = IMN_PRIVATE_TOGGLE_UI; lpTransMsg += 1; } } if (!i) { HIMCC hMem; if (!uNumMsg) { return (uNumMsg); } if (lpImcP->fdwImeMsg & MSG_IN_IMETOASCIIEX) { UINT uNumMsgLimit; // ++ for the start position of buffer to strore the messages uNumMsgLimit = lpTransBuf->uMsgCount; if (uNumMsg <= uNumMsgLimit) { lpTransMsg = lpTransBuf->TransMsg; continue; } } // we need to use message buffer if (!lpIMC->hMsgBuf) { lpIMC->hMsgBuf = ImmCreateIMCC(uNumMsg * sizeof(TRANSMSG)); lpIMC->dwNumMsgBuf = 0; } else if (hMem = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + uNumMsg) * sizeof(TRANSMSG))) { if (hMem != lpIMC->hMsgBuf) { ImmDestroyIMCC(lpIMC->hMsgBuf); lpIMC->hMsgBuf = hMem; } } else { return (0); } lpTransMsg = (LPTRANSMSG)ImmLockIMCC(lpIMC->hMsgBuf); if (!lpTransMsg) { return (0); } lpTransMsg += lpIMC->dwNumMsgBuf; bLockMsgBuf = TRUE; } else { if (bLockMsgBuf) { ImmUnlockIMCC(lpIMC->hMsgBuf); } } } return (uNumMsg); } /**********************************************************************/ /* ImeToAsciiEx() / UniImeToAsciiex() */ /* Return Value: */ /* the number of translated message */ /**********************************************************************/ UINT WINAPI ImeToAsciiEx( UINT uVirtKey, UINT uScanCode, CONST LPBYTE lpbKeyState, LPTRANSMSGLIST lpTransBuf, UINT fuState, HIMC hIMC) { WORD wCharCode; LPINPUTCONTEXT lpIMC; LPCOMPOSITIONSTRING lpCompStr; LPGUIDELINE lpGuideLine; LPPRIVCONTEXT lpImcP; UINT uNumMsg; int iRet; wCharCode = HIWORD(uVirtKey); uVirtKey = LOBYTE(uVirtKey); if (!hIMC) { return TranslateToAscii(uScanCode, &lpTransBuf->TransMsg[0], wCharCode); } lpIMC = (LPINPUTCONTEXT)ImmLockIMC(hIMC); if (!lpIMC) { return TranslateToAscii(uScanCode, &lpTransBuf->TransMsg[0], wCharCode); } lpImcP = (LPPRIVCONTEXT)ImmLockIMCC(lpIMC->hPrivate); if (!lpImcP) { ImmUnlockIMC(hIMC); return TranslateToAscii(uScanCode, &lpTransBuf->TransMsg[0], wCharCode); } // Now all composition realated information already pass to app // a brand new start lpImcP->fdwImeMsg = lpImcP->fdwImeMsg & (MSG_STATIC_STATE) | MSG_IN_IMETOASCIIEX; iRet = ProcessKey(wCharCode, uVirtKey, uScanCode, lpbKeyState, lpIMC, lpImcP); if (iRet == CST_ALPHABET) { // A-Z convert to a-z, a-z convert to A-Z wCharCode ^= 0x20; iRet = CST_ALPHANUMERIC; } if (iRet == CST_ALPHANUMERIC) { uNumMsg = TranslateImeMessage(lpTransBuf, lpIMC, lpImcP); uNumMsg += TranslateToAscii(uScanCode, &lpTransBuf->TransMsg[uNumMsg], wCharCode); } else if (iRet == CST_INPUT) { lpCompStr = (LPCOMPOSITIONSTRING)ImmLockIMCC(lpIMC->hCompStr); lpGuideLine = (LPGUIDELINE)ImmLockIMCC(lpIMC->hGuideLine); CompWord(wCharCode, hIMC, lpIMC, lpCompStr, lpGuideLine, lpImcP); if (lpGuideLine) { ImmUnlockIMCC(lpIMC->hGuideLine); } if (lpCompStr) { ImmUnlockIMCC(lpIMC->hCompStr); } uNumMsg = TranslateImeMessage(lpTransBuf, lpIMC, lpImcP); } else if (iRet == CST_BLOCKINPUT) { // // This codepoint should be blocked. We don't compose it for IME. // Nor do we pass it to normal input. Instead, we beep. // MessageBeep(-1); uNumMsg = 0; } else { uNumMsg = TranslateToAscii(uScanCode, &lpTransBuf->TransMsg[0], wCharCode); } lpImcP->fdwImeMsg &= (MSG_STATIC_STATE); lpImcP->fdwGcsFlag = 0; ImmUnlockIMCC(lpIMC->hPrivate); ImmUnlockIMC(hIMC); return (uNumMsg); }