improved keyboard controller detection

small doc update
This commit is contained in:
thrust26 2019-02-15 16:29:13 +01:00
parent f94fd34f99
commit 2cc035e4eb
4 changed files with 154 additions and 11 deletions

View File

@ -18,17 +18,23 @@
(thanks go to RomHunter for his tireless research in this area). (thanks go to RomHunter for his tireless research in this area).
Related to this, updated the snapshot collection. Related to this, updated the snapshot collection.
* Added various developer options for oddball TIAs: * Added various developer options for oddball TIAs: (TODO: doc)
- delayed playfield bits - delayed playfield bits
- delayed playfield color - delayed playfield color
- delayed player 0 swap - delayed player 0 swap
- delayed player 1 swap - delayed player 1 swap
- stuffed player move - stuffed player move
* Disabled some developer options for 'Player settings'. * Disabled some developer options for 'Player settings'. (TODO: doc)
* Enhanced command dialog. (TODO: doc)
* Added automatic controller detection. (TODO: doc, Stella.pro cleanup)
* Removed superfluous controller option 'PADDLES_IDIR'. * Removed superfluous controller option 'PADDLES_IDIR'.
* Added hotkey for sound on/off.
* Fixed not working 7800 pause key. * Fixed not working 7800 pause key.
* Fixed display of negative values in debugger; sometimes they were * Fixed display of negative values in debugger; sometimes they were

View File

@ -1477,7 +1477,7 @@
</tr> </tr>
</table> </table>
<p><b>Other Keys (cannot be remapped, except those marked with (*) )</b></p> <p><b>Other Keys (cannot be remapped, except those marked with (*) which can be mapped to a 2nd key)</b></p>
<table BORDER=2 cellpadding=4> <table BORDER=2 cellpadding=4>
<tr> <tr>

View File

@ -48,7 +48,9 @@ string ControllerDetector::autodetectPort(const uInt8* image, uInt32 size,
// default type joystick // default type joystick
string type = "JOYSTICK"; // TODO: remove magic strings string type = "JOYSTICK"; // TODO: remove magic strings
if(usesJoystickButton(image, size, port)) if(isProbablySaveKey(image, size, port))
type = "SAVEKEY";
else if(usesJoystickButton(image, size, port))
{ {
if(isProbablyTrakBall(image, size)) if(isProbablyTrakBall(image, size))
type = "TRAKBALL"; type = "TRAKBALL";
@ -56,8 +58,8 @@ string ControllerDetector::autodetectPort(const uInt8* image, uInt32 size,
type = "ATARIMOUSE"; type = "ATARIMOUSE";
else if(isProbablyAmigaMouse(image, size)) else if(isProbablyAmigaMouse(image, size))
type = "AMIGAMOUSE"; type = "AMIGAMOUSE";
else if(usesPaddle(image, size, port, settings)) else if(usesKeyboard(image, size, port))
type = "KEYBOARD"; // only keyboard uses joystick and paddle buttons type = "KEYBOARD";
else if(usesGenesisButton(image, size, port)) else if(usesGenesisButton(image, size, port))
type = "GENESIS"; type = "GENESIS";
} }
@ -65,8 +67,6 @@ string ControllerDetector::autodetectPort(const uInt8* image, uInt32 size,
{ {
if(usesPaddle(image, size, port, settings)) if(usesPaddle(image, size, port, settings))
type = "PADDLES"; type = "PADDLES";
if (isProbablySaveKey(image, size, port))
type = "SAVEKEY";
} }
// TODO: BOOSTERGRIP, DRIVING, MINDLINK, ATARIVOX, KIDVID // TODO: BOOSTERGRIP, DRIVING, MINDLINK, ATARIVOX, KIDVID
// not detectable: PADDLES_IAXIS, PADDLES_IAXDR // not detectable: PADDLES_IAXIS, PADDLES_IAXDR
@ -123,15 +123,16 @@ bool ControllerDetector::usesJoystickButton(const uInt8* image, uInt32 size, Con
{ 0xa4, 0x0c, 0x30 }, // ldy INPT4|; bmi (only Game of Concentration) { 0xa4, 0x0c, 0x30 }, // ldy INPT4|; bmi (only Game of Concentration)
{ 0xa4, 0x3c, 0x30 }, // ldy INPT4|$30; bmi (only Game of Concentration) { 0xa4, 0x3c, 0x30 }, // ldy INPT4|$30; bmi (only Game of Concentration)
}; };
const int NUM_SIGS_1 = 4; const int NUM_SIGS_1 = 5;
const int SIG_SIZE_1 = 4; const int SIG_SIZE_1 = 4;
uInt8 signature_1[NUM_SIGS_1][SIG_SIZE_1] = { uInt8 signature_1[NUM_SIGS_1][SIG_SIZE_1] = {
{ 0xb9, 0x0c, 0x00, 0x10 }, // lda INPT4,y; bpl (joystick games only) { 0xb9, 0x0c, 0x00, 0x10 }, // lda INPT4,y; bpl (joystick games only)
{ 0xb9, 0x0c, 0x00, 0x30 }, // lda INPT4,y; bmi (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, 0x10 }, // lda INPT4,y; bpl (joystick games only)
{ 0xb9, 0x3c, 0x00, 0x30 }, // lda INPT4,y; bmi (joystick games only) { 0xb9, 0x3c, 0x00, 0x30 }, // lda INPT4,y; bmi (joystick games only)
{ 0xa5, 0x0c, 0x0a, 0xb0 }, // lda INPT4; asl; bcs (joystick games only)
}; };
const int NUM_SIGS_2 = 5; const int NUM_SIGS_2 = 7;
const int SIG_SIZE_2 = 5; const int SIG_SIZE_2 = 5;
uInt8 signature_2[NUM_SIGS_2][SIG_SIZE_2] = { 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, 0x10 }, // lda INPT4; and INPT5; bpl (joystick games only)
@ -139,6 +140,8 @@ bool ControllerDetector::usesJoystickButton(const uInt8* image, uInt32 size, Con
{ 0xa5, 0x3c, 0x25, 0x3d, 0x10 }, // lda INPT4|$30; and INPT5|$30; bpl (joystick games only) { 0xa5, 0x3c, 0x25, 0x3d, 0x10 }, // lda INPT4|$30; and INPT5|$30; bpl (joystick games only)
{ 0xa5, 0x3c, 0x25, 0x3d, 0x30 }, // lda INPT4|$30; and INPT5|$30; bmi (joystick games only) { 0xa5, 0x3c, 0x25, 0x3d, 0x30 }, // lda INPT4|$30; and INPT5|$30; bmi (joystick games only)
{ 0xb5, 0x38, 0x29, 0x80, 0xd0 }, // lda INPT0|$30,y; and #$80; bne (Basic Programming) { 0xb5, 0x38, 0x29, 0x80, 0xd0 }, // lda INPT0|$30,y; and #$80; bne (Basic Programming)
{ 0xa9, 0x80, 0x24, 0x0c, 0xd0 }, // lda #$80; bit INPT4; bne (bBasic)
{ 0xa5, 0x0c, 0x29, 0x80, 0xd0 }, // lda INPT4; and #$80, bne (joystick games only)
}; };
for(uInt32 i = 0; i < NUM_SIGS_0; ++i) for(uInt32 i = 0; i < NUM_SIGS_0; ++i)
@ -181,10 +184,11 @@ bool ControllerDetector::usesJoystickButton(const uInt8* image, uInt32 size, Con
{ 0xb9, 0x3c, 0x00, 0x10 }, // lda INPT4,y; bpl (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) { 0xb9, 0x3c, 0x00, 0x30 }, // lda INPT4,y; bmi (joystick games only)
}; };
const int NUM_SIGS_2 = 1; const int NUM_SIGS_2 = 2;
const int SIG_SIZE_2 = 5; const int SIG_SIZE_2 = 5;
uInt8 signature_2[NUM_SIGS_2][SIG_SIZE_2] = { uInt8 signature_2[NUM_SIGS_2][SIG_SIZE_2] = {
{ 0xb5, 0x38, 0x29, 0x80, 0xd0 }, // lda INPT0|$30,y; and #$80; bne (Basic Programming) { 0xb5, 0x38, 0x29, 0x80, 0xd0 }, // lda INPT0|$30,y; and #$80; bne (Basic Programming)
{ 0xa9, 0x80, 0x24, 0x0c, 0xd0 }, // lda #$80; bit INPT4; bne (bBasic)
}; };
for(uInt32 i = 0; i < NUM_SIGS_0; ++i) for(uInt32 i = 0; i < NUM_SIGS_0; ++i)
@ -202,6 +206,136 @@ bool ControllerDetector::usesJoystickButton(const uInt8* image, uInt32 size, Con
return false; return false;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::usesKeyboard(const uInt8* image, uInt32 size, Controller::Jack port)
{
if(port == Controller::Left)
{
// check for INPT0 *AND* INPT1 access
const int NUM_SIGS_0_0 = 4;
const int SIG_SIZE_0_0 = 3;
uInt8 signature_0_0[NUM_SIGS_0_0][SIG_SIZE_0_0] = {
{ 0x24, 0x38, 0x30 }, // bit INPT0|$30; bmi
{ 0xa5, 0x38, 0x10 }, // lda INPT0|$30; bpl
{ 0xa4, 0x38, 0x30 }, // ldy INPT0|$30; bmi
{ 0xb5, 0x38, 0x30 }, // lda INPT0|$30,x; bmi
};
const int NUM_SIGS_0_2 = 1;
const int SIG_SIZE_0_2 = 5;
uInt8 signature_0_2[NUM_SIGS_0_2][SIG_SIZE_0_2] = {
{ 0xb5, 0x38, 0x29, 0x80, 0xd0 }, // lda INPT0,x; and #80; bne
};
const int NUM_SIGS_1_0 = 5;
const int SIG_SIZE_1_0 = 3;
uInt8 signature_1_0[NUM_SIGS_1_0][SIG_SIZE_1_0] = {
{ 0x24, 0x39, 0x10 }, // bit INPT1|$30;
{ 0x24, 0x39, 0x30 }, // bit INPT1|$30;
{ 0xa5, 0x39, 0x10 }, // lda INPT1|$30;
{ 0xa4, 0x39, 0x30 }, // ldy INPT1|$30; bmi
{ 0xb5, 0x38, 0x30 }, // lda INPT0|$30,x; bmi
};
const int NUM_SIGS_1_2 = 1;
const int SIG_SIZE_1_2 = 5;
uInt8 signature_1_2[NUM_SIGS_1_2][SIG_SIZE_1_2] = {
{ 0xb5, 0x38, 0x29, 0x80, 0xd0 }, // lda INPT0,x; and #80; bne
};
bool found = false;
for(uInt32 i = 0; i < NUM_SIGS_0_0; ++i)
if(searchForBytes(image, size, signature_0_0[i], SIG_SIZE_0_0))
{
found = true;
break;
}
if(!found)
for(uInt32 i = 0; i < NUM_SIGS_0_2; ++i)
if(searchForBytes(image, size, signature_0_2[i], SIG_SIZE_0_2))
{
found = true;
break;
}
if(found)
{
for(uInt32 j = 0; j < NUM_SIGS_1_0; ++j)
if(searchForBytes(image, size, signature_1_0[j], SIG_SIZE_1_0))
{
return true;
}
for(uInt32 j = 0; j < NUM_SIGS_1_2; ++j)
if(searchForBytes(image, size, signature_1_2[j], SIG_SIZE_1_2))
{
return true;
}
}
}
else if(port == Controller::Right)
{
// check for INPT2 *AND* INPT3 access
const int NUM_SIGS_0_0 = 3;
const int SIG_SIZE_0_0 = 3;
uInt8 signature_0_0[NUM_SIGS_0_0][SIG_SIZE_0_0] = {
{ 0x24, 0x3a, 0x30 }, // bit INPT2|$30; bmi
{ 0xa5, 0x3a, 0x10 }, // lda INPT2|$30; bpl
{ 0xa4, 0x3a, 0x30 }, // ldy INPT2|$30; bmi
};
const int NUM_SIGS_0_2 = 1;
const int SIG_SIZE_0_2 = 5;
uInt8 signature_0_2[NUM_SIGS_0_2][SIG_SIZE_0_2] = {
{ 0xb5, 0x38, 0x29, 0x80, 0xd0 }, // lda INPT2,x; and #80; bne
};
const int NUM_SIGS_1_0 = 3;
const int SIG_SIZE_1_0 = 3;
uInt8 signature_1_0[NUM_SIGS_1_0][SIG_SIZE_1_0] = {
{ 0x24, 0x3b, 0x30 }, // bit INPT3|$30;
{ 0xa5, 0x3b, 0x10 }, // lda INPT3|$30;
{ 0xa4, 0x3b, 0x30 }, // ldy INPT3|$30; bmi
};
const int NUM_SIGS_1_2 = 1;
const int SIG_SIZE_1_2 = 5;
uInt8 signature_1_2[NUM_SIGS_1_2][SIG_SIZE_1_2] = {
{ 0xb5, 0x38, 0x29, 0x80, 0xd0 }, // lda INPT2,x; and #80; bne
};
bool found = false;
for(uInt32 i = 0; i < NUM_SIGS_0_0; ++i)
if(searchForBytes(image, size, signature_0_0[i], SIG_SIZE_0_0))
{
found = true;
break;
}
if(!found)
for(uInt32 i = 0; i < NUM_SIGS_0_2; ++i)
if(searchForBytes(image, size, signature_0_2[i], SIG_SIZE_0_2))
{
found = true;
break;
}
if(found)
{
for(uInt32 j = 0; j < NUM_SIGS_1_0; ++j)
if(searchForBytes(image, size, signature_1_0[j], SIG_SIZE_1_0))
{
return true;
}
for(uInt32 j = 0; j < NUM_SIGS_1_2; ++j)
if(searchForBytes(image, size, signature_1_2[j], SIG_SIZE_1_2))
{
return true;
}
}
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool ControllerDetector::usesGenesisButton(const uInt8* image, uInt32 size, Controller::Jack port) bool ControllerDetector::usesGenesisButton(const uInt8* image, uInt32 size, Controller::Jack port)
{ {

View File

@ -73,6 +73,9 @@ class ControllerDetector
// Returns true if the port's joystick button access code is found. // Returns true if the port's joystick button access code is found.
static bool usesJoystickButton(const uInt8* image, uInt32 size, Controller::Jack port); static bool usesJoystickButton(const uInt8* image, uInt32 size, Controller::Jack port);
// Returns true if the port's keyboard access code is found.
static bool usesKeyboard(const uInt8* image, uInt32 size, Controller::Jack port);
// Returns true if the port's 2nd Genesis button access code is found. // Returns true if the port's 2nd Genesis button access code is found.
static bool usesGenesisButton(const uInt8* image, uInt32 size, Controller::Jack port); static bool usesGenesisButton(const uInt8* image, uInt32 size, Controller::Jack port);