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.
354 lines
10 KiB
354 lines
10 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: imehotky.c
|
|
*
|
|
* Copyright (c) Microsoft Corp. 1995-1996 All Rights Reserved
|
|
*
|
|
* Contents: Manage IME hotkey
|
|
*
|
|
* There are the following two kind of hotkeys defined in the IME specification.
|
|
*
|
|
* 1) IME hotkeys that changes the mode/status of current IME
|
|
* 2) IME hotkeys that causes IME (keyboard layout) change
|
|
*
|
|
* History:
|
|
* 10-Sep-1995 takaok Created for NT 3.51.
|
|
* 15-Mar-1996 takaok Ported to NT 4.0
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef FE_IME
|
|
|
|
typedef struct _tagIMEHOTKEYOBJ {
|
|
struct _tagIMEHOTKEYOBJ *pNext;
|
|
IMEHOTKEY hk;
|
|
} IMEHOTKEYOBJ, *PIMEHOTKEYOBJ;
|
|
|
|
PIMEHOTKEYOBJ gpImeHotKeyListHeader = NULL;
|
|
|
|
PIMEHOTKEYOBJ DeleteImeHotKey( PIMEHOTKEYOBJ *ppHead, PIMEHOTKEYOBJ pDelete );
|
|
VOID AddImeHotKey( PIMEHOTKEYOBJ *ppHead, PIMEHOTKEYOBJ pAdd );
|
|
PIMEHOTKEYOBJ FindImeHotKeyByKey( PIMEHOTKEYOBJ pHead, UINT uModifyKeys, UINT uRL, UINT uVKey);
|
|
PIMEHOTKEYOBJ FindImeHotKeyByID( PIMEHOTKEYOBJ pHead, DWORD dwHotKeyID );
|
|
|
|
BOOL
|
|
GetImeHotKey(
|
|
DWORD dwHotKeyID,
|
|
PUINT puModifiers,
|
|
PUINT puVKey,
|
|
HKL *phKL )
|
|
{
|
|
PIMEHOTKEYOBJ ph;
|
|
|
|
ph = FindImeHotKeyByID( gpImeHotKeyListHeader, dwHotKeyID );
|
|
if ( ph == NULL ) {
|
|
RIPERR0(ERROR_HOTKEY_NOT_REGISTERED, RIP_WARNING, "No such IME hotkey");
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// it is OK for NULL phKL, if the target hKL is NULL
|
|
//
|
|
if ( phKL ) {
|
|
*phKL = ph->hk.hKL;
|
|
} else if ( ph->hk.hKL != NULL ) {
|
|
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "phKL is null");
|
|
return (FALSE);
|
|
}
|
|
|
|
*puModifiers = ph->hk.uModifiers;
|
|
*puVKey = ph->hk.uVKey;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
//
|
|
// Insert/remove the specified IME hotkey into/from
|
|
// the IME hotkey list (gpImeHotKeyListHeader).
|
|
//
|
|
BOOL
|
|
SetImeHotKey(
|
|
DWORD dwHotKeyID,
|
|
UINT uModifiers,
|
|
UINT uVKey,
|
|
HKL hKL,
|
|
DWORD dwAction )
|
|
{
|
|
PIMEHOTKEYOBJ ph;
|
|
|
|
switch ( dwAction ) {
|
|
case ISHK_REMOVE:
|
|
ph = FindImeHotKeyByID( gpImeHotKeyListHeader, dwHotKeyID );
|
|
if ( ph != NULL ) {
|
|
if ( DeleteImeHotKey( &gpImeHotKeyListHeader, ph ) == ph ) {
|
|
UserFreePool( ph );
|
|
return ( TRUE );
|
|
} else {
|
|
RIPMSG0( RIP_ERROR, "IME hotkey list is messed up" );
|
|
return ( FALSE );
|
|
}
|
|
} else {
|
|
RIPERR0( ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"no such IME hotkey registered");
|
|
return ( FALSE );
|
|
}
|
|
break;
|
|
|
|
case ISHK_INITIALIZE:
|
|
ph = gpImeHotKeyListHeader;
|
|
while ( ph != NULL ) {
|
|
PIMEHOTKEYOBJ phNext;
|
|
|
|
phNext = ph->pNext;
|
|
UserFreePool( ph );
|
|
ph = phNext;
|
|
}
|
|
gpImeHotKeyListHeader = NULL;
|
|
return TRUE;
|
|
|
|
case ISHK_ADD:
|
|
ph = FindImeHotKeyByKey( gpImeHotKeyListHeader,
|
|
uModifiers & MOD_MODIFY_KEYS,
|
|
uModifiers & MOD_BOTH_SIDES,
|
|
uVKey );
|
|
if ( ph != NULL ) {
|
|
if ( ph->hk.dwHotKeyID != dwHotKeyID ) {
|
|
RIPERR0( ERROR_HOTKEY_ALREADY_REGISTERED,
|
|
RIP_WARNING,
|
|
"There is an IME hotkey that has the same vkey/modifiers");
|
|
return ( FALSE );
|
|
}
|
|
// So far we found a hotkey that has the
|
|
// same vkey and same ID.
|
|
// But because modifiers may be slightly
|
|
// different, so go ahead and change it.
|
|
} else {
|
|
//
|
|
// the specified vkey/modifiers combination cound not be found
|
|
// in the hotkey list. The caller may want to change the key
|
|
// assignment of an existing hotkey or add a new hotkey.
|
|
//
|
|
ph = FindImeHotKeyByID( gpImeHotKeyListHeader, dwHotKeyID );
|
|
}
|
|
|
|
if ( ph == NULL ) {
|
|
//
|
|
// adding a new hotkey
|
|
//
|
|
ph = (PIMEHOTKEYOBJ)UserAllocPool( sizeof(IMEHOTKEY), TAG_IMEHOTKEY );
|
|
if ( ph == NULL ) {
|
|
RIPERR0( ERROR_OUTOFMEMORY,
|
|
RIP_WARNING,
|
|
"Memory allocation failed in SetImeHotKey");
|
|
return ( FALSE );
|
|
}
|
|
ph->hk.dwHotKeyID = dwHotKeyID;
|
|
ph->hk.uModifiers = uModifiers;
|
|
ph->hk.uVKey = uVKey;
|
|
ph->hk.hKL = hKL;
|
|
ph->pNext = NULL;
|
|
AddImeHotKey( &gpImeHotKeyListHeader, ph );
|
|
|
|
} else {
|
|
//
|
|
// changing an existing hotkey
|
|
//
|
|
ph->hk.uModifiers = uModifiers;
|
|
ph->hk.uVKey = uVKey;
|
|
ph->hk.hKL = hKL;
|
|
|
|
}
|
|
return ( TRUE );
|
|
break;
|
|
};
|
|
}
|
|
|
|
|
|
PIMEHOTKEYOBJ DeleteImeHotKey( PIMEHOTKEYOBJ *ppHead, PIMEHOTKEYOBJ pDelete )
|
|
{
|
|
PIMEHOTKEYOBJ ph;
|
|
|
|
if ( pDelete == *ppHead ) {
|
|
*ppHead = pDelete->pNext;
|
|
return pDelete;
|
|
}
|
|
|
|
for ( ph = *ppHead; ph != NULL; ph = ph->pNext ) {
|
|
if ( ph->pNext == pDelete ) {
|
|
ph->pNext = pDelete->pNext;
|
|
return pDelete;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
VOID AddImeHotKey( PIMEHOTKEYOBJ *ppHead, PIMEHOTKEYOBJ pAdd )
|
|
{
|
|
PIMEHOTKEYOBJ ph;
|
|
|
|
if ( *ppHead == NULL ) {
|
|
*ppHead = pAdd;
|
|
} else {
|
|
ph = *ppHead;
|
|
while( ph->pNext != NULL )
|
|
ph = ph->pNext;
|
|
ph->pNext = pAdd;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* FindImeHotKeyByKey() */
|
|
/* Return Value: */
|
|
/* pHotKey - IMEHOTKEY pointer with the key, */
|
|
/* else NULL - failure */
|
|
/**********************************************************************/
|
|
PIMEHOTKEYOBJ FindImeHotKeyByKey( // Finds pHotKey with this input key
|
|
PIMEHOTKEYOBJ pHead,
|
|
UINT uModifyKeys, // the modify keys of this input key
|
|
UINT uRL, // the right and left hand side
|
|
UINT uVKey) // the input key
|
|
{
|
|
PIMEHOTKEYOBJ ph;
|
|
|
|
for (ph = pHead; ph != NULL; ph = ph->pNext) {
|
|
|
|
if (ph->hk.uVKey != uVKey) {
|
|
//
|
|
// vkey is different. Not need to see this any more
|
|
//
|
|
continue;
|
|
}
|
|
//
|
|
// vkey is same. Let's see the modifiers
|
|
//
|
|
|
|
if (ph->hk.uModifiers & MOD_IGNORE_ALL_MODIFIER) {
|
|
//
|
|
// doesn't care for modifiers.
|
|
//
|
|
return ph;
|
|
}
|
|
|
|
if ((ph->hk.uModifiers & MOD_MODIFY_KEYS) != uModifyKeys) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If both MOD_RIGHT and MOD_LEFT is set, it means that
|
|
// either key will work. For example, if we have a modifier
|
|
// like (MOD_ALT | MOD_RIGHT | MOD_LEFT), this means:
|
|
//
|
|
// ( [left alt key] OR [right alt key] ) AND vkey
|
|
//
|
|
if ( ((ph->hk.uModifiers & MOD_BOTH_SIDES) == uRL) ||
|
|
((ph->hk.uModifiers & MOD_BOTH_SIDES ) & uRL) ) {
|
|
return ph;
|
|
}
|
|
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* FindImeHotKeyByID() */
|
|
/* Return Value: */
|
|
/* pHotKey - IMEHOTKEY pointer with the dwHotKeyID, */
|
|
/* else NULL - failure */
|
|
/**********************************************************************/
|
|
PIMEHOTKEYOBJ FindImeHotKeyByID( PIMEHOTKEYOBJ pHead, DWORD dwHotKeyID )
|
|
{
|
|
PIMEHOTKEYOBJ ph;
|
|
|
|
for ( ph = pHead; ph != NULL; ph = ph->pNext ) {
|
|
if ( ph->hk.dwHotKeyID == dwHotKeyID )
|
|
return (ph);
|
|
}
|
|
return (PIMEHOTKEYOBJ)NULL;
|
|
}
|
|
|
|
DWORD
|
|
CheckImeHotKey(
|
|
PQ pq, // input queue
|
|
UINT uVKey, // virtual key
|
|
LPARAM lParam // lparam of WM_KEYxxx message
|
|
)
|
|
{
|
|
static UINT uVKeySaved = 0;
|
|
PIMEHOTKEYOBJ ph;
|
|
UINT uModifiers = 0;
|
|
BOOL fKeyUp;
|
|
|
|
//
|
|
// early return for key up message
|
|
//
|
|
fKeyUp = ( lParam & 0x80000000 ) ? TRUE : FALSE;
|
|
if ( fKeyUp ) {
|
|
//
|
|
// if the uVKey is not same as the vkey
|
|
// we previously saved, there is no chance
|
|
// that this is a hotkey.
|
|
//
|
|
if ( uVKeySaved != uVKey ) {
|
|
uVKeySaved = 0;
|
|
return IME_INVALID_HOTKEY;
|
|
}
|
|
uVKeySaved = 0;
|
|
//
|
|
// If it's same, we still need to check
|
|
// the hotkey list because there is a
|
|
// chance that the hotkey list is modified
|
|
// between the key make and break.
|
|
//
|
|
}
|
|
|
|
//
|
|
// Current specification doesn't allow us to use a complex
|
|
// hotkey such as LSHIFT+RMENU+SPACE
|
|
//
|
|
if ( uVKey != VK_SHIFT ) {
|
|
uModifiers |= TestKeyStateDown( pq, VK_LSHIFT ) ? (MOD_SHIFT | MOD_LEFT) : 0;
|
|
uModifiers |= TestKeyStateDown( pq, VK_RSHIFT ) ? (MOD_SHIFT | MOD_RIGHT) : 0;
|
|
}
|
|
if ( uVKey != VK_CONTROL ) {
|
|
uModifiers |= TestKeyStateDown( pq, VK_LCONTROL ) ? (MOD_CONTROL | MOD_LEFT) : 0;
|
|
uModifiers |= TestKeyStateDown( pq, VK_RCONTROL ) ? (MOD_CONTROL | MOD_RIGHT) : 0;
|
|
}
|
|
if ( uVKey != VK_MENU ) {
|
|
uModifiers |= TestKeyStateDown( pq, VK_LMENU ) ? (MOD_ALT | MOD_LEFT) : 0;
|
|
uModifiers |= TestKeyStateDown( pq, VK_RMENU ) ? (MOD_ALT | MOD_RIGHT) : 0;
|
|
}
|
|
|
|
ph = FindImeHotKeyByKey( gpImeHotKeyListHeader,
|
|
uModifiers & MOD_MODIFY_KEYS,
|
|
uModifiers & MOD_BOTH_SIDES,
|
|
uVKey );
|
|
|
|
if ( ph != NULL ) {
|
|
|
|
if ( fKeyUp ) {
|
|
if ( ph->hk.uModifiers & MOD_ON_KEYUP ) {
|
|
return ph->hk.dwHotKeyID;
|
|
}
|
|
} else {
|
|
if ( ph->hk.uModifiers & MOD_ON_KEYUP ) {
|
|
//
|
|
// save vkey for next keyup message time
|
|
//
|
|
// when ALT+Z is a hotkey, we don't want
|
|
// to handle #2 as the hotkey sequence.
|
|
// 1) ALT make -> 'Z' make -> 'Z' break
|
|
// 2) 'Z' make -> ALT make -> 'Z' break
|
|
//
|
|
uVKeySaved = uVKey;
|
|
} else {
|
|
return ph->hk.dwHotKeyID;
|
|
}
|
|
}
|
|
}
|
|
return IME_INVALID_HOTKEY;
|
|
}
|
|
|
|
#endif
|