Beginnings of the user interface required to actually see

changes that are being made to key remapping.  I think that
the key remapping will work, but we won't know for sure
until the GUI is done and we can actually test it :)

The eventhandler depends on getting *KEYPRESS* events.
Specifically, a key press is not the same thing as a pressed
key :)  For example, the Windows and DOS ports scan the
keyboard and send the state 60 times per second.  So if a key
was pressed and held for 1 second, the Windows and DOS ports
will send 60 keypresses, when it should send only one.

Having a key pressed for 60 seconds IS NOT equivalent
to 60 keypresses.

This will have to be fixed in the frontend, most likely
by having 2 keyboard state arrays and only sending the
changes per update.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@189 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2003-09-25 16:20:34 +00:00
parent fe9a77090e
commit 1359d7a14f
9 changed files with 461 additions and 80 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Console.cxx,v 1.15 2003-09-19 15:45:01 stephena Exp $
// $Id: Console.cxx,v 1.16 2003-09-25 16:20:33 stephena Exp $
//============================================================================
#include <assert.h>
@ -42,6 +42,7 @@
#include "Switches.hxx"
#include "System.hxx"
#include "TIA.hxx"
#include "UserInterface.hxx"
#ifdef SNAPSHOT_SUPPORT
#include "Snapshot.hxx"
@ -166,6 +167,9 @@ Console::Console(const uInt8* image, uInt32 size, const char* filename,
// Remember what my media source is
myMediaSource = tia;
// Create the graphical user interface to draw menus, text, etc.
myUserInterface = new UserInterface(this, myMediaSource);
// Reset, the system to its power-on state
mySystem->reset();
}
@ -187,6 +191,7 @@ Console::~Console()
delete myControllers[0];
delete myControllers[1];
delete myEventHandler;
delete myUserInterface;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Console.hxx,v 1.11 2003-09-19 15:45:01 stephena Exp $
// $Id: Console.hxx,v 1.12 2003-09-25 16:20:33 stephena Exp $
//============================================================================
#ifndef CONSOLE_HXX
@ -30,6 +30,7 @@ class Snapshot;
class Sound;
class Switches;
class System;
class UserInterface;
#include "bspf.hxx"
#include "Control.hxx"
@ -40,7 +41,7 @@ class System;
This class represents the entire game console.
@author Bradford W. Mott
@version $Id: Console.hxx,v 1.11 2003-09-19 15:45:01 stephena Exp $
@version $Id: Console.hxx,v 1.12 2003-09-25 16:20:33 stephena Exp $
*/
class Console
{
@ -137,6 +138,16 @@ class Console
return *myEventHandler;
}
/**
Get the user interfacee of the console
@return The graphical user interface
*/
UserInterface& gui() const
{
return *myUserInterface;
}
public:
/**
Overloaded assignment operator
@ -247,6 +258,9 @@ class Console
// Pointer to the EventHandler object
EventHandler* myEventHandler;
// Pointer to the UserInterface object
UserInterface* myUserInterface;
private:
// Default properties to use for properties objects
static Properties ourDefaultProperties;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Event.hxx,v 1.3 2003-09-06 21:17:48 stephena Exp $
// $Id: Event.hxx,v 1.4 2003-09-25 16:20:34 stephena Exp $
//============================================================================
#ifndef EVENT_HXX
@ -25,7 +25,7 @@ class Event;
/**
@author Bradford W. Mott
@version $Id: Event.hxx,v 1.3 2003-09-06 21:17:48 stephena Exp $
@version $Id: Event.hxx,v 1.4 2003-09-25 16:20:34 stephena Exp $
*/
class Event
{
@ -35,6 +35,7 @@ class Event
*/
enum Type
{
NoType,
ConsoleOn, ConsoleOff, ConsoleColor, ConsoleBlackWhite,
ConsoleLeftDifficultyA, ConsoleLeftDifficultyB,
ConsoleRightDifficultyA, ConsoleRightDifficultyB,

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EventHandler.cxx,v 1.9 2003-09-23 00:58:31 stephena Exp $
// $Id: EventHandler.cxx,v 1.10 2003-09-25 16:20:34 stephena Exp $
//============================================================================
#include <algorithm>
@ -26,6 +26,7 @@
#include "Settings.hxx"
#include "StellaEvent.hxx"
#include "System.hxx"
#include "UserInterface.hxx"
#include "bspf.hxx"
#ifdef SNAPSHOT_SUPPORT
@ -35,7 +36,11 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandler::EventHandler(Console* console)
: myConsole(console),
myCurrentState(0)
myCurrentState(0),
myMenuStatus(false),
myReturnPressedFlag(false),
myRemapModeFlag(false),
myEventSelectedFlag(false)
{
Int32 i;
@ -44,12 +49,12 @@ EventHandler::EventHandler(Console* console)
// Erase the KeyEvent array
for(i = 0; i < StellaEvent::LastKCODE; ++i)
myKeyTable[i] = Event::LastType;
myKeyTable[i] = Event::NoType;
// Erase the JoyEvent array
for(i = 0; i < StellaEvent::LastJSTICK; ++i)
for(Int32 j = 0; j < StellaEvent::LastJCODE; ++j)
myJoyTable[i][j] = Event::LastType;
myJoyTable[i][j] = Event::NoType;
// Erase the Message array
for(i = 0; i < Event::LastType; ++i)
@ -72,6 +77,8 @@ EventHandler::~EventHandler()
{
if(myEvent)
delete myEvent;
myEvent = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -83,64 +90,90 @@ Event* EventHandler::event()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::sendKeyEvent(StellaEvent::KeyCode key, Int32 state)
{
Event::Type event = myKeyTable[key];
// Ignore unmapped events
if(event == Event::LastType)
return;
// Take care of special events that aren't technically part of
// the emulation core
if(state == 1)
// First check if we are entering menu mode
if(key == StellaEvent::KCODE_TAB && state == 1)
{
if(event == Event::SaveState)
{
saveState();
return;
}
else if(event == Event::ChangeState)
{
changeState();
return;
}
else if(event == Event::LoadState)
{
loadState();
return;
}
else if(event == Event::TakeSnapshot)
{
takeSnapshot();
return;
}
else if(event == Event::Pause)
{
myConsole->settings().setPauseEvent();
return;
}
else if(event == Event::Quit)
{
myConsole->settings().saveConfig();
myConsole->settings().setQuitEvent();
return;
}
myMenuStatus = !myMenuStatus;
myConsole->gui().showMainMenu(myMenuStatus);
if(!myMenuStatus)
myReturnPressedFlag = myRemapModeFlag = myEventSelectedFlag = false;
if(ourMessageTable[event] != "")
myConsole->mediaSource().showMessage(ourMessageTable[event], 120);
return;
}
// Otherwise, pass it to the emulation core
myEvent->set(event, state);
// Determine where the event should be sent
if(myMenuStatus && state == 1)
{
if(key == StellaEvent::KCODE_RETURN)
myReturnPressedFlag = true;
processMenuEvent(key);
}
else
{
sendEvent(myKeyTable[key], state);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::processMenuEvent(StellaEvent::KeyCode key)
{
if(myRemapModeFlag && myEventSelectedFlag)
{
if(key == StellaEvent::KCODE_ESCAPE)
// associate nothing with the selected event
cerr << "delete binding for " << mySelectedEvent << endl;
else
// associate this stellaevent with the selected event
cerr << "add binding " << key << " for " << mySelectedEvent << endl;
myReturnPressedFlag = myEventSelectedFlag = false;
}
else if(myReturnPressedFlag && myRemapModeFlag)
{
cerr << "return pressed while in remap mode\n";
mySelectedEvent = Event::ConsoleSelect; // FIXME - get from gui() which event is currently selected
myEventSelectedFlag = true;
myReturnPressedFlag = false;
}
else if(myReturnPressedFlag)
{
// FIXME - get selected menu
if(1)//menu == REMAP)
{
// draw remap menu
cerr << "entering remap mode\n";
myRemapModeFlag = true;
}
/* else if(1)//menu == INFO)
{
// draw info menu
}
*/
myReturnPressedFlag = false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::sendJoyEvent(StellaEvent::JoyStick stick,
StellaEvent::JoyCode code, Int32 state)
{
Event::Type event = myJoyTable[stick][code];
// Determine where the event should be sent
if(myMenuStatus && state == 1)
{
cerr << "send joy event to remap class\n";
}
else
{
sendEvent(myJoyTable[stick][code], state);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::sendEvent(Event::Type event, Int32 state)
{
// Ignore unmapped events
if(event == Event::LastType)
if(event == Event::NoType)
return;
// Take care of special events that aren't technically part of
@ -187,26 +220,6 @@ void EventHandler::sendJoyEvent(StellaEvent::JoyStick stick,
myEvent->set(event, state);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::sendEvent(Event::Type event, Int32 state)
{
// Take care of special events that aren't technically part of
// the emulation core
if(event == Event::Pause && state == 1)
{
myConsole->settings().setPauseEvent();
return;
}
else if(event == Event::Quit && state == 1)
{
myConsole->settings().saveConfig();
myConsole->settings().setQuitEvent();
return;
}
myEvent->set(event, state);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setKeymap()
{

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EventHandler.hxx,v 1.6 2003-09-12 18:08:53 stephena Exp $
// $Id: EventHandler.hxx,v 1.7 2003-09-25 16:20:34 stephena Exp $
//============================================================================
#ifndef EVENTHANDLER_HXX
@ -40,7 +40,7 @@ class MediaSource;
unchanged to the remap class, where key remapping can take place.
@author Stephen Anthony
@version $Id: EventHandler.hxx,v 1.6 2003-09-12 18:08:53 stephena Exp $
@version $Id: EventHandler.hxx,v 1.7 2003-09-25 16:20:34 stephena Exp $
*/
class EventHandler
{
@ -124,6 +124,9 @@ class EventHandler
void loadState();
void takeSnapshot();
void processMenuEvent(StellaEvent::KeyCode key);
// void processMenuEvent(StellaEvent::JoyStick stick, StellaEvent::JoyCode code);
private:
// Array of key events
Event::Type myKeyTable[StellaEvent::LastKCODE];
@ -154,6 +157,15 @@ class EventHandler
// The current joymap in string form
string myJoymapString;
// Indicates that a menu should be entered
bool myMenuStatus;
// These are used for the state machine that processes menu events
bool myReturnPressedFlag, myRemapModeFlag, myEventSelectedFlag;
//
Event::Type mySelectedEvent;
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Settings.cxx,v 1.8 2003-09-23 17:27:11 stephena Exp $
// $Id: Settings.cxx,v 1.9 2003-09-25 16:20:34 stephena Exp $
//============================================================================
#include <assert.h>
@ -153,6 +153,10 @@ void Settings::saveConfig()
return;
}
// Make sure that any modifications to key remapping is saved
set("keymap", myConsole->eventHandler().getKeymap());
set("joymap", myConsole->eventHandler().getJoymap());
out << "; Stella configuration file" << endl
<< ";" << endl
<< "; Lines starting with ';' are comments and are ignored." << endl

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: StellaEvent.hxx,v 1.2 2003-09-06 21:17:48 stephena Exp $
// $Id: StellaEvent.hxx,v 1.3 2003-09-25 16:20:34 stephena Exp $
//============================================================================
#ifndef STELLAEVENT_HXX
@ -28,7 +28,7 @@
by the frontends directly.
@author Stephen Anthony
@version $Id: StellaEvent.hxx,v 1.2 2003-09-06 21:17:48 stephena Exp $
@version $Id: StellaEvent.hxx,v 1.3 2003-09-25 16:20:34 stephena Exp $
*/
class StellaEvent
{
@ -38,6 +38,7 @@ class StellaEvent
*/
enum KeyCode
{
KCODE_NONE,
KCODE_a, KCODE_b, KCODE_c, KCODE_d, KCODE_e, KCODE_f, KCODE_g, KCODE_h,
KCODE_i, KCODE_j, KCODE_k, KCODE_l, KCODE_m, KCODE_n, KCODE_o, KCODE_p,
KCODE_q, KCODE_r, KCODE_s, KCODE_t, KCODE_u, KCODE_v, KCODE_w, KCODE_x,
@ -69,12 +70,14 @@ class StellaEvent
*/
enum JoyStick
{
JSTICK_NONE,
JSTICK_0, JSTICK_1, JSTICK_2, JSTICK_3,
LastJSTICK
};
enum JoyCode
{
JCODE_NONE,
JAXIS_UP, JAXIS_DOWN, JAXIS_LEFT, JAXIS_RIGHT,
JBUTTON_0, JBUTTON_1, JBUTTON_2, JBUTTON_3, JBUTTON_4,
JBUTTON_5, JBUTTON_6, JBUTTON_7, JBUTTON_8, JBUTTON_9,

View File

@ -0,0 +1,239 @@
//============================================================================
//
// 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-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: UserInterface.cxx,v 1.1 2003-09-25 16:20:34 stephena Exp $
//============================================================================
#include "bspf.hxx"
#include "Console.hxx"
#include "Settings.hxx"
#include "MediaSrc.hxx"
#include "UserInterface.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
UserInterface::UserInterface(Console* console, MediaSource* mediasrc)
: myConsole(console),
myMediaSource(mediasrc),
myIsBufferDirtyFlag(true)
{
myMenuBuffer = new uInt8[160 * 300];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
UserInterface::~UserInterface(void)
{
// FIXME
cerr << "UserInterface::~UserInterface called\n";
delete[] myMenuBuffer;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UserInterface::showMainMenu(bool show)
{
if(show)
cerr << "Menu entered ...\n";
else
cerr << "Menu exit.\n";
return;
/* uInt8* frontbuffer = myMediaSource->currentFrameBuffer();
uInt8* backbuffer = myMediaSource->previousFrameBuffer();
// First, draw the surrounding box
for(uInt32 x = 0; x < 100; ++x)
{
for(uInt32 y = 0; y < 100; ++y)
{
uInt32 position = ((20 + y) * myWidth) + x + 20;
if((x == 0) || (x == 200 - 1) || (y == 0) || (y == 200 - 1))
frontbuffer[position] = backbuffer[position] = 10;
else
frontbuffer[position] = backbuffer[position] = 0;
}
}*/
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UserInterface::setXStart(uInt32 value)
{
myXStart = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UserInterface::setYStart(uInt32 value)
{
myYStart = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UserInterface::setWidth(uInt32 value)
{
myWidth = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UserInterface::setHeight(uInt32 value)
{
myHeight = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*void UserInterface::cls()
{
cerr << "UserInterface::cls() called\n";
uInt8* frontbuffer = myMediaSource->currentFrameBuffer();
uInt8* backbuffer = myMediaSource->previousFrameBuffer();
for(uInt32 i = 0; i < 160*300; ++i)
frontbuffer[i] = backbuffer[i] = (uInt8) 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UserInterface::drawMessageText(string& message)
{
// First, get access to the framebuffer
uInt8* buffer = myMediaSource->currentFrameBuffer();
// Make message uppercase, since there are no lowercase fonts defined
uInt8 length = message.length();
for(uInt32 i = 0; i < length; ++i)
message[i] = toupper(message[i]);
// Set up the correct coordinates to draw the surrounding box
uInt32 xBoxOffSet = 2 + myXStart;
uInt32 yBoxOffSet = myHeight - 18;
uInt32 boxToTextXOffSet = 2;
uInt32 boxToTextYOffSet = 4;
// Set up the correct coordinates to print the message
uInt32 xTextOffSet = xBoxOffSet + boxToTextXOffSet;
uInt32 yTextOffSet = yBoxOffSet + boxToTextYOffSet;
// Used to indicate the current x/y position of a pixel
uInt32 xPos, yPos;
// The actual font data for a letter
uInt32 data;
// The index into the palette to color the current text and background
uInt8 fontColor, backColor;
// These will probably change in the future ...
fontColor = 10;
backColor = 0;
// Clip the length if its wider than the screen
// uInt8 length = message.length();
if(((length * 5) + xTextOffSet) >= myWidth)
length = (myWidth - xTextOffSet) / 5;
// Reset the offsets to center the message
uInt32 boxWidth = (5 * length) + boxToTextXOffSet;
uInt32 boxHeight = 8 + (2 * (yTextOffSet - yBoxOffSet));
xBoxOffSet = (myWidth >> 1) - (boxWidth >> 1);
xTextOffSet = xBoxOffSet + boxToTextXOffSet;
// First, draw the surrounding box
for(uInt32 x = 0; x < boxWidth; ++x)
{
for(uInt32 y = 0; y < boxHeight; ++y)
{
uInt32 position = ((yBoxOffSet + y) * myWidth) + x + xBoxOffSet;
if((x == 0) || (x == boxWidth - 1) || (y == 0) || (y == boxHeight - 1))
buffer[position] = fontColor;
else
buffer[position] = backColor;
}
}
// Then, draw the text
for(uInt8 x = 0; x < length; ++x)
{
char letter = message[x];
if((letter >= 'A') && (letter <= 'Z'))
data = ourFontData[(int)letter - 65];
else if((letter >= '0') && (letter <= '9'))
data = ourFontData[(int)letter - 48 + 26];
else // unknown character or space
{
xTextOffSet += 3;
continue;
}
// start scanning the font data from the bottom up
yPos = 7;
for(uInt8 y = 0; y < 32; ++y)
{
// determine the correct scanline
xPos = y % 4;
if(xPos == 0)
--yPos;
if((data >> y) & 1)
{
uInt32 position = (yPos + yTextOffSet) * myWidth + (4 - xPos) + xTextOffSet;
buffer[position] = fontColor;
}
}
// move left to the next character
xTextOffSet += 5;
}
}
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt32 UserInterface::ourFontData[36] = {
0x699f999, // A
0xe99e99e, // B
0x6988896, // C
0xe99999e, // D
0xf88e88f, // E
0xf88e888, // F
0x698b996, // G
0x999f999, // H
0x7222227, // I
0x72222a4, // J
0x9accaa9, // K
0x888888f, // L
0x9ff9999, // M
0x9ddbb99, // N
0x6999996, // O
0xe99e888, // P
0x69999b7, // Q
0xe99ea99, // R
0x6986196, // S
0x7222222, // T
0x9999996, // U
0x9999966, // V
0x9999ff9, // W
0x99fff99, // X
0x9996244, // Y
0xf12488f, // Z
0x69bd996, // 0
0x2622227, // 1
0x691248f, // 2
0x6916196, // 3
0xaaaf222, // 4
0xf88e11e, // 5
0x698e996, // 6
0xf112244, // 7
0x6996996, // 8
0x6997196 // 9
};

View File

@ -0,0 +1,90 @@
//============================================================================
//
// 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-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: UserInterface.hxx,v 1.1 2003-09-25 16:20:34 stephena Exp $
//============================================================================
#ifndef USERINTERFACE_HXX
#define USERINTERFACE_HXX
#include "bspf.hxx"
class Console;
class MediaSource;
/**
This class implements a MAME-like user interface where Stella settings
can be changed.
@author Stephen Anthony
@version $Id: UserInterface.hxx,v 1.1 2003-09-25 16:20:34 stephena Exp $
*/
class UserInterface
{
public:
/**
Creates a new User Interface
@param console The Console object
@param mediasrc The MediaSource object to draw into
*/
UserInterface(Console* console, MediaSource* mediasrc);
/**
Destructor
*/
virtual ~UserInterface(void);
// @param key The key of the property to lookup
// @return The value of the property
public:
void setXStart(uInt32 value);
void setYStart(uInt32 value);
void setWidth(uInt32 value);
void setHeight(uInt32 value);
// void drawMessageText(string& message);
void showMainMenu(bool show);
void showRemapMenu(bool show);
void showInfoMenu(bool show);
private:
// Enumerations representing the different types of menus
enum MenuType { MENU_REMAP, MENU_INFO };
private:
// The Console for the system
Console* myConsole;
// The Mediasource for the system
MediaSource* myMediaSource;
// A buffer containing the current menu to be drawn
uInt8* myMenuBuffer;
// Bounds for the window frame
uInt32 myXStart, myYStart, myWidth, myHeight;
// Table of bitmapped fonts. Holds A..Z and 0..9.
static const uInt32 ourFontData[36];
// Indicates if buffers are dirty (have been modified)
bool myIsBufferDirtyFlag;
};
#endif