/**************************************************************************\ * Module Name: hotkey.c (corresponds to Win95 hotkey.c) * * Copyright (c) 1985 - 1999, Microsoft Corporation * * IME hot key management routines for imm32 dll * * History: * 03-Jan-1996 wkwok Created \**************************************************************************/ #include "precomp.h" #pragma hdrstop // // internal functions // BOOL CIMENonIMEToggle(HIMC hIMC, HKL hKL, HWND hWnd, LANGID langTarget); BOOL IMENonIMEToggle( HIMC hIMC, HKL hKL, HWND hWnd, BOOL fIME, LANGID langTarget); BOOL JCloseOpen( HIMC hIMC, HKL hKL, HWND hWnd); BOOL CSymbolToggle(HIMC hIMC, HKL hKL, HWND hWnd); BOOL TShapeToggle(HIMC hIMC, HKL hKL, HWND hWnd); BOOL KEnglishHangul( HIMC hIMC); BOOL KShapeToggle( HIMC hIMC); BOOL KHanjaConvert( HIMC hIMC); /***************************************************************************\ * ImmGetHotKey() * * Private API for IMEs and the control panel. The caller specifies * the IME hotkey ID:dwID. If a hotkey is registered with the specified * ID, this function returns the modifiers, vkey and hkl of the hotkey. * * History: * 25-Mar-1996 TakaoK Created \***************************************************************************/ BOOL WINAPI ImmGetHotKey( DWORD dwID, PUINT puModifiers, PUINT puVKey, HKL *phkl) { if (puModifiers == NULL || puVKey == NULL) { return FALSE; } return NtUserGetImeHotKey( dwID, puModifiers, puVKey, phkl ); } /**********************************************************************/ /* ImmSimulateHotKey() */ /* Return Value: */ /* TRUE - successful, FALSE - failure */ /**********************************************************************/ BOOL WINAPI ImmSimulateHotKey( // simulate the functionality of that hot key HWND hAppWnd, // application window handle DWORD dwHotKeyID) { HIMC hImc; HKL hKL; BOOL fReturn; hImc = ImmGetContext( hAppWnd ); hKL = GetKeyboardLayout( GetWindowThreadProcessId(hAppWnd, NULL) ); fReturn = HotKeyIDDispatcher( hAppWnd, hImc, hKL, dwHotKeyID); ImmReleaseContext( hAppWnd, hImc ); return fReturn; } /***************************************************************************\ * SaveImeHotKey() * * Put/Remove the specified IME hotkey entry from the registry * * History: * 25-Mar-1996 TakaoK Created \***************************************************************************/ /**********************************************************************/ /* HotKeyIDDispatcher */ /* Return Value: */ /* TRUE - a hot key processed, FALSE - not processed */ /**********************************************************************/ BOOL HotKeyIDDispatcher( HWND hWnd, HIMC hImc, HKL hKlCurrent, DWORD dwHotKeyID ) { /* * Dispatch the IME hotkey event for the specified hImc * only if the calling thread owns the hImc. */ if (hImc != NULL_HIMC && GetInputContextThread(hImc) != GetCurrentThreadId()) { return FALSE; } switch ( dwHotKeyID ) { case IME_CHOTKEY_IME_NONIME_TOGGLE: return CIMENonIMEToggle(hImc, hKlCurrent, hWnd, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)); case IME_THOTKEY_IME_NONIME_TOGGLE: return CIMENonIMEToggle(hImc, hKlCurrent, hWnd, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)); case IME_CHOTKEY_SYMBOL_TOGGLE: case IME_THOTKEY_SYMBOL_TOGGLE: return CSymbolToggle( hImc, hKlCurrent, hWnd); case IME_JHOTKEY_CLOSE_OPEN: return JCloseOpen( hImc, hKlCurrent, hWnd); case IME_KHOTKEY_ENGLISH: // VK_HANGUL : English/Hangul mode return KEnglishHangul( hImc ); case IME_KHOTKEY_SHAPE_TOGGLE: // VK_JUNJA : full/half width return KShapeToggle( hImc ); case IME_KHOTKEY_HANJACONVERT: // VK_HANJA : convert hangul to hanja return KHanjaConvert( hImc ); case IME_CHOTKEY_SHAPE_TOGGLE: case IME_THOTKEY_SHAPE_TOGGLE: return TShapeToggle( hImc, hKlCurrent, hWnd); default: /* * Direct swithing hotkey should have been handled in the kernel side. */ ImmAssert(dwHotKeyID < IME_HOTKEY_DSWITCH_FIRST || dwHotKeyID > IME_HOTKEY_DSWITCH_LAST); if ( dwHotKeyID >= IME_HOTKEY_PRIVATE_FIRST && dwHotKeyID <= IME_HOTKEY_PRIVATE_LAST ) { PIMEDPI pImeDpi; BOOL bRet = FALSE; if ( (pImeDpi = ImmLockImeDpi(hKlCurrent)) != NULL ) { bRet = (BOOL)(*pImeDpi->pfn.ImeEscape)( hImc, IME_ESC_PRIVATE_HOTKEY, (PVOID)&dwHotKeyID ); ImmUnlockImeDpi(pImeDpi); return bRet; } } } return (FALSE); } /**********************************************************************/ /* JCloseOpen() */ /* Return Value: */ /* TRUE - a hot key processed, FALSE - not processed */ /**********************************************************************/ BOOL JCloseOpen( // open/close toggle HIMC hIMC, HKL hCurrentKL, HWND hWnd) { if (ImmIsIME(hCurrentKL) && LOWORD(HandleToUlong(hCurrentKL)) == MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)) { // // If current KL is IME and its language is Japanese, // we only have to switch the open/close status. // ImmSetOpenStatus( hIMC, !ImmGetOpenStatus(hIMC) ); } else { // // If current KL is not IME or its language is not Japanese, // we should find the Japanese IME and set it open. // if (IMENonIMEToggle(hIMC, hCurrentKL, hWnd, FALSE, MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT))) { // // Mark it so that later we can initialize the fOpen // as expected. // PINPUTCONTEXT pInputContext = ImmLockIMC(hIMC); if (pInputContext) { pInputContext->fdwDirty |= IMSS_INIT_OPEN; ImmUnlockIMC(hIMC); } } } return TRUE; #if 0 // for your reference : old code ported from Win95 LPINPUTCONTEXT pInputContext; PIMEDPI pImeDpi; if ( (pInputContext = ImmLockIMC( hIMC )) == NULL ) { // // The return value is same as Win95. // Not happens so often any way. // return TRUE; } pImeDpi = ImmLockImeDpi( hCurrentKL ); if ( pImeDpi != NULL ) { // // update Input Context // pInputContext->fOpen = !pInputContext->fOpen; // // notify IME // (*pImeDpi->pfn.NotifyIME)( hIMC, NI_CONTEXTUPDATED, 0L, IMC_SETOPENSTATUS ); // // inform UI // SendMessage(hWnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0L); SendMessage(hWnd, WM_IME_SYSTEM, IMS_SETOPENSTATUS, 0L); ImmUnlockIMC( hIMC ); ImmUnlockImeDpi(pImeDpi); return TRUE; } else { if ( !pInputContext->fOpen ) { pInputContext->fOpen = TRUE; SendMessage(hWnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0L); SendMessage(hWnd, WM_IME_SYSTEM, IMS_SETOPENSTATUS, 0L); } ImmUnlockIMC( hIMC ); return IMENonIMEToggle(hIMC, hCurrentKL, hWnd, FALSE); } #endif } /***************************************************************************\ * HotkeyImmIsIME * * Checks whether the specified hKL is a HKL of an IME or not. * \***************************************************************************/ BOOL HotkeyImmIsIME( HKL hKL) { #if defined(CUAS_ENABLE) if (!IS_IME_KBDLAYOUT(hKL)) return FALSE; #else if (!ImmIsIME(hKL)) return FALSE; #endif return TRUE; } /**********************************************************************/ /* CIMENonIMEToggle() */ /* Return Value: */ /* TRUE - a hot key processed, FALSE - not processed */ /**********************************************************************/ BOOL CIMENonIMEToggle( // non-IME and IME toggle HIMC hIMC, HKL hKlCurrent, HWND hWnd, LANGID langId) { if (hWnd == NULL) return(FALSE); if (!HotkeyImmIsIME(hKlCurrent) || LOWORD(HandleToUlong(hKlCurrent)) != langId) { // // Current keyboard layout is not IME or its language does not match. // Let's try to switch to our IME. // IMENonIMEToggle(hIMC, hKlCurrent, hWnd, FALSE, langId); return TRUE; } else { LPINPUTCONTEXT pInputContext = ImmLockIMC( hIMC ); if ( pInputContext == NULL ) { // // returning TRUE even if we didn't change // return TRUE; } if (!pInputContext->fOpen) { // // toggle close to open // ImmSetOpenStatus(hIMC, TRUE); ImmUnlockIMC(hIMC); return TRUE; } else { ImmUnlockIMC(hIMC); IMENonIMEToggle(hIMC, hKlCurrent, hWnd, TRUE, 0); return TRUE; } } } /**********************************************************************/ /* IMENonIMEToggle() */ /* Return Value: */ /* TRUE - a hot key processed, FALSE - not processed */ /**********************************************************************/ BOOL IMENonIMEToggle( HIMC hIMC, HKL hCurrentKL, HWND hWnd, BOOL fCurrentIsIME, LANGID langTarget) { HKL hEnumKL[32], hTargetKL; UINT nLayouts, i; HKL hPrevKL; UNREFERENCED_PARAMETER(hIMC); hPrevKL = (HKL)NtUserGetThreadState( UserThreadStatePreviousKeyboardLayout ); // // If we find the same layout in the layout list, let's switch to // the layout. If we fail, let's switch to a first-found good // layout. // hTargetKL = NULL; nLayouts = GetKeyboardLayoutList(sizeof(hEnumKL)/sizeof(HKL), hEnumKL); // LATER: // Hmm, looks like we can't simply rely on hPrevKL on multiple lanugage // environment.. // if (hPrevKL != NULL) { if (langTarget == 0 || LOWORD(HandleToUlong(hPrevKL)) == langTarget) { // // If langtarget is not specified, or // if it matches the previous langauge. // for (i = 0; i < nLayouts; i++) { // valid target HKL if (hEnumKL[i] == hPrevKL) { hTargetKL = hPrevKL; break; } } } } if (hTargetKL == NULL) { for (i = 0; i < nLayouts; i++) { // find a valid target HKL if (fCurrentIsIME ^ HotkeyImmIsIME(hEnumKL[i])) { if (langTarget != 0 && LOWORD(HandleToUlong(hEnumKL[i])) != langTarget) { // If the target language is specified, check it continue; } hTargetKL = hEnumKL[i]; break; } } } if (hTargetKL != NULL && hCurrentKL != hTargetKL) { // depends on multilingual message and how to get the base charset // wait for confirmation of multiingual spec - tmp solution PostMessage(hWnd, WM_INPUTLANGCHANGEREQUEST, DEFAULT_CHARSET, (LPARAM)hTargetKL); } // // returning TRUE, even if we failed to switch // return HotkeyImmIsIME(hTargetKL); } /**********************************************************************/ /* CSymbolToggle() */ /* Return Value: */ /* TRUE - a hot key processed, FALSE - not processed */ /**********************************************************************/ BOOL CSymbolToggle( // symbol & non symbol toggle HIMC hIMC, HKL hKL, HWND hWnd) { LPINPUTCONTEXT pInputContext; // // Return TRUE even no layout switching - Win95 behavior // if (hWnd == NULL) return(FALSE); if ( ! HotkeyImmIsIME( hKL ) ) { return (FALSE); } if ( (pInputContext = ImmLockIMC( hIMC )) == NULL ) { // // The return value is same as Win95. // Not happens so often any way. // return TRUE; } if (pInputContext->fOpen) { // // toggle the symbol mode // ImmSetConversionStatus(hIMC, pInputContext->fdwConversion ^ IME_CMODE_SYMBOL, pInputContext->fdwSentence); } else { // // change close -> open // ImmSetOpenStatus(hIMC, TRUE); } ImmUnlockIMC(hIMC); return (TRUE); } /**********************************************************************/ /* TShapeToggle() */ /* Return Value: */ /* TRUE - a hot key processed, FALSE - not processed */ /**********************************************************************/ BOOL TShapeToggle( // fullshape & halfshape toggle HIMC hIMC, HKL hKL, HWND hWnd) { LPINPUTCONTEXT pInputContext; // // Return TRUE even no layout switching - Win95 behavior // if (hWnd == NULL) return(FALSE); if ( ! HotkeyImmIsIME( hKL ) ) { return (FALSE); } if ( (pInputContext = ImmLockIMC( hIMC )) == NULL ) { // // The return value is same as Win95. // Not happens so often any way. // return TRUE; } if (pInputContext->fOpen) { // // toggle the symbol mode // ImmSetConversionStatus(hIMC, pInputContext->fdwConversion ^ IME_CMODE_FULLSHAPE, pInputContext->fdwSentence); } else { // // change close -> open // ImmSetOpenStatus(hIMC, TRUE); } ImmUnlockIMC(hIMC); return (TRUE); } /**********************************************************************/ /* KEnglishHangul() - Egnlish & Hangeul toggle */ /* Return Value: */ /* TRUE - a hot key processed, FALSE - not processed */ /**********************************************************************/ BOOL KEnglishHangul( HIMC hImc ) { PINPUTCONTEXT pInputContext; if ((pInputContext = ImmLockIMC(hImc)) != NULL) { ImmSetConversionStatus(hImc, pInputContext->fdwConversion ^ IME_CMODE_HANGEUL, pInputContext->fdwSentence); if ((pInputContext->fdwConversion & IME_CMODE_HANGEUL) || (pInputContext->fdwConversion & IME_CMODE_FULLSHAPE)) { ImmSetOpenStatus(hImc, TRUE); } else { ImmSetOpenStatus(hImc, FALSE); } ImmUnlockIMC(hImc); return TRUE; } return FALSE; } /**********************************************************************/ /* KShapeToggle() - Fullshape & Halfshape toggle */ /* Return Value: */ /* TRUE - a hot key processed, FALSE - not processed */ /**********************************************************************/ BOOL KShapeToggle( HIMC hImc ) { PINPUTCONTEXT pInputContext; if ( (pInputContext = ImmLockIMC( hImc )) != NULL ) { ImmSetConversionStatus(hImc, pInputContext->fdwConversion ^ IME_CMODE_FULLSHAPE, pInputContext->fdwSentence); if ((pInputContext->fdwConversion & IME_CMODE_HANGEUL) || (pInputContext->fdwConversion & IME_CMODE_FULLSHAPE)) ImmSetOpenStatus(hImc, TRUE); else ImmSetOpenStatus(hImc, FALSE); ImmUnlockIMC(hImc); return TRUE; } return FALSE; } /**********************************************************************/ /* KHanjaConvert() - Hanja conversion toggle */ /* Return Value: */ /* TRUE - a hot key processed, FALSE - not processed */ /**********************************************************************/ BOOL KHanjaConvert( HIMC hImc ) { PINPUTCONTEXT pInputContext; if ( (pInputContext = ImmLockIMC( hImc )) != NULL ) { ImmSetConversionStatus( hImc, pInputContext->fdwConversion ^ IME_CMODE_HANJACONVERT, pInputContext->fdwSentence ); ImmUnlockIMC( hImc ); return TRUE; } return FALSE; }