The left and right mouse buttons are now recognized separately in emulation mode.

Checking in first pass at revamping the 'mcontrol' functionality.  The idea is
that the mouse will be able to emulate different controllers on each of its
axes.  For now, the left mouse button is tied to the X-axis, and the right to 
the Y-axis.  These modes will be saved per-ROM, meaning that the mapping can
be different for each ROM (it is saved as part of the ROM properties).  Only
the paddles and driving controllers will allow this, since they're the only
controllers where a single axis makes sense.

Switching between mouse modes will be done with Control-0 (the Control-1..3
keys have been removed).  This will allow switching all possible combinations
(left controller, right controller, per-ROM setting, etc).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2366 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-01-22 21:01:13 +00:00
parent 8704fea8be
commit c136a30cbc
25 changed files with 3693 additions and 3448 deletions

172
src/common/MouseControl.cxx Normal file
View File

@ -0,0 +1,172 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2012 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include "Console.hxx"
#include "Control.hxx"
#include "Props.hxx"
#include "MouseControl.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MouseControl::MouseControl(Console& console, const string& mode)
: myProps(console.properties()),
myLeftController(console.controller(Controller::Left)),
myRightController(console.controller(Controller::Right)),
myCurrentModeNum(0)
{
cerr << "MouseControl c'tor: using mode = " << mode << endl;
if(mode == "never")
{
MouseMode mmode;
myModeList.push_back(mmode);
return;
}
// First consider the possible modes for the mouse based on the left
// and right controllers
switch(myLeftController.type())
{
case Controller::Joystick:
case Controller::BoosterGrip:
case Controller::Genesis:
case Controller::Driving:
case Controller::TrackBall22:
case Controller::TrackBall80:
case Controller::AmigaMouse:
// case Controller::Mindlink:
{
ostringstream msg;
msg << "Mouse is left " << myLeftController.name() << " controller";
MouseMode mmode(Automatic, Automatic, 0, msg.str());
myModeList.push_back(mmode);
break;
}
case Controller::Paddles:
{
MouseMode mmode0(Automatic, Automatic, 0, "Mouse is Paddle 0 controller");
MouseMode mmode1(Automatic, Automatic, 1, "Mouse is Paddle 1 controller");
myModeList.push_back(mmode0);
myModeList.push_back(mmode1);
break;
}
default:
break;
}
switch(myRightController.type())
{
case Controller::Joystick:
case Controller::BoosterGrip:
case Controller::Genesis:
case Controller::Driving:
case Controller::TrackBall22:
case Controller::TrackBall80:
case Controller::AmigaMouse:
// case Controller::Mindlink:
{
ostringstream msg;
msg << "Mouse is right " << myRightController.name() << " controller";
MouseMode mmode(Automatic, Automatic, 1, msg.str());
myModeList.push_back(mmode);
break;
}
case Controller::Paddles:
{
MouseMode mmode0(Automatic, Automatic, 2, "Mouse is Paddle 2 controller");
MouseMode mmode1(Automatic, Automatic, 3, "Mouse is Paddle 3 controller");
myModeList.push_back(mmode0);
myModeList.push_back(mmode1);
break;
}
default:
break;
}
// Now add per-ROM setting (if one exists)
if(mode != "auto")
{
/*
// Note: these constants are from Controller::MouseAxisType enum
if(s.length() != 2 || s[0] < '0' || s[0] > '7' || s[1] < '0' || s[1] > '7')
setInternal("mcontrol", "auto");
*/
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MouseControl::~MouseControl()
{
}
#if 0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void MouseControl::setMode(const string& mode)
{
cerr << "MouseControl::setMode: " << mode << endl;
if(!&myOSystem->console())
return;
Controller& lc = myOSystem->console().controller(Controller::Left);
Controller& rc = myOSystem->console().controller(Controller::Right);
if(mode == "auto")
{
bool swap = myOSystem->console().properties().get(Controller_SwapPaddles) == "YES";
lc.setMouseControl(Controller::Automatic, Controller::Automatic, swap ? 1 : 0);
rc.setMouseControl(Controller::Automatic, Controller::Automatic, swap ? 1 : 0);
}
else
{
Controller::MouseAxisControl xaxis = (Controller::MouseAxisControl)
((int)mode[0] - '0');
Controller::MouseAxisControl yaxis = (Controller::MouseAxisControl)
((int)mode[1] - '0');
lc.setMouseControl(xaxis, yaxis);
rc.setMouseControl(xaxis, yaxis);
}
}
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string& MouseControl::next()
{
const MouseMode& mode = myModeList[myCurrentModeNum];
myCurrentModeNum = (myCurrentModeNum + 1) % myModeList.size();
return mode.message;
#if 0
if(myOSystem->settings().getString("mcontrol") == "auto")
{
myOSystem->console().controller(Controller::Left).setMouseControl(
Controller::Automatic, Controller::Automatic, paddle);
myOSystem->console().controller(Controller::Right).setMouseControl(
Controller::Automatic, Controller::Automatic, paddle);
myOSystem->frameBuffer().showMessage(message);
}
else
{
myOSystem->frameBuffer().showMessage(
"Mouse axis mode not auto, paddle not changed");
}
#endif
}

101
src/common/MouseControl.hxx Normal file
View File

@ -0,0 +1,101 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2012 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#ifndef MOUSE_CONTROL_HXX
#define MOUSE_CONTROL_HXX
class Console;
class Controller;
class Properties;
#include "bspf.hxx"
#include "Array.hxx"
/**
The mouse can control various virtual 'controllers' in many different
ways. In 'auto' mode, the entire mouse (both axes and buttons) are used
as one controller. In per-ROM axis mode, each axis/button may control
separate controllers. As well, we'd like to switch dynamically between
each of these modes at runtime.
This class encapsulates all required info to implement this functionality.
@author Stephen Anthony
*/
class MouseControl
{
public:
/**
Enumeration of mouse axis control types
*/
enum Axis
{
Paddle0 = 0, Paddle1, Paddle2, Paddle3,
Driving0, Driving1, Automatic, NoControl
};
public:
/**
Create a new MouseControl object
@param console The console in use by the system
@param mode Contains information about how to use the mouse axes/buttons
*/
MouseControl(Console& console, const string& mode);
/**
Destructor
*/
virtual ~MouseControl();
public:
/**
Cycle through each available mouse control mode
@return A message explaining the current mouse mode
*/
const string& next();
private:
const Properties& myProps;
Controller& myLeftController;
Controller& myRightController;
struct MouseMode {
Axis xaxis, yaxis;
int controlID;
string message;
MouseMode()
: xaxis(NoControl),
yaxis(NoControl),
controlID(-1),
message("Mouse input is disabled") { }
MouseMode(Axis x, Axis y, int id, const string& msg)
: xaxis(x),
yaxis(y),
controlID(id),
message(msg) { }
};
int myCurrentModeNum;
Common::Array<MouseMode> myModeList;
};
#endif

View File

@ -9,6 +9,7 @@ MODULE_OBJS := \
src/common/FBSurfaceGL.o \ src/common/FBSurfaceGL.o \
src/common/FBSurfaceTIA.o \ src/common/FBSurfaceTIA.o \
src/common/PNGLibrary.o \ src/common/PNGLibrary.o \
src/common/MouseControl.o \
src/common/RectList.o \ src/common/RectList.o \
src/common/Snapshot.o src/common/Snapshot.o

View File

@ -123,21 +123,22 @@ void BoosterGrip::update()
} }
} }
// Get mouse button state // Get mouse button state
if(myEvent.get(Event::MouseButtonValue)) if(myEvent.get(Event::MouseButtonLeftValue) ||
myEvent.get(Event::MouseButtonRightValue))
myDigitalPinState[Six] = false; myDigitalPinState[Six] = false;
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void BoosterGrip::setMouseControl( void BoosterGrip::setMouseControl(
MouseAxisControl xaxis, MouseAxisControl yaxis, int ctrlID) MouseControl::Axis xaxis, MouseControl::Axis yaxis, int ctrlID)
{ {
// In 'automatic' mode, both axes on the mouse map to a single normal booster // In 'automatic' mode, both axes on the mouse map to a single normal booster
if(xaxis == Controller::Automatic || yaxis == Controller::Automatic) if(xaxis == MouseControl::Automatic || yaxis == MouseControl::Automatic)
{ {
myControlID = ((myJack == Left && (ctrlID == 0 || ctrlID == 1)) || myControlID = ((myJack == Left && ctrlID == 0) ||
(myJack == Right && (ctrlID == 2 || ctrlID == 3)) (myJack == Right && ctrlID == 1)
) ? ctrlID & 0x01 : -1; ) ? ctrlID : -1;
} }
else // Otherwise, boosters are not used in 'non-auto' mode else // Otherwise, boosters are not used in 'non-auto' mode
myControlID = -1; myControlID = -1;

View File

@ -57,22 +57,21 @@ class BoosterGrip : public Controller
/** /**
Determines how this controller will treat values received from the Determines how this controller will treat values received from the
X and Y axis of the mouse. Since not all controllers use the mouse, X/Y axis and left/right buttons of the mouse. Since not all controllers
it's up to the specific class to decide how to use this data. use the mouse, it's up to the specific class to decide how to use this data.
If either of the axis is set to 'Automatic', then we automatically If either of the axis is set to 'Automatic', then we automatically
use this number for the control type as follows: use the ctrlID for the control type.
0 - paddle 0, joystick 0 (and controllers similar to a joystick)
1 - paddle 1, joystick 1 (and controllers similar to a joystick) In the current implementation, the left button is tied to the X axis,
2 - paddle 2, joystick 0 (and controllers similar to a joystick) and the right one tied to the Y axis.
3 - paddle 3, joystick 1 (and controllers similar to a joystick)
@param xaxis How the controller should use x-axis data @param xaxis How the controller should use x-axis data
@param yaxis How the controller should use y-axis data @param yaxis How the controller should use y-axis data
@param ctrlID The controller ID to use axis 'auto' mode @param ctrlID The controller ID to use axis 'auto' mode
*/ */
void setMouseControl( void setMouseControl(
MouseAxisControl xaxis, MouseAxisControl yaxis, int ctrlID = -1); MouseControl::Axis xaxis, MouseControl::Axis yaxis, int ctrlID = -1);
private: private:
// Pre-compute the events we care about based on given port // Pre-compute the events we care about based on given port

View File

@ -119,10 +119,9 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
// The 'fastscbios' option must be changed before the system is reset // The 'fastscbios' option must be changed before the system is reset
// The algorithm used is as follows: // The algorithm used is as follows:
// Run for 60 frames, only consider frames in appropriate scanline range // Run for 60 frames; if there's a frame that has more than 287
// If there's a frame that starts drawing at scanline 50 or // scanlines, count it as PAL
// has more than 287 scanlines, count it as PAL // If at least 25 PAL frames are found, then the format is PAL, else NTSC
// If at least 20 PAL frames are found, then the format is PAL, else NTSC
bool fastscbios = myOSystem->settings().getBool("fastscbios"); bool fastscbios = myOSystem->settings().getBool("fastscbios");
myOSystem->settings().setBool("fastscbios", true); myOSystem->settings().setBool("fastscbios", true);
mySystem->reset(true); // autodetect in reset enabled mySystem->reset(true); // autodetect in reset enabled
@ -130,12 +129,9 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
for(int i = 0; i < 60; ++i) for(int i = 0; i < 60; ++i)
{ {
myTIA->update(); myTIA->update();
int lines = myTIA->scanlines() - myTIA->startLine(); if(myTIA->scanlines() >= 287)
if((lines >= 180 && lines <= 342) &&
(myTIA->startLine() >= 50 || myTIA->scanlines() >= 287))
++palCount; ++palCount;
} }
myDisplayFormat = (palCount >= 25) ? "PAL" : "NTSC"; myDisplayFormat = (palCount >= 25) ? "PAL" : "NTSC";
if(myProperties.get(Display_Format) == "AUTO-DETECT") if(myProperties.get(Display_Format) == "AUTO-DETECT")
autodetected = "*"; autodetected = "*";

View File

@ -26,6 +26,7 @@ class System;
#include "Serializable.hxx" #include "Serializable.hxx"
#include "bspf.hxx" #include "bspf.hxx"
#include "MouseControl.hxx"
/** /**
A controller is a device that plugs into either the left or right A controller is a device that plugs into either the left or right
@ -93,15 +94,6 @@ class Controller : public Serializable
KidVid, Genesis, MindLink, CompuMate KidVid, Genesis, MindLink, CompuMate
}; };
/**
Enumeration of mouse axis control types
*/
enum MouseAxisControl
{
Paddle0 = 0, Paddle1, Paddle2, Paddle3,
Automatic, NoControl
};
public: public:
/** /**
Create a new controller plugged into the specified jack Create a new controller plugged into the specified jack
@ -190,22 +182,21 @@ class Controller : public Serializable
/** /**
Determines how this controller will treat values received from the Determines how this controller will treat values received from the
X and Y axis of the mouse. Since not all controllers use the mouse, X/Y axis and left/right buttons of the mouse. Since not all controllers
it's up to the specific class to decide how to use this data. use the mouse, it's up to the specific class to decide how to use this data.
If either of the axis is set to 'Automatic', then we automatically If either of the axis is set to 'Automatic', then we automatically
use this number for the control type as follows: use the ctrlID for the control type.
0 - paddle 0, joystick 0 (and controllers similar to a joystick)
1 - paddle 1, joystick 1 (and controllers similar to a joystick) In the current implementation, the left button is tied to the X axis,
2 - paddle 2, joystick 0 (and controllers similar to a joystick) and the right one tied to the Y axis.
3 - paddle 3, joystick 1 (and controllers similar to a joystick)
@param xaxis How the controller should use x-axis data @param xaxis How the controller should use x-axis data
@param yaxis How the controller should use y-axis data @param yaxis How the controller should use y-axis data
@param ctrlID The controller ID to use axis 'auto' mode @param ctrlID The controller ID to use axis 'auto' mode
*/ */
virtual void setMouseControl( virtual void setMouseControl(
MouseAxisControl xaxis, MouseAxisControl yaxis, int ctrlID = -1) { }; MouseControl::Axis xaxis, MouseControl::Axis yaxis, int ctrlID = -1) { };
/** /**
Returns the name of this controller. Returns the name of this controller.

File diff suppressed because it is too large Load Diff

View File

@ -78,7 +78,7 @@ void Driving::update()
int m_axis = myEvent.get(Event::MouseAxisXValue); int m_axis = myEvent.get(Event::MouseAxisXValue);
if(m_axis < -2) myCounter--; if(m_axis < -2) myCounter--;
else if(m_axis > 2) myCounter++; else if(m_axis > 2) myCounter++;
if(myEvent.get(Event::MouseButtonValue)) if(myEvent.get(Event::MouseButtonLeftValue))
myDigitalPinState[Six] = false; myDigitalPinState[Six] = false;
} }
@ -115,10 +115,10 @@ void Driving::update()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Driving::setMouseControl( void Driving::setMouseControl(
MouseAxisControl xaxis, MouseAxisControl yaxis, int ctrlID) MouseControl::Axis xaxis, MouseControl::Axis yaxis, int ctrlID)
{ {
// In 'automatic' mode, only the X-axis is used // In 'automatic' mode, only the X-axis is used
if(xaxis == Controller::Automatic || yaxis == Controller::Automatic) if(xaxis == MouseControl::Automatic || yaxis == MouseControl::Automatic)
{ {
myControlID = ((myJack == Left && (ctrlID == 0 || ctrlID == 1)) || myControlID = ((myJack == Left && (ctrlID == 0 || ctrlID == 1)) ||
(myJack == Right && (ctrlID == 2 || ctrlID == 3)) (myJack == Right && (ctrlID == 2 || ctrlID == 3))

View File

@ -57,22 +57,21 @@ class Driving : public Controller
/** /**
Determines how this controller will treat values received from the Determines how this controller will treat values received from the
X and Y axis of the mouse. Since not all controllers use the mouse, X/Y axis and left/right buttons of the mouse. Since not all controllers
it's up to the specific class to decide how to use this data. use the mouse, it's up to the specific class to decide how to use this data.
If either of the axis is set to 'Automatic', then we automatically If either of the axis is set to 'Automatic', then we automatically
use this number for the control type as follows: use the ctrlID for the control type.
0 - paddle 0, joystick 0 (and controllers similar to a joystick)
1 - paddle 1, joystick 1 (and controllers similar to a joystick) In the current implementation, the left button is tied to the X axis,
2 - paddle 2, joystick 0 (and controllers similar to a joystick) and the right one tied to the Y axis.
3 - paddle 3, joystick 1 (and controllers similar to a joystick)
@param xaxis How the controller should use x-axis data @param xaxis How the controller should use x-axis data
@param yaxis How the controller should use y-axis data @param yaxis How the controller should use y-axis data
@param ctrlID The controller ID to use axis 'auto' mode @param ctrlID The controller ID to use axis 'auto' mode
*/ */
void setMouseControl( void setMouseControl(
MouseAxisControl xaxis, MouseAxisControl yaxis, int ctrlID = -1); MouseControl::Axis xaxis, MouseControl::Axis yaxis, int ctrlID = -1);
private: private:
// Counter to iterate through the gray codes // Counter to iterate through the gray codes

View File

@ -70,7 +70,8 @@ class Event
SALeftAxis0Value, SALeftAxis1Value, SALeftAxis0Value, SALeftAxis1Value,
SARightAxis0Value, SARightAxis1Value, SARightAxis0Value, SARightAxis1Value,
MouseAxisXValue, MouseAxisYValue, MouseButtonValue, MouseAxisXValue, MouseAxisYValue,
MouseButtonLeftValue, MouseButtonRightValue,
ChangeState, LoadState, SaveState, TakeSnapshot, Quit, ChangeState, LoadState, SaveState, TakeSnapshot, Quit,
PauseMode, MenuMode, CmdMenuMode, DebuggerMode, LauncherMode, PauseMode, MenuMode, CmdMenuMode, DebuggerMode, LauncherMode,

View File

@ -43,6 +43,7 @@
#include "Sound.hxx" #include "Sound.hxx"
#include "StateManager.hxx" #include "StateManager.hxx"
#include "Switches.hxx" #include "Switches.hxx"
#include "MouseControl.hxx"
#include "EventHandler.hxx" #include "EventHandler.hxx"
@ -58,6 +59,7 @@
EventHandler::EventHandler(OSystem* osystem) EventHandler::EventHandler(OSystem* osystem)
: myOSystem(osystem), : myOSystem(osystem),
myOverlay(NULL), myOverlay(NULL),
myMouseControl(NULL),
myState(S_NONE), myState(S_NONE),
myAllowAllDirectionsFlag(false), myAllowAllDirectionsFlag(false),
myFryingFlag(false), myFryingFlag(false),
@ -102,6 +104,7 @@ EventHandler::~EventHandler()
if(ourMenuActionList[i].key) if(ourMenuActionList[i].key)
free(ourMenuActionList[i].key); free(ourMenuActionList[i].key);
delete myMouseControl;
delete[] myJoysticks; delete[] myJoysticks;
} }
@ -335,7 +338,7 @@ void EventHandler::poll(uInt64 time)
// These only work when in emulation mode // These only work when in emulation mode
else if(myState == S_EMULATE) else if(myState == S_EMULATE)
{ {
switch(int(key)) switch(key)
{ {
case KBDK_EQUALS: case KBDK_EQUALS:
myOSystem->frameBuffer().changeVidMode(+1); myOSystem->frameBuffer().changeVidMode(+1);
@ -496,22 +499,14 @@ void EventHandler::poll(uInt64 time)
// These only work when in emulation mode // These only work when in emulation mode
else if(myState == S_EMULATE) else if(myState == S_EMULATE)
{ {
switch(int(key)) switch(key)
{ {
case KBDK_0: // Ctrl-0 sets the mouse to paddle 0 case KBDK_0: // Ctrl-0 switches between mouse control modes
setMouseAsPaddle(0, "Mouse is paddle 0"); if(myMouseControl)
break; {
const string& message = myMouseControl->next();
case KBDK_1: // Ctrl-1 sets the mouse to paddle 1 myOSystem->frameBuffer().showMessage(message);
setMouseAsPaddle(1, "Mouse is paddle 1"); }
break;
case KBDK_2: // Ctrl-2 sets the mouse to paddle 2
setMouseAsPaddle(2, "Mouse is paddle 2");
break;
case KBDK_3: // Ctrl-3 sets the mouse to paddle 3
setMouseAsPaddle(3, "Mouse is paddle 3");
break; break;
case KBDK_f: // Ctrl-f toggles NTSC/PAL mode case KBDK_f: // Ctrl-f toggles NTSC/PAL mode
@ -613,11 +608,20 @@ void EventHandler::poll(uInt64 time)
// Determine which mode we're in, then send the event to the appropriate place // Determine which mode we're in, then send the event to the appropriate place
if(myState == S_EMULATE) if(myState == S_EMULATE)
{ {
myEvent.set(Event::MouseButtonValue, state); switch(event.button.button)
{
case SDL_BUTTON_LEFT:
myEvent.set(Event::MouseButtonLeftValue, state);
break;
case SDL_BUTTON_RIGHT:
myEvent.set(Event::MouseButtonRightValue, state);
break;
default:
break;
}
} }
else if(myOverlay) else if(myOverlay)
{ {
// Take window zooming into account
Int32 x = event.button.x, y = event.button.y; Int32 x = event.button.x, y = event.button.y;
switch(event.button.button) switch(event.button.button)
@ -1906,51 +1910,16 @@ void EventHandler::takeSnapshot(uInt32 number)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setMouseControllerMode(const string& mode, void EventHandler::setMouseControllerMode(const string& mode)
const string& message)
{ {
if(!&myOSystem->console()) delete myMouseControl; myMouseControl = NULL;
return; if(myState == S_EMULATE)
Controller& lc = myOSystem->console().controller(Controller::Left);
Controller& rc = myOSystem->console().controller(Controller::Right);
if(mode == "auto")
{ {
bool swap = myOSystem->console().properties().get(Controller_SwapPaddles) == "YES"; const string& control = mode == "rom" ?
lc.setMouseControl(Controller::Automatic, Controller::Automatic, swap ? 1 : 0); myOSystem->console().properties().get(Controller_MouseAxis) : mode;
rc.setMouseControl(Controller::Automatic, Controller::Automatic, swap ? 1 : 0);
}
else
{
Controller::MouseAxisControl xaxis = (Controller::MouseAxisControl)
((int)mode[0] - '0');
Controller::MouseAxisControl yaxis = (Controller::MouseAxisControl)
((int)mode[1] - '0');
lc.setMouseControl(xaxis, yaxis); myMouseControl = new MouseControl(myOSystem->console(), control);
rc.setMouseControl(xaxis, yaxis); myMouseControl->next(); // set first available mode
}
if(message != "")
myOSystem->frameBuffer().showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setMouseAsPaddle(int paddle, const string& message)
{
if(myOSystem->settings().getString("mcontrol") == "auto")
{
myOSystem->console().controller(Controller::Left).setMouseControl(
Controller::Automatic, Controller::Automatic, paddle);
myOSystem->console().controller(Controller::Right).setMouseControl(
Controller::Automatic, Controller::Automatic, paddle);
myOSystem->frameBuffer().showMessage(message);
}
else
{
myOSystem->frameBuffer().showMessage(
"Mouse axis mode not auto, paddle not changed");
} }
} }

View File

@ -29,6 +29,7 @@ class DialogContainer;
class EventMappingWidget; class EventMappingWidget;
class StringMap; class StringMap;
class StringList; class StringList;
class MouseControl;
#include "Array.hxx" #include "Array.hxx"
#include "Event.hxx" #include "Event.hxx"
@ -152,13 +153,12 @@ class EventHandler
void quit() { handleEvent(Event::Quit, 1); } void quit() { handleEvent(Event::Quit, 1); }
/** /**
Sets the mouse axis to act as controller 'mode', where the mode is Sets the mouse axes and buttons to act as controller 'mode', where
defined from the Controller::MouseAxisControl enum the mode is defined from the Controller::MouseAxisControl enum
@param mode The controller which the mouse axes should emulate @param mode The controller which the mouse axes should emulate
@param message Print the (non-empty) message to the framebuffer
*/ */
void setMouseControllerMode(const string& mode, const string& message = ""); void setMouseControllerMode(const string& mode);
/** /**
Set the number of seconds between taking a snapshot in Set the number of seconds between taking a snapshot in
@ -375,6 +375,10 @@ class EventHandler
// Indicates current overlay object // Indicates current overlay object
DialogContainer* myOverlay; DialogContainer* myOverlay;
// MouseControl object, which takes care of switching the mouse between
// all possible controller modes
MouseControl* myMouseControl;
// Array of key events, indexed by StellaKey // Array of key events, indexed by StellaKey
Event::Type myKeyTable[KBDK_LAST][kNumModes]; Event::Type myKeyTable[KBDK_LAST][kNumModes];
@ -411,9 +415,6 @@ class EventHandler
uInt32 myContSnapshotInterval; uInt32 myContSnapshotInterval;
uInt32 myContSnapshotCounter; uInt32 myContSnapshotCounter;
// Indicates which paddle the mouse currently emulates
Int8 myPaddleMode;
// Holds static strings for the remap menu (emulation and menu events) // Holds static strings for the remap menu (emulation and menu events)
static ActionList ourEmulActionList[kEmulActionListSize]; static ActionList ourEmulActionList[kEmulActionListSize];
static ActionList ourMenuActionList[kMenuActionListSize]; static ActionList ourMenuActionList[kMenuActionListSize];

View File

@ -115,21 +115,22 @@ void Joystick::update()
} }
} }
// Get mouse button state // Get mouse button state
if(myEvent.get(Event::MouseButtonValue)) if(myEvent.get(Event::MouseButtonLeftValue) ||
myEvent.get(Event::MouseButtonRightValue))
myDigitalPinState[Six] = false; myDigitalPinState[Six] = false;
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Joystick::setMouseControl( void Joystick::setMouseControl(
MouseAxisControl xaxis, MouseAxisControl yaxis, int ctrlID) MouseControl::Axis xaxis, MouseControl::Axis yaxis, int ctrlID)
{ {
// In 'automatic' mode, both axes on the mouse map to a single normal joystick // In 'automatic' mode, both axes on the mouse map to a single normal joystick
if(xaxis == Controller::Automatic || yaxis == Controller::Automatic) if(xaxis == MouseControl::Automatic || yaxis == MouseControl::Automatic)
{ {
myControlID = ((myJack == Left && (ctrlID == 0 || ctrlID == 1)) || myControlID = ((myJack == Left && ctrlID == 0) ||
(myJack == Right && (ctrlID == 2 || ctrlID == 3)) (myJack == Right && ctrlID == 1)
) ? ctrlID & 0x01 : -1; ) ? ctrlID : -1;
} }
else // Otherwise, joysticks are not used in 'non-auto' mode else // Otherwise, joysticks are not used in 'non-auto' mode
myControlID = -1; myControlID = -1;

View File

@ -56,22 +56,21 @@ class Joystick : public Controller
/** /**
Determines how this controller will treat values received from the Determines how this controller will treat values received from the
X and Y axis of the mouse. Since not all controllers use the mouse, X/Y axis and left/right buttons of the mouse. Since not all controllers
it's up to the specific class to decide how to use this data. use the mouse, it's up to the specific class to decide how to use this data.
If either of the axis is set to 'Automatic', then we automatically If either of the axis is set to 'Automatic', then we automatically
use this number for the control type as follows: use the ctrlID for the control type.
0 - paddle 0, joystick 0 (and controllers similar to a joystick)
1 - paddle 1, joystick 1 (and controllers similar to a joystick) In the current implementation, the left button is tied to the X axis,
2 - paddle 2, joystick 0 (and controllers similar to a joystick) and the right one tied to the Y axis.
3 - paddle 3, joystick 1 (and controllers similar to a joystick)
@param xaxis How the controller should use x-axis data @param xaxis How the controller should use x-axis data
@param yaxis How the controller should use y-axis data @param yaxis How the controller should use y-axis data
@param ctrlID The controller ID to use axis 'auto' mode @param ctrlID The controller ID to use axis 'auto' mode
*/ */
void setMouseControl( void setMouseControl(
MouseAxisControl xaxis, MouseAxisControl yaxis, int ctrlID = -1); MouseControl::Axis xaxis, MouseControl::Axis yaxis, int ctrlID = -1);
/** /**
Sets the deadzone amount for real analog joysticks. Sets the deadzone amount for real analog joysticks.

View File

@ -66,7 +66,8 @@ void MindLink::update()
myMindlinkShift = 1; myMindlinkShift = 1;
nextMindlinkBit(); nextMindlinkBit();
if(myEvent.get(Event::MouseButtonValue)) if(myEvent.get(Event::MouseButtonLeftValue) ||
myEvent.get(Event::MouseButtonRightValue))
myMindlinkPos |= 0x4000; /* this bit starts a game */ myMindlinkPos |= 0x4000; /* this bit starts a game */
//cerr << HEX4 << (int)myMindlinkPos << " : " << HEX2 << (int)myIOPort << endl; //cerr << HEX4 << (int)myMindlinkPos << " : " << HEX2 << (int)myIOPort << endl;

View File

@ -293,7 +293,8 @@ void Paddles::update()
myCharge[myMPaddleID] = TRIGMIN; myCharge[myMPaddleID] = TRIGMIN;
if(myCharge[myMPaddleID] > TRIGMAX) if(myCharge[myMPaddleID] > TRIGMAX)
myCharge[myMPaddleID] = TRIGMAX; myCharge[myMPaddleID] = TRIGMAX;
if(myEvent.get(Event::MouseButtonValue)) if(myEvent.get(Event::MouseButtonLeftValue) ||
myEvent.get(Event::MouseButtonRightValue))
myDigitalPinState[ourButtonPin[myMPaddleID]] = false; myDigitalPinState[ourButtonPin[myMPaddleID]] = false;
} }
else else
@ -308,6 +309,8 @@ void Paddles::update()
myCharge[myMPaddleIDX] = TRIGMIN; myCharge[myMPaddleIDX] = TRIGMIN;
if(myCharge[myMPaddleIDX] > TRIGMAX) if(myCharge[myMPaddleIDX] > TRIGMAX)
myCharge[myMPaddleIDX] = TRIGMAX; myCharge[myMPaddleIDX] = TRIGMAX;
if(myEvent.get(Event::MouseButtonLeftValue))
myDigitalPinState[ourButtonPin[myMPaddleIDX]] = false;
} }
if(myMPaddleIDY > -1) if(myMPaddleIDY > -1)
{ {
@ -317,6 +320,8 @@ void Paddles::update()
myCharge[myMPaddleIDY] = TRIGMIN; myCharge[myMPaddleIDY] = TRIGMIN;
if(myCharge[myMPaddleIDY] > TRIGMAX) if(myCharge[myMPaddleIDY] > TRIGMAX)
myCharge[myMPaddleIDY] = TRIGMAX; myCharge[myMPaddleIDY] = TRIGMAX;
if(myEvent.get(Event::MouseButtonRightValue))
myDigitalPinState[ourButtonPin[myMPaddleIDY]] = false;
} }
} }
@ -377,11 +382,11 @@ void Paddles::update()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Paddles::setMouseControl( void Paddles::setMouseControl(
MouseAxisControl xaxis, MouseAxisControl yaxis, int ctrlID) MouseControl::Axis xaxis, MouseControl::Axis yaxis, int ctrlID)
{ {
// In 'automatic' mode, both axes on the mouse map to a single paddle // In 'automatic' mode, both axes on the mouse map to a single paddle
// This overrides any other mode // This overrides any other mode
if(xaxis == Controller::Automatic || yaxis == Controller::Automatic) if(xaxis == MouseControl::Automatic || yaxis == MouseControl::Automatic)
{ {
myMPaddleID = ((myJack == Left && (ctrlID == 0 || ctrlID == 1)) || myMPaddleID = ((myJack == Left && (ctrlID == 0 || ctrlID == 1)) ||
(myJack == Right && (ctrlID == 2 || ctrlID == 3)) (myJack == Right && (ctrlID == 2 || ctrlID == 3))
@ -397,14 +402,14 @@ void Paddles::setMouseControl(
{ {
switch(xaxis) switch(xaxis)
{ {
case Controller::Paddle0: myMPaddleIDX = 0; break; case MouseControl::Paddle0: myMPaddleIDX = 0; break;
case Controller::Paddle1: myMPaddleIDX = 1; break; case MouseControl::Paddle1: myMPaddleIDX = 1; break;
default: myMPaddleIDX = -1; break; default: myMPaddleIDX = -1; break;
} }
switch(yaxis) switch(yaxis)
{ {
case Controller::Paddle0: myMPaddleIDY = 0; break; case MouseControl::Paddle0: myMPaddleIDY = 0; break;
case Controller::Paddle1: myMPaddleIDY = 1; break; case MouseControl::Paddle1: myMPaddleIDY = 1; break;
default: myMPaddleIDY = -1; break; default: myMPaddleIDY = -1; break;
} }
} }
@ -412,14 +417,14 @@ void Paddles::setMouseControl(
{ {
switch(xaxis) switch(xaxis)
{ {
case Controller::Paddle2: myMPaddleIDX = 0; break; case MouseControl::Paddle2: myMPaddleIDX = 0; break;
case Controller::Paddle3: myMPaddleIDX = 1; break; case MouseControl::Paddle3: myMPaddleIDX = 1; break;
default: myMPaddleIDX = -1; break; default: myMPaddleIDX = -1; break;
} }
switch(yaxis) switch(yaxis)
{ {
case Controller::Paddle2: myMPaddleIDY = 0; break; case MouseControl::Paddle2: myMPaddleIDY = 0; break;
case Controller::Paddle3: myMPaddleIDY = 1; break; case MouseControl::Paddle3: myMPaddleIDY = 1; break;
default: myMPaddleIDY = -1; break; default: myMPaddleIDY = -1; break;
} }
} }

View File

@ -63,22 +63,21 @@ class Paddles : public Controller
/** /**
Determines how this controller will treat values received from the Determines how this controller will treat values received from the
X and Y axis of the mouse. Since not all controllers use the mouse, X/Y axis and left/right buttons of the mouse. Since not all controllers
it's up to the specific class to decide how to use this data. use the mouse, it's up to the specific class to decide how to use this data.
If either of the axis is set to 'Automatic', then we automatically If either of the axis is set to 'Automatic', then we automatically
use this number for the control type as follows: use the ctrlID for the control type.
0 - paddle 0, joystick 0 (and controllers similar to a joystick)
1 - paddle 1, joystick 1 (and controllers similar to a joystick) In the current implementation, the left button is tied to the X axis,
2 - paddle 2, joystick 0 (and controllers similar to a joystick) and the right one tied to the Y axis.
3 - paddle 3, joystick 1 (and controllers similar to a joystick)
@param xaxis How the controller should use x-axis data @param xaxis How the controller should use x-axis data
@param yaxis How the controller should use y-axis data @param yaxis How the controller should use y-axis data
@param ctrlID The controller ID to use axis 'auto' mode @param ctrlID The controller ID to use axis 'auto' mode
*/ */
void setMouseControl( void setMouseControl(
MouseAxisControl xaxis, MouseAxisControl yaxis, int ctrlID = -1); MouseControl::Axis xaxis, MouseControl::Axis yaxis, int ctrlID = -1);
/** /**
Sets the sensitivity for digital emulation of paddle movement. Sets the sensitivity for digital emulation of paddle movement.

View File

@ -68,6 +68,7 @@ void Properties::set(PropertyType key, const string& value)
case Controller_Left: case Controller_Left:
case Controller_Right: case Controller_Right:
case Controller_SwapPaddles: case Controller_SwapPaddles:
case Controller_MouseAxis:
case Display_Format: case Display_Format:
case Display_Phosphor: case Display_Phosphor:
{ {
@ -244,6 +245,7 @@ void Properties::print() const
<< get(Controller_Left) << "|" << get(Controller_Left) << "|"
<< get(Controller_Right) << "|" << get(Controller_Right) << "|"
<< get(Controller_SwapPaddles) << "|" << get(Controller_SwapPaddles) << "|"
<< get(Controller_MouseAxis) << "|"
<< get(Display_Format) << "|" << get(Display_Format) << "|"
<< get(Display_YStart) << "|" << get(Display_YStart) << "|"
<< get(Display_Height) << "|" << get(Display_Height) << "|"
@ -288,6 +290,7 @@ void Properties::printHeader()
<< "Controller_Left|" << "Controller_Left|"
<< "Controller_Right|" << "Controller_Right|"
<< "Controller_SwapPaddles|" << "Controller_SwapPaddles|"
<< "Controller_MouseAxis|"
<< "Display_Format|" << "Display_Format|"
<< "Display_YStart|" << "Display_YStart|"
<< "Display_Height|" << "Display_Height|"
@ -313,6 +316,7 @@ const char* Properties::ourDefaultProperties[LastPropType] = {
"JOYSTICK", // Controller.Left "JOYSTICK", // Controller.Left
"JOYSTICK", // Controller.Right "JOYSTICK", // Controller.Right
"NO", // Controller.SwapPaddles "NO", // Controller.SwapPaddles
"AUTO", // Controller.MouseAxis
"AUTO-DETECT", // Display.Format "AUTO-DETECT", // Display.Format
"34", // Display.YStart "34", // Display.YStart
"210", // Display.Height "210", // Display.Height
@ -337,6 +341,7 @@ const char* Properties::ourPropertyNames[LastPropType] = {
"Controller.Left", "Controller.Left",
"Controller.Right", "Controller.Right",
"Controller.SwapPaddles", "Controller.SwapPaddles",
"Controller.MouseAxis",
"Display.Format", "Display.Format",
"Display.YStart", "Display.YStart",
"Display.Height", "Display.Height",

View File

@ -38,6 +38,7 @@ enum PropertyType {
Controller_Left, Controller_Left,
Controller_Right, Controller_Right,
Controller_SwapPaddles, Controller_SwapPaddles,
Controller_MouseAxis,
Display_Format, Display_Format,
Display_YStart, Display_YStart,
Display_Height, Display_Height,

View File

@ -279,12 +279,8 @@ void Settings::validate()
else if(i > 29) setInternal("joydeadzone", "29"); else if(i > 29) setInternal("joydeadzone", "29");
s = getString("mcontrol"); s = getString("mcontrol");
if(s != "auto") if(s != "never" && s != "auto" && s != "rom")
{
// Note: these constants are from Controller::MouseAxisType enum
if(s.length() != 2 || s[0] < '0' || s[0] > '5' || s[1] < '0' || s[1] > '5')
setInternal("mcontrol", "auto"); setInternal("mcontrol", "auto");
}
if(i < 1) setInternal("dsense", "1"); if(i < 1) setInternal("dsense", "1");
else if(i > 10) setInternal("dsense", "10"); else if(i > 10) setInternal("dsense", "10");
@ -373,7 +369,8 @@ void Settings::usage()
<< " -logtoconsole <1|0> Log output to console/commandline\n" << " -logtoconsole <1|0> Log output to console/commandline\n"
<< " -joydeadzone <number> Sets 'deadzone' area for analog joysticks (0-29)\n" << " -joydeadzone <number> Sets 'deadzone' area for analog joysticks (0-29)\n"
<< " -joyallow4 <1|0> Allow all 4 directions on a joystick to be pressed simultaneously\n" << " -joyallow4 <1|0> Allow all 4 directions on a joystick to be pressed simultaneously\n"
<< " -mcontrol <auto|XY> Use mouse axes as specified paddle controller type (see manual)\n" << " -mcontrol <never|auto| Use mouse axes as specified controller type (see manual)\n"
<< " rom>\n"
<< " -dsense <number> Sensitivity of digital emulated paddle movement (1-10)\n" << " -dsense <number> Sensitivity of digital emulated paddle movement (1-10)\n"
<< " -msense <number> Sensitivity of mouse emulated paddle movement (1-15)\n" << " -msense <number> Sensitivity of mouse emulated paddle movement (1-15)\n"
<< " -sa1 <left|right> Stelladaptor 1 emulates specified joystick port\n" << " -sa1 <left|right> Stelladaptor 1 emulates specified joystick port\n"

View File

@ -30,9 +30,9 @@ class Sound;
#include "TIATables.hxx" #include "TIATables.hxx"
/** /**
This class is a device that emulates the Television Interface Adapator This class is a device that emulates the Television Interface Adaptor
found in the Atari 2600 and 7800 consoles. The Television Interface found in the Atari 2600 and 7800 consoles. The Television Interface
Adapator is an integrated circuit designed to interface between an Adaptor is an integrated circuit designed to interface between an
eight bit microprocessor and a television video modulator. It converts eight bit microprocessor and a television video modulator. It converts
eight bit parallel data into serial outputs for the color, luminosity, eight bit parallel data into serial outputs for the color, luminosity,
and composite sync required by a video modulator. and composite sync required by a video modulator.

View File

@ -131,7 +131,9 @@ void TrackBall::update()
if(myTrakBallLinesV == 0) myTrakBallLinesV = 1; if(myTrakBallLinesV == 0) myTrakBallLinesV = 1;
// Get mouse button state // Get mouse button state
myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonValue) == 0); myDigitalPinState[Six] =
(myEvent.get(Event::MouseButtonLeftValue) == 0) ||
(myEvent.get(Event::MouseButtonRightValue) == 0);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -204,13 +204,15 @@ void InputDialog::addDevicePortTab(const GUI::Font& font)
// Mouse controller specific axis // Mouse controller specific axis
lwidth = font.getStringWidth("X-Axis is: "); lwidth = font.getStringWidth("X-Axis is: ");
pwidth = font.getStringWidth("Paddle 3"); pwidth = font.getStringWidth("Driving 0");
items.clear(); items.clear();
items.push_back("not used", BSPF_toString(Controller::NoControl)); items.push_back("not used", BSPF_toString(MouseControl::NoControl));
items.push_back("Paddle 0", BSPF_toString(Controller::Paddle0)); items.push_back("Paddle 0", BSPF_toString(MouseControl::Paddle0));
items.push_back("Paddle 1", BSPF_toString(Controller::Paddle1)); items.push_back("Paddle 1", BSPF_toString(MouseControl::Paddle1));
items.push_back("Paddle 2", BSPF_toString(Controller::Paddle2)); items.push_back("Paddle 2", BSPF_toString(MouseControl::Paddle2));
items.push_back("Paddle 3", BSPF_toString(Controller::Paddle3)); items.push_back("Paddle 3", BSPF_toString(MouseControl::Paddle3));
items.push_back("Driving 0", BSPF_toString(MouseControl::Driving0));
items.push_back("Driving 1", BSPF_toString(MouseControl::Driving1));
xpos = 45; ypos += lineHeight + 4; xpos = 45; ypos += lineHeight + 4;
myMouseX = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, myMouseX = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items,

View File

@ -19,11 +19,12 @@ my %proptype = (
"Controller.Left" => 12, "Controller.Left" => 12,
"Controller.Right" => 13, "Controller.Right" => 13,
"Controller.SwapPaddles" => 14, "Controller.SwapPaddles" => 14,
"Display.Format" => 15, "Controller.MouseAxis" => 15,
"Display.YStart" => 16, "Display.Format" => 16,
"Display.Height" => 17, "Display.YStart" => 17,
"Display.Phosphor" => 18, "Display.Height" => 18,
"Display.PPBlend" => 19 "Display.Phosphor" => 19,
"Display.PPBlend" => 20
); );
my @prop_defaults = ( my @prop_defaults = (
@ -42,6 +43,7 @@ my @prop_defaults = (
"JOYSTICK", "JOYSTICK",
"JOYSTICK", "JOYSTICK",
"NO", "NO",
"AUTO",
"AUTO-DETECT", "AUTO-DETECT",
"34", "34",
"210", "210",