Leaked source code of windows server 2003
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.
 
 
 
 
 
 

423 lines
12 KiB

/****************************** Module Header ******************************\
* Module Name: keyboard.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* History:
* 11-11-90 DavidPe Created.
* 13-Feb-1991 mikeke Added Revalidation code (None)
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* _GetKeyState (API)
*
* This API returns the up/down and toggle state of the specified VK based
* on the input synchronized keystate in the current queue. The toggle state
* is mainly for 'state' keys like Caps-Lock that are toggled each time you
* press them.
*
* History:
* 11-11-90 DavidPe Created.
\***************************************************************************/
SHORT _GetKeyState(
int vk)
{
UINT wKeyState;
PTHREADINFO pti;
if ((UINT)vk >= CVKKEYSTATE) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"Invalid parameter \"vk\" (%ld) to _GetKeyState",
vk);
return 0;
}
pti = PtiCurrentShared();
#ifdef LATER
//
// note - anything that accesses the pq structure is a bad idea since it
// can be changed between any two instructions.
//
#endif
wKeyState = 0;
/*
* Set the toggle bit.
*/
if (TestKeyStateToggle(pti->pq, vk))
wKeyState = 0x0001;
/*
* Set the keyup/down bit.
*/
if (TestKeyStateDown(pti->pq, vk)) {
/*
* Used to be wKeyState|= 0x8000.Fix for bug 28820; Ctrl-Enter
* accelerator doesn't work on Nestscape Navigator Mail 2.0
*/
wKeyState |= 0xff80; // This is what 3.1 returned!!!!
}
return (SHORT)wKeyState;
}
/***************************************************************************\
* _GetAsyncKeyState (API)
*
* This function is similar to GetKeyState except it returns what could be
* considered the 'hardware' keystate or what state the key is in at the
* moment the function is called, rather than based on what key events the
* application has processed. Also, rather than returning the toggle bit,
* it has a bit telling whether the key was pressed since the last call to
* GetAsyncKeyState().
*
* History:
* 11-11-90 DavidPe Created.
\***************************************************************************/
SHORT _GetAsyncKeyState(
int vk)
{
SHORT sKeyState;
if ((UINT)vk >= CVKKEYSTATE) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"Invalid parameter \"vk\" (%ld) to _GetAsyncKeyState",
vk);
return 0;
}
/*
* See if this key went down since the last time state for it was
* read. Clear the flag if so.
*/
sKeyState = 0;
if (TestAsyncKeyStateRecentDown(vk)) {
ClearAsyncKeyStateRecentDown(vk);
sKeyState = 1;
}
/*
* Set the keyup/down bit.
*/
if (TestAsyncKeyStateDown(vk))
sKeyState |= 0x8000;
/*
* Don't return the toggle bit since it's a new bit and might
* cause compatibility problems.
*/
return sKeyState;
}
/***************************************************************************\
* _SetKeyboardState (API)
*
* This function allows the app to set the current keystate. This is mainly
* useful for setting the toggle bit, particularly for the keys associated
* with the LEDs on the physical keyboard.
*
* History:
* 11-11-90 DavidPe Created.
* 16-May-1991 mikeke Changed to return BOOL
\***************************************************************************/
BOOL _SetKeyboardState(
CONST BYTE *pb)
{
int i;
PQ pq;
PTHREADINFO ptiCurrent = PtiCurrent();
pq = ptiCurrent->pq;
/*
* Copy in the new state table.
*/
for (i = 0; i < 256; i++, pb++) {
if (*pb & 0x80) {
SetKeyStateDown(pq, i);
} else {
ClearKeyStateDown(pq, i);
}
if (*pb & 0x01) {
SetKeyStateToggle(pq, i);
} else {
ClearKeyStateToggle(pq, i);
}
}
/*
* Update the key cache index.
*/
gpsi->dwKeyCache++;
#ifdef LATER
// scottlu 6-9-91
// I don't think we ought to do this unless someone really complains. This
// could have bad side affects, especially considering that terminal
// apps will want to do this, and terminal apps could easily not respond
// to input for awhile, causing this state to change unexpectedly while
// a user is using some other application. - scottlu.
/* DavidPe 02/05/92
* How about if we only do it when the calling app is foreground?
*/
/*
* Propagate the toggle bits for the keylight keys to the
* async keystate table and update the keylights.
*
* THIS could be evil in a de-synced environment, but to do this
* in a totally "synchronous" way is hard.
*/
if (pb[VK_CAPITAL] & 0x01) {
SetAsyncKeyStateToggle(VK_CAPITAL);
} else {
ClearAsyncKeyStateToggle(VK_CAPITAL);
}
if (pb[VK_NUMLOCK] & 0x01) {
SetAsyncKeyStateToggle(VK_NUMLOCK);
} else {
ClearAsyncKeyStateToggle(VK_NUMLOCK);
}
if (pb[VK_SCROLL] & 0x01) {
SetAsyncKeyStateToggle(VK_SCROLL);
} else {
ClearAsyncKeyStateToggle(VK_SCROLL);
}
UpdateKeyLights(TRUE);
#endif
return TRUE;
}
/***************************************************************************\
* RegisterPerUserKeyboardIndicators
*
* Saves the current keyboard indicators in the user's profile.
*
* ASSUMPTIONS:
*
* 10-14-92 IanJa Created.
\***************************************************************************/
static CONST WCHAR wszInitialKeyboardIndicators[] = L"InitialKeyboardIndicators";
VOID
RegisterPerUserKeyboardIndicators(PUNICODE_STRING pProfileUserName)
{
WCHAR wszInitKbdInd[2] = L"0";
/*
* Initial Keyboard state (Num-Lock only)
*/
/*
* For HYDRA we do not want to save this.
*/
if (gbRemoteSession) {
return;
}
wszInitKbdInd[0] += TestAsyncKeyStateToggle(VK_NUMLOCK) ? 2 : 0;
FastWriteProfileStringW(pProfileUserName,
PMAP_KEYBOARD,
wszInitialKeyboardIndicators,
wszInitKbdInd);
}
/***************************************************************************\
* UpdatePerUserKeyboardIndicators
*
* Sets the initial keyboard indicators according to the user's profile.
*
* ASSUMPTIONS:
*
* 10-14-92 IanJa Created.
\***************************************************************************/
VOID
UpdatePerUserKeyboardIndicators(PUNICODE_STRING pProfileUserName)
{
DWORD dw = 0x80000000;
PQ pq;
PTHREADINFO ptiCurrent = PtiCurrent();
pq = ptiCurrent->pq;
/*
* For terminal server, the client is responsible for synchronizing the
* keyboard state.
*/
if (IsRemoteConnection()) {
return;
}
/*
* Initial Keyboard state (Num-Lock only)
*/
FastGetProfileIntW(pProfileUserName,
PMAP_KEYBOARD,
wszInitialKeyboardIndicators,
0x80000000,
&dw,
0);
dw &= 0x80000002;
/*
* The special value 0x80000000 in the registry indicates that the BIOS
* settings are to be used as the initial LED state. (This is undocumented)
*/
if (dw == 0x80000000) {
dw = gklpBootTime.LedFlags;
}
if (dw & KEYBOARD_NUM_LOCK_ON) {
SetKeyStateToggle(pq, VK_NUMLOCK);
SetAsyncKeyStateToggle(VK_NUMLOCK);
SetRawKeyToggle(VK_NUMLOCK);
} else {
ClearKeyStateToggle(pq, VK_NUMLOCK);
ClearAsyncKeyStateToggle(VK_NUMLOCK);
ClearRawKeyToggle(VK_NUMLOCK);
}
/*
* Initialize KANA Toggle status
*/
gfKanaToggle = FALSE;
ClearKeyStateToggle(pq, VK_KANA);
ClearAsyncKeyStateToggle(VK_KANA);
ClearRawKeyToggle(VK_KANA);
UpdateKeyLights(FALSE);
}
/***************************************************************************\
* UpdateAsyncKeyState
*
* Based on a VK and a make/break flag, this function will update the async
* keystate table.
*
* History:
* 06-09-91 ScottLu Added keystate synchronization across threads.
* 11-12-90 DavidPe Created.
\***************************************************************************/
void UpdateAsyncKeyState(
PQ pqOwner,
UINT wVK,
BOOL fBreak)
{
PQ pqT;
PLIST_ENTRY pHead, pEntry;
PTHREADINFO pti;
CheckCritIn();
/*
* First check to see if the queue this key is going to has a pending
* key state event. If it does, post it because we need to copy the
* async key state into this event as it is before we modify
* this key's state, or else we'll generate a key state event with
* the wrong key state in it.
*/
if (pqOwner != NULL && pqOwner->QF_flags & QF_UPDATEKEYSTATE) {
PostUpdateKeyStateEvent(pqOwner);
}
if (!fBreak) {
/*
* This key has gone down - update the "recent down" bit in the
* async key state table.
*/
SetAsyncKeyStateRecentDown(wVK);
/*
* This is a key make. If the key was not already down, update the
* toggle bit.
*/
if (!TestAsyncKeyStateDown(wVK)) {
if (TestAsyncKeyStateToggle(wVK)) {
ClearAsyncKeyStateToggle(wVK);
} else {
SetAsyncKeyStateToggle(wVK);
}
}
/*
* This is a make, so turn on the key down bit.
*/
SetAsyncKeyStateDown(wVK);
} else {
/*
* This is a break, so turn off the key down bit.
*/
ClearAsyncKeyStateDown(wVK);
}
/*
* If this is one of the keys we cache, update the async key cache index.
*/
if (wVK < CVKASYNCKEYCACHE) {
gpsi->dwAsyncKeyCache++;
}
/*
* A key has changed state. Update all queues not receiving this input so
* they know that this key has changed state. This lets us know which keys to
* update in the thread specific key state table to keep it in sync
* with the user. Walking down the thread list may mean that an
* individual queue may by updated more than once, but it is cheaper
* than maintaining a list of queues on the desktop.
*/
UserAssert(grpdeskRitInput != NULL);
pHead = &grpdeskRitInput->PtiList;
for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) {
pti = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink);
/*
* Don't update the queue this message is going to - it'll be
* in sync because it is receiving this message.
*/
pqT = pti->pq;
if (pqT == pqOwner)
continue;
/*
* Set the "recent down" bit. In this case this doesn't really mean
* "recent down", it means "recent change" (since the last time
* we synced this queue), either up or down. This tells us which
* keys went down since the last time this thread synced with key
* state. Set the "update key state" flag so we know that later
* we need to sync with these keys.
*/
SetKeyRecentDownBit(pqT->afKeyRecentDown, wVK);
pqT->QF_flags |= QF_UPDATEKEYSTATE;
}
/*
* Update the key cache index.
*/
gpsi->dwKeyCache++;
}