improved controller detection and added Genesis

adapted GameInfoDialog to controller detection
moved detection from OSystem to Console
This commit is contained in:
thrust26 2019-02-11 22:10:30 +01:00
parent 854a891a36
commit a4456e6af8
7 changed files with 196 additions and 111 deletions

View File

@ -51,7 +51,7 @@ class ControllerWidget : public Widget, public CommandSender
bool isLeftPort()
{
bool swappedPorts = instance().console().properties().get(Console_SwapPorts) == "YES";
return (myController.jack() == Controller::Left) ^ swappedPorts;
}

View File

@ -26,6 +26,7 @@
#include "Driving.hxx"
#include "Event.hxx"
#include "EventHandler.hxx"
#include "ControllerDetector.hxx"
#include "Joystick.hxx"
#include "Keyboard.hxx"
#include "KidVid.hxx"
@ -845,8 +846,17 @@ void Console::setControllers(const string& rommd5)
else
{
// Setup the controllers based on properties
const string& left = myProperties.get(Controller_Left);
const string& right = myProperties.get(Controller_Right);
string left = myProperties.get(Controller_Left);
string right = myProperties.get(Controller_Right);
uInt32 size = 0;
const uInt8* image = myCart->getImage(size);
// try to detect controllers
if(image != nullptr || size != 0)
{
left = ControllerDetector::detect(image, size, left, Controller::Left, myOSystem.settings());
right = ControllerDetector::detect(image, size, right, Controller::Right, myOSystem.settings());
}
unique_ptr<Controller> leftC = getControllerPort(rommd5, left, Controller::Left),
rightC = getControllerPort(rommd5, right, Controller::Right);

View File

@ -16,21 +16,20 @@
//============================================================================
#include "Settings.hxx"
#include "OSystem.hxx"
#include "ControllerDetector.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string ControllerDetector::detect(const BytePtr& image, uInt32 size,
string ControllerDetector::detect(const uInt8* image, uInt32 size,
const string& controller, const Controller::Jack port,
const OSystem& osystem)
const Settings& settings)
{
string type(controller);
//string type("AUTO"); // dirty hack for testing!!!
//string type(controller);
string type("AUTO"); // dirty hack for testing!!!
if(type == "AUTO" || osystem.settings().getBool("rominfo"))
if(type == "AUTO" || settings.getBool("rominfo"))
{
string detectedType = autodetectPort(image, size, port, osystem);
string detectedType = autodetectPort(image, size, port, settings);
if(type != "AUTO" && type != detectedType)
{
@ -44,17 +43,15 @@ string ControllerDetector::detect(const BytePtr& image, uInt32 size,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string ControllerDetector::autodetectPort(const BytePtr& image, uInt32 size,
Controller::Jack port, const OSystem& osystem)
string ControllerDetector::autodetectPort(const uInt8* image, uInt32 size,
Controller::Jack port, const Settings& settings)
{
// default type joystick
string type = "JOYSTICK"; // TODO: remove magic strings
if(isProbablyAtariVox(image, size, port))
type = "ATARIVOX";
else if (isProbablySaveKey(image, size, port))
if (isProbablySaveKey(image, size, port))
type = "SAVEKEY";
else if(usesJoystickButtons(image, size, port))
else if(usesJoystickButton(image, size, port))
{
if(isProbablyTrakBall(image, size))
type = "TRAKBALL";
@ -62,29 +59,25 @@ string ControllerDetector::autodetectPort(const BytePtr& image, uInt32 size,
type = "ATARIMOUSE";
else if(isProbablyAmigaMouse(image, size))
type = "AMIGAMOUSE";
else if(usesPaddleButtons(image, size, port, osystem))
else if(usesPaddle(image, size, port, settings))
type = "KEYBOARD"; // only keyboard uses joystick and paddle buttons
// TODO: Big Bird, Brain Games, Cookie Monster Munch (right),
// Game of Concentration, Grover's Music Maker (right)
// Holey Moley, Hunt & Score
// Monster Cise, Oscar's Trash Race (different, Peek-A-Boo
else if(usesGenesisButton(image, size, port))
type = "GENESIS";
}
else
{
if(usesPaddleButtons(image, size, port, osystem))
if(usesPaddle(image, size, port, settings))
type = "PADDLES";
}
// TODO: GENESIS, BOOSTERGRIP, DRIVING, MINDLINK, ATARIVOX, KIDVID
// TODO: BOOSTERGRIP, DRIVING, MINDLINK, ATARIVOX, KIDVID
// not detectable: PADDLES_IAXIS, PADDLES_IAXDR
return type;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::searchForBytes(const uInt8* image, uInt32 imagesize,
const uInt8* signature, uInt32 sigsize,
uInt32 minhits)
const uInt8* signature, uInt32 sigsize)
{
uInt32 count = 0;
for(uInt32 i = 0; i < imagesize - sigsize; ++i)
{
uInt32 matches = 0;
@ -97,22 +90,19 @@ bool ControllerDetector::searchForBytes(const uInt8* image, uInt32 imagesize,
}
if(matches == sigsize)
{
++count;
i += sigsize; // skip past this signature 'window' entirely
return true;
}
if(count >= minhits)
break;
}
return (count >= minhits);
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::usesJoystickButtons(const BytePtr& image, uInt32 size, Controller::Jack port)
bool ControllerDetector::usesJoystickButton(const uInt8* image, uInt32 size, Controller::Jack port)
{
if(port == Controller::Left)
{
const int NUM_SIGS_0 = 13;
const int NUM_SIGS_0 = 17;
const int SIG_SIZE_0 = 3;
uInt8 signature_0[NUM_SIGS_0][SIG_SIZE_0] = {
{ 0x24, 0x0c, 0x10 }, // bit INPT4; bpl (joystick games only)
@ -127,11 +117,23 @@ bool ControllerDetector::usesJoystickButtons(const BytePtr& image, uInt32 size,
{ 0xa5, 0x3c, 0x30 }, // lda INPT4|$30; bmi (joystick, keyboard and mindlink games)
{ 0xb5, 0x3c, 0x10 }, // lda INPT4|$30,x; bpl (joystick, keyboard and driving games)
{ 0xb5, 0x3c, 0x30 }, // lda INPT4|$30,x; bmi (joystick and keyboard games)
{ 0xb4, 0x0c, 0x30 } // ldy INPT4|$30,x; bmi (joystick games only)
{ 0xb4, 0x0c, 0x30 }, // ldy INPT4|$30,x; bmi (joystick games only)
{ 0xa5, 0x3c, 0x2a }, // ldy INPT4|$30; rol (joystick games only)
{ 0xa6, 0x3c, 0x8e }, // ldx INPT4|$30; stx (joystick games only)
{ 0xa4, 0x0c, 0x30 }, // ldy INPT4|; bmi (only Game of Concentration)
{ 0xa4, 0x3c, 0x30 }, // ldy INPT4|$30; bmi (only Game of Concentration)
};
const int NUM_SIGS_1 = 5;
const int SIG_SIZE_1 = 5;
const int NUM_SIGS_1 = 4;
const int SIG_SIZE_1 = 4;
uInt8 signature_1[NUM_SIGS_1][SIG_SIZE_1] = {
{ 0xb9, 0x0c, 0x00, 0x10 }, // lda INPT4,y; bpl (joystick games only)
{ 0xb9, 0x0c, 0x00, 0x30 }, // lda INPT4,y; bmi (joystick games only)
{ 0xb9, 0x3c, 0x00, 0x10 }, // lda INPT4,y; bpl (joystick games only)
{ 0xb9, 0x3c, 0x00, 0x30 }, // lda INPT4,y; bmi (joystick games only)
};
const int NUM_SIGS_2 = 5;
const int SIG_SIZE_2 = 5;
uInt8 signature_2[NUM_SIGS_2][SIG_SIZE_2] = {
{ 0xa5, 0x0c, 0x25, 0x0d, 0x10 }, // lda INPT4; and INPT5; bpl (joystick games only)
{ 0xa5, 0x0c, 0x25, 0x0d, 0x30 }, // lda INPT4; and INPT5; bmi (joystick games only)
{ 0xa5, 0x3c, 0x25, 0x3d, 0x10 }, // lda INPT4|$30; and INPT5|$30; bpl (joystick games only)
@ -140,18 +142,22 @@ bool ControllerDetector::usesJoystickButtons(const BytePtr& image, uInt32 size,
};
for(uInt32 i = 0; i < NUM_SIGS_0; ++i)
if(searchForBytes(image.get(), size, signature_0[i], SIG_SIZE_0))
if(searchForBytes(image, size, signature_0[i], SIG_SIZE_0))
return true;
for(uInt32 i = 0; i < NUM_SIGS_1; ++i)
if(searchForBytes(image.get(), size, signature_1[i], SIG_SIZE_1))
if(searchForBytes(image, size, signature_1[i], SIG_SIZE_1))
return true;
for(uInt32 i = 0; i < NUM_SIGS_2; ++i)
if(searchForBytes(image, size, signature_2[i], SIG_SIZE_2))
return true;
}
else if(port == Controller::Right)
{
const int NUM_SIGS = 12;
const int SIG_SIZE = 3;
uInt8 signature[NUM_SIGS][SIG_SIZE] = {
const int NUM_SIGS_0 = 13;
const int SIG_SIZE_0 = 3;
uInt8 signature_0[NUM_SIGS_0][SIG_SIZE_0] = {
{ 0x24, 0x0d, 0x10 }, // bit INPT5; bpl (joystick games only)
{ 0x24, 0x0d, 0x30 }, // bit INPT5; bmi (joystick games only)
{ 0xa5, 0x0d, 0x10 }, // lda INPT5; bpl (joystick games only)
@ -163,31 +169,87 @@ bool ControllerDetector::usesJoystickButtons(const BytePtr& image, uInt32 size,
{ 0xa5, 0x3d, 0x10 }, // lda INPT5|$30; bpl (joystick games only)
{ 0xa5, 0x3d, 0x30 }, // lda INPT5|$30; bmi (joystick and keyboard games)
{ 0xb5, 0x3c, 0x10 }, // lda INPT4|$30,x; bpl (joystick, keyboard and driving games)
{ 0xb5, 0x3c, 0x30 } // lda INPT4|$30,x; bmi (joystick and keyboard games)
{ 0xb5, 0x3c, 0x30 }, // lda INPT4|$30,x; bmi (joystick and keyboard games)
{ 0xa4, 0x3d, 0x30 }, // ldy INPT5; bmi (only Game of Concentration)
};
const int NUM_SIGS_1 = 1;
const int SIG_SIZE_1 = 5;
const int NUM_SIGS_1 = 4;
const int SIG_SIZE_1 = 4;
uInt8 signature_1[NUM_SIGS_1][SIG_SIZE_1] = {
{ 0xb9, 0x0c, 0x00, 0x10 }, // lda INPT4,y; bpl (joystick games only)
{ 0xb9, 0x0c, 0x00, 0x30 }, // lda INPT4,y; bmi (joystick games only)
{ 0xb9, 0x3c, 0x00, 0x10 }, // lda INPT4,y; bpl (joystick games only)
{ 0xb9, 0x3c, 0x00, 0x30 }, // lda INPT4,y; bmi (joystick games only)
};
const int NUM_SIGS_2 = 1;
const int SIG_SIZE_2 = 5;
uInt8 signature_2[NUM_SIGS_2][SIG_SIZE_2] = {
{ 0xb5, 0x38, 0x29, 0x80, 0xd0 }, // lda INPT0|$30,y; and #$80; bne (Basic Programming)
};
for(uInt32 i = 0; i < NUM_SIGS; ++i)
if(searchForBytes(image.get(), size, signature[i], SIG_SIZE))
for(uInt32 i = 0; i < NUM_SIGS_0; ++i)
if(searchForBytes(image, size, signature_0[i], SIG_SIZE_0))
return true;
for(uInt32 i = 0; i < NUM_SIGS_1; ++i)
if(searchForBytes(image.get(), size, signature_1[i], SIG_SIZE_1))
if(searchForBytes(image, size, signature_1[i], SIG_SIZE_1))
return true;
for(uInt32 i = 0; i < NUM_SIGS_2; ++i)
if(searchForBytes(image, size, signature_2[i], SIG_SIZE_2))
return true;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::usesPaddleButtons(const BytePtr& image, uInt32 size,
Controller::Jack port, const OSystem& osystem)
bool ControllerDetector::usesGenesisButton(const uInt8* image, uInt32 size, Controller::Jack port)
{
if(port == Controller::Left)
{
const int NUM_SIGS_0 = 10;
const int SIG_SIZE_0 = 3;
uInt8 signature_0[NUM_SIGS_0][SIG_SIZE_0] = {
{ 0x24, 0x09, 0x10 }, // bit INPT1; bpl
{ 0x24, 0x09, 0x30 }, // bit INPT1; bmi
{ 0xa5, 0x09, 0x10 }, // lda INPT1; bpl
{ 0xa5, 0x09, 0x30 }, // lda INPT1; bmi
{ 0x24, 0x39, 0x10 }, // bit INPT1|$30; bpl
{ 0x24, 0x39, 0x30 }, // bit INPT1|$30; bmi
{ 0xa5, 0x39, 0x10 }, // lda INPT1|$30; bpl
{ 0xa5, 0x39, 0x30 }, // lda INPT1|$30; bmi
{ 0xa5, 0x39, 0x6a }, // lda INPT1|$30; ror
{ 0xa6, 0x39, 0x8e }, // ldx INPT1|$30; stx
};
for(uInt32 i = 0; i < NUM_SIGS_0; ++i)
if(searchForBytes(image, size, signature_0[i], SIG_SIZE_0))
return true;
}
else if(port == Controller::Right)
{
const int NUM_SIGS_0 = 9;
const int SIG_SIZE_0 = 3;
uInt8 signature_0[NUM_SIGS_0][SIG_SIZE_0] = {
{ 0x24, 0x0b, 0x10 }, // bit INPT3; bpl
{ 0x24, 0x0b, 0x30 }, // bit INPT3; bmi
{ 0xa5, 0x0b, 0x10 }, // lda INPT3; bpl
{ 0xa5, 0x0b, 0x30 }, // lda INPT3; bmi
{ 0x24, 0x3b, 0x10 }, // bit INPT3|$30; bpl
{ 0x24, 0x3b, 0x30 }, // bit INPT3|$30; bmi
{ 0xa5, 0x3b, 0x10 }, // lda INPT3|$30; bpl
{ 0xa5, 0x3b, 0x30 }, // lda INPT3|$30; bmi
{ 0xa6, 0x3b, 0x8e }, // ldx INPT3|$30; stx
};
for(uInt32 i = 0; i < NUM_SIGS_0; ++i)
if(searchForBytes(image, size, signature_0[i], SIG_SIZE_0))
return true;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::usesPaddle(const uInt8* image, uInt32 size,
Controller::Jack port, const Settings& settings)
{
// TODO: swap paddles/ports (uses INPT1/INPT3)
if(port == Controller::Left)
{
const int NUM_SIGS_0 = 13;
@ -197,7 +259,7 @@ bool ControllerDetector::usesPaddleButtons(const BytePtr& image, uInt32 size,
//{ 0x24, 0x08, 0x30 }, // bit INPT0; bmi (joystick games: Spike's Peak, Sweat, Turbo!)
{ 0xa5, 0x08, 0x10 }, // lda INPT0; bpl (no joystick games)
{ 0xa5, 0x08, 0x30 }, // lda INPT0; bmi (no joystick games)
{ 0xb5, 0x08, 0x10 }, // lda INPT0,x; bpl (Duck Attack!)
//{ 0xb5, 0x08, 0x10 }, // lda INPT0,x; bpl (Duck Attack (graphics)!, Toyshop Trouble (Easter Egg))
{ 0xb5, 0x08, 0x30 }, // lda INPT0,x; bmi (no joystick games)
{ 0x24, 0x38, 0x10 }, // bit INPT0|$30; bpl (no joystick games)
{ 0x24, 0x38, 0x30 }, // bit INPT0|$30; bmi (no joystick games)
@ -207,13 +269,15 @@ bool ControllerDetector::usesPaddleButtons(const BytePtr& image, uInt32 size,
{ 0xb5, 0x38, 0x30 }, // lda INPT0|$30,x; bmi (no joystick games)
{ 0x68, 0x48, 0x10 }, // pla; pha; bpl (i.a. Bachelor Party)
{ 0xa5, 0x3b, 0x30 }, // lda INPT3|$30; bmi (only Tac Scan, ports and paddles swapped)
{ 0xa5, 0x09, 0x30 }, // lda INPT3|$30; bmi (only Backgammon)
{ 0xa5, 0x08, 0x4c }, // lda INPT0; jmp (only Backgammon)
{ 0xa4, 0x38, 0x30 }, // ldy INPT0; bmi (no joystick games)
};
const int NUM_SIGS_1 = 2;
const int NUM_SIGS_1 = 3;
const int SIG_SIZE_1 = 4;
uInt8 signature_1[NUM_SIGS_1][SIG_SIZE_1] = {
{ 0xb9, 0x08, 0x00, 0x30 }, // lda INPT0,y; bmi (i.a. Encounter at L-5)
{ 0xb9, 0x38, 0x00, 0x30 }, // lda INPT0|$30,y; bmi (i.a. SW-Jedi Arena, Video Olympics)
{ 0x24, 0x08, 0x30, 0x02 }, // bit INPT0; bmi +2 (Picnic)
};
const int NUM_SIGS_2 = 4;
const int SIG_SIZE_2 = 5;
@ -225,25 +289,25 @@ bool ControllerDetector::usesPaddleButtons(const BytePtr& image, uInt32 size,
};
for(uInt32 i = 0; i < NUM_SIGS_0; ++i)
if(searchForBytes(image.get(), size, signature_0[i], SIG_SIZE_0))
if(searchForBytes(image, size, signature_0[i], SIG_SIZE_0))
return true;
for(uInt32 i = 0; i < NUM_SIGS_1; ++i)
if(searchForBytes(image.get(), size, signature_1[i], SIG_SIZE_1))
if(searchForBytes(image, size, signature_1[i], SIG_SIZE_1))
return true;
for(uInt32 i = 0; i < NUM_SIGS_2; ++i)
if(searchForBytes(image.get(), size, signature_2[i], SIG_SIZE_2))
if(searchForBytes(image, size, signature_2[i], SIG_SIZE_2))
return true;
}
else if(port == Controller::Right)
{
const int NUM_SIGS_0 = 16;
const int NUM_SIGS_0 = 17;
const int SIG_SIZE_0 = 3;
uInt8 signature_0[NUM_SIGS_0][SIG_SIZE_0] = {
{ 0x24, 0x0a, 0x10 }, // bit INPT2; bpl
{ 0x24, 0x0a, 0x30 }, // bit INPT2; bmi
{ 0xa5, 0x0a, 0x10 }, // lda INPT2; bpl
{ 0x24, 0x0a, 0x10 }, // bit INPT2; bpl (no joystick games)
{ 0x24, 0x0a, 0x30 }, // bit INPT2; bmi (no joystick games)
{ 0xa5, 0x0a, 0x10 }, // lda INPT2; bpl (no joystick games)
{ 0xa5, 0x0a, 0x30 }, // lda INPT2; bmi
{ 0xb5, 0x0a, 0x10 }, // lda INPT2,x; bpl
{ 0xb5, 0x0a, 0x30 }, // lda INPT2,x; bmi
@ -257,6 +321,7 @@ bool ControllerDetector::usesPaddleButtons(const BytePtr& image, uInt32 size,
{ 0xb5, 0x3a, 0x30 }, // lda INPT2|$30,x; bmi
{ 0xb5, 0x38, 0x10 }, // lda INPT0|$30,x; bpl (Circus Atari, old code!)
{ 0xb5, 0x38, 0x30 }, // lda INPT0|$30,x; bmi (no joystick games)
{ 0xa4, 0x3a, 0x30 }, // ldy INPT2|$30; bmi (no joystick games)
};
const int NUM_SIGS_1 = 1;
const int SIG_SIZE_1 = 4;
@ -272,15 +337,15 @@ bool ControllerDetector::usesPaddleButtons(const BytePtr& image, uInt32 size,
};
for(uInt32 i = 0; i < NUM_SIGS_0; ++i)
if(searchForBytes(image.get(), size, signature_0[i], SIG_SIZE_0))
if(searchForBytes(image, size, signature_0[i], SIG_SIZE_0))
return true;
for(uInt32 i = 0; i < NUM_SIGS_1; ++i)
if(searchForBytes(image.get(), size, signature_1[i], SIG_SIZE_1))
if(searchForBytes(image, size, signature_1[i], SIG_SIZE_1))
return true;
for(uInt32 i = 0; i < NUM_SIGS_2; ++i)
if(searchForBytes(image.get(), size, signature_2[i], SIG_SIZE_2))
if(searchForBytes(image, size, signature_2[i], SIG_SIZE_2))
return true;
}
@ -288,7 +353,7 @@ bool ControllerDetector::usesPaddleButtons(const BytePtr& image, uInt32 size,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::isProbablyTrakBall(const BytePtr& image, uInt32 size)
bool ControllerDetector::isProbablyTrakBall(const uInt8* image, uInt32 size)
{
const int NUM_SIGS = 1;
const int SIG_SIZE = 8;
@ -297,14 +362,14 @@ bool ControllerDetector::isProbablyTrakBall(const BytePtr& image, uInt32 size)
// TODO: Omegamatrix's signature (.MovementTab_1)
};
if(searchForBytes(image.get(), size, signature, SIG_SIZE))
if(searchForBytes(image, size, signature, SIG_SIZE))
return true;
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::isProbablyAtariMouse(const BytePtr& image, uInt32 size)
bool ControllerDetector::isProbablyAtariMouse(const uInt8* image, uInt32 size)
{
const int SIG_SIZE = 8;
uInt8 signature[SIG_SIZE] = {
@ -312,14 +377,14 @@ bool ControllerDetector::isProbablyAtariMouse(const BytePtr& image, uInt32 size)
// TODO: Omegamatrix's signature (.MovementTab_1)
};
if(searchForBytes(image.get(), size, signature, SIG_SIZE))
if(searchForBytes(image, size, signature, SIG_SIZE))
return true;
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::isProbablyAmigaMouse(const BytePtr& image, uInt32 size)
bool ControllerDetector::isProbablyAmigaMouse(const uInt8* image, uInt32 size)
{
const int SIG_SIZE = 8;
uInt8 signature[SIG_SIZE] = {
@ -327,21 +392,14 @@ bool ControllerDetector::isProbablyAmigaMouse(const BytePtr& image, uInt32 size)
// TODO: Omegamatrix's signature (.MovementTab_1)
};
if(searchForBytes(image.get(), size, signature, SIG_SIZE))
if(searchForBytes(image, size, signature, SIG_SIZE))
return true;
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::isProbablyAtariVox(const BytePtr& image, uInt32 size, Controller::Jack port)
{
// TOOD: analyse example code
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::isProbablySaveKey(const BytePtr& image, uInt32 size, Controller::Jack port)
bool ControllerDetector::isProbablySaveKey(const uInt8* image, uInt32 size, Controller::Jack port)
{
// known SaveKey code only supports right port
if(port == Controller::Right)
@ -354,7 +412,7 @@ bool ControllerDetector::isProbablySaveKey(const BytePtr& image, uInt32 size, Co
0x8d, 0x81, 0x02 // sta SWACNT
};
return (searchForBytes(image.get(), size, signature, SIG_SIZE));
return (searchForBytes(image, size, signature, SIG_SIZE));
}
return false;

View File

@ -44,12 +44,13 @@ class ControllerDetector
@param osystem The osystem associated with the system
@return The detected controller name
*/
static string detect(const BytePtr& image, uInt32 size,
static string detect(const uInt8* image, uInt32 size,
const string& controller, const Controller::Jack port,
const OSystem& osystem);
const Settings& settings);
private:
static string autodetectPort(const BytePtr& image, uInt32 size, Controller::Jack port, const OSystem& osystem);
static string autodetectPort(const uInt8* image, uInt32 size, Controller::Jack port,
const Settings& settings);
/**
Search the image for the specified byte signature
@ -63,29 +64,28 @@ class ControllerDetector
@return True if the signature was found at least 'minhits' time, else false
*/
static bool searchForBytes(const uInt8* image, uInt32 imagesize,
const uInt8* signature, uInt32 sigsize,
uInt32 minhits = 1);
const uInt8* signature, uInt32 sigsize);
// Returns true if the port's joystick button access code is found
static bool usesJoystickButtons(const BytePtr& image, uInt32 size, Controller::Jack port);
static bool usesJoystickButton(const uInt8* image, uInt32 size, Controller::Jack port);
static bool usesGenesisButton(const uInt8* image, uInt32 size, Controller::Jack port);
// Returns true if the port's paddle button access code is found
static bool usesPaddleButtons(const BytePtr& image, uInt32 size, Controller::Jack port, const OSystem& osystem);
static bool usesPaddle(const uInt8* image, uInt32 size, Controller::Jack port,
const Settings& settings);
// Returns true if Trak-Ball table is found
static bool isProbablyTrakBall(const BytePtr& image, uInt32 size);
static bool isProbablyTrakBall(const uInt8* image, uInt32 size);
// Returns true if Atari Mouse table is found
static bool isProbablyAtariMouse(const BytePtr& image, uInt32 size);
static bool isProbablyAtariMouse(const uInt8* image, uInt32 size);
// Returns true if Amiga Mouse table is found
static bool isProbablyAmigaMouse(const BytePtr& image, uInt32 size);
// Returns true if the AtariVox code pattern is found (TODO)
static bool isProbablyAtariVox(const BytePtr& image, uInt32 size, Controller::Jack port);
static bool isProbablyAmigaMouse(const uInt8* image, uInt32 size);
// Returns true if the SaveKey code pattern is found
static bool isProbablySaveKey(const BytePtr& image, uInt32 size, Controller::Jack port);
static bool isProbablySaveKey(const uInt8* image, uInt32 size, Controller::Jack port);
private:
// Following constructors and assignment operators not supported

View File

@ -34,7 +34,6 @@
#include "MD5.hxx"
#include "Cart.hxx"
#include "CartDetector.hxx"
#include "ControllerDetector.hxx"
#include "FrameBuffer.hxx"
#include "TIASurface.hxx"
#include "TIAConstants.hxx"
@ -485,7 +484,6 @@ unique_ptr<Console> OSystem::openConsole(const FilesystemNode& romfile, string&
}
}
// read controller properties...
CMDLINE_PROPS_UPDATE("sp", Console_SwapPorts);
CMDLINE_PROPS_UPDATE("lc", Controller_Left);
CMDLINE_PROPS_UPDATE("rc", Controller_Right);
@ -493,14 +491,6 @@ unique_ptr<Console> OSystem::openConsole(const FilesystemNode& romfile, string&
if(s != "") { props.set(Controller_Left, s); props.set(Controller_Right, s); }
CMDLINE_PROPS_UPDATE("cp", Controller_SwapPaddles);
CMDLINE_PROPS_UPDATE("ma", Controller_MouseAxis);
// ...and try to detect controllers
const string& left = props.get(Controller_Left);
const string& detectedLeft = ControllerDetector::detect(image, size, left, Controller::Left, *this);
props.set(Controller_Left, detectedLeft);
const string& right = props.get(Controller_Right);
const string& detectedRight = ControllerDetector::detect(image, size, right, Controller::Right, *this);
props.set(Controller_Right, detectedRight);
CMDLINE_PROPS_UPDATE("channels", Cartridge_Sound);
CMDLINE_PROPS_UPDATE("ld", Console_LeftDifficulty);
CMDLINE_PROPS_UPDATE("rd", Console_RightDifficulty);

View File

@ -51,7 +51,8 @@ GameInfoDialog::GameInfoDialog(
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
buttonHeight = font.getLineHeight() + 4;
buttonHeight = font.getLineHeight() + 4,
infoLineHeight = ifont.getLineHeight();
const int VBORDER = 8;
const int HBORDER = 10;
const int VGAP = 4;
@ -63,7 +64,8 @@ GameInfoDialog::GameInfoDialog(
// Set real dimensions
setSize(53 * fontWidth + 8,
8 * (lineHeight + VGAP) + VBORDER * 2 + _th + buttonHeight + fontHeight + ifont.getLineHeight() + 20,
8 * (lineHeight + VGAP) + 2 * (infoLineHeight + VGAP) + VBORDER * 2 + _th +
buttonHeight + fontHeight + ifont.getLineHeight() + 20,
max_w, max_h);
// The tab widget
@ -182,6 +184,7 @@ GameInfoDialog::GameInfoDialog(
tabID = myTab->addTab("Controller");
ctrls.clear();
VarList::push_back(ctrls, "Auto-detect", "AUTO");
VarList::push_back(ctrls, "Joystick", "JOYSTICK");
VarList::push_back(ctrls, "Paddles", "PADDLES");
VarList::push_back(ctrls, "Paddles_IAxis", "PADDLES_IAXIS");
@ -204,24 +207,32 @@ GameInfoDialog::GameInfoDialog(
myP0Controller = new PopUpWidget(myTab, font, myP0Label->getRight(), myP0Label->getTop()-1,
pwidth, lineHeight, ctrls, "", 0, kLeftCChanged);
wid.push_back(myP0Controller);
ypos += lineHeight + VGAP;
myP0ControllerDetected = new StaticTextWidget(myTab, ifont, myP0Controller->getLeft(), ypos,
"BoosterGrip detected");
wid.push_back(myP0ControllerDetected);
ypos += ifont.getLineHeight() + VGAP;
myP1Label = new StaticTextWidget(myTab, font, HBORDER, ypos+1, "P1 controller ");
myP1Controller = new PopUpWidget(myTab, font, myP1Label->getRight(), myP1Label->getTop()-1,
pwidth, lineHeight, ctrls, "", 0, kRightCChanged);
wid.push_back(myP1Controller);
ypos += lineHeight + VGAP;
myP1ControllerDetected = new StaticTextWidget(myTab, ifont, myP1Controller->getLeft(), ypos,
"BoosterGrip detected");
wid.push_back(myP0ControllerDetected);
ypos += ifont.getLineHeight() + VGAP + 4;
//ypos += lineHeight + VGAP;
mySwapPorts = new CheckboxWidget(myTab, font, myP0Controller->getRight() + fontWidth*4, myP0Controller->getTop()+1,
"Swap ports");
wid.push_back(mySwapPorts);
//ypos += lineHeight + VGAP;
mySwapPaddles = new CheckboxWidget(myTab, font, myP1Controller->getRight() + fontWidth*4, myP1Controller->getTop()+1,
"Swap paddles");
wid.push_back(mySwapPaddles);
// EEPROM erase button for P0/P1
ypos += lineHeight + VGAP + 4;
//ypos += lineHeight + VGAP + 4;
pwidth = myP1Controller->getWidth(); //font.getStringWidth("Erase EEPROM ") + 23;
myEraseEEPROMLabel = new StaticTextWidget(myTab, font, HBORDER, ypos, "AtariVox/SaveKey ");
myEraseEEPROMButton = new ButtonWidget(myTab, font, myEraseEEPROMLabel->getRight(), ypos - 4,
@ -405,8 +416,22 @@ void GameInfoDialog::loadConsoleProperties(const Properties& props)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GameInfoDialog::loadControllerProperties(const Properties& props)
{
myP0Controller->setSelected(props.get(Controller_Left), "JOYSTICK");
myP1Controller->setSelected(props.get(Controller_Right), "JOYSTICK");
myP0Controller->setSelected(props.get(Controller_Left), "AUTO");
if(instance().hasConsole() && myP0Controller->getSelectedTag().toString() == "AUTO")
{
myP0ControllerDetected->setLabel(instance().console().leftController().name() + " detected");
}
else
myP0ControllerDetected->setLabel("");
myP1Controller->setSelected(props.get(Controller_Right), "AUTO");
if(instance().hasConsole() && myP1Controller->getSelectedTag().toString() == "AUTO")
{
myP1ControllerDetected->setLabel(instance().console().rightController().name() + " detected");
}
else
myP1ControllerDetected->setLabel("");
mySwapPorts->setState(props.get(Console_SwapPorts) == "YES");
mySwapPaddles->setState(props.get(Controller_SwapPaddles) == "YES");

View File

@ -78,7 +78,9 @@ class GameInfoDialog : public Dialog, public CommandSender
StaticTextWidget* myP0Label;
StaticTextWidget* myP1Label;
PopUpWidget* myP0Controller;
StaticTextWidget* myP0ControllerDetected;
PopUpWidget* myP1Controller;
StaticTextWidget* myP1ControllerDetected;
CheckboxWidget* mySwapPorts;
CheckboxWidget* mySwapPaddles;
StaticTextWidget* myEraseEEPROMLabel;