mirror of https://github.com/lianthony/NT4.0
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.
937 lines
28 KiB
937 lines
28 KiB
/**************************************************************************\
|
|
* Module Name: hotkey.c (corresponds to Win95 hotkey.c)
|
|
*
|
|
* Copyright (c) Microsoft Corp. 1995 All Rights Reserved
|
|
*
|
|
* IME hot key management routines for imm32 dll
|
|
*
|
|
* History:
|
|
* 03-Jan-1996 wkwok Created
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// internal functions
|
|
//
|
|
BOOL SaveImeHotKey( DWORD dwID, UINT uModifiers, UINT uVKey, HKL hkl, BOOL fDelete );
|
|
BOOL ImmSetHotKeyWorker( DWORD dwID, UINT uModifiers, UINT uVKey, HKL hkl, DWORD dwAction );
|
|
VOID NumToHexAscii( DWORD, PTSTR);
|
|
BOOL CIMENonIMEToggle( HIMC hIMC, HKL hKL, HWND hWnd);
|
|
BOOL IMENonIMEToggle( HIMC hIMC, HKL hKL, HWND hWnd, BOOL fIME);
|
|
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 GetImeHotKeysFromRegistry();
|
|
BOOL SetSingleHotKey( PKEY_BASIC_INFORMATION pKeyInfo, HANDLE hKey );
|
|
VOID SetDefaultImeHotKeys( PIMEHOTKEY ph, INT num, BOOL fCheckExistingHotKey );
|
|
BOOL KEnglishHangeul( HIMC hIMC, HKL hKL, HWND hWnd );
|
|
BOOL KShapeToggle( HIMC hIMC, HKL hKL, HWND hWnd );
|
|
BOOL KHanjaConvert( HIMC hIMC, HKL hKL, HWND hWnd );
|
|
|
|
//
|
|
// IMM hotkey related registry keys under HKEY_CURRENT_USER
|
|
//
|
|
TCHAR *szaRegImmHotKeys[] = { TEXT("Control Panel"),
|
|
TEXT("Input Method"),
|
|
TEXT("Hot Keys"),
|
|
NULL };
|
|
|
|
TCHAR szRegImeHotKey[] = TEXT("Control Panel\\Input Method\\Hot Keys");
|
|
|
|
TCHAR szRegVK[] = TEXT("Virtual Key");
|
|
TCHAR szRegMOD[] = TEXT("Key Modifiers");
|
|
TCHAR szRegHKL[] = TEXT("Target IME");
|
|
|
|
//
|
|
// Default IME HotKey Tables
|
|
//
|
|
// CR:takaok - move this to the resource if you have time
|
|
//
|
|
IMEHOTKEY DefaultHotKeyTableJ[]= {
|
|
{IME_JHOTKEY_CLOSE_OPEN, VK_KANJI, MOD_IGNORE_ALL_MODIFIER, NULL}
|
|
};
|
|
INT DefaultHotKeyNumJ = sizeof(DefaultHotKeyTableJ) / sizeof(IMEHOTKEY);
|
|
|
|
IMEHOTKEY DefaultHotKeyTableK[] = {
|
|
{ IME_KHOTKEY_ENGLISH, VK_HANGEUL, MOD_IGNORE_ALL_MODIFIER, NULL },
|
|
{ IME_KHOTKEY_SHAPE_TOGGLE, VK_JUNJA, MOD_IGNORE_ALL_MODIFIER, NULL },
|
|
{ IME_KHOTKEY_HANJACONVERT, VK_HANJA, MOD_IGNORE_ALL_MODIFIER, NULL }
|
|
};
|
|
INT DefaultHotKeyNumK = sizeof(DefaultHotKeyTableK) / sizeof(IMEHOTKEY);
|
|
|
|
IMEHOTKEY DefaultHotKeyTableT[] = {
|
|
{ IME_THOTKEY_IME_NONIME_TOGGLE, VK_SPACE, MOD_BOTH_SIDES|MOD_CONTROL, NULL },
|
|
{ IME_THOTKEY_SHAPE_TOGGLE, VK_SPACE, MOD_BOTH_SIDES|MOD_SHIFT, NULL }
|
|
};
|
|
INT DefaultHotKeyNumT = sizeof(DefaultHotKeyTableT) / sizeof(IMEHOTKEY);
|
|
|
|
IMEHOTKEY DefaultHotKeyTableC[] = {
|
|
{ IME_CHOTKEY_IME_NONIME_TOGGLE, VK_SPACE, MOD_BOTH_SIDES|MOD_CONTROL, NULL },
|
|
{ IME_CHOTKEY_SHAPE_TOGGLE, VK_SPACE, MOD_BOTH_SIDES|MOD_SHIFT, NULL }
|
|
};
|
|
INT DefaultHotKeyNumC = sizeof(DefaultHotKeyTableC) / sizeof(IMEHOTKEY);
|
|
|
|
/***************************************************************************\
|
|
* ImmInitializeHotkeys()
|
|
*
|
|
* Called from user\client\UpdatePerUserSystemParameters()
|
|
*
|
|
* Read the User registry and set the IME hotkey.
|
|
*
|
|
* History:
|
|
* 25-Mar-1996 TakaoK Created
|
|
\***************************************************************************/
|
|
VOID ImmInitializeHotKeys( BOOL bUserLoggedOn )
|
|
{
|
|
LCID lcid;
|
|
BOOL fFoundAny;
|
|
|
|
ImmSetHotKeyWorker( 0, 0, 0, NULL, ISHK_INITIALIZE );
|
|
fFoundAny = GetImeHotKeysFromRegistry();
|
|
|
|
lcid = GetUserDefaultLCID();
|
|
|
|
switch ( PRIMARYLANGID(LANGIDFROMLCID(lcid)) ) {
|
|
case LANG_JAPANESE:
|
|
|
|
SetDefaultImeHotKeys( DefaultHotKeyTableJ, DefaultHotKeyNumJ, fFoundAny );
|
|
break;
|
|
|
|
case LANG_KOREAN:
|
|
|
|
SetDefaultImeHotKeys( DefaultHotKeyTableK, DefaultHotKeyNumK, fFoundAny );
|
|
break;
|
|
|
|
case LANG_CHINESE:
|
|
switch ( SUBLANGID(lcid) ) {
|
|
case SUBLANG_CHINESE_TRADITIONAL:
|
|
case SUBLANG_CHINESE_HONGKONG:
|
|
|
|
SetDefaultImeHotKeys( DefaultHotKeyTableT, DefaultHotKeyNumT, fFoundAny );
|
|
break;
|
|
|
|
case SUBLANG_CHINESE_SIMPLIFIED:
|
|
case SUBLANG_CHINESE_SINGAPORE:
|
|
default:
|
|
SetDefaultImeHotKeys( DefaultHotKeyTableC, DefaultHotKeyNumC, fFoundAny );
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID SetDefaultImeHotKeys( PIMEHOTKEY ph, INT num, BOOL fNeedToCheckExistingHotKey )
|
|
{
|
|
IMEHOTKEY hkt;
|
|
|
|
while( num-- > 0 ) {
|
|
|
|
//
|
|
// Set IME hotkey only if there is no such
|
|
// hotkey in the registry
|
|
//
|
|
if ( !fNeedToCheckExistingHotKey ||
|
|
!ImmGetHotKey( ph->dwHotKeyID,
|
|
&hkt.uModifiers,
|
|
&hkt.uVKey,
|
|
&hkt.hKL ) ) {
|
|
|
|
ImmSetHotKeyWorker( ph->dwHotKeyID,
|
|
ph->uModifiers,
|
|
ph->uVKey,
|
|
ph->hKL,
|
|
ISHK_ADD );
|
|
}
|
|
ph++;
|
|
}
|
|
}
|
|
|
|
BOOL GetImeHotKeysFromRegistry()
|
|
{
|
|
BOOL fFoundAny = FALSE;
|
|
|
|
HANDLE hCurrentUserKey;
|
|
HANDLE hKeyHotKeys;
|
|
|
|
OBJECT_ATTRIBUTES Obja;
|
|
UNICODE_STRING SubKeyName;
|
|
|
|
NTSTATUS Status;
|
|
ULONG Index;
|
|
|
|
//
|
|
// Open the current user registry key
|
|
//
|
|
Status = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &hCurrentUserKey);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return fFoundAny;
|
|
}
|
|
|
|
RtlInitUnicodeString( &SubKeyName, szRegImeHotKey );
|
|
InitializeObjectAttributes( &Obja,
|
|
&SubKeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hCurrentUserKey,
|
|
NULL);
|
|
Status = NtOpenKey( &hKeyHotKeys, KEY_READ, &Obja );
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose( hCurrentUserKey );
|
|
return fFoundAny;
|
|
}
|
|
|
|
for( Index = 0; TRUE; Index++ ) {
|
|
|
|
BYTE KeyBuffer[ sizeof(KEY_BASIC_INFORMATION) + 16 * sizeof( WCHAR ) ];
|
|
PKEY_BASIC_INFORMATION pKeyInfo;
|
|
ULONG ResultLength;
|
|
|
|
pKeyInfo = (PKEY_BASIC_INFORMATION)KeyBuffer;
|
|
Status = NtEnumerateKey( hKeyHotKeys,
|
|
Index,
|
|
KeyBasicInformation,
|
|
pKeyInfo,
|
|
sizeof( KeyBuffer ),
|
|
&ResultLength );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
if ( SetSingleHotKey(pKeyInfo, hKeyHotKeys) ) {
|
|
|
|
fFoundAny = TRUE;
|
|
}
|
|
|
|
} else if ( Status == STATUS_NO_MORE_ENTRIES ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
NtClose( hKeyHotKeys );
|
|
NtClose( hCurrentUserKey );
|
|
return ( fFoundAny );
|
|
}
|
|
|
|
DWORD
|
|
ReadRegistryValue( HANDLE hKey, PWSTR pName )
|
|
{
|
|
BYTE ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(UCHAR)];
|
|
PKEY_VALUE_PARTIAL_INFORMATION pKeyValue;
|
|
UNICODE_STRING ValueName;
|
|
ULONG ResultLength;
|
|
NTSTATUS Status;
|
|
|
|
pKeyValue = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
|
|
|
|
RtlInitUnicodeString( &ValueName, pName );
|
|
Status = NtQueryValueKey( hKey,
|
|
&ValueName,
|
|
KeyValuePartialInformation,
|
|
pKeyValue,
|
|
sizeof(ValueBuffer),
|
|
&ResultLength );
|
|
|
|
if ( NT_SUCCESS(Status) && pKeyValue->DataLength > 3 ) {
|
|
//
|
|
// In Win95 registry, these items are written as BYTE data...
|
|
//
|
|
return ( (DWORD)(MAKEWORD( pKeyValue->Data[0], pKeyValue->Data[1])) |
|
|
(((DWORD)(MAKEWORD( pKeyValue->Data[2], pKeyValue->Data[3]))) << 16) );
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
SetSingleHotKey( PKEY_BASIC_INFORMATION pKeyInfo, HANDLE hKey )
|
|
{
|
|
UNICODE_STRING SubKeyName;
|
|
HANDLE hKeySingleHotKey;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
|
|
DWORD dwID = 0;
|
|
UINT uVKey = 0;
|
|
UINT uModifiers = 0;
|
|
HKL hKL = NULL;
|
|
|
|
NTSTATUS Status;
|
|
|
|
SubKeyName.Buffer = (PWSTR)&(pKeyInfo->Name[0]);
|
|
SubKeyName.Length = (USHORT)pKeyInfo->NameLength;
|
|
SubKeyName.MaximumLength = (USHORT)pKeyInfo->NameLength;
|
|
InitializeObjectAttributes( &Obja,
|
|
&SubKeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hKey,
|
|
NULL );
|
|
|
|
Status = NtOpenKey( &hKeySingleHotKey, KEY_READ, &Obja );
|
|
if (!NT_SUCCESS(Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
RtlUnicodeStringToInteger( &SubKeyName, 16L, &dwID );
|
|
uVKey = ReadRegistryValue( hKeySingleHotKey, szRegVK );
|
|
uModifiers = ReadRegistryValue( hKeySingleHotKey, szRegMOD );
|
|
hKL = (HKL)ReadRegistryValue( hKeySingleHotKey, szRegHKL );
|
|
|
|
NtClose( hKeySingleHotKey );
|
|
return ImmSetHotKeyWorker( dwID, uModifiers, uVKey, hKL, ISHK_ADD);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* 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 );
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ImmSetHotKey()
|
|
*
|
|
* Private API for IMEs and the control panel.
|
|
*
|
|
* History:
|
|
* 25-Mar-1996 TakaoK Created
|
|
\***************************************************************************/
|
|
BOOL WINAPI ImmSetHotKey(
|
|
DWORD dwID,
|
|
UINT uModifiers,
|
|
UINT uVKey,
|
|
HKL hkl)
|
|
{
|
|
BOOL fResult;
|
|
BOOL fTmp;
|
|
BOOL fDelete = (uVKey == 0 ) ? TRUE : FALSE;
|
|
|
|
if ( fDelete ) {
|
|
//
|
|
// Removing an IME hotkey from the list in the kernel side
|
|
// should not be failed, if we succeed to remove the IME
|
|
// hotkey entry from the registry. Therefore SaveImeHotKey
|
|
// is called first.
|
|
//
|
|
fResult = SaveImeHotKey( dwID, uModifiers, uVKey, hkl, fDelete );
|
|
if ( fResult ) {
|
|
fTmp = ImmSetHotKeyWorker( dwID, uModifiers, uVKey, hkl, ISHK_REMOVE );
|
|
ImmAssert( fTmp );
|
|
}
|
|
} else {
|
|
//
|
|
// ImmSetHotKeyWorker should be called first since
|
|
// adding an IME hotkey into the list in the kernel side
|
|
// will be faild in various reasons.
|
|
//
|
|
fResult = ImmSetHotKeyWorker( dwID, uModifiers, uVKey, hkl, ISHK_ADD );
|
|
if ( fResult ) {
|
|
fResult = SaveImeHotKey( dwID, uModifiers, uVKey, hkl, fDelete );
|
|
if ( ! fResult ) {
|
|
//
|
|
// We failed to save the hotkey to the registry.
|
|
// We need to remove the entry from the IME hotkey
|
|
// list in the kernel side.
|
|
//
|
|
fTmp = ImmSetHotKeyWorker( dwID, uModifiers, uVKey, hkl, ISHK_REMOVE );
|
|
ImmAssert( fTmp );
|
|
}
|
|
}
|
|
}
|
|
return fResult;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* 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;
|
|
|
|
hImc = ImmGetContext( hAppWnd );
|
|
hKL = GetKeyboardLayout( GetWindowThreadProcessId(hAppWnd, NULL) );
|
|
return HotKeyIDDispatcher( hAppWnd, hImc, hKL, dwHotKeyID);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* SameImeHotKey()
|
|
*
|
|
* Put/Remove the specified IME hotkey entry from the registry
|
|
*
|
|
* History:
|
|
* 25-Mar-1996 TakaoK Created
|
|
\***************************************************************************/
|
|
|
|
|
|
BOOL SaveImeHotKey( DWORD id, UINT mod, UINT vk, HKL hkl, BOOL fDelete )
|
|
{
|
|
HKEY hKey, hKeyParent;
|
|
INT i;
|
|
LONG lResult;
|
|
TCHAR szHex[16];
|
|
|
|
if ( fDelete ) {
|
|
|
|
TCHAR szRegTmp[ (sizeof(szRegImeHotKey) / sizeof(TCHAR) + 1 + 8 + 1) ];
|
|
|
|
lstrcpy( szRegTmp, szRegImeHotKey );
|
|
lstrcat(szRegTmp, TEXT("\\"));
|
|
NumToHexAscii( id, szHex );
|
|
lstrcat(szRegTmp, szHex);
|
|
|
|
lResult = RegDeleteKey( HKEY_CURRENT_USER, szRegTmp);
|
|
if ( lResult != ERROR_SUCCESS ) {
|
|
RIPERR1( lResult, RIP_WARNING,
|
|
"SaveImeHotKey:deleting %s failed", szRegTmp);
|
|
return ( FALSE );
|
|
}
|
|
return ( TRUE );
|
|
}
|
|
|
|
hKeyParent = HKEY_CURRENT_USER;
|
|
for ( i = 0; szaRegImmHotKeys[i] != NULL; i++ ) {
|
|
lResult = RegCreateKeyEx( hKeyParent,
|
|
szaRegImmHotKeys[i],
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE|KEY_READ,
|
|
NULL,
|
|
&hKey,
|
|
NULL );
|
|
RegCloseKey( hKeyParent );
|
|
if ( lResult == ERROR_SUCCESS ) {
|
|
hKeyParent = hKey;
|
|
} else {
|
|
RIPERR1( lResult, RIP_WARNING,
|
|
"SaveImeHotKey:creating %s failed", szaRegImmHotKeys[i]);
|
|
|
|
return ( FALSE );
|
|
}
|
|
}
|
|
|
|
NumToHexAscii( id, szHex );
|
|
lResult = RegCreateKeyEx( hKeyParent,
|
|
szHex,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE|KEY_READ,
|
|
NULL,
|
|
&hKey,
|
|
NULL );
|
|
RegCloseKey( hKeyParent );
|
|
if ( lResult != ERROR_SUCCESS ) {
|
|
RIPERR1( lResult, RIP_WARNING,
|
|
"SaveImeHotKey:creating %s failed", szHex );
|
|
return ( FALSE );
|
|
}
|
|
|
|
lResult = RegSetValueEx( hKey,
|
|
szRegVK,
|
|
0,
|
|
REG_BINARY,
|
|
(LPBYTE)&vk,
|
|
sizeof(DWORD) );
|
|
if ( lResult != ERROR_SUCCESS ) {
|
|
RegCloseKey( hKey );
|
|
SaveImeHotKey( id, vk, mod, hkl, TRUE );
|
|
RIPERR1( lResult, RIP_WARNING,
|
|
"SaveImeHotKey:setting value on %s failed", szRegVK );
|
|
return ( FALSE );
|
|
}
|
|
lResult = RegSetValueEx( hKey,
|
|
szRegMOD,
|
|
0,
|
|
REG_BINARY,
|
|
(LPBYTE)&mod,
|
|
sizeof(DWORD) );
|
|
|
|
if ( lResult != ERROR_SUCCESS ) {
|
|
RegCloseKey( hKey );
|
|
SaveImeHotKey( id, vk, mod, hkl, TRUE );
|
|
RIPERR1( lResult, RIP_WARNING,
|
|
"SaveImeHotKey:setting value on %s failed", szRegMOD );
|
|
return ( FALSE );
|
|
}
|
|
|
|
lResult = RegSetValueEx( hKey,
|
|
szRegHKL,
|
|
0,
|
|
REG_BINARY,
|
|
(LPBYTE)&hkl,
|
|
sizeof(DWORD) );
|
|
|
|
if ( lResult != ERROR_SUCCESS ) {
|
|
RegCloseKey( hKey );
|
|
SaveImeHotKey( id, vk, mod, hkl, TRUE );
|
|
RIPERR1( lResult, RIP_WARNING,
|
|
"SaveImeHotKey:setting value on %s failed", szRegHKL );
|
|
return ( FALSE );
|
|
}
|
|
|
|
RegCloseKey( hKey );
|
|
return ( TRUE );
|
|
}
|
|
|
|
BOOL ImmSetHotKeyWorker(
|
|
DWORD dwID,
|
|
UINT uModifiers,
|
|
UINT uVKey,
|
|
HKL hkl,
|
|
DWORD dwAction)
|
|
{
|
|
//
|
|
// if we're adding an IME hotkey entry, let's check
|
|
// the parameters before calling the kernel side code
|
|
//
|
|
if ( dwAction == ISHK_ADD ) {
|
|
|
|
if ( dwID >= IME_HOTKEY_DSWITCH_FIRST &&
|
|
dwID <= IME_HOTKEY_DSWITCH_LAST ) {
|
|
//
|
|
// IME direct switching hot key - switch to
|
|
// the keyboard layout specified.
|
|
// We need to specify keyboard layout.
|
|
//
|
|
if ( hkl == NULL ) {
|
|
RIPERR0( ERROR_INVALID_PARAMETER, RIP_WARNING, "hkl should be specified");
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// normal hot keys - change the mode of current iME
|
|
//
|
|
// Because it should be effective in all IME no matter
|
|
// which IME is active we should not specify a target IME
|
|
//
|
|
if ( hkl != NULL ) {
|
|
RIPERR0( ERROR_INVALID_PARAMETER, RIP_WARNING, "hkl shouldn't be specified");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if ( uModifiers & MOD_MODIFY_KEYS ) {
|
|
//
|
|
// Because normal keyboard has left and right key for
|
|
// these keys, you should specify left or right ( or both )
|
|
//
|
|
if ( ! (uModifiers & MOD_BOTH_SIDES ) ) {
|
|
RIPERR0( ERROR_INVALID_PARAMETER, RIP_WARNING, "invalid modifiers");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// It doesn't make sense if vkey is same as modifiers
|
|
//
|
|
if ( ((uModifiers & MOD_ALT) && (uVKey == VK_MENU)) ||
|
|
((uModifiers & MOD_CONTROL) && (uVKey == VK_CONTROL)) ||
|
|
((uModifiers & MOD_SHIFT) && (uVKey == VK_SHIFT)) ||
|
|
((uModifiers & MOD_WIN) && ((uVKey == VK_LWIN)||(uVKey == VK_RWIN)))
|
|
) {
|
|
|
|
RIPERR0( ERROR_INVALID_PARAMETER, RIP_WARNING, "vkey and modifiers are same");
|
|
return FALSE;
|
|
}
|
|
}
|
|
return NtUserSetImeHotKey( dwID, uModifiers, uVKey, hkl, dwAction );
|
|
}
|
|
|
|
//
|
|
// NumToHexAscii
|
|
//
|
|
// convert a DWORD into the hex string
|
|
// (e.g. 0x31 -> "00000031")
|
|
//
|
|
// 29-Jan-1996 takaok ported from Win95.
|
|
//
|
|
static TCHAR szHexString[] = TEXT("0123456789ABCDEF");
|
|
|
|
VOID
|
|
NumToHexAscii(
|
|
DWORD dwNum,
|
|
PWSTR szAscii)
|
|
{
|
|
int i;
|
|
|
|
for ( i = 7; i >= 0; i--) {
|
|
szAscii[i] = szHexString[ dwNum & 0x0000000f ];
|
|
dwNum >>= 4;
|
|
}
|
|
szAscii[8] = TEXT('\0');
|
|
|
|
return;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* HotKeyIDDispatcher */
|
|
/* Return Value: */
|
|
/* TRUE - a hot key processed, FALSE - not processed */
|
|
/**********************************************************************/
|
|
BOOL HotKeyIDDispatcher( HWND hWnd, HIMC hIMC, HKL hkl, DWORD dwHotKeyID )
|
|
{
|
|
|
|
switch ( dwHotKeyID ) {
|
|
case IME_CHOTKEY_IME_NONIME_TOGGLE:
|
|
case IME_THOTKEY_IME_NONIME_TOGGLE:
|
|
return CIMENonIMEToggle(hIMC, hkl, hWnd);
|
|
|
|
case IME_CHOTKEY_SYMBOL_TOGGLE:
|
|
case IME_THOTKEY_SYMBOL_TOGGLE:
|
|
return CSymbolToggle(hIMC, hkl, hWnd);
|
|
|
|
case IME_JHOTKEY_CLOSE_OPEN:
|
|
return JCloseOpen( hIMC, hkl, hWnd);
|
|
|
|
#ifdef LATER
|
|
case IME_KHOTKEY_ENGLISH:
|
|
return KEnglishHangeul(pThreadLink);
|
|
case IME_KHOTKEY_SHAPE_TOGGLE:
|
|
return KShapeToggle(pThreadLink);
|
|
case IME_KHOTKEY_HANJACONVERT:
|
|
return KHanjaConvert(pThreadLink);
|
|
#endif
|
|
|
|
case IME_CHOTKEY_SHAPE_TOGGLE:
|
|
case IME_THOTKEY_SHAPE_TOGGLE:
|
|
return TShapeToggle(hIMC, hkl, hWnd);
|
|
|
|
default:
|
|
if ( dwHotKeyID >= IME_HOTKEY_DSWITCH_FIRST &&
|
|
dwHotKeyID <= IME_HOTKEY_DSWITCH_LAST )
|
|
{
|
|
UINT uModifiers;
|
|
UINT uVKey;
|
|
HKL hkl;
|
|
|
|
if ( ImmGetHotKey( dwHotKeyID, &uModifiers, &uVKey, &hkl ) ) {
|
|
HKL hklCurrent;
|
|
|
|
hklCurrent = GetKeyboardLayout( GetWindowThreadProcessId( hWnd, NULL) );
|
|
if ( hklCurrent != hkl ) {
|
|
PostMessage( hWnd,
|
|
WM_INPUTLANGCHANGEREQUEST,
|
|
DEFAULT_CHARSET,
|
|
(LPARAM)hkl );
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* JCloseOpen() */
|
|
/* Return Value: */
|
|
/* TRUE - a hot key processed, FALSE - not processed */
|
|
/**********************************************************************/
|
|
BOOL JCloseOpen( // open/close toggle
|
|
HIMC hIMC,
|
|
HKL hCurrentKL,
|
|
HWND hWnd)
|
|
{
|
|
|
|
LPINPUTCONTEXT pInputContext;
|
|
PIMEDPI pImeDpi;
|
|
|
|
#ifdef LATER
|
|
// FJMERGE 95/11/07 K.Aizawa
|
|
#if defined(JAPAN) && defined(i386)
|
|
WORD KbdType = IsThumbKey();
|
|
#endif
|
|
#endif
|
|
|
|
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 );
|
|
|
|
#ifdef LATER
|
|
// FJMERGE 95/07/10 K.Aizawa
|
|
#if defined(JAPAN) && defined(i386)
|
|
if ((KbdType == MAKEWORD(FMV_KBD_OASYS_TYPE, SUB_KBD_TYPE_FUJITSU)) ||
|
|
(KbdType == MAKEWORD(FMR_KBD_OASYS_TYPE, SUB_KBD_TYPE_FUJITSU))) {
|
|
|
|
if ( pInputContext->fOpen ) {
|
|
UINT uRet = ThumbkeyGet31Mode(pInputContext->fdwConversion);
|
|
if ( uRet & IME_MODE_ALPHANUMERIC ) {
|
|
uRet = 0; // 0 is alpanumeric mode.
|
|
}
|
|
ThumbIoControl( uRet );
|
|
} else {
|
|
ThumbIoControl( 0 );
|
|
}
|
|
}
|
|
#endif // JAPAN && i386
|
|
#endif
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************/
|
|
/* CIMENonIMEToggle() */
|
|
/* Return Value: */
|
|
/* TRUE - a hot key processed, FALSE - not processed */
|
|
/**********************************************************************/
|
|
BOOL CIMENonIMEToggle( // non-IME and IME toggle
|
|
HIMC hIMC,
|
|
HKL hKlCurrent,
|
|
HWND hWnd)
|
|
{
|
|
if (hWnd == NULL)
|
|
return(FALSE);
|
|
|
|
if ( ! ImmIsIME( hKlCurrent ) ) {
|
|
//
|
|
// Current keyboard layout is not IME.
|
|
// Let's try to switch to IME.
|
|
//
|
|
return IMENonIMEToggle(hIMC, hKlCurrent, hWnd, FALSE );
|
|
|
|
} 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);
|
|
return IMENonIMEToggle(hIMC, hKlCurrent, hWnd, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* IMENonIMEToggle() */
|
|
/* Return Value: */
|
|
/* TRUE - a hot key processed, FALSE - not processed */
|
|
/**********************************************************************/
|
|
BOOL IMENonIMEToggle(
|
|
HIMC hIMC,
|
|
HKL hCurrentKL,
|
|
HWND hWnd,
|
|
BOOL fCurrentIsIME)
|
|
{
|
|
HKL hEnumKL[32], hTargetKL;
|
|
UINT nLayouts, i;
|
|
HKL hPrevKL = NULL;
|
|
|
|
#ifdef LATER
|
|
PTHREADINFO pti;
|
|
//
|
|
// Get the previous layout
|
|
//
|
|
pti = PtiCurrent();
|
|
if ( pti == NULL ) {
|
|
return FALSE;
|
|
}
|
|
hPrevKL = pti->hPrevKL;
|
|
#endif
|
|
|
|
//
|
|
// 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);
|
|
if ( hPrevKL != NULL ) {
|
|
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 ^ ImmIsIME(hEnumKL[i])) {
|
|
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 (TRUE);
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* 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 ( ! ImmIsIME( 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 ( ! ImmIsIME( 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);
|
|
}
|