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.
554 lines
18 KiB
554 lines
18 KiB
/**************************************************************************\
|
|
* 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;
|
|
}
|