Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA 2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
No known key found for this signature in database
GPG key ID: C6EBE8C2EA08F7E0
6072 changed files with 2283311 additions and 0 deletions

View file

@ -0,0 +1,425 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: Win32DIKeyboard.cpp //////////////////////////////////////////////////////////////////////
// Created: Colin Day, June 2001
// Desc: Device implementation of the keyboard interface on Win32
// using Microsoft Direct Input
///////////////////////////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <assert.h>
#include "Common/Debug.h"
#include "Common/Language.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/Keyboard.h"
#include "Win32Device/GameClient/Win32DIKeyboard.h"
#include "WinMain.h"
// DEFINES ////////////////////////////////////////////////////////////////////////////////////////
enum { KEYBOARD_BUFFER_SIZE = 256 };
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
struct ErrorLookup
{
HRESULT error;
char *string;
};
static ErrorLookup errorLookup[] =
{
{ DIERR_ACQUIRED, "DIERR_ACQUIRED" },
{ DIERR_ALREADYINITIALIZED, "DIERR_ALREADYINITIALIZED" },
{ DIERR_BADDRIVERVER, "DIERR_BADDRIVERVER" },
{ DIERR_BETADIRECTINPUTVERSION, "DIERR_BETADIRECTINPUTVERSION" },
{ DIERR_DEVICEFULL, "DIERR_DEVICEFULL" },
{ DIERR_DEVICENOTREG, "DIERR_DEVICENOTREG" },
{ DIERR_EFFECTPLAYING, "DIERR_EFFECTPLAYING" },
{ DIERR_GENERIC, "DIERR_GENERIC" },
{ DIERR_HANDLEEXISTS, "DIERR_HANDLEEXISTS" },
{ DIERR_HASEFFECTS, "DIERR_HASEFFECTS" },
{ DIERR_INCOMPLETEEFFECT, "DIERR_INCOMPLETEEFFECT" },
{ DIERR_INPUTLOST, "DIERR_INPUTLOST" },
{ DIERR_INVALIDPARAM, "DIERR_INVALIDPARAM" },
{ DIERR_MAPFILEFAIL, "DIERR_MAPFILEFAIL" },
{ DIERR_MOREDATA, "DIERR_MOREDATA" },
{ DIERR_NOAGGREGATION, "DIERR_NOAGGREGATION" },
{ DIERR_NOINTERFACE, "DIERR_NOINTERFACE" },
{ DIERR_NOTACQUIRED, "DIERR_NOTACQUIRED" },
{ DIERR_NOTBUFFERED, "DIERR_NOTBUFFERED" },
{ DIERR_NOTDOWNLOADED, "DIERR_NOTDOWNLOADED" },
{ DIERR_NOTEXCLUSIVEACQUIRED, "DIERR_NOTEXCLUSIVEACQUIRED" },
{ DIERR_NOTFOUND, "DIERR_NOTFOUND" },
{ DIERR_NOTINITIALIZED, "DIERR_NOTINITIALIZED" },
{ DIERR_OBJECTNOTFOUND, "DIERR_OBJECTNOTFOUND" },
{ DIERR_OLDDIRECTINPUTVERSION, "DIERR_OLDDIRECTINPUTVERSION" },
{ DIERR_OTHERAPPHASPRIO, "DIERR_OTHERAPPHASPRIO" },
{ DIERR_OUTOFMEMORY, "DIERR_OUTOFMEMORY" },
{ DIERR_READONLY, "DIERR_READONLY" },
{ DIERR_REPORTFULL, "DIERR_REPORTFULL" },
{ DIERR_UNPLUGGED, "DIERR_UNPLUGGED" },
{ DIERR_UNSUPPORTED, "DIERR_UNSUPPORTED" },
{ 0, NULL }
};
///////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
/** For debugging, prints the return code using direct input errors */
//-------------------------------------------------------------------------------------------------
static void printReturnCode( char *label, HRESULT hr )
{
ErrorLookup *error = errorLookup;
while( error->string != NULL )
{
if( error->error == hr )
{
DEBUG_LOG(( "%s: '%s' - '0x%08x'\n", label, error->string, hr ));
break;
}
error++;
}
} // end printReturnCode
//-------------------------------------------------------------------------------------------------
/** create our interface to the direct input keybard */
//-------------------------------------------------------------------------------------------------
void DirectInputKeyboard::openKeyboard( void )
{
HRESULT hr;
// create our interface to direct input
hr = DirectInput8Create( ApplicationHInstance,
DIRECTINPUT_VERSION,
IID_IDirectInput8,
(void **)&m_pDirectInput,
NULL );
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openKeyboard: DirectInputCreate failed\r\n" ));
assert( 0 );
closeKeyboard();
return;
} // end if
// obtain an interface to the system keyboard device
hr = m_pDirectInput->CreateDevice( GUID_SysKeyboard,
&m_pKeyboardDevice,
NULL );
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openKeyboard: Unabled to create keyboard device\n" ));
assert( 0 );
closeKeyboard();
return;
} // end if
// set the data format for the keyboard
hr = m_pKeyboardDevice->SetDataFormat( &c_dfDIKeyboard );
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openKeyboard: Unabled to set data format for keyboard\n" ));
assert( 0 );
closeKeyboard();
return;
} // end if
/// @todo Check the cooperative level of keyboard for NT, 2000, DX8 etc ...
// set the cooperative level for the keyboard, must be non-exclusive for
// NT support, but we should check with the latest versions of DirectX
// on 2000 etc
//
hr = m_pKeyboardDevice->SetCooperativeLevel( ApplicationHWnd,
DISCL_FOREGROUND |
DISCL_NONEXCLUSIVE );
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openKeyboard: Unabled to set cooperative level\n" ));
assert( 0 );
closeKeyboard();
return;
} // end if
// set the keyboard buffer size
DIPROPDWORD prop;
prop.diph.dwSize = sizeof( DIPROPDWORD );
prop.diph.dwHeaderSize = sizeof( DIPROPHEADER );
prop.diph.dwObj = 0;
prop.diph.dwHow = DIPH_DEVICE;
prop.dwData = KEYBOARD_BUFFER_SIZE;
hr = m_pKeyboardDevice->SetProperty( DIPROP_BUFFERSIZE, &prop.diph );
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openKeyboard: Unable to set keyboard buffer size property\n" ));
assert( 0 );
closeKeyboard();
return;
} // end if
// acquire the keyboard
hr = m_pKeyboardDevice->Acquire();
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openKeyboard: Unable to acquire keyboard device\n" ));
// Note - This can happen in windowed mode, and we can re-acquire later. So don't
// close the keyboard. jba.
// closeKeyboard();
return;
} // end if
DEBUG_LOG(( "OK - Keyboard initialized successfully.\n" ));
} // end openKeyboard
//-------------------------------------------------------------------------------------------------
/** close the direct input keyboard */
//-------------------------------------------------------------------------------------------------
void DirectInputKeyboard::closeKeyboard( void )
{
if( m_pKeyboardDevice )
{
m_pKeyboardDevice->Unacquire();
m_pKeyboardDevice->Release();
m_pKeyboardDevice = NULL;
DEBUG_LOG(( "OK - Keyboard deviced closed\n" ));
} // end if
if( m_pDirectInput )
{
m_pDirectInput->Release();
m_pDirectInput = NULL;
DEBUG_LOG(( "OK - Keyboard direct input interface closed\n" ));
} // end if
DEBUG_LOG(( "OK - Keyboard shutdown complete\n" ));
} // end closeKeyboard
//-------------------------------------------------------------------------------------------------
/** Get a single keyboard event from direct input */
//-------------------------------------------------------------------------------------------------
void DirectInputKeyboard::getKey( KeyboardIO *key )
{
static int errs = 0;
DIDEVICEOBJECTDATA kbdat;
DWORD num = 0;
// int done = 0;
HRESULT hr;
assert( key );
key->sequence = 0;
key->key = KEY_NONE;
if( m_pKeyboardDevice )
{
// get 1 key, if available
num = 1;
hr = m_pKeyboardDevice->Acquire();
if (hr == DI_OK || hr == S_FALSE)
hr = m_pKeyboardDevice->GetDeviceData( sizeof( DIDEVICEOBJECTDATA ),
&kbdat, &num, 0 );
switch( hr )
{
// ----------------------------------------------------------------------
case DI_OK:
break;
// ----------------------------------------------------------------------
case DIERR_INPUTLOST:
case DIERR_NOTACQUIRED:
// if we lost focus, attempt to re-acquire
hr = m_pKeyboardDevice->Acquire();
switch( hr )
{
// ------------------------------------------------------------------
//If an error occurs return KEY_NONE
case DIERR_INVALIDPARAM:
case DIERR_NOTINITIALIZED:
case DIERR_OTHERAPPHASPRIO:
break;
// ------------------------------------------------------------------
// If successful... tell system to loop back
case DI_OK:
case S_FALSE:
{
// this will tell the system to loop again
key->key = KEY_LOST;
break;
} // end, got the keyboard back OK
} // end switch
return;
// ----------------------------------------------------------------------
default:
return;
} // end switch( hr )
// no keys returned
if( num == 0 )
return;
// set the key
key->key = (UnsignedByte)(kbdat.dwOfs & 0xFF);
// sequence
key->sequence = kbdat.dwSequence;
//
// state of key, note we are setting the key state here with an assignment
// and not a bit set of the up/down state, this is the "start"
// of building this "key"
//
key->state = (( kbdat.dwData & 0x0080 ) ? KEY_STATE_DOWN : KEY_STATE_UP);
// set status as unused (unprocessed)
key->status = KeyboardIO::STATUS_UNUSED;
} // end if, we have a DI keyboard device
} // end getKey
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
DirectInputKeyboard::DirectInputKeyboard( void )
{
m_pDirectInput = NULL;
m_pKeyboardDevice = NULL;
if( GetKeyState( VK_CAPITAL ) & 0x01 )
{
m_modifiers |= KEY_STATE_CAPSLOCK;
}
else
{
m_modifiers &= ~KEY_STATE_CAPSLOCK;
}
} // end DirectInputKeyboard
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
DirectInputKeyboard::~DirectInputKeyboard( void )
{
// close keyboard and release all resource
closeKeyboard();
} // end ~DirectInputKeyboard
//-------------------------------------------------------------------------------------------------
/** initialize the keyboard */
//-------------------------------------------------------------------------------------------------
void DirectInputKeyboard::init( void )
{
// extending functionality
Keyboard::init();
// open the direct input keyboard
openKeyboard();
} // end init
//-------------------------------------------------------------------------------------------------
/** Reset keyboard system */
//-------------------------------------------------------------------------------------------------
void DirectInputKeyboard::reset( void )
{
// extend functionality
Keyboard::reset();
} // end reset
//-------------------------------------------------------------------------------------------------
/** called once per frame to update the keyboard state */
//-------------------------------------------------------------------------------------------------
void DirectInputKeyboard::update( void )
{
// extending functionality
Keyboard::update();
/*
// make sure the keyboard buffer is flushed
if( m_pKeyboardDevice )
{
DWORD items = INFINITE;
m_pKeyboardDevice->GetDeviceData( sizeof( DIDEVICEOBJECTDATA ),
NULL, &items, 0 );
} // end if
*/
} // end update
//-------------------------------------------------------------------------------------------------
/** Return TRUE if the caps lock key is down/hilighted */
//-------------------------------------------------------------------------------------------------
Bool DirectInputKeyboard::getCapsState( void )
{
return BitTest( GetKeyState( VK_CAPITAL ), 0X01);
} // end getCapsState

View file

@ -0,0 +1,513 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// FILE: Win32DIMouse.cpp /////////////////////////////////////////////////////////////////////////
// Created: Colin Day, June 2001
// Desc: Win32 direct input implementation for the mouse
///////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <windows.h>
#include <assert.h>
#include "Common/Debug.h"
#include "GameClient/Display.h"
#include "Win32Device/GameClient/Win32DIMouse.h"
#include "WinMain.h"
// DEFINES ////////////////////////////////////////////////////////////////////////////////////////
enum { MOUSE_BUFFER_SIZE = 256, };
///////////////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
/** Create our direct input object, mouse device, and initialize it to the
* data formats we want */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::openMouse( void )
{
HRESULT hr;
// create our direct input device for mouse access
hr = DirectInput8Create( ApplicationHInstance,
DIRECTINPUT_VERSION,
IID_IDirectInput8,
(void **)&m_pDirectInput,
NULL );
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openMouse: Unabled to create direct input interface\n" ));
assert( 0 );
closeMouse();
return;
} // end if
// create a device for the system mouse
hr = m_pDirectInput->CreateDevice( GUID_SysMouse,
&m_pMouseDevice,
NULL );
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openMouse: Unable to create mouse device\n" ));
assert( 0 );
closeMouse();
return;
} // end if
// set the data format for the mouse
hr = m_pMouseDevice->SetDataFormat( &c_dfDIMouse );
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openMouse: Unabled to set mouse data format\n" ));
assert( 0 );
closeMouse();
return;
} // end if
// set the mouse cooperative level
hr = m_pMouseDevice->SetCooperativeLevel( ApplicationHWnd,
DISCL_NONEXCLUSIVE |
DISCL_FOREGROUND );
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openMouse: Unabled to set coop level\n" ));
assert( 0 );
closeMouse();
return;
} // end if
// set the mouse buffer size
DIPROPDWORD prop;
prop.diph.dwSize = sizeof( DIPROPDWORD );
prop.diph.dwHeaderSize = sizeof( DIPROPHEADER );
prop.diph.dwObj = 0;
prop.diph.dwHow = DIPH_DEVICE;
prop.dwData = MOUSE_BUFFER_SIZE;
hr = m_pMouseDevice->SetProperty( DIPROP_BUFFERSIZE, &prop.diph );
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openMouse: Unabled to set buffer property\n" ));
assert( 0 );
closeMouse();
return;
} // end if
// acquire the mouse
hr = m_pMouseDevice->Acquire();
if( FAILED( hr ) )
{
DEBUG_LOG(( "ERROR - openMouse: Unabled to acquire mouse\n" ));
assert( 0 );
closeMouse();
return;
} // end if
// get some information about the mouse
DIDEVCAPS diDevCaps;
diDevCaps.dwSize = sizeof( DIDEVCAPS );
hr = m_pMouseDevice->GetCapabilities( &diDevCaps );
if( FAILED( hr ) )
{
DEBUG_LOG(( "WARNING - openMouse: Cann't get capabilities of mouse for button setup\n" ));
} // end if
else
{
// keep some data about the mouse we care about
m_numButtons = (UnsignedByte)diDevCaps.dwButtons;
m_numAxes = (UnsignedByte)diDevCaps.dwAxes;
m_forceFeedback = BitTest( diDevCaps.dwFlags, DIDC_FORCEFEEDBACK );
DEBUG_LOG(( "OK - Mouse info: Buttons = '%d', Force Feedback = '%s', Axes = '%d'\n",
m_numButtons, m_forceFeedback ? "Yes" : "No", m_numAxes ));
} // end else
DEBUG_LOG(( "OK - Mouse initialized successfully\n" ));
} // end openMouse
//-------------------------------------------------------------------------------------------------
/** Release any resources for our direct input mouse */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::closeMouse( void )
{
// release the mouse device
if( m_pMouseDevice )
{
m_pMouseDevice->Unacquire();
m_pMouseDevice->Release();
m_pMouseDevice = NULL;
DEBUG_LOG(( "OK - Mouse device closed\n" ));
} // end if
// release our direct input interface for the mouse
if( m_pDirectInput )
{
m_pDirectInput->Release();
m_pDirectInput = NULL;
DEBUG_LOG(( "OK - Mouse direct input interface closed\n" ));
} // end if
DEBUG_LOG(( "OK - Mouse shutdown complete\n" ));
} // end closeMouse
//-------------------------------------------------------------------------------------------------
/** Get a single mouse event from the device */
//-------------------------------------------------------------------------------------------------
UnsignedByte DirectInputMouse::getMouseEvent( MouseIO *result, Bool flush )
{
HRESULT hr;
DIDEVICEOBJECTDATA mdat;
UnsignedByte mouseResult = MOUSE_NONE;
DWORD num;
/* set these to defaults */
result->leftState = result->middleState = result->rightState = FALSE;
result->leftFrame = result->middleFrame = result->rightFrame = 0;
result->pos.x = result->pos.y = result->wheelPos = 0;
if( m_pMouseDevice )
{
// get 1 event, if available
num = 1;
m_pMouseDevice->Poll();
hr = m_pMouseDevice->GetDeviceData( sizeof( DIDEVICEOBJECTDATA ),
&mdat,
&num,
0 );
switch( hr )
{
// ----------------------------------------------------------------------
case DI_OK:
{
// nothing returned
if( num != 0 )
{
mapDirectInputMouse( result, &mdat );
mouseResult = MOUSE_OK;
}
break;
}
// ----------------------------------------------------------------------
case DIERR_NOTACQUIRED:
case DIERR_INPUTLOST:
{
// if we lost focus, attempt to re-acquire
hr = m_pMouseDevice->Acquire();
switch( hr )
{
// ------------------------------------------------------------------
// If successful... tell system to loop back
case DI_OK:
case S_FALSE:
mouseResult = MOUSE_LOST;
// ------------------------------------------------------------------
//If an error occurs return MOUSE_NONE
case DIERR_INVALIDPARAM:
case DIERR_NOTINITIALIZED:
case DIERR_OTHERAPPHASPRIO:
default:
break;
} // end switch
break;
}
// ----------------------------------------------------------------------
default:
// DBGPRINTF(("GetMouseEvent: GetDeviceData Error: %X.\r\n", hr ));
break;
} // end switch
} // end if
return mouseResult;
} // end getMouseEvent
//-------------------------------------------------------------------------------------------------
/** Map the direct input codes to our own mouse format */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::mapDirectInputMouse( MouseIO *mouse,
DIDEVICEOBJECTDATA *mdat )
{
switch( mdat->dwOfs )
{
case DIMOFS_BUTTON0:
mouse->leftState = (( mdat->dwData & 0x0080 ) ? TRUE : FALSE);
mouse->leftFrame = mdat->dwSequence;
break;
case DIMOFS_BUTTON1:
mouse->rightState = (( mdat->dwData & 0x0080 ) ? TRUE : FALSE);
mouse->rightFrame = mdat->dwSequence;
break;
case DIMOFS_BUTTON2:
mouse->middleState = (( mdat->dwData & 0x0080 ) ? TRUE : FALSE);
mouse->middleFrame = mdat->dwSequence;
break;
case DIMOFS_BUTTON3:
break;
case DIMOFS_X:
mouse->pos.x = mdat->dwData;
break;
case DIMOFS_Y:
mouse->pos.y = mdat->dwData;
break;
case DIMOFS_Z:
mouse->wheelPos = mdat->dwData;
break;
}
} // end mapDirectInputMouse
///////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
DirectInputMouse::DirectInputMouse( void )
{
m_pDirectInput = NULL;
m_pMouseDevice = NULL;
} // end DirectInputMouse
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
DirectInputMouse::~DirectInputMouse( void )
{
// relase all mouse resources
closeMouse();
// ShowCursor( TRUE );
} // end ~DirectInputMouse
//-------------------------------------------------------------------------------------------------
/** Initialize the direct input mouse device */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::init( void )
{
POINT p;
// extending functionality from our base class
Mouse::init();
// open the mouse and create the direct input interfaces we need
openMouse();
// move the window mouse to the location we have initialized in our system
p.x = m_currMouse.pos.x;
p.y = m_currMouse.pos.y;
ClientToScreen( ApplicationHWnd, &p );
SetCursorPos( p.x, p.y );
// ShowCursor( FALSE );
} // end init
//-------------------------------------------------------------------------------------------------
/** Reset direct input mouse */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::reset( void )
{
// extend
Mouse::reset();
} // end reset
//-------------------------------------------------------------------------------------------------
/** Update the mouse position and button data, this is called once per
* frame in the engine. NOTE that this routine is extendion functionality
* that we may need that is direct input specific, not replacing */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::update( void )
{
// extendion functionality from our base class
Mouse::update();
//
// since we are currently using the windows cursor because it updates at
// an independent rate of our application we will always just use the windows
// mouse cursor position
//
/** @todo we need to really visit this system and possibly come up with
our own multi-threaded cursor etc */
POINT p;
GetCursorPos( &p );
ScreenToClient( ApplicationHWnd, &p );
moveMouse( p.x, p.y, MOUSE_MOVE_ABSOLUTE );
} // end update
//-------------------------------------------------------------------------------------------------
/** Set the limits which the mouse is allowed to move around in. We
* will limit it to the client area, and if we are windowed we will
* allow for the mouse to move within the title bar at the top of
* the window */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::setMouseLimits( void )
{
//
// extending functionality, although we may overwrite the limits set
// from the base class
//
Mouse::setMouseLimits();
//
// when runing windowed we want to keep the mouse within the game
// window cause it's annoying to mouse out of the window and click
// on a background window.
//
if( TheDisplay && TheDisplay->getWindowed() == TRUE )
{
RECT windowRect;
// get the window rect
GetWindowRect( ApplicationHWnd, &windowRect );
// keep the cursor clipped to these coords when running windowed
ClipCursor( &windowRect );
} // end if
} // end setMouseLimits
//-------------------------------------------------------------------------------------------------
/** set the cursor position for windows OS */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::setPosition( Int x, Int y )
{
POINT p;
// extending functionality
Mouse::setPosition( x, y );
// set the windows cursor
p.x = x;
p.y = y;
ClientToScreen( ApplicationHWnd, &p );
// set the window mouse
SetCursorPos( p.x, p.y );
} // end setPosition
//-------------------------------------------------------------------------------------------------
/** Super basic simplistic cursor */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::setCursor( MouseCursor cursor )
{
// extend
Mouse::setCursor( cursor );
// if we're already on this cursor ignore
if( m_currentCursor == cursor )
return;
switch( cursor )
{
case NONE:
SetCursor( NULL );
break;
case NORMAL:
case ARROW:
SetCursor( LoadCursor( NULL, IDC_ARROW ) );
break;
case SCROLL:
SetCursor( LoadCursor( NULL, IDC_SIZEALL ) );
break;
case CROSS:
SetCursor( LoadCursor( NULL, IDC_CROSS ) );
break;
} // end switch
// save current cursor
m_currentCursor = cursor;
} // end setCursor
//-------------------------------------------------------------------------------------------------
/** Capture the mouse to our application */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::capture( void )
{
SetCapture( ApplicationHWnd );
} // end capture
//-------------------------------------------------------------------------------------------------
/** Release the mouse capture for our app window */
//-------------------------------------------------------------------------------------------------
void DirectInputMouse::releaseCapture( void )
{
ReleaseCapture();
} // end releaseCapture

View file

@ -0,0 +1,467 @@
/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: Win32Mouse.cpp ///////////////////////////////////////////////////////////////////////////
// Created: Colin Day, July 2001
// Desc: Interface for the mouse using only the Win32 messages
///////////////////////////////////////////////////////////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "Common/Debug.h"
#include "Common/GlobalData.h"
#include "Common/LocalFileSystem.h"
#include "GameClient/GameClient.h"
#include "Win32Device/GameClient/Win32Mouse.h"
#include "WinMain.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// EXTERN /////////////////////////////////////////////////////////////////////////////////////////
extern Win32Mouse *TheWin32Mouse;
HCURSOR cursorResources[Mouse::NUM_MOUSE_CURSORS][MAX_2D_CURSOR_DIRECTIONS];
///////////////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
/** Get a mouse event from the buffer if available, we need to translate
* from the windows message meanings to our own internal mouse
* structure */
//-------------------------------------------------------------------------------------------------
UnsignedByte Win32Mouse::getMouseEvent( MouseIO *result, Bool flush )
{
// if there is nothing here there is no event data to do
if( m_eventBuffer[ m_nextGetIndex ].msg == 0 )
return MOUSE_NONE;
// translate the win32 mouse message to our own system
translateEvent( m_nextGetIndex, result );
// remove this event from the buffer by setting msg to zero
m_eventBuffer[ m_nextGetIndex ].msg = 0;
//
// our next get index will now be advanced to the next index, wrapping at
// the mad
//
m_nextGetIndex++;
if( m_nextGetIndex >= Mouse::NUM_MOUSE_EVENTS )
m_nextGetIndex = 0;
// got event OK and all done with this one
return MOUSE_OK;
} // end getMouseEvent
//-------------------------------------------------------------------------------------------------
/** Translate a win32 mouse event to our own event info */
//-------------------------------------------------------------------------------------------------
void Win32Mouse::translateEvent( UnsignedInt eventIndex, MouseIO *result )
{
UINT msg = m_eventBuffer[ eventIndex ].msg;
WPARAM wParam = m_eventBuffer[ eventIndex ].wParam;
LPARAM lParam = m_eventBuffer[ eventIndex ].lParam;
UnsignedInt frame;
//
// get the current input frame from the client, if we don't have
// a client (like in the GUI editor) we just use frame 1 so it
// registers with the system
//
if( TheGameClient )
frame = TheGameClient->getFrame();
else
frame = 1;
// set these to defaults
result->leftState = result->middleState = result->rightState = MBS_Up;
result->leftFrame = result->middleFrame = result->rightFrame = 0;
result->pos.x = result->pos.y = result->wheelPos = 0;
// Time is the same for all events
result->time = m_eventBuffer[ eventIndex ].time;
switch( msg )
{
// ------------------------------------------------------------------------
case WM_LBUTTONDOWN:
{
result->leftState = MBS_Down;
result->leftFrame = frame;
result->pos.x = LOWORD( lParam );
result->pos.y = HIWORD( lParam );
break;
} // end left button down
// ------------------------------------------------------------------------
case WM_LBUTTONUP:
{
result->leftState = MBS_Up;
result->leftFrame = frame;
result->pos.x = LOWORD( lParam );
result->pos.y = HIWORD( lParam );
break;
} // end left button up
// ------------------------------------------------------------------------
case WM_LBUTTONDBLCLK:
{
result->leftState = MBS_DoubleClick;
result->leftFrame = frame;
result->pos.x = LOWORD( lParam );
result->pos.y = HIWORD( lParam );
break;
} // end left button double click
// ------------------------------------------------------------------------
case WM_MBUTTONDOWN:
{
result->middleState = MBS_Down;
result->middleFrame = frame;
result->pos.x = LOWORD( lParam );
result->pos.y = HIWORD( lParam );
break;
} // end middle button down
// ------------------------------------------------------------------------
case WM_MBUTTONUP:
{
result->middleState = MBS_Up;
result->middleFrame = frame;
result->pos.x = LOWORD( lParam );
result->pos.y = HIWORD( lParam );
break;
} // end middle button up
// ------------------------------------------------------------------------
case WM_MBUTTONDBLCLK:
{
result->middleState = MBS_DoubleClick;
result->middleFrame = frame;
result->pos.x = LOWORD( lParam );
result->pos.y = HIWORD( lParam );
break;
} // end middle button double click
// ------------------------------------------------------------------------
case WM_RBUTTONDOWN:
{
result->rightState = MBS_Down;
result->rightFrame = frame;
result->pos.x = LOWORD( lParam );
result->pos.y = HIWORD( lParam );
break;
} // end right button down
// ------------------------------------------------------------------------
case WM_RBUTTONUP:
{
result->rightState = MBS_Up;
result->rightFrame = frame;
result->pos.x = LOWORD( lParam );
result->pos.y = HIWORD( lParam );
break;
} // end right button up
// ------------------------------------------------------------------------
case WM_RBUTTONDBLCLK:
{
result->rightState = MBS_DoubleClick;
result->rightFrame = frame;
result->pos.x = LOWORD( lParam );
result->pos.y = HIWORD( lParam );
break;
} // end right button double click
// ------------------------------------------------------------------------
case WM_MOUSEMOVE:
{
result->pos.x = LOWORD( lParam );
result->pos.y = HIWORD( lParam );
break;
} // end mouse move
// ------------------------------------------------------------------------
case 0x020A: // WM_MOUSEWHEEL
{
POINT p;
// translate the screen mouse position to be relative to the application window
p.x = LOWORD( lParam );
p.y = HIWORD( lParam );
ScreenToClient( ApplicationHWnd, &p );
// note the short cast here to keep signed information in tact
result->wheelPos = (Short)HIWORD( wParam );
result->pos.x = p.x;
result->pos.y = p.y;
break;
} // end mouse wheel
// ------------------------------------------------------------------------
default:
{
DEBUG_CRASH(( "translateEvent: Unknown Win32 mouse event [%d,%d,%d]\n",
msg, wParam, lParam ));
return;
} // end default
} // end switch on message at event index in buffer
} // end translateEvent
///////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
Win32Mouse::Win32Mouse( void )
{
// zero our event list
memset( &m_eventBuffer, 0, sizeof( m_eventBuffer ) );
m_nextFreeIndex = 0;
m_nextGetIndex = 0;
m_currentWin32Cursor = NONE;
for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
for (Int j=0; j<MAX_2D_CURSOR_DIRECTIONS; j++)
cursorResources[i][j]=NULL;
m_directionFrame=0; //points up.
m_lostFocus = FALSE;
} // end Win32Mouse
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
Win32Mouse::~Win32Mouse( void )
{
// remove our global reference that was for the WndProc() only
TheWin32Mouse = NULL;
} // end ~Win32Mouse
//-------------------------------------------------------------------------------------------------
/** Initialize our device */
//-------------------------------------------------------------------------------------------------
void Win32Mouse::init( void )
{
// extending functionality
Mouse::init();
//
// when we receive messages from a Windows message procedure, the mouse
// moves report the current cursor position and not deltas, our mouse
// needs to process those positions as absolute and not relative
//
m_inputMovesAbsolute = TRUE;
} // end int
//-------------------------------------------------------------------------------------------------
/** Reset */
//-------------------------------------------------------------------------------------------------
void Win32Mouse::reset( void )
{
// extend
Mouse::reset();
} // end reset
//-------------------------------------------------------------------------------------------------
/** Update, called once per frame */
//-------------------------------------------------------------------------------------------------
void Win32Mouse::update( void )
{
// extend
Mouse::update();
} // end update
//-------------------------------------------------------------------------------------------------
/** Add a window message event along with its WPARAM and LPARAM parameters
* to our input storage buffer */
//-------------------------------------------------------------------------------------------------
void Win32Mouse::addWin32Event( UINT msg, WPARAM wParam, LPARAM lParam, DWORD time )
{
//
// we can only add this event if our next free index does not already
// have an event in it, if it does ... our buffer is full and this input
// event will be lost
//
if( m_eventBuffer[ m_nextFreeIndex ].msg != 0 )
return;
// add to this index
m_eventBuffer[ m_nextFreeIndex ].msg = msg;
m_eventBuffer[ m_nextFreeIndex ].wParam = wParam;
m_eventBuffer[ m_nextFreeIndex ].lParam = lParam;
m_eventBuffer[ m_nextFreeIndex ].time = time;
// wrap index at max
m_nextFreeIndex++;
if( m_nextFreeIndex >= Mouse::NUM_MOUSE_EVENTS )
m_nextFreeIndex = 0;
} // end addWin32Event
extern HINSTANCE ApplicationHInstance;
void Win32Mouse::setVisibility(Bool visible)
{
//Extend
Mouse::setVisibility(visible);
//Maybe need to set cursor to force hiding of some cursors.
Win32Mouse::setCursor(getMouseCursor());
}
/**Preload all the cursors we may need during the game. This must be done before the D3D device
is created to avoid cursor corruption on buggy ATI Radeon cards. */
void Win32Mouse::initCursorResources(void)
{
for (Int cursor=FIRST_CURSOR; cursor<NUM_MOUSE_CURSORS; cursor++)
{
for (Int direction=0; direction<m_cursorInfo[cursor].numDirections; direction++)
{ if (!cursorResources[cursor][direction] && !m_cursorInfo[cursor].textureName.isEmpty())
{ //this cursor has never been loaded before.
char resourcePath[256];
//Check if this is a directional cursor
if (m_cursorInfo[cursor].numDirections > 1)
sprintf(resourcePath,"data\\cursors\\%s%d.ANI",m_cursorInfo[cursor].textureName.str(),direction);
else
sprintf(resourcePath,"data\\cursors\\%s.ANI",m_cursorInfo[cursor].textureName.str());
// check for a MOD cursor.
Bool loaded = FALSE;
if (TheGlobalData->m_modDir.isNotEmpty())
{
AsciiString fname;
if (m_cursorInfo[cursor].numDirections > 1)
fname.format("%sdata\\cursors\\%s%d.ANI", TheGlobalData->m_modDir.str(), m_cursorInfo[cursor].textureName.str(), direction);
else
fname.format("%sdata\\cursors\\%s.ANI", TheGlobalData->m_modDir.str(), m_cursorInfo[cursor].textureName.str());
if (TheLocalFileSystem->doesFileExist(fname.str()))
{
cursorResources[cursor][direction]=LoadCursorFromFile(fname.str());
loaded = TRUE;
}
}
if (!loaded)
cursorResources[cursor][direction]=LoadCursorFromFile(resourcePath);
DEBUG_ASSERTCRASH(cursorResources[cursor][direction], ("MissingCursor %s\n",resourcePath));
}
}
// SetCursor(cursorResources[cursor][m_directionFrame]);
}
}
//-------------------------------------------------------------------------------------------------
/** Super basic simplistic cursor */
//-------------------------------------------------------------------------------------------------
void Win32Mouse::setCursor( MouseCursor cursor )
{
// extend
Mouse::setCursor( cursor );
if (m_lostFocus)
return; //stop messing with mouse cursor if we don't have focus.
if (cursor == NONE || !m_visible)
SetCursor( NULL );
else
{
SetCursor(cursorResources[cursor][m_directionFrame]);
} // end switch
// save current cursor
m_currentWin32Cursor=m_currentCursor = cursor;
} // end setCursor
//-------------------------------------------------------------------------------------------------
/** Capture the mouse to our application */
//-------------------------------------------------------------------------------------------------
void Win32Mouse::capture( void )
{
// SetCapture( ApplicationHWnd );
} // end capture
//-------------------------------------------------------------------------------------------------
/** Release the mouse capture for our app window */
//-------------------------------------------------------------------------------------------------
void Win32Mouse::releaseCapture( void )
{
// ReleaseCapture();
} // end releaseCapture