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
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;
|
|
}
|