mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
* More unused stuff removal
delete:
- giant 'metaheaders' (JA2 All.h, Laptop All.h, etc), preferring to add #includes directly where needed
- unused ExceptionHandling and DbMan translation units
- unused WizShare.h, Bitmap.h, trle.h, video_private.h headers
* remove mentions from vc proj files too
* remove preprocessor conditionals for unused definitions
find . -iname '*.h' -o -iname '*.cpp' -exec unifdef.exe -m -UPRECOMPILED_HEADERS -UJA2_PRECOMPILED_HEADERS -UWIZ8_PRECOMPILED_HEADERS -UPRECOMPILEDHEADERS {} ';'
then manually fixed a couple files the tool errored out on
* yes, the comments too
as title
1760 lines
48 KiB
C++
1760 lines
48 KiB
C++
// WANNE: Only include _WIN32_WINNT WINVER in VS versions <= 2005
|
|
#if _MSC_VER < 1500
|
|
#define _WIN32_WINNT WINVER
|
|
#endif
|
|
|
|
//** dd for defines that needed for additional mouse buttons
|
|
#define _WIN32_WINNT 0x500
|
|
|
|
//**
|
|
#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"
|
|
|
|
|
|
// 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;
|
|
extern BOOLEAN gfMouseLockedOnBorder;
|
|
extern int iWindowedMode;
|
|
|
|
|
|
// 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; // SHIFT_DOWN = Pressed, FALSE = Not Pressed
|
|
UINT16 gfAltState; // ALT_DOWN = Pressed, FALSE = Not Pressed
|
|
UINT16 gfCtrlState; // CTRL_DOWN = 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;
|
|
UINT32 guiMiddleButtonRepeatTimer;
|
|
UINT32 guiX1ButtonRepeatTimer;
|
|
UINT32 guiX2ButtonRepeatTimer;
|
|
|
|
BOOLEAN gfTrackMousePos; // TRUE = queue mouse movement events, FALSE = don't
|
|
BOOLEAN gfLeftButtonState; // TRUE = Pressed, FALSE = Not Pressed
|
|
BOOLEAN gfRightButtonState; // TRUE = Pressed, FALSE = Not Pressed
|
|
BOOLEAN gfMiddleButtonState;//dnl ch4 210909 TRUE = Pressed, FALSE = Not Pressed
|
|
INT16 gsMouseWheelDeltaValue;//dnl ch4 210909 positive value indicates that the wheel was rotated forward, negative value indicates that the wheel was rotated backward, and user handler procedure for mouse wheel should restore after usege this value to zero!
|
|
BOOLEAN gfX1ButtonState;
|
|
BOOLEAN gfX2ButtonState;
|
|
|
|
INT16 gusMouseXPos; // X position of the mouse on screen
|
|
INT16 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;
|
|
|
|
// Thread
|
|
static CRITICAL_SECTION gcsInputQueueLock;
|
|
|
|
|
|
// 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)
|
|
{
|
|
if (Code < 0) // 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;
|
|
}
|
|
|
|
|
|
LRESULT CALLBACK MouseHandler(int Code, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UINT32 uiParam;
|
|
POINT mpos;
|
|
MOUSEHOOKSTRUCTEX* p_mhs;
|
|
|
|
if (Code < 0) // Do not handle this message, pass it on to another window
|
|
return CallNextHookEx(ghMouseHook, Code, wParam, lParam);
|
|
|
|
p_mhs = (MOUSEHOOKSTRUCTEX*)lParam;
|
|
|
|
mpos = ((MOUSEHOOKSTRUCT *)lParam)->pt;
|
|
ScreenToClient( ghWindow, &mpos);
|
|
gusMouseXPos = (INT16)mpos.x;
|
|
gusMouseYPos = (INT16)mpos.y;
|
|
uiParam = gusMouseYPos;
|
|
uiParam = uiParam << 16;
|
|
uiParam = uiParam | gusMouseXPos;
|
|
|
|
switch (wParam)
|
|
{
|
|
case WM_XBUTTONDOWN://** code is working
|
|
if( p_mhs->mouseData== (XBUTTON1<<16) ) //MessageBeep(-1);
|
|
{
|
|
gfX1ButtonState = TRUE;
|
|
gfSGPInputReceived = TRUE;
|
|
QueueEvent(X1_BUTTON_DOWN, 0, uiParam);
|
|
}
|
|
if( p_mhs->mouseData== (XBUTTON2<<16) ) //MessageBeep(0x00000040L);
|
|
{
|
|
gfX2ButtonState = TRUE;
|
|
gfSGPInputReceived = TRUE;
|
|
QueueEvent(X2_BUTTON_DOWN, 0, uiParam);
|
|
}
|
|
break;
|
|
case WM_XBUTTONUP://** code is working
|
|
if( p_mhs->mouseData== (XBUTTON1<<16) )
|
|
{
|
|
gfX1ButtonState = FALSE;
|
|
gfSGPInputReceived = TRUE;
|
|
QueueEvent(X1_BUTTON_UP, 0, uiParam);
|
|
}
|
|
if( p_mhs->mouseData== (XBUTTON2<<16) )
|
|
{
|
|
gfX2ButtonState = FALSE;
|
|
gfSGPInputReceived = TRUE;
|
|
QueueEvent(X2_BUTTON_UP, 0, uiParam);
|
|
}
|
|
break;
|
|
case WM_MOUSEWHEEL:
|
|
gsMouseWheelDeltaValue = GetMouseWheelDeltaValue(((MOUSEHOOKSTRUCTEX *)lParam)->mouseData);//dnl ch4 210909
|
|
if(p_mhs->mouseData==(WHEEL_DELTA<<16)) //up MessageBeep(-1);
|
|
QueueEvent(MOUSE_WHEEL_UP, 0, uiParam);
|
|
if(p_mhs->mouseData==(-WHEEL_DELTA<<16)) //dn MessageBeep(0x00000040L);
|
|
QueueEvent(MOUSE_WHEEL_DOWN, 0, uiParam);
|
|
break;
|
|
case WM_MBUTTONDOWN:
|
|
gfMiddleButtonState= TRUE; //Set that we have input
|
|
gfSGPInputReceived = TRUE;//Set that we have input
|
|
QueueEvent(MIDDLE_BUTTON_DOWN, 0, uiParam);// Trigger an input event
|
|
break;
|
|
case WM_MBUTTONUP:
|
|
gfMiddleButtonState= FALSE;
|
|
gfSGPInputReceived = TRUE;
|
|
QueueEvent(MIDDLE_BUTTON_UP, 0, uiParam);
|
|
break;
|
|
case WM_LBUTTONDOWN:
|
|
gfLeftButtonState = TRUE;
|
|
gfSGPInputReceived = TRUE;
|
|
QueueEvent(LEFT_BUTTON_DOWN, 0, uiParam);
|
|
break;
|
|
case WM_LBUTTONUP:
|
|
gfLeftButtonState = FALSE;
|
|
gfSGPInputReceived = TRUE;
|
|
QueueEvent(LEFT_BUTTON_UP, 0, uiParam);
|
|
break;
|
|
case WM_RBUTTONDOWN:
|
|
gfRightButtonState = TRUE;
|
|
gfSGPInputReceived = TRUE;
|
|
QueueEvent(RIGHT_BUTTON_DOWN, 0, uiParam);
|
|
break;
|
|
case WM_RBUTTONUP:
|
|
gfRightButtonState = FALSE;
|
|
gfSGPInputReceived = TRUE;
|
|
QueueEvent(RIGHT_BUTTON_UP, 0, uiParam);
|
|
break;
|
|
case WM_MOUSEMOVE:
|
|
// Trigger an input event
|
|
if (gfTrackMousePos == TRUE)
|
|
QueueEvent(MOUSE_POS, 0, uiParam);
|
|
gfSGPInputReceived = TRUE;
|
|
break;
|
|
default:
|
|
return CallNextHookEx(ghMouseHook, Code, wParam, lParam);
|
|
}
|
|
|
|
//ddd why below code commented?
|
|
// if (gusMouseXPos < 0 || gusMouseXPos >= SCREEN_WIDTH ||
|
|
// gusMouseYPos < 0 || gusMouseYPos >= SCREEN_HEIGHT)
|
|
return CallNextHookEx(ghMouseHook, Code, wParam, lParam);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
InitializeCriticalSection(&gcsInputQueueLock);
|
|
|
|
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);
|
|
|
|
DeleteCriticalSection(&gcsInputQueueLock);
|
|
}
|
|
|
|
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 InternalQueueEvent(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 == MIDDLE_BUTTON_DOWN)
|
|
guiMiddleButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIMEOUT;
|
|
if (ubInputEvent == X1_BUTTON_DOWN)
|
|
guiX1ButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIMEOUT;
|
|
if (ubInputEvent == X2_BUTTON_DOWN)
|
|
guiX2ButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIMEOUT;
|
|
|
|
if (ubInputEvent == LEFT_BUTTON_UP)
|
|
guiLeftButtonRepeatTimer = 0;
|
|
if (ubInputEvent == RIGHT_BUTTON_UP)
|
|
guiRightButtonRepeatTimer = 0;
|
|
if (ubInputEvent == MIDDLE_BUTTON_UP)
|
|
guiMiddleButtonRepeatTimer = 0;
|
|
if (ubInputEvent == X1_BUTTON_UP)
|
|
guiX1ButtonRepeatTimer = 0;
|
|
if (ubInputEvent == X2_BUTTON_UP)
|
|
guiX2ButtonRepeatTimer = 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++;
|
|
}
|
|
}
|
|
|
|
|
|
void QueueEvent(UINT16 ubInputEvent, UINT32 usParam, UINT32 uiParam)
|
|
{
|
|
EnterCriticalSection(&gcsInputQueueLock);
|
|
__try {
|
|
InternalQueueEvent(ubInputEvent, usParam, uiParam);
|
|
}__finally {
|
|
LeaveCriticalSection(&gcsInputQueueLock);
|
|
}
|
|
}
|
|
|
|
BOOLEAN DequeueSpecificEvent(InputAtom *Event, UINT32 uiMaskFlags )
|
|
{
|
|
EnterCriticalSection(&gcsInputQueueLock);
|
|
|
|
BOOLEAN result = FALSE;
|
|
|
|
__try
|
|
{
|
|
// 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 ) )
|
|
{
|
|
result = DequeueEvent( Event);
|
|
}
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
LeaveCriticalSection(&gcsInputQueueLock);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOLEAN InternalDequeueEvent(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;
|
|
}
|
|
}
|
|
|
|
BOOLEAN DequeueEvent(InputAtom *Event)
|
|
{
|
|
BOOLEAN result = FALSE;
|
|
__try
|
|
{
|
|
EnterCriticalSection(&gcsInputQueueLock);
|
|
result = InternalDequeueEvent(Event);
|
|
}
|
|
__finally
|
|
{
|
|
LeaveCriticalSection(&gcsInputQueueLock);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
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);
|
|
ScreenToClient(ghWindow, &MousePos); // In window coords!
|
|
|
|
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 == SHIFT)
|
|
{
|
|
// SHIFT key is PRESSED
|
|
gfShiftState = SHIFT_DOWN;
|
|
gfKeyState[SHIFT] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (usParam == CTRL)
|
|
{
|
|
// CTRL key is PRESSED
|
|
gfCtrlState = CTRL_DOWN;
|
|
gfKeyState[CTRL] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (usParam == ALT)
|
|
{
|
|
// ALT key is pressed
|
|
gfAltState = ALT_DOWN;
|
|
gfKeyState[ALT] = 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 == SHIFT)
|
|
{
|
|
// SHIFT key is RELEASED
|
|
gfShiftState = FALSE;
|
|
gfKeyState[SHIFT] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (usParam == CTRL)
|
|
{
|
|
// CTRL key is RELEASED
|
|
gfCtrlState = FALSE;
|
|
gfKeyState[CTRL] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (usParam == ALT)
|
|
{
|
|
// ALT key is RELEASED
|
|
gfAltState = FALSE;
|
|
gfKeyState[ALT] = 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);
|
|
ScreenToClient(ghWindow, &MousePos); // In window coords!
|
|
|
|
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 ) );
|
|
ClientToScreen( ghWindow, (LPPOINT)&gCursorClipRect);
|
|
ClientToScreen( ghWindow, ((LPPOINT)&gCursorClipRect)+1);
|
|
ClipCursor(&gCursorClipRect);
|
|
fCursorWasClipped = TRUE;
|
|
}
|
|
|
|
void FreeMouseCursor( BOOLEAN fLockForTacticalWindowedMode )
|
|
{
|
|
ClipCursor(NULL);
|
|
fCursorWasClipped = FALSE;
|
|
|
|
// Buggler: Need to relock for fullscreen mode as ClipCursor release mouse boundary to full desktop resolution on multi-monitor setup &&
|
|
// for windowed mode, lockscreen only when player activates feature in tactical screen due to mouse restriction applies to desktop too!
|
|
if ( !iWindowedMode || ( iWindowedMode && gfMouseLockedOnBorder && fLockForTacticalWindowedMode ) )
|
|
{
|
|
SGPRect LJDRect;
|
|
|
|
LJDRect.iLeft = 0;
|
|
LJDRect.iTop = 0;
|
|
LJDRect.iRight = SCREEN_WIDTH;
|
|
LJDRect.iBottom = SCREEN_HEIGHT;
|
|
RestrictMouseCursor( &LJDRect );
|
|
}
|
|
}
|
|
|
|
void RestoreCursorClipRect( void )
|
|
{
|
|
if ( fCursorWasClipped )
|
|
{
|
|
ClipCursor( &gCursorClipRect );
|
|
}
|
|
}
|
|
|
|
void GetRestrictedClipCursor( SGPRect *pRectangle )
|
|
{
|
|
GetClipCursor((RECT *) pRectangle );
|
|
ScreenToClient( ghWindow, (LPPOINT)pRectangle);
|
|
ScreenToClient( ghWindow, ((LPPOINT)pRectangle)+1);
|
|
}
|
|
|
|
BOOLEAN IsCursorRestricted( void )
|
|
{
|
|
return( fCursorWasClipped );
|
|
}
|
|
|
|
void SimulateMouseMovement( UINT32 uiNewXPos, UINT32 uiNewYPos )
|
|
{
|
|
#if 0
|
|
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 );
|
|
#endif
|
|
// 0verhaul:
|
|
// The above is a bad hack. Especially in windowed mode. We don't want coords relative to the entire screen in that case.
|
|
// So instead, get screen coords and then use the setcursorpos call.
|
|
POINT newmouse;
|
|
newmouse.x = uiNewXPos;
|
|
newmouse.y = uiNewYPos;
|
|
ClientToScreen( ghWindow, &newmouse);
|
|
SetCursorPos( newmouse.x, newmouse.y);
|
|
}
|
|
|
|
|
|
|
|
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
|
|
//Give them proper processing like the old window hook method used to.
|
|
while( PeekMessage( &KeyMessage, ghWindow, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) )
|
|
{
|
|
TranslateMessage( &KeyMessage);
|
|
DispatchMessage( &KeyMessage);
|
|
}
|
|
|
|
//Now deque all the events waiting in the SGP queue
|
|
//Including those that were just posted in the code above
|
|
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);
|
|
ScreenToClient(ghWindow, &MousePos); // In window coords!
|
|
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);
|
|
ScreenToClient(ghWindow, &MousePos); // In window coords!
|
|
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 );
|
|
}
|
|
|
|
BOOLEAN PeekSpecificEvent(UINT32 uiMaskFlags)//dnl ch74 221013
|
|
{
|
|
BOOLEAN result = FALSE;
|
|
EnterCriticalSection(&gcsInputQueueLock);
|
|
if(gusQueueCount > 0 && (gEventQueue[gusHeadIndex].usEvent & uiMaskFlags))
|
|
result = TRUE;
|
|
LeaveCriticalSection(&gcsInputQueueLock);
|
|
return(result);
|
|
}
|