Second pass at joystick hat support. It seems to be working fine in

emulation mode, but it's somewhat sensitive in GUI navigation (could
be my cheap gamepad).

Remapping is mostly complete, except for assignment of hats to analog
events.  Some more thought is required for this one.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@946 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2006-01-09 19:30:04 +00:00
parent 34e281d1b7
commit 24aa8c782f
7 changed files with 214 additions and 21 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: EventHandler.cxx,v 1.144 2006-01-09 16:50:01 stephena Exp $ // $Id: EventHandler.cxx,v 1.145 2006-01-09 19:30:04 stephena Exp $
//============================================================================ //============================================================================
#include <sstream> #include <sstream>
@ -673,6 +673,7 @@ void EventHandler::poll(uInt32 time)
handleJoyEvent(stick, button, state); handleJoyEvent(stick, button, state);
break; break;
} }
break; // Regular button
} }
case JT_STELLADAPTOR_LEFT: case JT_STELLADAPTOR_LEFT:
@ -783,10 +784,22 @@ void EventHandler::poll(uInt32 time)
if(stick >= kNumJoysticks || hat >= kNumJoyHats) if(stick >= kNumJoysticks || hat >= kNumJoyHats)
break; break;
if(myState == S_EMULATE) // Preprocess all hat events, converting to Stella JoyHat type
handleJoyHatEvent(stick, hat, value); // Generate two equivalent hat events representing combined direction
else if(myOverlay != NULL) // when we get a diagonal hat event
myOverlay->handleJoyHatEvent(stick, hat, value); if(value == SDL_HAT_CENTERED)
handleJoyHatEvent(stick, hat, kJHatCentered);
else
{
if(value & SDL_HAT_UP)
handleJoyHatEvent(stick, hat, kJHatUp);
if(value & SDL_HAT_RIGHT)
handleJoyHatEvent(stick, hat, kJHatRight);
if(value & SDL_HAT_DOWN)
handleJoyHatEvent(stick, hat, kJHatDown);
if(value & SDL_HAT_LEFT)
handleJoyHatEvent(stick, hat, kJHatLeft);
}
break; // SDL_JOYHATMOTION break; // SDL_JOYHATMOTION
} }
#endif // JOYSTICK_SUPPORT #endif // JOYSTICK_SUPPORT
@ -950,7 +963,72 @@ void EventHandler::handleJoyAxisEvent(int stick, int axis, int value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::handleJoyHatEvent(int stick, int hat, int value) void EventHandler::handleJoyHatEvent(int stick, int hat, int value)
{ {
cerr << "stick = " << stick << ", hat = " << hat << ", value = " << value << endl; if(myState == S_EMULATE)
{
cerr << "stick = " << stick << ", hat = " << hat;
switch(value) {
case kJHatCentered: cerr << " centered\n"; break;
case kJHatUp: cerr << " up\n"; break;
case kJHatDown: cerr << " down\n"; break;
case kJHatLeft: cerr << " left\n"; break;
case kJHatRight: cerr << " right\n"; break;
}
// Treat hats as pairs of directions, similar to joystick axes
// Every hat pair has two associated values, negative and positive
// Analog events are stored in the negative portion
Event::Type eventHatAnalog;
switch(value)
{
case kJHatUp:
case kJHatDown:
eventHatAnalog = myJoyHatTable[stick][hat][0];
break;
case kJHatLeft:
case kJHatRight:
eventHatAnalog = myJoyHatTable[stick][hat][2];
break;
default:
eventHatAnalog = Event::NoType;
break;
}
// Check for analog events, which are handled differently
switch((int)eventHatAnalog)
{
case Event::PaddleZeroAnalog:
myEvent->set(Event::PaddleZeroResistance,
(int)(1000000.0 * (32767 - value) / 65534));
break;
case Event::PaddleOneAnalog:
myEvent->set(Event::PaddleOneResistance,
(int)(1000000.0 * (32767 - value) / 65534));
break;
case Event::PaddleTwoAnalog:
myEvent->set(Event::PaddleTwoResistance,
(int)(1000000.0 * (32767 - value) / 65534));
break;
case Event::PaddleThreeAnalog:
myEvent->set(Event::PaddleThreeResistance,
(int)(1000000.0 * (32767 - value) / 65534));
break;
default:
// Otherwise, we know the event is digital
if(value == kJHatCentered)
{
// Turn off all associated events, since we don't know exactly
// which one was previously activated.
handleEvent(myJoyHatTable[stick][hat][0], 0);
handleEvent(myJoyHatTable[stick][hat][1], 0);
handleEvent(myJoyHatTable[stick][hat][2], 0);
handleEvent(myJoyHatTable[stick][hat][3], 0);
}
else
handleEvent(myJoyHatTable[stick][hat][value] , 1);
break;
}
}
else if(myOverlay != NULL)
myOverlay->handleJoyHatEvent(stick, hat, value);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1241,7 +1319,7 @@ void EventHandler::createMouseButtonEvent(int x, int y, int state)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setActionMappings() void EventHandler::setActionMappings()
{ {
int i, j, stick, button, axis, dir; int i, j, stick, button, axis, hat, dir;
ostringstream buf; ostringstream buf;
// Fill the ActionList with the current key and joystick mappings // Fill the ActionList with the current key and joystick mappings
@ -1305,8 +1383,43 @@ void EventHandler::setActionMappings()
} }
} }
} }
// Joystick hat mapping/labeling
// FIXME - add joy hat labeling for(stick = 0; stick < kNumJoysticks; ++stick)
{
for(hat = 0; hat < kNumJoyHats; ++hat)
{
for(dir = 0; dir < 4; ++dir)
{
if(myJoyHatTable[stick][hat][dir] == event)
{
buf.str("");
buf << "J" << stick << " hat " << hat;
switch(dir)
{
case kJHatUp: buf << " up"; break;
case kJHatDown: buf << " down"; break;
case kJHatLeft: buf << " left"; break;
case kJHatRight: buf << " right"; break;
}
/* FIXME - figure out how to combine analog & hats
if(eventIsAnalog(event))
{
dir = 2; // Immediately exit the inner loop after this iteration
buf << " abs";
}
else if(dir == 0)
buf << " neg";
else
buf << " pos";
*/
if(key == "")
key = key + buf.str();
else
key = key + ", " + buf.str();
}
}
}
}
// There are some keys which are hardcoded. These should be represented too. // There are some keys which are hardcoded. These should be represented too.
string prepend = ""; string prepend = "";
@ -1474,8 +1587,17 @@ void EventHandler::setDefaultJoyHatMapping(Event::Type event, int stick,
hat >= 0 && hat < kNumJoyHats && hat >= 0 && hat < kNumJoyHats &&
event >= 0 && event < Event::LastType) event >= 0 && event < Event::LastType)
{ {
cerr << "add mapping for stick = " << stick << ", hat = " << hat << ", value = " << value << endl; switch(value)
/* {
case kJHatUp:
case kJHatDown:
case kJHatLeft:
case kJHatRight:
myJoyHatTable[stick][hat][value] = event;
break;
}
/* FIXME - deal with assignment of analog events
// This confusing code is because each axis has two associated values, // This confusing code is because each axis has two associated values,
// but analog events only affect one of the axis. // but analog events only affect one of the axis.
if(eventIsAnalog(event)) if(eventIsAnalog(event))

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: EventHandler.hxx,v 1.74 2006-01-09 16:50:01 stephena Exp $ // $Id: EventHandler.hxx,v 1.75 2006-01-09 19:30:04 stephena Exp $
//============================================================================ //============================================================================
#ifndef EVENTHANDLER_HXX #ifndef EVENTHANDLER_HXX
@ -60,6 +60,16 @@ enum {
#endif #endif
}; };
// A wrapper around SDL hat events, so we don't drag SDL
// through all the child classes
enum JoyHat {
kJHatUp,
kJHatDown,
kJHatLeft,
kJHatRight,
kJHatCentered
};
enum MouseButton { enum MouseButton {
EVENT_LBUTTONDOWN, EVENT_LBUTTONDOWN,
EVENT_LBUTTONUP, EVENT_LBUTTONUP,
@ -123,7 +133,7 @@ struct JoyMouse {
mapping can take place. mapping can take place.
@author Stephen Anthony @author Stephen Anthony
@version $Id: EventHandler.hxx,v 1.74 2006-01-09 16:50:01 stephena Exp $ @version $Id: EventHandler.hxx,v 1.75 2006-01-09 19:30:04 stephena Exp $
*/ */
class EventHandler class EventHandler
{ {

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: DialogContainer.cxx,v 1.29 2006-01-09 16:50:01 stephena Exp $ // $Id: DialogContainer.cxx,v 1.30 2006-01-09 19:30:04 stephena Exp $
//============================================================================ //============================================================================
#include "OSystem.hxx" #include "OSystem.hxx"
@ -389,8 +389,44 @@ void DialogContainer::handleJoyAxisEvent(int stick, int axis, int value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DialogContainer::handleJoyHatEvent(int stick, int hat, int value) void DialogContainer::handleJoyHatEvent(int stick, int hat, int value)
{ {
cerr << "received hat event in dialogcontainer:" << endl if(myDialogStack.empty())
<< "stick = " << stick << ", hat = " << hat << ", value = " << value << endl; return;
// Send the event to the dialog box on the top of the stack
Dialog* activeDialog = myDialogStack.top();
// Only preprocess hat events if the dialog absolutely doesn't want them
// Translate to axis events for movement
if(!activeDialog->wantsAllEvents())
{
bool handled = true;
switch(value)
{
case kJHatCentered:
handleJoyAxisEvent(stick, 0, 0);
handleJoyAxisEvent(stick, 1, 0); // axis 0 & 1, 0 ==> OFF
break;
case kJHatUp:
handleJoyAxisEvent(stick, 1, -32767); // axis 1, -value ==> UP
break;
case kJHatLeft:
handleJoyAxisEvent(stick, 0, -32767); // axis 0, -value ==> LEFT
break;
case kJHatDown:
handleJoyAxisEvent(stick, 1, 32767); // axis 1, +value ==> DOWN
break;
case kJHatRight:
handleJoyAxisEvent(stick, 0, 32767); // axis 0, +value ==> RIGHT
break;
default:
handled = false;
}
if(handled)
return;
}
if(activeDialog->wantsEvents())
activeDialog->handleJoyHat(stick, hat, value);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: EventMappingWidget.cxx,v 1.8 2006-01-08 02:28:03 stephena Exp $ // $Id: EventMappingWidget.cxx,v 1.9 2006-01-09 19:30:04 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -208,7 +208,7 @@ void EventMappingWidget::handleJoyDown(int stick, int button)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventMappingWidget::handleJoyAxis(int stick, int axis, int value) void EventMappingWidget::handleJoyAxis(int stick, int axis, int value)
{ {
// Remap joystick buttons in remap mode // Remap joystick axes in remap mode
if(myRemapStatus && myActionSelected >= 0) if(myRemapStatus && myActionSelected >= 0)
{ {
Event::Type event = EventHandler::ourActionList[ myActionSelected ].event; Event::Type event = EventHandler::ourActionList[ myActionSelected ].event;
@ -218,6 +218,19 @@ void EventMappingWidget::handleJoyAxis(int stick, int axis, int value)
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventMappingWidget::handleJoyHat(int stick, int hat, int value)
{
// Remap joystick hats in remap mode
if(myRemapStatus && myActionSelected >= 0)
{
Event::Type event = EventHandler::ourActionList[ myActionSelected ].event;
instance()->eventHandler().addJoyHatMapping(event, stick, hat, value);
stopRemapping();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventMappingWidget::handleCommand(CommandSender* sender, int cmd, void EventMappingWidget::handleCommand(CommandSender* sender, int cmd,
int data, int id) int data, int id)

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: EventMappingWidget.hxx,v 1.4 2005-12-24 22:09:36 stephena Exp $ // $Id: EventMappingWidget.hxx,v 1.5 2006-01-09 19:30:04 stephena Exp $
// //
// Based on code from ScummVM - Scumm Interpreter // Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project // Copyright (C) 2002-2004 The ScummVM project
@ -47,6 +47,7 @@ class EventMappingWidget : public Widget, public CommandSender
virtual bool handleKeyDown(int ascii, int keycode, int modifiers); virtual bool handleKeyDown(int ascii, int keycode, int modifiers);
virtual void handleJoyDown(int stick, int button); virtual void handleJoyDown(int stick, int button);
virtual void handleJoyAxis(int stick, int axis, int value); virtual void handleJoyAxis(int stick, int axis, int value);
virtual void handleJoyHat(int stick, int hat, int value);
bool remapMode() { return myRemapStatus; } bool remapMode() { return myRemapStatus; }

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: InputDialog.cxx,v 1.8 2005-12-21 01:50:16 stephena Exp $ // $Id: InputDialog.cxx,v 1.9 2006-01-09 19:30:04 stephena Exp $
//============================================================================ //============================================================================
#include "OSystem.hxx" #include "OSystem.hxx"
@ -250,6 +250,16 @@ void InputDialog::handleJoyAxis(int stick, int axis, int value)
Dialog::handleJoyAxis(stick, axis, value); Dialog::handleJoyAxis(stick, axis, value);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputDialog::handleJoyHat(int stick, int hat, int value)
{
// Remap joystick hat in remap mode, otherwise pass to listwidget
if(myEventMapper->remapMode())
myEventMapper->handleJoyHat(stick, hat, value);
else
Dialog::handleJoyHat(stick, hat, value);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void InputDialog::handleCommand(CommandSender* sender, int cmd, void InputDialog::handleCommand(CommandSender* sender, int cmd,
int data, int id) int data, int id)

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: InputDialog.hxx,v 1.4 2005-12-16 14:41:15 stephena Exp $ // $Id: InputDialog.hxx,v 1.5 2006-01-09 19:30:04 stephena Exp $
//============================================================================ //============================================================================
#ifndef INPUT_DIALOG_HXX #ifndef INPUT_DIALOG_HXX
@ -42,6 +42,7 @@ class InputDialog : public Dialog
virtual void handleKeyDown(int ascii, int keycode, int modifiers); virtual void handleKeyDown(int ascii, int keycode, int modifiers);
virtual void handleJoyDown(int stick, int button); virtual void handleJoyDown(int stick, int button);
virtual void handleJoyAxis(int stick, int axis, int value); virtual void handleJoyAxis(int stick, int axis, int value);
virtual void handleJoyHat(int stick, int hat, int value);
virtual void handleCommand(CommandSender* sender, int cmd, int data, int id); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id);
void loadConfig(); void loadConfig();