mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@21 3b4a5df2-a311-0410-b5c6-a8a6f20db521
1654 lines
49 KiB
C++
1654 lines
49 KiB
C++
#ifdef JA2_PRECOMPILED_HEADERS
|
|
#include "JA2 SGP ALL.H"
|
|
#elif defined( WIZ8_PRECOMPILED_HEADERS )
|
|
#include "WIZ8 SGP ALL.H"
|
|
#else
|
|
#include "types.h"
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <memory.h>
|
|
#include "debug.h"
|
|
#include "input.h"
|
|
#include "memman.h"
|
|
#include "english.h"
|
|
#if defined( JA2 ) || defined( UTIL )
|
|
#include "video.h"
|
|
#else
|
|
#include "video2.h"
|
|
#endif
|
|
#include "local.h"
|
|
#endif
|
|
|
|
#include "zmouse.h"
|
|
|
|
// Make sure to refer to the translation table which is within one of the following files (depending
|
|
// on the language used). ENGLISH.C, JAPANESE.C, FRENCH.C, GERMAN.C, SPANISH.C, etc...
|
|
|
|
extern UINT16 gsKeyTranslationTable[1024];
|
|
|
|
extern BOOLEAN gfApplicationActive;
|
|
|
|
#ifndef JA2
|
|
|
|
#undef GetCursorPos
|
|
#define GetCursorPos SGPMouseGetPos
|
|
|
|
#endif
|
|
|
|
// The gfKeyState table is used to track which of the keys is up or down at any one time. This is used while polling
|
|
// the interface.
|
|
|
|
BOOLEAN gfKeyState[256]; // TRUE = Pressed, FALSE = Not Pressed
|
|
BOOLEAN fCursorWasClipped = FALSE;
|
|
RECT gCursorClipRect;
|
|
|
|
|
|
|
|
// The gsKeyTranslationTables basically translates scan codes to our own key value table. Please note that the table is 2 bytes
|
|
// wide per entry. This will be used since we will use 2 byte characters for translation purposes.
|
|
|
|
UINT16 gfShiftState; // TRUE = Pressed, FALSE = Not Pressed
|
|
UINT16 gfAltState; // TRUE = Pressed, FALSE = Not Pressed
|
|
UINT16 gfCtrlState; // TRUE = Pressed, FALSE = Not Pressed
|
|
|
|
// These data structure are used to track the mouse while polling
|
|
|
|
BOOLEAN gfTrackDblClick;
|
|
UINT32 guiDoubleClkDelay; // Current delay in milliseconds for a delay
|
|
UINT32 guiSingleClickTimer;
|
|
UINT32 guiRecordedWParam;
|
|
UINT32 guiRecordedLParam;
|
|
UINT16 gusRecordedKeyState;
|
|
BOOLEAN gfRecordedLeftButtonUp;
|
|
|
|
UINT32 guiLeftButtonRepeatTimer;
|
|
UINT32 guiRightButtonRepeatTimer;
|
|
|
|
BOOLEAN gfTrackMousePos; // TRUE = queue mouse movement events, FALSE = don't
|
|
BOOLEAN gfLeftButtonState; // TRUE = Pressed, FALSE = Not Pressed
|
|
BOOLEAN gfRightButtonState; // TRUE = Pressed, FALSE = Not Pressed
|
|
UINT16 gusMouseXPos; // X position of the mouse on screen
|
|
UINT16 gusMouseYPos; // y position of the mouse on screen
|
|
|
|
// The queue structures are used to track input events using queued events
|
|
|
|
InputAtom gEventQueue[256];
|
|
UINT16 gusQueueCount;
|
|
UINT16 gusHeadIndex;
|
|
UINT16 gusTailIndex;
|
|
|
|
// ATE: Added to signal if we have had input this frame - cleared by the SGP main loop
|
|
BOOLEAN gfSGPInputReceived = FALSE;
|
|
|
|
// This is the WIN95 hook specific data and defines used to handle the keyboard and
|
|
// mouse hook
|
|
|
|
HHOOK ghKeyboardHook;
|
|
HHOOK ghMouseHook;
|
|
|
|
// If the following pointer is non NULL then input characters are redirected to
|
|
// the related string
|
|
|
|
BOOLEAN gfCurrentStringInputState;
|
|
StringInput *gpCurrentStringDescriptor;
|
|
|
|
// Local function headers
|
|
|
|
void QueueEvent(UINT16 ubInputEvent, UINT32 usParam, UINT32 uiParam);
|
|
void RedirectToString(UINT16 uiInputCharacter);
|
|
void HandleSingleClicksAndButtonRepeats( void );
|
|
void AdjustMouseForWindowOrigin(void);
|
|
|
|
// These are the hook functions for both keyboard and mouse
|
|
|
|
LRESULT CALLBACK KeyboardHandler(int Code, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
#ifndef JA2
|
|
if((Code < 0) || (!gfApplicationActive))
|
|
#else
|
|
if (Code < 0)
|
|
#endif
|
|
{ // Do not handle this message, pass it on to another window
|
|
return CallNextHookEx(ghKeyboardHook, Code, wParam, lParam);
|
|
}
|
|
|
|
if (lParam & TRANSITION_MASK)
|
|
{ // The key has been released
|
|
KeyUp(wParam, lParam);
|
|
//gfSGPInputReceived = TRUE;
|
|
}
|
|
else
|
|
{ // Key was up
|
|
KeyDown(wParam, lParam);
|
|
gfSGPInputReceived = TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef JA2
|
|
|
|
LRESULT CALLBACK MouseHandler(int Code, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UINT32 uiParam;
|
|
|
|
#ifndef JA2
|
|
if((Code < 0) || (!gfApplicationActive))
|
|
#else
|
|
if (Code < 0)
|
|
#endif
|
|
{ // Do not handle this message, pass it on to another window
|
|
return CallNextHookEx(ghMouseHook, Code, wParam, lParam);
|
|
}
|
|
|
|
switch (wParam)
|
|
{
|
|
case WM_LBUTTONDOWN
|
|
: // Update the current mouse position
|
|
gusMouseXPos = (UINT16)(((MOUSEHOOKSTRUCT *)lParam)->pt).x;
|
|
gusMouseYPos = (UINT16)(((MOUSEHOOKSTRUCT *)lParam)->pt).y;
|
|
uiParam = gusMouseYPos;
|
|
uiParam = uiParam << 16;
|
|
uiParam = uiParam | gusMouseXPos;
|
|
// Update the button state
|
|
gfLeftButtonState = TRUE;
|
|
//Set that we have input
|
|
gfSGPInputReceived = TRUE;
|
|
// Trigger an input event
|
|
QueueEvent(LEFT_BUTTON_DOWN, 0, uiParam);
|
|
break;
|
|
case WM_LBUTTONUP
|
|
: // Update the current mouse position
|
|
gusMouseXPos = (UINT16)(((MOUSEHOOKSTRUCT *)lParam)->pt).x;
|
|
gusMouseYPos = (UINT16)(((MOUSEHOOKSTRUCT *)lParam)->pt).y;
|
|
uiParam = gusMouseYPos;
|
|
uiParam = uiParam << 16;
|
|
uiParam = uiParam | gusMouseXPos;
|
|
// Update the button state
|
|
gfLeftButtonState = FALSE;
|
|
//Set that we have input
|
|
gfSGPInputReceived = TRUE;
|
|
// Trigger an input event
|
|
QueueEvent(LEFT_BUTTON_UP, 0, uiParam);
|
|
break;
|
|
case WM_RBUTTONDOWN
|
|
: // Update the current mouse position
|
|
gusMouseXPos = (UINT16)(((MOUSEHOOKSTRUCT *)lParam)->pt).x;
|
|
gusMouseYPos = (UINT16)(((MOUSEHOOKSTRUCT *)lParam)->pt).y;
|
|
uiParam = gusMouseYPos;
|
|
uiParam = uiParam << 16;
|
|
uiParam = uiParam | gusMouseXPos;
|
|
// Update the button state
|
|
gfRightButtonState = TRUE;
|
|
//Set that we have input
|
|
gfSGPInputReceived = TRUE;
|
|
// Trigger an input event
|
|
QueueEvent(RIGHT_BUTTON_DOWN, 0, uiParam);
|
|
break;
|
|
case WM_RBUTTONUP
|
|
: // Update the current mouse position
|
|
gusMouseXPos = (UINT16)(((MOUSEHOOKSTRUCT *)lParam)->pt).x;
|
|
gusMouseYPos = (UINT16)(((MOUSEHOOKSTRUCT *)lParam)->pt).y;
|
|
uiParam = gusMouseYPos;
|
|
uiParam = uiParam << 16;
|
|
uiParam = uiParam | gusMouseXPos;
|
|
// Update the button state
|
|
gfRightButtonState = FALSE;
|
|
//Set that we have input
|
|
gfSGPInputReceived = TRUE;
|
|
// Trigger an input event
|
|
QueueEvent(RIGHT_BUTTON_UP, 0, uiParam);
|
|
break;
|
|
case WM_MOUSEMOVE
|
|
: // Update the current mouse position
|
|
gusMouseXPos = (UINT16)(((MOUSEHOOKSTRUCT *)lParam)->pt).x;
|
|
gusMouseYPos = (UINT16)(((MOUSEHOOKSTRUCT *)lParam)->pt).y;
|
|
uiParam = gusMouseYPos;
|
|
uiParam = uiParam << 16;
|
|
uiParam = uiParam | gusMouseXPos;
|
|
// Trigger an input event
|
|
if (gfTrackMousePos == TRUE)
|
|
{
|
|
QueueEvent(MOUSE_POS, 0, uiParam);
|
|
}
|
|
//Set that we have input
|
|
gfSGPInputReceived = TRUE;
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#else
|
|
|
|
// Wizardry mouse hander
|
|
|
|
LRESULT CALLBACK MouseHandler(int Code, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UINT32 uiParam;
|
|
UINT32 uiXPos, uiYPos;
|
|
RECT rcClient;
|
|
BOOLEAN fOutsideClient=FALSE;
|
|
static BOOLEAN fResizing=FALSE;
|
|
LRESULT Result;
|
|
|
|
uiXPos= (((MOUSEHOOKSTRUCT *)lParam)->pt).x;
|
|
uiYPos= (((MOUSEHOOKSTRUCT *)lParam)->pt).y;
|
|
|
|
|
|
if(!VideoIsFullScreen())
|
|
{
|
|
if(wParam==WM_NCLBUTTONDOWN)
|
|
fResizing=TRUE;
|
|
|
|
VideoGetClientRect(&rcClient);
|
|
if((uiXPos < (UINT32)rcClient.left) || (uiXPos > (UINT32)rcClient.right) || (uiYPos < (UINT32)rcClient.top) || (uiYPos > (UINT32)rcClient.bottom))
|
|
fOutsideClient=TRUE;
|
|
}
|
|
|
|
if((Code < 0) || (!gfApplicationActive) || fOutsideClient || fResizing)
|
|
{ // Do not handle this message, pass it on to another window
|
|
Result = CallNextHookEx(ghMouseHook, Code, wParam, lParam);
|
|
|
|
if((wParam==WM_LBUTTONUP) || (wParam==WM_NCLBUTTONUP))
|
|
fResizing=FALSE;
|
|
|
|
return(Result);
|
|
}
|
|
|
|
switch (wParam)
|
|
{
|
|
case WM_LBUTTONUP:
|
|
case WM_LBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
case WM_RBUTTONUP:
|
|
case WM_MOUSEMOVE:
|
|
if(VideoIsFullScreen())
|
|
{
|
|
gusMouseXPos = (UINT16)(uiXPos);
|
|
gusMouseYPos = (UINT16)(uiYPos);
|
|
}
|
|
else
|
|
{
|
|
gusMouseXPos = (UINT16)(uiXPos-rcClient.left);
|
|
gusMouseYPos = (UINT16)(uiYPos-rcClient.top);
|
|
}
|
|
uiParam = (UINT32)gusMouseYPos<<16 | (UINT32)gusMouseXPos;
|
|
//Set that we have input
|
|
gfSGPInputReceived = TRUE;
|
|
break;
|
|
}
|
|
|
|
if ( wParam == WM_MOUSEWHEEL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
switch (wParam)
|
|
{
|
|
case WM_LBUTTONDOWN:
|
|
gfLeftButtonState = TRUE;
|
|
QueueEvent(LEFT_BUTTON_DOWN, 0, uiParam);
|
|
break;
|
|
case WM_LBUTTONUP:
|
|
gfLeftButtonState = FALSE;
|
|
QueueEvent(LEFT_BUTTON_UP, 0, uiParam);
|
|
break;
|
|
case WM_RBUTTONDOWN:
|
|
gfRightButtonState = TRUE;
|
|
QueueEvent(RIGHT_BUTTON_DOWN, 0, uiParam);
|
|
break;
|
|
case WM_RBUTTONUP:
|
|
gfRightButtonState = FALSE;
|
|
QueueEvent(RIGHT_BUTTON_UP, 0, uiParam);
|
|
break;
|
|
case WM_MOUSEMOVE:
|
|
if(gfTrackMousePos)
|
|
QueueEvent(MOUSE_POS, 0, uiParam);
|
|
break;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
#endif
|
|
|
|
BOOLEAN InitializeInputManager(void)
|
|
{
|
|
// Link to debugger
|
|
RegisterDebugTopic(TOPIC_INPUT, "Input Manager");
|
|
// Initialize the gfKeyState table to FALSE everywhere
|
|
memset(gfKeyState, FALSE, 256);
|
|
// Initialize the Event Queue
|
|
gusQueueCount = 0;
|
|
gusHeadIndex = 0;
|
|
gusTailIndex = 0;
|
|
// By default, we will not queue mousemove events
|
|
gfTrackMousePos = FALSE;
|
|
// Initialize other variables
|
|
gfShiftState = FALSE;
|
|
gfAltState = FALSE;
|
|
gfCtrlState = FALSE;
|
|
// Initialize variables pertaining to DOUBLE CLIK stuff
|
|
gfTrackDblClick = TRUE;
|
|
guiDoubleClkDelay = DBL_CLK_TIME;
|
|
guiSingleClickTimer = 0;
|
|
gfRecordedLeftButtonUp = FALSE;
|
|
// Initialize variables pertaining to the button states
|
|
gfLeftButtonState = FALSE;
|
|
gfRightButtonState = FALSE;
|
|
// Initialize variables pertaining to the repeat mechanism
|
|
guiLeftButtonRepeatTimer = 0;
|
|
guiRightButtonRepeatTimer = 0;
|
|
// Set the mouse to the center of the screen
|
|
gusMouseXPos = 320;
|
|
gusMouseYPos = 240;
|
|
// Initialize the string input mechanism
|
|
gfCurrentStringInputState = FALSE;
|
|
gpCurrentStringDescriptor = NULL;
|
|
// Activate the hook functions for both keyboard and Mouse
|
|
ghKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) KeyboardHandler, (HINSTANCE) 0, GetCurrentThreadId());
|
|
DbgMessage(TOPIC_INPUT, DBG_LEVEL_2, String("Set keyboard hook returned %d", ghKeyboardHook));
|
|
|
|
ghMouseHook = SetWindowsHookEx(WH_MOUSE, (HOOKPROC) MouseHandler, (HINSTANCE) 0, GetCurrentThreadId());
|
|
DbgMessage(TOPIC_INPUT, DBG_LEVEL_2, String("Set mouse hook returned %d", ghMouseHook));
|
|
return TRUE;
|
|
}
|
|
|
|
void ShutdownInputManager(void)
|
|
{ // There's very little to do when shutting down the input manager. In the future, this is where the keyboard and
|
|
// mouse hooks will be destroyed
|
|
UnRegisterDebugTopic(TOPIC_INPUT, "Input Manager");
|
|
UnhookWindowsHookEx(ghKeyboardHook);
|
|
UnhookWindowsHookEx(ghMouseHook);
|
|
}
|
|
|
|
void QueuePureEvent(UINT16 ubInputEvent, UINT32 usParam, UINT32 uiParam)
|
|
{
|
|
UINT32 uiTimer;
|
|
UINT16 usKeyState;
|
|
|
|
uiTimer = GetTickCount();
|
|
usKeyState = gfShiftState | gfCtrlState | gfAltState;
|
|
|
|
// Can we queue up one more event, if not, the event is lost forever
|
|
if (gusQueueCount == 256)
|
|
{ // No more queue space
|
|
return;
|
|
}
|
|
|
|
// Okey Dokey, we can queue up the event, so we do it
|
|
gEventQueue[gusTailIndex].uiTimeStamp = uiTimer;
|
|
gEventQueue[gusTailIndex].usKeyState = usKeyState;
|
|
gEventQueue[gusTailIndex].usEvent = ubInputEvent;
|
|
gEventQueue[gusTailIndex].usParam = usParam;
|
|
gEventQueue[gusTailIndex].uiParam = uiParam;
|
|
|
|
// Increment the number of items on the input queue
|
|
gusQueueCount++;
|
|
|
|
// Increment the gusTailIndex pointer
|
|
if (gusTailIndex == 255)
|
|
{ // The gusTailIndex is about to wrap around the queue ring
|
|
gusTailIndex = 0;
|
|
}
|
|
else
|
|
{ // We simply increment the gusTailIndex
|
|
gusTailIndex++;
|
|
}
|
|
}
|
|
|
|
void QueueEvent(UINT16 ubInputEvent, UINT32 usParam, UINT32 uiParam)
|
|
{
|
|
UINT32 uiTimer;
|
|
UINT16 usKeyState;
|
|
|
|
uiTimer = GetTickCount();
|
|
usKeyState = gfShiftState | gfCtrlState | gfAltState;
|
|
|
|
// Can we queue up one more event, if not, the event is lost forever
|
|
if (gusQueueCount == 256)
|
|
{ // No more queue space
|
|
return;
|
|
}
|
|
|
|
if (ubInputEvent == LEFT_BUTTON_DOWN)
|
|
{
|
|
guiLeftButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIMEOUT;
|
|
}
|
|
|
|
if (ubInputEvent == RIGHT_BUTTON_DOWN)
|
|
{
|
|
guiRightButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIMEOUT;
|
|
}
|
|
|
|
if (ubInputEvent == LEFT_BUTTON_UP)
|
|
{
|
|
guiLeftButtonRepeatTimer = 0;
|
|
}
|
|
|
|
if (ubInputEvent == RIGHT_BUTTON_UP)
|
|
{
|
|
guiRightButtonRepeatTimer = 0;
|
|
}
|
|
|
|
if ( (ubInputEvent == LEFT_BUTTON_UP) )
|
|
{
|
|
// Do we have a double click
|
|
if ( ( uiTimer - guiSingleClickTimer ) < DBL_CLK_TIME )
|
|
{
|
|
guiSingleClickTimer = 0;
|
|
|
|
// Add a button up first...
|
|
gEventQueue[gusTailIndex].uiTimeStamp = uiTimer;
|
|
gEventQueue[gusTailIndex].usKeyState = gusRecordedKeyState;
|
|
gEventQueue[gusTailIndex].usEvent = LEFT_BUTTON_UP;
|
|
gEventQueue[gusTailIndex].usParam = usParam;
|
|
gEventQueue[gusTailIndex].uiParam = uiParam;
|
|
|
|
// Increment the number of items on the input queue
|
|
gusQueueCount++;
|
|
|
|
// Increment the gusTailIndex pointer
|
|
if (gusTailIndex == 255)
|
|
{ // The gusTailIndex is about to wrap around the queue ring
|
|
gusTailIndex = 0;
|
|
}
|
|
else
|
|
{ // We simply increment the gusTailIndex
|
|
gusTailIndex++;
|
|
}
|
|
|
|
|
|
// Now do double click
|
|
gEventQueue[gusTailIndex].uiTimeStamp = uiTimer;
|
|
gEventQueue[gusTailIndex].usKeyState = gusRecordedKeyState ;
|
|
gEventQueue[gusTailIndex].usEvent = LEFT_BUTTON_DBL_CLK;
|
|
gEventQueue[gusTailIndex].usParam = usParam;
|
|
gEventQueue[gusTailIndex].uiParam = uiParam;
|
|
|
|
// Increment the number of items on the input queue
|
|
gusQueueCount++;
|
|
|
|
// Increment the gusTailIndex pointer
|
|
if (gusTailIndex == 255)
|
|
{ // The gusTailIndex is about to wrap around the queue ring
|
|
gusTailIndex = 0;
|
|
}
|
|
else
|
|
{ // We simply increment the gusTailIndex
|
|
gusTailIndex++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// Save time
|
|
guiSingleClickTimer = uiTimer;
|
|
}
|
|
}
|
|
|
|
// Okey Dokey, we can queue up the event, so we do it
|
|
gEventQueue[gusTailIndex].uiTimeStamp = uiTimer;
|
|
gEventQueue[gusTailIndex].usKeyState = usKeyState;
|
|
gEventQueue[gusTailIndex].usEvent = ubInputEvent;
|
|
gEventQueue[gusTailIndex].usParam = usParam;
|
|
gEventQueue[gusTailIndex].uiParam = uiParam;
|
|
|
|
// Increment the number of items on the input queue
|
|
gusQueueCount++;
|
|
|
|
// Increment the gusTailIndex pointer
|
|
if (gusTailIndex == 255)
|
|
{ // The gusTailIndex is about to wrap around the queue ring
|
|
gusTailIndex = 0;
|
|
}
|
|
else
|
|
{ // We simply increment the gusTailIndex
|
|
gusTailIndex++;
|
|
}
|
|
}
|
|
|
|
BOOLEAN DequeueSpecificEvent(InputAtom *Event, UINT32 uiMaskFlags )
|
|
{
|
|
// Is there an event to dequeue
|
|
if (gusQueueCount > 0)
|
|
{
|
|
memcpy( Event, &( gEventQueue[gusHeadIndex] ), sizeof( InputAtom ) );
|
|
|
|
// Check if it has the masks!
|
|
if ( ( Event->usEvent & uiMaskFlags ) )
|
|
{
|
|
return( DequeueEvent( Event) );
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN DequeueEvent(InputAtom *Event)
|
|
{
|
|
HandleSingleClicksAndButtonRepeats( );
|
|
|
|
// Is there an event to dequeue
|
|
if (gusQueueCount > 0)
|
|
{
|
|
// We have an event, so we dequeue it
|
|
memcpy( Event, &( gEventQueue[gusHeadIndex] ), sizeof( InputAtom ) );
|
|
|
|
if (gusHeadIndex == 255)
|
|
{
|
|
gusHeadIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
gusHeadIndex++;
|
|
}
|
|
|
|
// Decrement the number of items on the input queue
|
|
gusQueueCount--;
|
|
|
|
// dequeued an event, return TRUE
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// No events to dequeue, return FALSE
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
void KeyChange(UINT32 usParam, UINT32 uiParam, UINT8 ufKeyState)
|
|
{
|
|
UINT32 ubKey;
|
|
UINT16 ubChar;
|
|
POINT MousePos;
|
|
UINT32 uiTmpLParam;
|
|
|
|
if ((usParam >= 96)&&(usParam <= 110))
|
|
{ // Well this could be a NUMPAD character imitating the center console characters (when NUMLOCK is OFF). Well we
|
|
// gotta find out what was pressed and translate it to the actual physical key (i.e. if we think that HOME was
|
|
// pressed but NUM_7 was pressed, the we translate the key into NUM_7
|
|
switch(usParam)
|
|
{ case 96 // NUM_0
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 82)
|
|
{ // Well its the NUM_9 key and not actually the PGUP key
|
|
ubKey = 223;
|
|
}
|
|
else
|
|
{ // NOP, its the PGUP key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 110 // NUM_PERIOD
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 83)
|
|
{ // Well its the NUM_3 key and not actually the PGDN key
|
|
ubKey = 224;
|
|
}
|
|
else
|
|
{ // NOP, its the PGDN key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 97 // NUM_1
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 79)
|
|
{ // Well its the NUM_1 key and not actually the END key
|
|
ubKey = 225;
|
|
}
|
|
else
|
|
{ // NOP, its the END key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 98 // NUM_2
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 80)
|
|
{ // Well its the NUM_7 key and not actually the HOME key
|
|
ubKey = 226;
|
|
}
|
|
else
|
|
{ // NOP, its the HOME key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 99 // NUM_3
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 81)
|
|
{ // Well its the NUM_4 key and not actually the LARROW key
|
|
ubKey = 227;
|
|
}
|
|
else
|
|
{ // NOP, it's the LARROW key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 100 // NUM_4
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 75)
|
|
{ // Well its the NUM_8 key and not actually the UPARROW key
|
|
ubKey = 228;
|
|
}
|
|
else
|
|
{ // NOP, it's the UPARROW key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 101 // NUM_5
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 76)
|
|
{ // Well its the NUM_6 key and not actually the RARROW key
|
|
ubKey = 229;
|
|
}
|
|
else
|
|
{ // NOP, it's the RARROW key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 102 // NUM_6
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 77)
|
|
{ // Well its the NUM_2 key and not actually the DNARROW key
|
|
ubKey = 230;
|
|
}
|
|
else
|
|
{ // NOP, it's the DNARROW key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 103 // NUM_7
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 71)
|
|
{ // Well its the NUM_0 key and not actually the INSERT key
|
|
ubKey = 231;
|
|
}
|
|
else
|
|
{ // NOP, it's the INSERT key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 104 // NUM_8
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 72)
|
|
{ // Well its the NUM_PERIOD key and not actually the DELETE key
|
|
ubKey = 232;
|
|
}
|
|
else
|
|
{ // NOP, it's the DELETE key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 105 // NUM_9
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 73)
|
|
{ // Well its the NUM_PERIOD key and not actually the DELETE key
|
|
ubKey = 233;
|
|
}
|
|
else
|
|
{ // NOP, it's the DELETE key all right
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
default
|
|
: ubKey = usParam;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((usParam >= 33)&&(usParam <= 46))
|
|
{ // Well this could be a NUMPAD character imitating the center console characters (when NUMLOCK is OFF). Well we
|
|
// gotta find out what was pressed and translate it to the actual physical key (i.e. if we think that HOME was
|
|
// pressed but NUM_7 was pressed, the we translate the key into NUM_7
|
|
switch(usParam)
|
|
{ case 45 // NUM_0
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 82)
|
|
{ // Is it the NUM_0 key or the INSERT key
|
|
if (((uiParam & EXT_CODE_MASK) >> 17) != 0)
|
|
{ // It's the INSERT key
|
|
ubKey = 245;
|
|
}
|
|
else
|
|
{ // Is the NUM_0 key with NUM lock off
|
|
ubKey = 234;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 46 // NUM_PERIOD
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 83)
|
|
{ // Is it the NUM_PERIOD key or the DEL key
|
|
if (((uiParam & EXT_CODE_MASK) >> 17) != 0)
|
|
{ // It's the DELETE key
|
|
ubKey = 246;
|
|
}
|
|
else
|
|
{ // Is the NUM_PERIOD key with NUM lock off
|
|
ubKey = 235;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 35 // NUM_1
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 79)
|
|
{ // Is it the NUM_1 key or the END key
|
|
if (((uiParam & EXT_CODE_MASK) >> 17) != 0)
|
|
{ // It's the END key
|
|
ubKey = 247;
|
|
}
|
|
else
|
|
{ // Is the NUM_1 key with NUM lock off
|
|
ubKey = 236;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 40 // NUM_2
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 80)
|
|
{ // Is it the NUM_2 key or the DOWN key
|
|
if (((uiParam & EXT_CODE_MASK) >> 17) != 0)
|
|
{ // It's the DOWN key
|
|
ubKey = 248;
|
|
}
|
|
else
|
|
{ // Is the NUM_2 key with NUM lock off
|
|
ubKey = 237;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 34 // NUM_3
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 81)
|
|
{ // Is it the NUM_3 key or the PGDN key
|
|
if (((uiParam & EXT_CODE_MASK) >> 17) != 0)
|
|
{ // It's the PGDN key
|
|
ubKey = 249;
|
|
}
|
|
else
|
|
{ // Is the NUM_3 key with NUM lock off
|
|
ubKey = 238;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 37 // NUM_4
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 75)
|
|
{ // Is it the NUM_4 key or the LEFT key
|
|
if (((uiParam & EXT_CODE_MASK) >> 17) != 0)
|
|
{ // It's the LEFT key
|
|
ubKey = 250;
|
|
}
|
|
else
|
|
{ // Is the NUM_4 key with NUM lock off
|
|
ubKey = 239;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 39 // NUM_6
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 77)
|
|
{ // Is it the NUM_6 key or the RIGHT key
|
|
if (((uiParam & EXT_CODE_MASK) >> 17) != 0)
|
|
{ // It's the RIGHT key
|
|
ubKey = 251;
|
|
}
|
|
else
|
|
{ // Is the NUM_6 key with NUM lock off
|
|
ubKey = 241;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 36 // NUM_7
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 71)
|
|
{ // Is it the NUM_7 key or the HOME key
|
|
if (((uiParam & EXT_CODE_MASK) >> 17) != 0)
|
|
{ // It's the HOME key
|
|
ubKey = 252;
|
|
}
|
|
else
|
|
{ // Is the NUM_7 key with NUM lock off
|
|
ubKey = 242;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 38 // NUM_8
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 72)
|
|
{ // Is it the NUM_8 key or the UP key
|
|
if (((uiParam & EXT_CODE_MASK) >> 17) != 0)
|
|
{ // It's the UP key
|
|
ubKey = 253;
|
|
}
|
|
else
|
|
{ // Is the NUM_8 key with NUM lock off
|
|
ubKey = 243;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
case 33 // NUM_9
|
|
: if (((uiParam & SCAN_CODE_MASK) >> 16) == 73)
|
|
{ // Is it the NUM_9 key or the PGUP key
|
|
if (((uiParam & EXT_CODE_MASK) >> 17) != 0)
|
|
{ // It's the PGUP key
|
|
ubKey = 254;
|
|
}
|
|
else
|
|
{ // Is the NUM_9 key with NUM lock off
|
|
ubKey = 244;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubKey = usParam;
|
|
}
|
|
break;
|
|
default
|
|
: ubKey = usParam;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (usParam == 12)
|
|
{ // NUM_5 with NUM_LOCK off
|
|
ubKey = 240;
|
|
}
|
|
else
|
|
{ // Normal key
|
|
ubKey = usParam;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Find ucChar by translating ubKey using the gsKeyTranslationTable. If the SHIFT, ALT or CTRL key are down, then
|
|
// the index into the translation table us changed from ubKey to ubKey+256, ubKey+512 and ubKey+768 respectively
|
|
if (gfShiftState == TRUE)
|
|
{ // SHIFT is pressed, hence we add 256 to ubKey before translation to ubChar
|
|
ubChar = gsKeyTranslationTable[ubKey+256];
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Even though gfAltState is checked as if it was a BOOLEAN, it really contains 0x02, which
|
|
// is NOT == to true. This is broken, however to fix it would break Ja2 and Wizardry.
|
|
// The same thing goes for gfCtrlState and gfShiftState, howver gfShiftState is assigned 0x01 which IS == to TRUE.
|
|
// Just something i found, and thought u should know about. DF.
|
|
//
|
|
|
|
if( gfAltState == TRUE )
|
|
{ // ALT is pressed, hence ubKey is multiplied by 3 before translation to ubChar
|
|
ubChar = gsKeyTranslationTable[ubKey+512];
|
|
}
|
|
else
|
|
{
|
|
if (gfCtrlState == TRUE)
|
|
{ // CTRL is pressed, hence ubKey is multiplied by 4 before translation to ubChar
|
|
ubChar = gsKeyTranslationTable[ubKey+768];
|
|
}
|
|
else
|
|
{ // None of the SHIFT, ALT or CTRL are pressed hence we have a default translation of ubKey
|
|
ubChar = gsKeyTranslationTable[ubKey];
|
|
}
|
|
}
|
|
}
|
|
|
|
GetCursorPos(&MousePos);
|
|
uiTmpLParam = ((MousePos.y << 16) & 0xffff0000) | (MousePos.x & 0x0000ffff);
|
|
|
|
if (ufKeyState == TRUE)
|
|
{ // Key has been PRESSED
|
|
// Find out if the key is already pressed and if not, queue an event and update the gfKeyState array
|
|
if (gfKeyState[ubKey] == FALSE)
|
|
{ // Well the key has just been pressed, therefore we queue up and event and update the gsKeyState
|
|
if (gfCurrentStringInputState == FALSE)
|
|
{
|
|
// There is no string input going on right now, so we queue up the event
|
|
gfKeyState[ubKey] = TRUE;
|
|
QueueEvent(KEY_DOWN, ubChar, uiTmpLParam);
|
|
}
|
|
else
|
|
{ // There is a current input string which will capture this event
|
|
RedirectToString(ubChar);
|
|
DbgMessage(TOPIC_INPUT, DBG_LEVEL_0, String("Pressed character %d (%d)", ubChar, ubKey));
|
|
}
|
|
}
|
|
else
|
|
{ // Well the key gets repeated
|
|
if (gfCurrentStringInputState == FALSE)
|
|
{ // There is no string input going on right now, so we queue up the event
|
|
QueueEvent(KEY_REPEAT, ubChar, uiTmpLParam);
|
|
}
|
|
else
|
|
{ // There is a current input string which will capture this event
|
|
RedirectToString(ubChar);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ // Key has been RELEASED
|
|
// Find out if the key is already pressed and if so, queue an event and update the gfKeyState array
|
|
if (gfKeyState[ubKey] == TRUE)
|
|
{ // Well the key has just been pressed, therefore we queue up and event and update the gsKeyState
|
|
gfKeyState[ubKey] = FALSE;
|
|
QueueEvent(KEY_UP, ubChar, uiTmpLParam);
|
|
}
|
|
//else if the alt tab key was pressed
|
|
else if( ubChar == TAB && gfAltState )
|
|
{
|
|
// therefore minimize the application
|
|
ShowWindow( ghWindow, SW_MINIMIZE );
|
|
gfKeyState[ ALT ] = FALSE;
|
|
gfAltState = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
void KeyDown(UINT32 usParam, UINT32 uiParam)
|
|
{ // Are we PRESSING down one of SHIFT, ALT or CTRL ???
|
|
if (usParam == 16)
|
|
{ // SHIFT key is PRESSED
|
|
gfShiftState = SHIFT_DOWN;
|
|
gfKeyState[16] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (usParam == 17)
|
|
{ // CTRL key is PRESSED
|
|
gfCtrlState = CTRL_DOWN;
|
|
gfKeyState[17] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (usParam == 18)
|
|
{ // ALT key is pressed
|
|
gfAltState = ALT_DOWN;
|
|
gfKeyState[18] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (usParam == SNAPSHOT)
|
|
{
|
|
//PrintScreen();
|
|
// DB Done in the KeyUp function
|
|
// this used to be keyed to SCRL_LOCK
|
|
// which I believe Luis gave the wrong value
|
|
}
|
|
else
|
|
{
|
|
// No special keys have been pressed
|
|
// Call KeyChange() and pass TRUE to indicate key has been PRESSED and not RELEASED
|
|
KeyChange(usParam, uiParam, TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void KeyUp(UINT32 usParam, UINT32 uiParam)
|
|
{ // Are we RELEASING one of SHIFT, ALT or CTRL ???
|
|
if (usParam == 16)
|
|
{ // SHIFT key is RELEASED
|
|
gfShiftState = FALSE;
|
|
gfKeyState[16] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (usParam == 17)
|
|
{ // CTRL key is RELEASED
|
|
gfCtrlState = FALSE;
|
|
gfKeyState[17] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (usParam == 18)
|
|
{ // ALT key is RELEASED
|
|
gfAltState = FALSE;
|
|
gfKeyState[18] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (usParam == SNAPSHOT)
|
|
{
|
|
// DB this used to be keyed to SCRL_LOCK
|
|
// which I believe Luis gave the wrong value
|
|
//#ifndef JA2
|
|
if (_KeyDown(CTRL))
|
|
VideoCaptureToggle();
|
|
else
|
|
//#endif
|
|
PrintScreen();
|
|
}
|
|
else
|
|
{
|
|
// No special keys have been pressed
|
|
// Call KeyChange() and pass FALSE to indicate key has been PRESSED and not RELEASED
|
|
KeyChange(usParam, uiParam, FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void EnableDoubleClk(void)
|
|
{
|
|
// Obsolete
|
|
}
|
|
|
|
void DisableDoubleClk(void)
|
|
{
|
|
// Obsolete
|
|
}
|
|
|
|
void GetMousePos(SGPPoint *Point)
|
|
{
|
|
POINT MousePos;
|
|
|
|
GetCursorPos(&MousePos);
|
|
|
|
Point->iX = (UINT32) MousePos.x;
|
|
Point->iY = (UINT32) MousePos.y;
|
|
|
|
return;
|
|
}
|
|
|
|
// These functions will be used for string input
|
|
|
|
// Since all string input will have to be handle by reentrant capable functions (since we must attend
|
|
// to windows messaging as well as network traffic related issues), whenever there is ongoing string input
|
|
// going on, we must use InitStringInput() and HandleStringInput() to get the job done. HandleStringInput()
|
|
// will return TRUE as long as the string input is going on, and FALSE when its done
|
|
//
|
|
// During string input, all keyboard are rerouted to the string and hence are not queued up on the
|
|
// event queue or registered in the state table. Also note that several string inputs can occur
|
|
// at the same time. Use the SetStringFocus() function to manager the focus for multiple
|
|
// string inputs
|
|
|
|
StringInput *InitStringInput(UINT16 *pInputString, UINT16 usLength, UINT16 *pFilter)
|
|
{
|
|
StringInput *pStringDescriptor;
|
|
|
|
if ((pStringDescriptor = (StringInput *) MemAlloc(sizeof(StringInput))) == NULL)
|
|
{
|
|
//
|
|
// Hum we failed to allocate memory for the string descriptor
|
|
//
|
|
|
|
DbgMessage(TOPIC_INPUT, DBG_LEVEL_1, "Failed to allocate memory for string descriptor");
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
if ((pStringDescriptor->pOriginalString = (UINT16 *) MemAlloc(usLength * 2)) == NULL)
|
|
{
|
|
//
|
|
// free up structure before aborting
|
|
//
|
|
|
|
MemFree(pStringDescriptor);
|
|
DbgMessage(TOPIC_INPUT, DBG_LEVEL_1, "Failed to allocate memory for string duplicate");
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(pStringDescriptor->pOriginalString, pInputString, usLength * 2);
|
|
|
|
pStringDescriptor->pString = pInputString;
|
|
pStringDescriptor->pFilter = pFilter;
|
|
pStringDescriptor->usMaxStringLength = usLength;
|
|
pStringDescriptor->usStringOffset = 0;
|
|
pStringDescriptor->usCurrentStringLength = 0;
|
|
while ((pStringDescriptor->usStringOffset < pStringDescriptor->usMaxStringLength)&&(*(pStringDescriptor->pString + pStringDescriptor->usStringOffset) != 0))
|
|
{
|
|
//
|
|
// Find the last character in the string
|
|
//
|
|
|
|
pStringDescriptor->usStringOffset++;
|
|
pStringDescriptor->usCurrentStringLength++;
|
|
}
|
|
|
|
if (pStringDescriptor->usStringOffset == pStringDescriptor->usMaxStringLength)
|
|
{
|
|
//
|
|
// Hum the current string has no null terminator. Invalidate the string and
|
|
// start from scratch
|
|
//
|
|
|
|
memset(pStringDescriptor->pString, 0, usLength * 2);
|
|
pStringDescriptor->usStringOffset = 0;
|
|
pStringDescriptor->usCurrentStringLength = 0;
|
|
}
|
|
|
|
pStringDescriptor->fInsertMode = FALSE;
|
|
pStringDescriptor->fFocus = FALSE;
|
|
pStringDescriptor->pPreviousString = NULL;
|
|
pStringDescriptor->pNextString = NULL;
|
|
|
|
return pStringDescriptor;
|
|
}
|
|
}
|
|
|
|
void LinkPreviousString(StringInput *pCurrentString, StringInput *pPreviousString)
|
|
{
|
|
if (pCurrentString != NULL)
|
|
{
|
|
if (pCurrentString->pPreviousString != NULL)
|
|
{
|
|
pCurrentString->pPreviousString->pNextString = NULL;
|
|
}
|
|
|
|
pCurrentString->pPreviousString = pPreviousString;
|
|
|
|
if (pPreviousString != NULL)
|
|
{
|
|
pPreviousString->pNextString = pCurrentString;
|
|
}
|
|
}
|
|
}
|
|
|
|
void LinkNextString(StringInput *pCurrentString, StringInput *pNextString)
|
|
{
|
|
if (pCurrentString != NULL)
|
|
{
|
|
if (pCurrentString->pNextString != NULL)
|
|
{
|
|
pCurrentString->pNextString->pPreviousString = NULL;
|
|
}
|
|
|
|
pCurrentString->pNextString = pNextString;
|
|
|
|
if (pNextString != NULL)
|
|
{
|
|
pNextString->pPreviousString = pCurrentString;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN CharacterIsValid(UINT16 usCharacter, UINT16 *pFilter)
|
|
{
|
|
UINT32 uiIndex, uiEndIndex;
|
|
|
|
if (pFilter != NULL)
|
|
{
|
|
uiEndIndex = *pFilter;
|
|
for (uiIndex = 1; uiIndex <= *pFilter; uiIndex++)
|
|
{
|
|
if (usCharacter == *(pFilter + uiIndex))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void RedirectToString(UINT16 usInputCharacter)
|
|
{
|
|
UINT16 usIndex;
|
|
|
|
if (gpCurrentStringDescriptor != NULL)
|
|
{
|
|
// Handle the new character input
|
|
switch (usInputCharacter)
|
|
{
|
|
case ENTER
|
|
: // ENTER is pressed, the last character field should be set to ENTER
|
|
if (gpCurrentStringDescriptor->pNextString != NULL)
|
|
{
|
|
gpCurrentStringDescriptor->fFocus = FALSE;
|
|
gpCurrentStringDescriptor = gpCurrentStringDescriptor->pNextString;
|
|
gpCurrentStringDescriptor->fFocus = TRUE;
|
|
gpCurrentStringDescriptor->usLastCharacter = 0;
|
|
}
|
|
else
|
|
{
|
|
gpCurrentStringDescriptor->fFocus = FALSE;
|
|
gpCurrentStringDescriptor->usLastCharacter = usInputCharacter;
|
|
gfCurrentStringInputState = FALSE;
|
|
}
|
|
break;
|
|
case ESC
|
|
: // ESC was pressed, the last character field should be set to ESC
|
|
gpCurrentStringDescriptor->fFocus = FALSE;
|
|
gpCurrentStringDescriptor->usLastCharacter = usInputCharacter;
|
|
gfCurrentStringInputState = FALSE;
|
|
break;
|
|
case SHIFT_TAB
|
|
: // TAB was pressed, the last character field should be set to TAB
|
|
if (gpCurrentStringDescriptor->pPreviousString != NULL)
|
|
{
|
|
gpCurrentStringDescriptor->fFocus = FALSE;
|
|
gpCurrentStringDescriptor = gpCurrentStringDescriptor->pPreviousString;
|
|
gpCurrentStringDescriptor->fFocus = TRUE;
|
|
gpCurrentStringDescriptor->usLastCharacter = 0;
|
|
}
|
|
break;
|
|
case TAB
|
|
: // TAB was pressed, the last character field should be set to TAB
|
|
if (gpCurrentStringDescriptor->pNextString != NULL)
|
|
{
|
|
gpCurrentStringDescriptor->fFocus = FALSE;
|
|
gpCurrentStringDescriptor = gpCurrentStringDescriptor->pNextString;
|
|
gpCurrentStringDescriptor->fFocus = TRUE;
|
|
gpCurrentStringDescriptor->usLastCharacter = 0;
|
|
}
|
|
break;
|
|
case UPARROW
|
|
: // The UPARROW was pressed, the last character field should be set to UPARROW
|
|
if (gpCurrentStringDescriptor->pPreviousString != NULL)
|
|
{
|
|
gpCurrentStringDescriptor->fFocus = FALSE;
|
|
gpCurrentStringDescriptor = gpCurrentStringDescriptor->pPreviousString;
|
|
gpCurrentStringDescriptor->fFocus = TRUE;
|
|
gpCurrentStringDescriptor->usLastCharacter = 0;
|
|
}
|
|
break;
|
|
case DNARROW
|
|
: // The DNARROW was pressed, the last character field should be set to DNARROW
|
|
if (gpCurrentStringDescriptor->pNextString != NULL)
|
|
{
|
|
gpCurrentStringDescriptor->fFocus = FALSE;
|
|
gpCurrentStringDescriptor = gpCurrentStringDescriptor->pNextString;
|
|
gpCurrentStringDescriptor->fFocus = TRUE;
|
|
gpCurrentStringDescriptor->usLastCharacter = 0;
|
|
}
|
|
break;
|
|
case LEFTARROW
|
|
: // The LEFTARROW was pressed, move one character to the left
|
|
if (gpCurrentStringDescriptor->usStringOffset > 0)
|
|
{ // Decrement the offset
|
|
gpCurrentStringDescriptor->usStringOffset--;
|
|
}
|
|
gpCurrentStringDescriptor->usLastCharacter = usInputCharacter;
|
|
break;
|
|
case RIGHTARROW
|
|
: // The RIGHTARROW was pressed, move one character to the right
|
|
if (gpCurrentStringDescriptor->usStringOffset < gpCurrentStringDescriptor->usCurrentStringLength)
|
|
{ // Ok we can move the cursor one up without going past the end of string
|
|
gpCurrentStringDescriptor->usStringOffset++;
|
|
}
|
|
gpCurrentStringDescriptor->usLastCharacter = usInputCharacter;
|
|
break;
|
|
case BACKSPACE
|
|
: // Delete the character preceding the cursor
|
|
if (gpCurrentStringDescriptor->usStringOffset > 0)
|
|
{ // Ok, we are not at the beginning of the string, so we may proceed
|
|
for (usIndex = gpCurrentStringDescriptor->usStringOffset; usIndex <= gpCurrentStringDescriptor->usCurrentStringLength; usIndex++)
|
|
{ // Shift the characters one at a time
|
|
*(gpCurrentStringDescriptor->pString + usIndex - 1) = *(gpCurrentStringDescriptor->pString + usIndex);
|
|
}
|
|
gpCurrentStringDescriptor->usStringOffset--;
|
|
gpCurrentStringDescriptor->usCurrentStringLength--;
|
|
}
|
|
|
|
break;
|
|
case DEL
|
|
: // Delete the character which follows the cursor
|
|
if (gpCurrentStringDescriptor->usStringOffset < gpCurrentStringDescriptor->usCurrentStringLength)
|
|
{ // Ok we are not at the end of the string, so we may proceed
|
|
for (usIndex = gpCurrentStringDescriptor->usStringOffset; usIndex < gpCurrentStringDescriptor->usCurrentStringLength; usIndex++)
|
|
{ // Shift the characters one at a time
|
|
*(gpCurrentStringDescriptor->pString + usIndex) = *(gpCurrentStringDescriptor->pString + usIndex + 1);
|
|
}
|
|
gpCurrentStringDescriptor->usCurrentStringLength--;
|
|
}
|
|
gpCurrentStringDescriptor->usLastCharacter = usInputCharacter;
|
|
break;
|
|
case INSERT
|
|
: // Toggle insert mode
|
|
if (gpCurrentStringDescriptor->fInsertMode == TRUE)
|
|
{
|
|
gpCurrentStringDescriptor->fInsertMode = FALSE;
|
|
}
|
|
else
|
|
{
|
|
gpCurrentStringDescriptor->fInsertMode = TRUE;
|
|
}
|
|
gpCurrentStringDescriptor->usLastCharacter = usInputCharacter;
|
|
break;
|
|
case HOME
|
|
: // Go to the beginning of the input string
|
|
gpCurrentStringDescriptor->usStringOffset = 0 ;
|
|
gpCurrentStringDescriptor->usLastCharacter = usInputCharacter;
|
|
break;
|
|
#ifndef JA2
|
|
// Stupid definition causes problems with headers that use the keyword END -- DB
|
|
case KEY_END
|
|
#else
|
|
case END
|
|
#endif
|
|
: // Go to the end of the input string
|
|
gpCurrentStringDescriptor->usStringOffset = gpCurrentStringDescriptor->usCurrentStringLength;
|
|
gpCurrentStringDescriptor->usLastCharacter = usInputCharacter;
|
|
break;
|
|
default
|
|
: //
|
|
// normal input
|
|
//
|
|
if (CharacterIsValid(usInputCharacter, gpCurrentStringDescriptor->pFilter) == TRUE)
|
|
{
|
|
if (gpCurrentStringDescriptor->fInsertMode == TRUE)
|
|
{ // Before we can shift characters for the insert, we must make sure we have the space
|
|
if (gpCurrentStringDescriptor->usCurrentStringLength < (gpCurrentStringDescriptor->usMaxStringLength - 1))
|
|
{ // Before we can add a new character we must shift existing ones to for the insert
|
|
for (usIndex = gpCurrentStringDescriptor->usCurrentStringLength; usIndex > gpCurrentStringDescriptor->usStringOffset; usIndex--)
|
|
{ // Shift the characters one at a time
|
|
*(gpCurrentStringDescriptor->pString + usIndex) = *(gpCurrentStringDescriptor->pString + usIndex - 1);
|
|
}
|
|
// Ok now we introduce the new character
|
|
*(gpCurrentStringDescriptor->pString + usIndex) = usInputCharacter;
|
|
gpCurrentStringDescriptor->usStringOffset++;
|
|
gpCurrentStringDescriptor->usCurrentStringLength++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Ok, add character to string (by overwriting)
|
|
if (gpCurrentStringDescriptor->usStringOffset < (gpCurrentStringDescriptor->usMaxStringLength - 1))
|
|
{ // Ok, we have not exceeded the maximum number of characters yet
|
|
*(gpCurrentStringDescriptor->pString + gpCurrentStringDescriptor->usStringOffset) = usInputCharacter;
|
|
gpCurrentStringDescriptor->usStringOffset++;
|
|
}
|
|
// Did we push back the current string length (i.e. add character to end of string)
|
|
if (gpCurrentStringDescriptor->usStringOffset > gpCurrentStringDescriptor->usCurrentStringLength)
|
|
{ // Add a NULL character
|
|
*(gpCurrentStringDescriptor->pString + gpCurrentStringDescriptor->usStringOffset) = 0;
|
|
gpCurrentStringDescriptor->usCurrentStringLength++;
|
|
}
|
|
}
|
|
gpCurrentStringDescriptor->usLastCharacter = usInputCharacter;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT16 GetStringInputState(void)
|
|
{
|
|
if (gpCurrentStringDescriptor != NULL)
|
|
{
|
|
return gpCurrentStringDescriptor->usLastCharacter;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
BOOLEAN StringInputHasFocus(void)
|
|
{
|
|
return gfCurrentStringInputState;
|
|
}
|
|
|
|
BOOLEAN SetStringFocus(StringInput *pStringDescriptor)
|
|
{
|
|
if (pStringDescriptor != NULL)
|
|
{
|
|
if (gpCurrentStringDescriptor != NULL)
|
|
{
|
|
gpCurrentStringDescriptor->fFocus = FALSE;
|
|
}
|
|
// Ok overide current entry
|
|
gfCurrentStringInputState = TRUE;
|
|
gpCurrentStringDescriptor = pStringDescriptor;
|
|
gpCurrentStringDescriptor->fFocus = TRUE;
|
|
gpCurrentStringDescriptor->usLastCharacter = 0;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (gpCurrentStringDescriptor != NULL)
|
|
{
|
|
gpCurrentStringDescriptor->fFocus = FALSE;
|
|
}
|
|
// Ok overide current entry
|
|
gfCurrentStringInputState = FALSE;
|
|
gpCurrentStringDescriptor = NULL;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
UINT16 GetCursorPositionInString(StringInput *pStringDescriptor)
|
|
{
|
|
return pStringDescriptor->usStringOffset;
|
|
}
|
|
|
|
BOOLEAN StringHasFocus(StringInput *pStringDescriptor)
|
|
{
|
|
if (pStringDescriptor != NULL)
|
|
{
|
|
return pStringDescriptor->fFocus;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
void RestoreString(StringInput *pStringDescriptor)
|
|
{
|
|
memcpy(pStringDescriptor->pString, pStringDescriptor->pOriginalString, pStringDescriptor->usMaxStringLength * 2);
|
|
|
|
pStringDescriptor->usStringOffset = 0;
|
|
pStringDescriptor->usCurrentStringLength = 0;
|
|
while ((pStringDescriptor->usStringOffset < pStringDescriptor->usMaxStringLength)&&(*(pStringDescriptor->pString + pStringDescriptor->usStringOffset) != 0))
|
|
{
|
|
//
|
|
// Find the last character in the string
|
|
//
|
|
|
|
pStringDescriptor->usStringOffset++;
|
|
pStringDescriptor->usCurrentStringLength++;
|
|
}
|
|
|
|
if (pStringDescriptor->usStringOffset == pStringDescriptor->usMaxStringLength)
|
|
{
|
|
//
|
|
// Hum the current string has no null terminator. Invalidate the string and
|
|
// start from scratch
|
|
//
|
|
memset(pStringDescriptor->pString, 0, pStringDescriptor->usMaxStringLength * 2);
|
|
pStringDescriptor->usStringOffset = 0;
|
|
pStringDescriptor->usCurrentStringLength = 0;
|
|
}
|
|
|
|
pStringDescriptor->fInsertMode = FALSE;
|
|
}
|
|
|
|
void EndStringInput(StringInput *pStringDescriptor)
|
|
{ // Make sure we have a valid pStringDescriptor
|
|
if (pStringDescriptor != NULL)
|
|
{ // make sure the gpCurrentStringDescriptor is NULL if necessary
|
|
if (pStringDescriptor == gpCurrentStringDescriptor)
|
|
{
|
|
gpCurrentStringDescriptor = NULL;
|
|
gfCurrentStringInputState = FALSE;
|
|
}
|
|
// Make sure we have a valid string within the string descriptor
|
|
if (pStringDescriptor->pOriginalString != NULL)
|
|
{ // free up the string
|
|
MemFree(pStringDescriptor->pOriginalString);
|
|
}
|
|
// free up the descriptor
|
|
MemFree(pStringDescriptor);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Miscellaneous input-related utility functions:
|
|
//
|
|
|
|
void RestrictMouseToXYXY(UINT16 usX1, UINT16 usY1, UINT16 usX2, UINT16 usY2)
|
|
{
|
|
SGPRect TempRect;
|
|
|
|
TempRect.iLeft = usX1;
|
|
TempRect.iTop = usY1;
|
|
TempRect.iRight = usX2;
|
|
TempRect.iBottom = usY2;
|
|
|
|
RestrictMouseCursor(&TempRect);
|
|
}
|
|
|
|
void RestrictMouseCursor(SGPRect *pRectangle)
|
|
{
|
|
// Make a copy of our rect....
|
|
memcpy( &gCursorClipRect, pRectangle, sizeof( gCursorClipRect ) );
|
|
ClipCursor((RECT *)pRectangle);
|
|
fCursorWasClipped = TRUE;
|
|
}
|
|
|
|
void FreeMouseCursor(void)
|
|
{
|
|
ClipCursor(NULL);
|
|
fCursorWasClipped = FALSE;
|
|
}
|
|
|
|
void RestoreCursorClipRect( void )
|
|
{
|
|
if ( fCursorWasClipped )
|
|
{
|
|
ClipCursor( &gCursorClipRect );
|
|
}
|
|
}
|
|
|
|
void GetRestrictedClipCursor( SGPRect *pRectangle )
|
|
{
|
|
GetClipCursor((RECT *) pRectangle );
|
|
}
|
|
|
|
BOOLEAN IsCursorRestricted( void )
|
|
{
|
|
return( fCursorWasClipped );
|
|
}
|
|
|
|
void SimulateMouseMovement( UINT32 uiNewXPos, UINT32 uiNewYPos )
|
|
{
|
|
FLOAT flNewXPos, flNewYPos;
|
|
|
|
// Wizardry NOTE: This function currently doesn't quite work right for in any Windows resolution other than 640x480.
|
|
// mouse_event() uses your current Windows resolution to calculate the resulting x,y coordinates. So in order to get
|
|
// the right coordinates, you'd have to find out the current Windows resolution through a system call, and then do:
|
|
// uiNewXPos = uiNewXPos * SCREEN_WIDTH / WinScreenResX;
|
|
// uiNewYPos = uiNewYPos * SCREEN_HEIGHT / WinScreenResY;
|
|
//
|
|
// JA2 doesn't have this problem, 'cause they use DirectDraw calls that change the Windows resolution properly.
|
|
//
|
|
// Alex Meduna, Dec. 3, 1997
|
|
|
|
// Adjust coords based on our resolution
|
|
flNewXPos = ( (FLOAT)uiNewXPos / SCREEN_WIDTH ) * 65536;
|
|
flNewYPos = ( (FLOAT)uiNewYPos / SCREEN_HEIGHT ) * 65536;
|
|
|
|
mouse_event( MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, (UINT32)flNewXPos, (UINT32)flNewYPos, 0, 0 );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN InputEventInside(InputAtom *Event, UINT32 uiX1, UINT32 uiY1, UINT32 uiX2, UINT32 uiY2)
|
|
{
|
|
UINT32 uiEventX, uiEventY;
|
|
|
|
uiEventX = _EvMouseX(Event);
|
|
uiEventY = _EvMouseY(Event);
|
|
|
|
return((uiEventX >= uiX1) && (uiEventX <= uiX2) && (uiEventY >= uiY1) && (uiEventY <= uiY2));
|
|
}
|
|
|
|
|
|
void DequeueAllKeyBoardEvents()
|
|
{
|
|
InputAtom InputEvent;
|
|
MSG KeyMessage;
|
|
|
|
|
|
//dequeue all the events waiting in the windows queue
|
|
while( PeekMessage( &KeyMessage, ghWindow, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) );
|
|
|
|
//Deque all the events waiting in the SGP queue
|
|
while (DequeueEvent(&InputEvent) == TRUE)
|
|
{
|
|
//dont do anything
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void HandleSingleClicksAndButtonRepeats( void )
|
|
{
|
|
UINT32 uiTimer;
|
|
|
|
|
|
uiTimer = GetTickCount();
|
|
|
|
// Is there a LEFT mouse button repeat
|
|
if (gfLeftButtonState)
|
|
{
|
|
if ((guiLeftButtonRepeatTimer > 0)&&(guiLeftButtonRepeatTimer <= uiTimer))
|
|
{
|
|
UINT32 uiTmpLParam;
|
|
POINT MousePos;
|
|
|
|
GetCursorPos(&MousePos);
|
|
uiTmpLParam = ((MousePos.y << 16) & 0xffff0000) | (MousePos.x & 0x0000ffff);
|
|
QueueEvent(LEFT_BUTTON_REPEAT, 0, uiTmpLParam);
|
|
guiLeftButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIME;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
guiLeftButtonRepeatTimer = 0;
|
|
}
|
|
|
|
|
|
// Is there a RIGHT mouse button repeat
|
|
if (gfRightButtonState)
|
|
{
|
|
if ((guiRightButtonRepeatTimer > 0)&&(guiRightButtonRepeatTimer <= uiTimer))
|
|
{
|
|
UINT32 uiTmpLParam;
|
|
POINT MousePos;
|
|
|
|
GetCursorPos(&MousePos);
|
|
uiTmpLParam = ((MousePos.y << 16) & 0xffff0000) | (MousePos.x & 0x0000ffff);
|
|
QueueEvent(RIGHT_BUTTON_REPEAT, 0, uiTmpLParam);
|
|
guiRightButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIME;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
guiRightButtonRepeatTimer = 0;
|
|
}
|
|
}
|
|
|
|
|
|
INT16 GetMouseWheelDeltaValue( UINT32 wParam )
|
|
{
|
|
INT16 sDelta = HIWORD( wParam );
|
|
|
|
return( sDelta / WHEEL_DELTA );
|
|
}
|