Added mouse support to the DirectInput class, and detection

of mouse events to MainWin32.

Removed the DI_Event type structures.  While it made the code
look nicer, we really didn't need the performance hit (however
small it may have been) of serializing and deserializing the
events.

Removed the rest of the framebuffer code from MainWin32.
Made sure the exit event (Escape) was sent to the core,
so that current settings could be saved.

Next I'll look at the joystick code (should be quite easy).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@208 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2003-11-14 00:47:35 +00:00
parent 98d447fcbc
commit 6861331670
5 changed files with 200 additions and 278 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DirectInput.cxx,v 1.3 2003-11-13 00:25:07 stephena Exp $
// $Id: DirectInput.cxx,v 1.4 2003-11-14 00:47:35 stephena Exp $
//============================================================================
#include "pch.hxx"
@ -43,7 +43,11 @@ bool DirectInput::initialize(HWND hwnd)
IID_IDirectInput8, (void**)&mylpdi, NULL)))
return false;
// initialize the keyboard
// We use buffered mode whenever possible, since it is more
// efficient than constantly getting a full state snapshot
// and analyzing it for state changes
// Initialize the keyboard
if(FAILED(mylpdi->CreateDevice(GUID_SysKeyboard, &myKeyboard, NULL)))
return false;
if(FAILED(myKeyboard->SetDataFormat(&c_dfDIKeyboard)))
@ -51,77 +55,91 @@ bool DirectInput::initialize(HWND hwnd)
if(FAILED(myKeyboard->SetCooperativeLevel(hwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))
return false;
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = 256;
if(FAILED(myKeyboard->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)))
DIPROPDWORD k_dipdw;
k_dipdw.diph.dwSize = sizeof(DIPROPDWORD);
k_dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
k_dipdw.diph.dwObj = 0;
k_dipdw.diph.dwHow = DIPH_DEVICE;
k_dipdw.dwData = 64;
if(FAILED(myKeyboard->SetProperty(DIPROP_BUFFERSIZE, &k_dipdw.diph)))
return false;
if(FAILED(myKeyboard->Acquire()))
return false;
// Make sure to reset the event buffer
myEventBufferPos = 0;
// Initialize the mouse
if(FAILED(mylpdi->CreateDevice(GUID_SysMouse, &myMouse, NULL)))
return false;
if(FAILED(myMouse->SetDataFormat(&c_dfDIMouse2)))
return false;
if(FAILED(myMouse->SetCooperativeLevel(hwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))
return false; // DISCL_FOREGROUND | DISCL_EXCLUSIVE
DIPROPDWORD m_dipdw;
m_dipdw.diph.dwSize = sizeof(DIPROPDWORD);
m_dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
m_dipdw.diph.dwObj = 0;
m_dipdw.diph.dwHow = DIPH_DEVICE;
m_dipdw.dwData = 64;
if(FAILED(myMouse->SetProperty(DIPROP_BUFFERSIZE, &m_dipdw.diph)))
return false;
if(FAILED(myMouse->Acquire()))
return false;
return true;
}
void DirectInput::update()
bool DirectInput::getKeyEvents(DIDEVICEOBJECTDATA* keyEvents,
DWORD* numKeyEvents)
{
HRESULT hr;
if(myKeyboard != NULL)
// Make sure the keyboard has been initialized
if(myKeyboard == NULL)
return false;
// Check for keyboard events
hr = myKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),
keyEvents, numKeyEvents, 0 );
if(hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED)
{
DIDEVICEOBJECTDATA keyEvents[256];
DWORD numKeyEvents = 256;
hr = myKeyboard->Acquire();
if(hr == DIERR_OTHERAPPHASPRIO)
return false;
hr = myKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),
keyEvents, &numKeyEvents, 0 );
if(hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED)
{
hr = myKeyboard->Acquire();
if(hr == DIERR_OTHERAPPHASPRIO)
return;
hr = myKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),
keyEvents, &numKeyEvents, 0 );
}
// add these new key events to the event buffer
for(unsigned int i = 0; i < numKeyEvents; i++ )
{
uInt32 j = myEventBufferPos;
if(j < 100)
{
myEventBuffer[j].type = (keyEvents[i].dwData & 0x80) ? KEY_DOWN : KEY_UP;
myEventBuffer[j].key.key = keyEvents[i].dwOfs;
myEventBuffer[j].key.state = (myEventBuffer[j].type == KEY_DOWN) ? 1 : 0;
myEventBufferPos++;
}
else // if we run out of room, then ignore new events
{
myEventBufferPos = 100;
break;
}
}
keyEvents, numKeyEvents, 0 );
}
// else check mouse
return true;
}
bool DirectInput::pollEvent(DI_Event* event)
bool DirectInput::getMouseEvents(DIDEVICEOBJECTDATA* mouseEvents,
DWORD* numMouseEvents)
{
// Pump the event buffer and return if a new event is found
if(myEventBufferPos > 0)
{
*event = myEventBuffer[--myEventBufferPos];
return true;
}
else
HRESULT hr;
// Make sure the mouse has been initialized
if(myMouse == NULL)
return false;
// Check for mouse events
hr = myMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),
mouseEvents, numMouseEvents, 0 );
if(hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED)
{
hr = myMouse->Acquire();
if(hr == DIERR_OTHERAPPHASPRIO)
return false;
hr = myMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),
mouseEvents, numMouseEvents, 0 );
}
return true;
}
void DirectInput::cleanup()

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DirectInput.hxx,v 1.4 2003-11-13 00:25:07 stephena Exp $
// $Id: DirectInput.hxx,v 1.5 2003-11-14 00:47:35 stephena Exp $
//============================================================================
#ifndef DIRECT_INPUT_HXX
@ -28,34 +28,14 @@ class DirectInput
DirectInput();
~DirectInput();
public:
enum type_tt { KEY_DOWN, KEY_UP };
struct KeyboardEvent
{
uInt32 key;
uInt8 state;
};
struct DI_Event
{
type_tt type;
union
{
KeyboardEvent key;
};
};
bool getKeyEvents(DIDEVICEOBJECTDATA* keyEvents, DWORD* numKeyEvents);
bool getMouseEvents(DIDEVICEOBJECTDATA* mouseEvents, DWORD* numMouseEvents);
bool initialize(HWND hwnd);
void update();
bool pollEvent(DI_Event* event);
private:
DI_Event myEventBuffer[100];
uInt32 myEventBufferPos;
void cleanup();
static BOOL CALLBACK EnumDevicesProc(const DIDEVICEINSTANCE* lpddi, LPVOID pvRef );

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferWin32.cxx,v 1.2 2003-11-13 00:25:07 stephena Exp $
// $Id: FrameBufferWin32.cxx,v 1.3 2003-11-14 00:47:35 stephena Exp $
//============================================================================
#include <sstream>
@ -48,12 +48,14 @@ FrameBufferWin32::FrameBufferWin32()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferWin32::~FrameBufferWin32()
{
OutputDebugString("got here FrameBufferWin32::~FrameBufferWin32()");
cleanup();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferWin32::cleanup()
{
OutputDebugString("got here FrameBufferWin32::cleanup()");
if(m_piDDPalette)
{
m_piDDPalette->Release();
@ -81,7 +83,7 @@ void FrameBufferWin32::cleanup()
if(myHWND)
{
::DestroyWindow( myHWND );
OutputDebugString("got here destroyed window");
//
// Remove the WM_QUIT which will be in the message queue
// so that the main window doesn't exit
@ -186,6 +188,7 @@ OutputDebugString("got here failed 4");
//
// Get the best video mode for game width
//
//int cx = 640; int cy = 480;
int cx = 320; int cy = 240;
::SetRect( &m_rectScreen, 0, 0, cx, cy );
@ -319,7 +322,7 @@ OutputDebugString("got here failed 12");
cleanup();
return false;
}
OutputDebugString("got here init exited with true");
// If we get this far, then assume that there were no problems
return true;
}
@ -459,57 +462,46 @@ LRESULT CALLBACK FrameBufferWin32::StaticWindowProc(
}
BOOL FrameBufferWin32::WndProc(
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
BOOL FrameBufferWin32::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_ACTIVATE:
m_fActiveWindow = ( wParam != WA_INACTIVE );
break;
switch (uMsg)
{
case WM_ACTIVATE:
m_fActiveWindow = (wParam != WA_INACTIVE);
break;
case WM_DESTROY:
::PostQuitMessage( 0 );
break;
case WM_DESTROY:
::PostQuitMessage(0);
break;
case WM_KEYDOWN:
switch ( (int)wParam )
{
case VK_ESCAPE:
//
// Escape = Exit
//
switch((int)wParam)
{
case VK_ESCAPE:
::PostMessage(myHWND, WM_CLOSE, 0, 0);
::PostMessage( myHWND, WM_CLOSE, 0, 0 );
break;
}
break;
// For some braindead reason, the exit event must be handled
// here. Normally, an Escape event would be the same as any
// other and the Console would handle it.
// But since Windows insists on doing it this way, we have
// to make sure that the Escape event is still received by
// the core.
myConsole->eventHandler().sendEvent(Event::Quit, 1);
break;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
::BeginPaint( myHWND, &ps );
::EndPaint( myHWND, &ps );
}
break;
PAINTSTRUCT ps;
::BeginPaint( myHWND, &ps );
::EndPaint( myHWND, &ps );
break;
default:
//
// Unhandled message
//
return FALSE;
}
return FALSE;
}
//
// Handled message
//
return TRUE;
return TRUE;
}
HRESULT WINAPI FrameBufferWin32::EnumModesCallback(

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MainWin32.cxx,v 1.1 2003-11-13 00:25:07 stephena Exp $
// $Id: MainWin32.cxx,v 1.2 2003-11-14 00:47:35 stephena Exp $
//============================================================================
#define STRICT
@ -39,10 +39,12 @@ MainWin32::MainWin32(const uInt8* image, uInt32 size, const char* filename,
Settings& settings, PropertiesSet& properties)
: theSettings(settings),
thePropertiesSet(properties),
myIsInitialized(false),
theDisplay(NULL),
theSound(NULL),
theInput(NULL)
theInput(NULL),
theMouseX(0),
thePaddleMode(0),
myIsInitialized(false)
{
// Setup the DirectX window
theDisplay = new FrameBufferWin32();
@ -58,13 +60,12 @@ MainWin32::MainWin32(const uInt8* image, uInt32 size, const char* filename,
// theSound = new SoundWin32();
// else
theSound = new Sound();
/*
if(!theSound)
{
cleanup();
return;
}
*/
// theSound->setSoundVolume(theSettings.getInt("volume"));
// Create the 2600 game console
@ -138,16 +139,13 @@ DWORD MainWin32::run()
for(;;)
{
if( ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
if(::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
{
if( msg.message == WM_QUIT )
{
// theConsole->eventHandler().sendEvent(Event::Quit, 1);
if(msg.message == WM_QUIT)
break;
}
::TranslateMessage( &msg );
::DispatchMessage( &msg );
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else if (theDisplay->windowActive())
{
@ -204,51 +202,85 @@ DWORD MainWin32::run()
void MainWin32::UpdateEvents()
{
// Update the input devices, and gather all pending events
theInput->update();
DIDEVICEOBJECTDATA eventArray[64];
DWORD numEvents;
const int nSize = _countof(keyList);
DirectInput::DI_Event event;
while(theInput->pollEvent(&event))
// Check for keyboard events
numEvents = 64;
if(theInput->getKeyEvents(eventArray, &numEvents))
{
switch(event.type)
for(unsigned int i = 0; i < numEvents; i++ )
{
case DirectInput::KEY_DOWN:
case DirectInput::KEY_UP:
uInt32 key = event.key.key;
uInt8 state = event.key.state;
uInt32 key = eventArray[i].dwOfs;
uInt8 state = eventArray[i].dwData & 0x80 ? 1 : 0;
for(uInt32 i = 0; i < sizeof(keyList) / sizeof(Switches); ++i)
{
if(keyList[i].nVirtKey == key)
theConsole->eventHandler().sendKeyEvent(keyList[i].keyCode, state);
}
break;
}
for(uInt32 i = 0; i < sizeof(keyList) / sizeof(Switches); ++i)
{
if(keyList[i].nVirtKey == key)
theConsole->eventHandler().sendKeyEvent(keyList[i].keyCode, state);
}
}
}
//
// I do this because an event may appear multiple times in the map
// and I don't want to undo a set i may have done earlier in the loop
//
// long rgKeyEventState[ nSize ];
// ZeroMemory( rgKeyEventState, nSize * sizeof(StellaEvent::KeyCode) );
// Update keyboard
/*
if(m_pDirectKeyboard->Update() == S_OK)
// Check for mouse events
numEvents = 64;
if(theInput->getMouseEvents(eventArray, &numEvents))
{
for(int i = 0; i < nSize; ++i)
for(unsigned int i = 0; i < numEvents; i++ )
{
int state = (m_pDirectKeyboard->IsButtonPressed(keyList[i].nVirtKey)) ? 1 : 0;
theConsole->eventHandler().sendKeyEvent(keyList[i].keyCode, state);
}
Event::Type type = Event::LastType;
Int32 value;
switch(eventArray[i].dwOfs)
{
// Check for button press and release
case DIMOFS_BUTTON0:
case DIMOFS_BUTTON1:
case DIMOFS_BUTTON2:
case DIMOFS_BUTTON3:
case DIMOFS_BUTTON4:
case DIMOFS_BUTTON5:
case DIMOFS_BUTTON6:
case DIMOFS_BUTTON7:
value = (Int32) eventArray[i].dwData & 0x80 ? 1 : 0;
if(thePaddleMode == 0)
type = Event::PaddleZeroFire;
else if(thePaddleMode == 1)
type = Event::PaddleOneFire;
else if(thePaddleMode == 2)
type = Event::PaddleTwoFire;
else if(thePaddleMode == 3)
type = Event::PaddleThreeFire;
theConsole->eventHandler().sendEvent(type, value);
break;
// Check for horizontal movement
case DIMOFS_X:
theMouseX = theMouseX + eventArray[i].dwData;
// Force mouseX between 0 ... 999
if(theMouseX < 0)
theMouseX = 0;
else if(theMouseX > 999)
theMouseX = 999;
Int32 value = (999 - theMouseX) * 1000;
if(thePaddleMode == 0)
type = Event::PaddleZeroResistance;
else if(thePaddleMode == 1)
type = Event::PaddleOneResistance;
else if(thePaddleMode == 2)
type = Event::PaddleTwoResistance;
else if(thePaddleMode == 3)
type = Event::PaddleThreeResistance;
theConsole->eventHandler().sendEvent(type, value);
break;
}
}
}
*/
/*
//
// Update joystick

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MainWin32.hxx,v 1.1 2003-11-13 00:25:07 stephena Exp $
// $Id: MainWin32.hxx,v 1.2 2003-11-14 00:47:35 stephena Exp $
//============================================================================
#ifndef MAIN_WIN32_HXX
@ -41,7 +41,7 @@ class DirectInput;
in the Porting.txt document
@author Stephen Anthony
@version $Id: MainWin32.hxx,v 1.1 2003-11-13 00:25:07 stephena Exp $
@version $Id: MainWin32.hxx,v 1.2 2003-11-14 00:47:35 stephena Exp $
*/
class MainWin32
{
@ -68,6 +68,7 @@ class MainWin32
private:
void UpdateEvents();
void cleanup();
private:
// Pointer to the console object
@ -95,117 +96,16 @@ class MainWin32
};
static Switches keyList[StellaEvent::LastKCODE];
/////////////////////////////////////////////////////////
//
// These will move into a separate Framebuffer class soon
//
/////////////////////////////////////////////////////////
#if 0
public:
HWND hwnd() const { return myHWND; }
//////////////////////////////////////////////////////////////////////
// The following methods are derived from FrameBuffer.hxx
//////////////////////////////////////////////////////////////////////
/**
This routine should be called once the console is created to setup
the video system for us to use. Return false if any operation fails,
otherwise return true.
*/
bool init();
/**
This routine should be called anytime the MediaSource needs to be redrawn
to the screen.
*/
void drawMediaSource();
/**
This routine should be called to draw a rectangular box with sides
at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param w The width of the box
@param h The height of the box
*/
void drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h);
/**
This routine should be called to draw text at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param message The message text
*/
void drawText(uInt32 x, uInt32 y, const string& message);
/**
This routine should be called to draw character 'c' at the specified coordinates.
@param x The x coordinate
@param y The y coordinate
@param c The character to draw
*/
void drawChar(uInt32 x, uInt32 y, uInt32 c);
/**
This routine is called before any drawing is done (per-frame).
*/
void preFrameUpdate();
/**
This routine is called after any drawing is done (per-frame).
*/
void postFrameUpdate();
/**
This routine is called when the emulation has received
a pause event.
@param status The received pause status
*/
virtual void pauseEvent(bool status);
#endif
//////////////////////////////////////////////////
// Some of this will stay here, some will go to
// the FrameBufferWin32 class
//////////////////////////////////////////////////
private:
const CGlobalData* m_rGlobalData;
// Indicates the current mouse position in the X direction
Int32 theMouseX;
// Indicates the current paddle mode
uInt32 thePaddleMode;
// Indicates that all subsystems were initialized
bool myIsInitialized;
void cleanup();
#if 0
static LRESULT CALLBACK StaticWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
BOOL WndProc( UINT uMsg, WPARAM wParam, LPARAM lParam );
static HRESULT WINAPI EnumModesCallback( LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext);
void cleanup();
HWND myHWND;
bool m_fActiveWindow;
RECT m_rectScreen;
POINT m_ptBlitOffset;
// Stella objects
SIZE mySizeGame;
BYTE myPalette[256];
//
// DirectX
//
IDirectDraw* m_piDD;
IDirectDrawSurface* m_piDDSPrimary;
IDirectDrawSurface* m_piDDSBack;
IDirectDrawPalette* m_piDDPalette;
static LPCTSTR pszClassName;
#endif
};
#endif