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