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.
 
 
 
 
 
 

459 lines
10 KiB

/* File: D:\WACKER\tdll\getchar.c (Created: 30-Nov-1993)
*
* Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
* All rights reserved
*
* $Revision: 6 $
* $Date: 3/14/02 3:45p $
*/
#include <windows.h>
#pragma hdrstop
//#define DEBUGSTR
#include <time.h>
#include <stdio.h>
#include "stdtyp.h"
#include "globals.h"
#include "session.h"
#include "term.h"
#include "chars.h"
#include "assert.h"
#include "statusbr.h"
#include "cloop.h"
#include "cnct.h"
#include "htchar.h"
#if defined(INCL_KEY_MACROS)
#include "keyutil.h"
#endif
#include <emu\emu.h>
#include <term\res.h>
static BOOL WackerKeys(const KEY_T Key);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* TranslateToKey
*
* DESCRIPTION:
* Translates a key into our internal format. Waits for the WM_CHAR if
* windows is going to translate the key by checking the message queue.
*
* ARGUMENTS:
* hSession - external session handle
* pmsg - pointer to message
*
* RETURNS:
* Internal key value if translated, otherwise 0.
*
*/
KEY_T TranslateToKey(const LPMSG pmsg)
{
KEY_T Key = 0;
switch (pmsg->message)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
switch (pmsg->wParam)
{
case VK_SHIFT:
case VK_CONTROL:
return 0;
case VK_MENU:
return (KEY_T)-1;
default:
Key = (KEY_T)(VIRTUAL_KEY | pmsg->wParam);
if (GetKeyState(VK_MENU) < 0)
Key |= ALT_KEY;
if (GetKeyState(VK_CONTROL) < 0)
Key |= CTRL_KEY;
if (GetKeyState(VK_SHIFT) < 0)
Key |= SHIFT_KEY;
if (pmsg->lParam & 0x01000000) /* Extended, bit 24 */
Key |= EXTENDED_KEY;
break;
}
break;
case WM_CHAR:
case WM_SYSCHAR:
Key = (KEY_T)pmsg->wParam;
if (pmsg->lParam & 0x01000000) /* Extended, bit 24 */
Key |= EXTENDED_KEY;
if (pmsg->lParam & 0x20000000) /* Context, bit 29 */
Key |= ALT_KEY;
if (pmsg->wParam == VK_TAB)
{
if (GetKeyState(VK_SHIFT) < 0)
{
Key |= SHIFT_KEY;
Key |= VIRTUAL_KEY;
}
}
// Believe it or not CTRL+SHIFT+@ gets translated to a
// char of 0 (zero). So virtualize the key if it matches
// the criteria. - mrw
//
if (pmsg->wParam == 0)
{
if (GetKeyState(VK_SHIFT) < 0 && GetKeyState(VK_CONTROL) < 0)
Key |= VIRTUAL_KEY | SHIFT_KEY | CTRL_KEY;
}
break;
default:
break;
}
DbgOutStr("%x %x\r\n", Key, pmsg->message, 0, 0, 0);
return Key;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* WackerKeys
*
* DESCRIPTION:
* Handles our special global keys.
*
* ARGUMENTS:
* Key - key from TranslateToKey()
*
* RETURNS:
* TRUE if this routine acts on it, FALSE if not.
*
*/
static BOOL WackerKeys(const KEY_T Key)
{
BYTE pbKeyState[256];
switch (Key)
{
case VIRTUAL_KEY | VK_SCROLL:
case VIRTUAL_KEY | SHIFT_KEY | VK_SCROLL:
case VIRTUAL_KEY | ALT_KEY | VK_SCROLL:
case VIRTUAL_KEY | ALT_KEY | SHIFT_KEY | VK_SCROLL:
// In the case of scroll lock, we want to toggle to the
// previous state. Only when it is destined for the terminal
// window is it processed meaning it doesn't get here.
if(GetKeyboardState(pbKeyState))
{
if (GetKeyState(VK_SCROLL) & 1)
{
pbKeyState[VK_SCROLL] &= ~0x01;
}
else
{
pbKeyState[VK_SCROLL] |= 0x01;
}
SetKeyboardState(pbKeyState);
}
#if TODO // TODO:REV 3/1/2002 Set the ScrollLock key state when GetKeyboardState fails.
else
{
SHORT lScrollKeyState = GetKeyState(VK_SCROLL);
if (lScrollKeyState & 1)
{
lScrollKeyState &= ~0x01;
}
else
{
lScrollKeyState |= 0x01;
}
if (lScrollKeyState)
{
INPUT lInput;
lInput.ki =
SendInput(1, lInput, sizeof(INPUT));
}
}
#endif // TODO:REV 3/1/2002
break;
default:
return FALSE;
}
return TRUE;
}
//******************************************************************************
// Method:
// IsSessionMacroKey
//
// Description:
// Determines if the specified key is a user defined macro key
//
// Arguments:
// hSess - Session handle
// Key - The key to be tested
//
// Returns:
// TRUE if the key is defined as a macro FALSE otherwise
//
// Throws:
// None
//
// Author: Dwayne M. Newsome, 06/10/1998
//
//
static BOOL IsSessionMacroKey(const HSESSION hSess, const KEY_T Key)
{
#if defined INCL_KEY_MACROS
keyMacro lKeyMacro;
lKeyMacro.keyName = Key;
return keysFindMacro( &lKeyMacro ) == -1 ? FALSE : TRUE;
#else
return FALSE;
#endif
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* ProcessMessage
*
* DESCRIPTION:
* Despite the apparent simplicity of this function it is any but simple.
* The entire functionality of the keyboard interface rests upon this
* function. Handle with care!
*
* ARGUMENTS:
* pmsg - pointer to message struct returned from GetMessage()
*
* RETURNS:
* void
*
*/
void ProcessMessage(MSG *pmsg)
{
#if defined(FAR_EAST)
static KEY_T keyLeadByte = 0;
#endif
KEY_T Key;
HSESSION hSession;
HCNCT hCnct;
TCHAR achClassName[20];
switch (pmsg->message)
{
case WM_CHAR:
#if defined(FAR_EAST)
hSession = (HSESSION)GetWindowLongPtr(pmsg->hwnd, 0);
if ((IsDBCSLeadByte( (BYTE) pmsg->wParam)) && (keyLeadByte == 0))
{
keyLeadByte = (KEY_T)pmsg->wParam;
return ;
}
else
{
if (keyLeadByte != 0)
{
Key = (KEY_T)pmsg->wParam;
CLoopSend(sessQueryCLoopHdl(hSession), &keyLeadByte, 1, CLOOP_KEYS);
CLoopSend(sessQueryCLoopHdl(hSession), &Key, 1, CLOOP_KEYS);
keyLeadByte = 0;
return ;
}
keyLeadByte = 0;
}
#endif
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_SYSCHAR:
/* --- Translate the key to our format --- */
Key = TranslateToKey(pmsg);
// We need to decide if the window this message is going to is
// a terminal window since that's the only place we do our
// translations. We check if the window class matches our
// terminal class. If so, the session handle is stored in the
// 0 offset of the window's extra data. This way multiple sessions
// can be serviced from this one routine.
if (GetClassName(pmsg->hwnd, achClassName, sizeof(achClassName)) == 0)
break;
if (StrCharCmp(achClassName, TERM_CLASS))
break;
hSession = (HSESSION)GetWindowLongPtr(pmsg->hwnd, 0);
if (hSession == 0)
{
// There are certain keys we want to handle regardless of
// their destination.
if (WackerKeys(Key))
return;
break;
}
// We need to prevent an F1 key event from initiating
// a connection when "emu keys" is turned on.
//
if (Key == (VIRTUAL_KEY | VK_F1))
{
hCnct = sessQueryCnctHdl(hSession);
assert(hCnct);
if((cnctQueryStatus(hCnct) == CNCT_STATUS_TRUE) &&
emuIsEmuKey(sessQueryEmuHdl(hSession), Key))
{
// do nothing - fall through
}
else
{
// eat it
// We handle the F1 key event in the terminal proc
// (to bring up help), so we don't need to here.
return;
}
}
// The order of evaluation is important here. Both IsMacroKey()
// and emuIsEmuKey() know if that the message is bound for the
// terminal. Also emuIsEmuKey() checks if terminal keys are
// enabled. Evaluating messages in this order keeps us from
// having to "disable" accelerators when the user defines macro
// or terminal keys that conflict with accelerator keys.
if ( IsSessionMacroKey(hSession, Key) ||
emuIsEmuKey(sessQueryEmuHdl(hSession), Key))
{
// We need to modify this message to an internal message
// for two reasons.
//
// 1. Menu accelerators get translated in DispatchMessage().
// This seems a little strange but hey, that's windows
// for ya.
//
// 2. It's important to know if the key was an emulator key.
// The emulator's keys take precedence over window's
// accelerators yet the emulator is the last guy to see
// the key. For instance, PageUp can pageup through the
// backscroll execept when it is mapped to an emulator
// key. Unfortuanately, the PageUp key is interperted
// by the client-terminal before being passed to the
// emulator. If we sent this as a WM_KEYDOWN or WM_CHAR
// message, we would have to play it through the emulator
// again to find out if it is an emulator key.
pmsg->message = WM_TERM_KEY;
pmsg->wParam = (WPARAM)Key;
DbgOutStr("Session or Macro key\r\n", 0, 0, 0, 0, 0);
DispatchMessage(pmsg);
if (Key == (VK_NUMLOCK | VIRTUAL_KEY | EXTENDED_KEY))
{
static BYTE abKeyState[256];
if (GetKeyboardState(abKeyState))
{
if ((GetKeyState(VK_NUMLOCK) & 1))
{
abKeyState[VK_NUMLOCK] &= 0xfe;
}
else
{
abKeyState[VK_NUMLOCK] |= 0x01;
}
SetKeyboardState(abKeyState);
}
#if TODO // TODO:REV 3/1/2002 Set the NumLock key state when GetKeyboardState fails.
else
{
SHORT lNumLockKeyState = GetKeyState(VK_NUMLOCK);
if (lNumLockKeyState & 1)
{
lNumLockKeyState &= 0xfe;
}
else
{
lNumLockKeyState |= 0x01;
}
if (lNumLockKeyState)
{
INPUT lInput;
lInput.ki =
SendInput(1, lInput, sizeof(INPUT));
}
}
#endif // TODO:REV 3/1/2002
}
return;
}
else
{
// Win32 got this one right. TranslateMesssage returns TRUE
// only if it translates (ie. produces a WM_CHAR). Win31
// didn't do this. If a WM_CHAR is generated, then we want
// to eat the WM_KEYDOWN and wait for the WM_CHAR event.
// Bug in TranslateMessage(). It returns TRUE on all
// WM_KEYDOWN messages regardless of translation. Reported
// bug 1/5/93
if (!TranslateAccelerator(glblQueryHwndFrame(),
glblQueryAccelHdl(), pmsg))
{
MSG msg;
TranslateMessage(pmsg);
if (PeekMessage(&msg, pmsg->hwnd, WM_CHAR, WM_CHAR,
PM_NOREMOVE) == FALSE)
{
DispatchMessage(pmsg);
}
}
return;
}
default:
break;
}
// Not for the terminal window? Do the normal thing...
if (!TranslateAccelerator(glblQueryHwndFrame(), glblQueryAccelHdl(), pmsg))
{
TranslateMessage(pmsg);
DispatchMessage(pmsg);
}
return;
}