Use QGamepad in QApple.
This requires an interface as napple uses libevdev. Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
This commit is contained in:
parent
6ec2408e44
commit
348ba1ecd9
15 changed files with 381 additions and 192 deletions
|
@ -27,7 +27,7 @@ add_library(appleii SHARED
|
||||||
source/linux/wwrapper.cpp
|
source/linux/wwrapper.cpp
|
||||||
source/linux/state.cpp
|
source/linux/state.cpp
|
||||||
source/linux/benchmark.cpp
|
source/linux/benchmark.cpp
|
||||||
source/linux/joy_input.cpp
|
source/linux/paddle.cpp
|
||||||
|
|
||||||
source/Z80VICE/z80.cpp
|
source/Z80VICE/z80.cpp
|
||||||
source/Z80VICE/z80mem.cpp
|
source/Z80VICE/z80mem.cpp
|
||||||
|
@ -44,6 +44,7 @@ add_executable(applen
|
||||||
source/frontends/ncurses/main.cpp
|
source/frontends/ncurses/main.cpp
|
||||||
source/frontends/ncurses/world.cpp
|
source/frontends/ncurses/world.cpp
|
||||||
source/frontends/ncurses/colors.cpp
|
source/frontends/ncurses/colors.cpp
|
||||||
|
source/frontends/ncurses/evdevpaddle.cpp
|
||||||
source/frontends/ncurses/nframe.cpp
|
source/frontends/ncurses/nframe.cpp
|
||||||
source/frontends/ncurses/asciiart.cpp
|
source/frontends/ncurses/asciiart.cpp
|
||||||
source/frontends/ncurses/resources.cpp
|
source/frontends/ncurses/resources.cpp
|
||||||
|
|
107
source/frontends/ncurses/evdevpaddle.cpp
Normal file
107
source/frontends/ncurses/evdevpaddle.cpp
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#include "frontends/ncurses/evdevpaddle.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libevdev/libevdev.h>
|
||||||
|
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
EvDevPaddle::EvDevPaddle(const std::string & device)
|
||||||
|
: myButtonCodes(2), myAxisCodes(2), myAxisMins(2), myAxisMaxs(2)
|
||||||
|
{
|
||||||
|
myFD = open(device.c_str(), O_RDONLY | O_NONBLOCK);
|
||||||
|
if (myFD > 0)
|
||||||
|
{
|
||||||
|
libevdev * dev;
|
||||||
|
int rc = libevdev_new_from_fd(myFD, &dev);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
LogFileOutput("Input: failed to init libevdev (%s): %s\n", strerror(-rc), device.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
myDev.reset(dev, libevdev_free);
|
||||||
|
|
||||||
|
myName = libevdev_get_name(dev);
|
||||||
|
|
||||||
|
myButtonCodes[0] = BTN_SOUTH;
|
||||||
|
myButtonCodes[1] = BTN_EAST;
|
||||||
|
myAxisCodes[0] = ABS_X;
|
||||||
|
myAxisCodes[1] = ABS_Y;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < myAxisCodes.size(); ++i)
|
||||||
|
{
|
||||||
|
myAxisMins[i] = libevdev_get_abs_minimum(dev, myAxisCodes[i]);
|
||||||
|
myAxisMaxs[i] = libevdev_get_abs_maximum(dev, myAxisCodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogFileOutput("Input: failed to open device (%s): %s\n", strerror(errno), device.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EvDevPaddle::~EvDevPaddle()
|
||||||
|
{
|
||||||
|
if (myFD > 0)
|
||||||
|
{
|
||||||
|
close(myFD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int EvDevPaddle::poll()
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
if (!myDev)
|
||||||
|
{
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_event ev;
|
||||||
|
int rc = LIBEVDEV_READ_STATUS_SUCCESS;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (rc == LIBEVDEV_READ_STATUS_SYNC)
|
||||||
|
rc = libevdev_next_event(myDev.get(), LIBEVDEV_READ_FLAG_SYNC, &ev);
|
||||||
|
else
|
||||||
|
rc = libevdev_next_event(myDev.get(), LIBEVDEV_READ_FLAG_NORMAL, &ev);
|
||||||
|
++counter;
|
||||||
|
} while (rc >= 0);
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string & EvDevPaddle::getName() const
|
||||||
|
{
|
||||||
|
return myName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EvDevPaddle::getButton(int i) const
|
||||||
|
{
|
||||||
|
int value = 0;
|
||||||
|
if (myDev)
|
||||||
|
{
|
||||||
|
int rc = libevdev_fetch_event_value(myDev.get(), EV_KEY, myButtonCodes[i], &value);
|
||||||
|
}
|
||||||
|
return value != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EvDevPaddle::getAxis(int i) const
|
||||||
|
{
|
||||||
|
if (myDev)
|
||||||
|
{
|
||||||
|
int value = 0;
|
||||||
|
int rc = libevdev_fetch_event_value(myDev.get(), EV_ABS, myAxisCodes[i], &value);
|
||||||
|
int pdl = 255 * (value - myAxisMins[i]) / (myAxisMaxs[i] - myAxisMins[i]);
|
||||||
|
return pdl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,26 +1,24 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "linux/paddle.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct libevdev;
|
struct libevdev;
|
||||||
struct input_event;
|
struct input_event;
|
||||||
|
|
||||||
class Input
|
class EvDevPaddle : public Paddle
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Input(const std::string & device);
|
EvDevPaddle(const std::string & device);
|
||||||
~Input();
|
~EvDevPaddle();
|
||||||
|
|
||||||
int poll();
|
int poll();
|
||||||
|
|
||||||
bool getButton(int i) const;
|
const std::string & getName() const;
|
||||||
int getAxis(int i) const;
|
virtual bool getButton(int i) const;
|
||||||
|
virtual int getAxis(int i) const;
|
||||||
static void initialise(const std::string & device);
|
|
||||||
|
|
||||||
static Input & instance();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int myFD;
|
int myFD;
|
||||||
|
@ -28,10 +26,10 @@ private:
|
||||||
|
|
||||||
void process(const input_event & ev);
|
void process(const input_event & ev);
|
||||||
|
|
||||||
|
std::string myName;
|
||||||
|
|
||||||
std::vector<unsigned int> myButtonCodes;
|
std::vector<unsigned int> myButtonCodes;
|
||||||
std::vector<unsigned int> myAxisCodes;
|
std::vector<unsigned int> myAxisCodes;
|
||||||
std::vector<int> myAxisMins;
|
std::vector<int> myAxisMins;
|
||||||
std::vector<int> myAxisMaxs;
|
std::vector<int> myAxisMaxs;
|
||||||
|
|
||||||
static std::shared_ptr<Input> ourSingleton;
|
|
||||||
};
|
};
|
|
@ -13,11 +13,12 @@
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
|
|
||||||
#include "linux/interface.h"
|
#include "linux/interface.h"
|
||||||
#include "linux/joy_input.h"
|
#include "linux/paddle.h"
|
||||||
|
|
||||||
#include "frontends/ncurses/nframe.h"
|
#include "frontends/ncurses/nframe.h"
|
||||||
#include "frontends/ncurses/colors.h"
|
#include "frontends/ncurses/colors.h"
|
||||||
#include "frontends/ncurses/asciiart.h"
|
#include "frontends/ncurses/asciiart.h"
|
||||||
|
#include "frontends/ncurses/evdevpaddle.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -25,6 +26,7 @@ namespace
|
||||||
std::shared_ptr<Frame> frame;
|
std::shared_ptr<Frame> frame;
|
||||||
std::shared_ptr<GraphicsColors> colors;
|
std::shared_ptr<GraphicsColors> colors;
|
||||||
std::shared_ptr<ASCIIArt> asciiArt;
|
std::shared_ptr<ASCIIArt> asciiArt;
|
||||||
|
std::shared_ptr<EvDevPaddle> paddle;
|
||||||
|
|
||||||
int g_nTrackDrive1 = -1;
|
int g_nTrackDrive1 = -1;
|
||||||
int g_nTrackDrive2 = -1;
|
int g_nTrackDrive2 = -1;
|
||||||
|
@ -372,7 +374,10 @@ void VideoInitialize()
|
||||||
|
|
||||||
frame.reset(new Frame());
|
frame.reset(new Frame());
|
||||||
asciiArt.reset(new ASCIIArt());
|
asciiArt.reset(new ASCIIArt());
|
||||||
Input::initialise("/dev/input/by-id/usb-©Microsoft_Corporation_Controller_1BBE3DB-event-joystick");
|
|
||||||
|
paddle.reset(new EvDevPaddle("/dev/input/by-id/usb-©Microsoft_Corporation_Controller_1BBE3DB-event-joystick"));
|
||||||
|
|
||||||
|
Paddle::instance() = paddle;
|
||||||
|
|
||||||
signal(SIGINT, sig_handler);
|
signal(SIGINT, sig_handler);
|
||||||
}
|
}
|
||||||
|
@ -515,7 +520,7 @@ int ProcessKeyboard()
|
||||||
|
|
||||||
void ProcessInput()
|
void ProcessInput()
|
||||||
{
|
{
|
||||||
Input::instance().poll();
|
paddle->poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
BYTE KeybGetKeycode ()
|
BYTE KeybGetKeycode ()
|
||||||
|
|
38
source/frontends/qapple/gamepadpaddle.cpp
Normal file
38
source/frontends/qapple/gamepadpaddle.cpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include "gamepadpaddle.h"
|
||||||
|
|
||||||
|
GamepadPaddle::GamepadPaddle(const std::shared_ptr<QGamepad> & gamepad) : myGamepad(gamepad)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GamepadPaddle::getButton(int i) const
|
||||||
|
{
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return myGamepad->buttonA();
|
||||||
|
case 1:
|
||||||
|
return myGamepad->buttonB();
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GamepadPaddle::getAxis(int i) const
|
||||||
|
{
|
||||||
|
double value;
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
value = myGamepad->axisLeftX();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
value = myGamepad->axisLeftY();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int pdl = int((value + 1.0) / 2.0 * 255.0);
|
||||||
|
return pdl;
|
||||||
|
}
|
20
source/frontends/qapple/gamepadpaddle.h
Normal file
20
source/frontends/qapple/gamepadpaddle.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef GAMEPADPADDLE_H
|
||||||
|
#define GAMEPADPADDLE_H
|
||||||
|
|
||||||
|
#include <QGamepad>
|
||||||
|
|
||||||
|
#include "linux/paddle.h"
|
||||||
|
|
||||||
|
class GamepadPaddle : public Paddle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GamepadPaddle(const std::shared_ptr<QGamepad> & gamepad);
|
||||||
|
|
||||||
|
virtual bool getButton(int i) const;
|
||||||
|
virtual int getAxis(int i) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::shared_ptr<QGamepad> myGamepad;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GAMEPADPADDLE_H
|
|
@ -1,5 +1,6 @@
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
#include <QtGamepad/QGamepad>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -105,6 +106,32 @@ Preferences::Preferences(QWidget *parent) :
|
||||||
myHDs.push_back(hd2);
|
myHDs.push_back(hd2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Preferences::setup(const Data & data, const boost::property_tree::ptree & registry)
|
||||||
|
{
|
||||||
|
populateJoysticks();
|
||||||
|
setData(data);
|
||||||
|
setRegistry(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Preferences::populateJoysticks()
|
||||||
|
{
|
||||||
|
joystick->clear();
|
||||||
|
const QList<int> gamepads = QGamepadManager::instance()->connectedGamepads();
|
||||||
|
|
||||||
|
joystick->addItem("None");
|
||||||
|
|
||||||
|
for (int id : gamepads)
|
||||||
|
{
|
||||||
|
QGamepad gp(id);
|
||||||
|
QString name = gp.name();
|
||||||
|
if (name.isEmpty())
|
||||||
|
{
|
||||||
|
name = QString::number(id);
|
||||||
|
}
|
||||||
|
joystick->addItem(name, QVariant::fromValue(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Preferences::setRegistry(const boost::property_tree::ptree & registry)
|
void Preferences::setRegistry(const boost::property_tree::ptree & registry)
|
||||||
{
|
{
|
||||||
registryTree->clear();
|
registryTree->clear();
|
||||||
|
@ -126,6 +153,8 @@ void Preferences::setData(const Data & data)
|
||||||
|
|
||||||
// synchronise
|
// synchronise
|
||||||
on_hd_7_clicked(data.hdInSlot7);
|
on_hd_7_clicked(data.hdInSlot7);
|
||||||
|
|
||||||
|
joystick->setCurrentText(data.joystick);
|
||||||
}
|
}
|
||||||
|
|
||||||
Preferences::Data Preferences::getData() const
|
Preferences::Data Preferences::getData() const
|
||||||
|
@ -139,6 +168,13 @@ Preferences::Data Preferences::getData() const
|
||||||
data.mouseInSlot4 = mouse_4->isChecked();
|
data.mouseInSlot4 = mouse_4->isChecked();
|
||||||
data.cpmInSlot5 = cpm_5->isChecked();
|
data.cpmInSlot5 = cpm_5->isChecked();
|
||||||
data.hdInSlot7 = hd_7->isChecked();
|
data.hdInSlot7 = hd_7->isChecked();
|
||||||
|
data.joystick = joystick->currentText();
|
||||||
|
|
||||||
|
if (joystick->currentIndex() >= 1)
|
||||||
|
{
|
||||||
|
const QVariant & device = joystick->itemData(joystick->currentIndex());
|
||||||
|
data.joystickId = device.toInt();
|
||||||
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,17 @@ public:
|
||||||
bool mouseInSlot4;
|
bool mouseInSlot4;
|
||||||
bool cpmInSlot5;
|
bool cpmInSlot5;
|
||||||
bool hdInSlot7;
|
bool hdInSlot7;
|
||||||
|
|
||||||
|
QString joystick;
|
||||||
|
int joystickId; // only putput
|
||||||
|
|
||||||
std::vector<QString> disks;
|
std::vector<QString> disks;
|
||||||
std::vector<QString> hds;
|
std::vector<QString> hds;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Preferences(QWidget *parent);
|
explicit Preferences(QWidget *parent);
|
||||||
|
|
||||||
void setRegistry(const boost::property_tree::ptree & registry);
|
void setup(const Data & data, const boost::property_tree::ptree & registry);
|
||||||
void setData(const Data & data);
|
|
||||||
Data getData() const;
|
Data getData() const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -45,6 +48,9 @@ private:
|
||||||
std::vector<QComboBox *> myDisks;
|
std::vector<QComboBox *> myDisks;
|
||||||
std::vector<QComboBox *> myHDs;
|
std::vector<QComboBox *> myHDs;
|
||||||
|
|
||||||
|
void setRegistry(const boost::property_tree::ptree & registry);
|
||||||
|
void setData(const Data & data);
|
||||||
|
void populateJoysticks();
|
||||||
void browseDisk(const std::vector<QComboBox *> & disks, const size_t id);
|
void browseDisk(const std::vector<QComboBox *> & disks, const size_t id);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -145,6 +145,16 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Joystick</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="joystick"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -17,10 +17,11 @@
|
||||||
#include "linux/data.h"
|
#include "linux/data.h"
|
||||||
#include "linux/configuration.h"
|
#include "linux/configuration.h"
|
||||||
#include "linux/benchmark.h"
|
#include "linux/benchmark.h"
|
||||||
#include "linux/joy_input.h"
|
#include "linux/paddle.h"
|
||||||
|
|
||||||
#include "emulator.h"
|
#include "emulator.h"
|
||||||
#include "memorycontainer.h"
|
#include "memorycontainer.h"
|
||||||
|
#include "gamepadpaddle.h"
|
||||||
|
|
||||||
#include <QMdiSubWindow>
|
#include <QMdiSubWindow>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
@ -34,7 +35,6 @@ namespace
|
||||||
setbuf(g_fh, NULL);
|
setbuf(g_fh, NULL);
|
||||||
|
|
||||||
InitializeRegistry("../qapple/applen.conf");
|
InitializeRegistry("../qapple/applen.conf");
|
||||||
Input::initialise("/dev/input/by-id/usb-©Microsoft_Corporation_Controller_1BBE3DB-event-joystick");
|
|
||||||
|
|
||||||
LogFileOutput("Initialisation\n");
|
LogFileOutput("Initialisation\n");
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ void QApple::on_timer()
|
||||||
g_dwCyclesThisFrame -= dwClksPerFrame;
|
g_dwCyclesThisFrame -= dwClksPerFrame;
|
||||||
myEmulator->redrawScreen();
|
myEmulator->redrawScreen();
|
||||||
}
|
}
|
||||||
Input::instance().poll();
|
//Input::instance().poll();
|
||||||
}
|
}
|
||||||
while (DiskIsSpinning());
|
while (DiskIsSpinning());
|
||||||
}
|
}
|
||||||
|
@ -314,8 +314,13 @@ void QApple::on_actionOptions_triggered()
|
||||||
|
|
||||||
currentOptions.apple2Type = getApple2ComputerType();
|
currentOptions.apple2Type = getApple2ComputerType();
|
||||||
|
|
||||||
myPreferences.setData(currentOptions);
|
if (myGamepad)
|
||||||
myPreferences.setRegistry(getProperties());
|
{
|
||||||
|
currentOptions.joystick = myGamepad->name();
|
||||||
|
currentOptions.joystickId = myGamepad->deviceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
myPreferences.setup(currentOptions, getProperties());
|
||||||
|
|
||||||
if (myPreferences.exec())
|
if (myPreferences.exec())
|
||||||
{
|
{
|
||||||
|
@ -347,6 +352,20 @@ void QApple::on_actionOptions_triggered()
|
||||||
HD_SetEnabled(newOptions.hdInSlot7);
|
HD_SetEnabled(newOptions.hdInSlot7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newOptions.joystick.isEmpty())
|
||||||
|
{
|
||||||
|
myGamepad.reset();
|
||||||
|
Paddle::instance() = std::make_shared<Paddle>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (newOptions.joystickId != currentOptions.joystickId)
|
||||||
|
{
|
||||||
|
myGamepad.reset(new QGamepad(newOptions.joystickId));
|
||||||
|
Paddle::instance() = std::make_shared<GamepadPaddle>(myGamepad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < diskIDs.size(); ++i)
|
for (size_t i = 0; i < diskIDs.size(); ++i)
|
||||||
{
|
{
|
||||||
if (currentOptions.disks[i] != newOptions.disks[i])
|
if (currentOptions.disks[i] != newOptions.disks[i])
|
||||||
|
@ -362,6 +381,7 @@ void QApple::on_actionOptions_triggered()
|
||||||
insertHD(newOptions.hds[i], hdIDs[i]);
|
insertHD(newOptions.hds[i], hdIDs[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "ui_qapple.h"
|
#include "ui_qapple.h"
|
||||||
|
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
|
#include <QGamepad>
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
|
|
||||||
class Emulator;
|
class Emulator;
|
||||||
|
@ -52,6 +53,7 @@ private:
|
||||||
|
|
||||||
QElapsedTimer myElapsedTimer;
|
QElapsedTimer myElapsedTimer;
|
||||||
QMdiSubWindow * myEmulatorWindow;
|
QMdiSubWindow * myEmulatorWindow;
|
||||||
|
std::shared_ptr<QGamepad> myGamepad;
|
||||||
Emulator * myEmulator;
|
Emulator * myEmulator;
|
||||||
|
|
||||||
int myMSGap;
|
int myMSGap;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
QT += core gui
|
QT += core gui
|
||||||
|
|
||||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets gamepad
|
||||||
|
|
||||||
TARGET = qapple
|
TARGET = qapple
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
|
@ -22,7 +22,8 @@ SOURCES += main.cpp\
|
||||||
commands.cpp \
|
commands.cpp \
|
||||||
qhexedit.cpp \
|
qhexedit.cpp \
|
||||||
memorycontainer.cpp \
|
memorycontainer.cpp \
|
||||||
preferences.cpp
|
preferences.cpp \
|
||||||
|
gamepadpaddle.cpp
|
||||||
|
|
||||||
HEADERS += qapple.h \
|
HEADERS += qapple.h \
|
||||||
emulator.h \
|
emulator.h \
|
||||||
|
@ -32,7 +33,8 @@ HEADERS += qapple.h \
|
||||||
commands.h \
|
commands.h \
|
||||||
qhexedit.h \
|
qhexedit.h \
|
||||||
memorycontainer.h \
|
memorycontainer.h \
|
||||||
preferences.h
|
preferences.h \
|
||||||
|
gamepadpaddle.h
|
||||||
|
|
||||||
FORMS += qapple.ui \
|
FORMS += qapple.ui \
|
||||||
emulator.ui \
|
emulator.ui \
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
#include "StdAfx.h"
|
|
||||||
|
|
||||||
#include "linux/joy_input.h"
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <libevdev/libevdev.h>
|
|
||||||
|
|
||||||
#include "Log.h"
|
|
||||||
#include "Memory.h"
|
|
||||||
#include "Common.h"
|
|
||||||
#include "CPU.h"
|
|
||||||
|
|
||||||
unsigned __int64 g_nJoyCntrResetCycle = 0; // Abs cycle that joystick counters were reset
|
|
||||||
const double PDL_CNTR_INTERVAL = 2816.0 / 255.0; // 11.04 (From KEGS)
|
|
||||||
|
|
||||||
std::shared_ptr<Input> Input::ourSingleton;
|
|
||||||
|
|
||||||
void Input::initialise(const std::string & device)
|
|
||||||
{
|
|
||||||
ourSingleton.reset(new Input(device));
|
|
||||||
}
|
|
||||||
|
|
||||||
Input & Input::instance()
|
|
||||||
{
|
|
||||||
return *ourSingleton;
|
|
||||||
}
|
|
||||||
|
|
||||||
Input::Input(const std::string & device)
|
|
||||||
: myButtonCodes(2), myAxisCodes(2), myAxisMins(2), myAxisMaxs(2)
|
|
||||||
{
|
|
||||||
myFD = open(device.c_str(), O_RDONLY | O_NONBLOCK);
|
|
||||||
if (myFD > 0)
|
|
||||||
{
|
|
||||||
libevdev * dev;
|
|
||||||
int rc = libevdev_new_from_fd(myFD, &dev);
|
|
||||||
if (rc < 0)
|
|
||||||
{
|
|
||||||
LogFileOutput("Input: failed to init libevdev (%s): %s\n", strerror(-rc), device.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
myDev.reset(dev, libevdev_free);
|
|
||||||
myButtonCodes[0] = BTN_SOUTH;
|
|
||||||
myButtonCodes[1] = BTN_EAST;
|
|
||||||
myAxisCodes[0] = ABS_X;
|
|
||||||
myAxisCodes[1] = ABS_Y;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < myAxisCodes.size(); ++i)
|
|
||||||
{
|
|
||||||
myAxisMins[i] = libevdev_get_abs_minimum(myDev.get(), myAxisCodes[i]);
|
|
||||||
myAxisMaxs[i] = libevdev_get_abs_maximum(myDev.get(), myAxisCodes[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogFileOutput("Input: failed to open device (%s): %s\n", strerror(errno), device.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Input::~Input()
|
|
||||||
{
|
|
||||||
if (myFD > 0)
|
|
||||||
{
|
|
||||||
close(myFD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Input::poll()
|
|
||||||
{
|
|
||||||
int counter = 0;
|
|
||||||
if (!myDev)
|
|
||||||
{
|
|
||||||
return counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
input_event ev;
|
|
||||||
int rc = LIBEVDEV_READ_STATUS_SUCCESS;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (rc == LIBEVDEV_READ_STATUS_SYNC)
|
|
||||||
rc = libevdev_next_event(myDev.get(), LIBEVDEV_READ_FLAG_SYNC, &ev);
|
|
||||||
else
|
|
||||||
rc = libevdev_next_event(myDev.get(), LIBEVDEV_READ_FLAG_NORMAL, &ev);
|
|
||||||
++counter;
|
|
||||||
} while (rc >= 0);
|
|
||||||
|
|
||||||
return counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Input::getButton(int i) const
|
|
||||||
{
|
|
||||||
int value = 0;
|
|
||||||
if (myDev)
|
|
||||||
{
|
|
||||||
int rc = libevdev_fetch_event_value(myDev.get(), EV_KEY, myButtonCodes[i], &value);
|
|
||||||
}
|
|
||||||
return value != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Input::getAxis(int i) const
|
|
||||||
{
|
|
||||||
if (myDev)
|
|
||||||
{
|
|
||||||
int value = 0;
|
|
||||||
int rc = libevdev_fetch_event_value(myDev.get(), EV_ABS, myAxisCodes[i], &value);
|
|
||||||
int pdl = 255 * (value - myAxisMins[i]) / (myAxisMaxs[i] - myAxisMins[i]);
|
|
||||||
return pdl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
BYTE __stdcall JoyReadButton(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft)
|
|
||||||
{
|
|
||||||
addr &= 0xFF;
|
|
||||||
BOOL pressed = 0;
|
|
||||||
|
|
||||||
switch (addr)
|
|
||||||
{
|
|
||||||
case 0x61:
|
|
||||||
pressed = Input::instance().getButton(0);
|
|
||||||
break;
|
|
||||||
case 0x62:
|
|
||||||
pressed = Input::instance().getButton(1);
|
|
||||||
break;
|
|
||||||
case 0x63:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return MemReadFloatingBus(pressed, nCyclesLeft);
|
|
||||||
}
|
|
||||||
|
|
||||||
BYTE __stdcall JoyReadPosition(WORD pc, WORD address, BYTE bWrite, BYTE d, ULONG nCyclesLeft)
|
|
||||||
{
|
|
||||||
const int nJoyNum = (address & 2) ? 1 : 0; // $C064..$C067
|
|
||||||
|
|
||||||
CpuCalcCycles(nCyclesLeft);
|
|
||||||
BOOL nPdlCntrActive = 0;
|
|
||||||
|
|
||||||
if (nJoyNum == 0)
|
|
||||||
{
|
|
||||||
int axis = address & 1;
|
|
||||||
int pdl = Input::instance().getAxis(axis);
|
|
||||||
// This is from KEGS. It helps games like Championship Lode Runner & Boulderdash
|
|
||||||
if (pdl >= 255)
|
|
||||||
pdl = 280;
|
|
||||||
|
|
||||||
nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)pdl * PDL_CNTR_INTERVAL));
|
|
||||||
}
|
|
||||||
|
|
||||||
return MemReadFloatingBus(nPdlCntrActive, nCyclesLeft);
|
|
||||||
}
|
|
||||||
|
|
||||||
BYTE __stdcall JoyResetPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft)
|
|
||||||
{
|
|
||||||
CpuCalcCycles(nCyclesLeft);
|
|
||||||
g_nJoyCntrResetCycle = g_nCumulativeCycles;
|
|
||||||
|
|
||||||
return MemReadFloatingBus(nCyclesLeft);
|
|
||||||
}
|
|
94
source/linux/paddle.cpp
Normal file
94
source/linux/paddle.cpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#include "StdAfx.h"
|
||||||
|
|
||||||
|
#include "linux/paddle.h"
|
||||||
|
|
||||||
|
#include "Log.h"
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "CPU.h"
|
||||||
|
|
||||||
|
unsigned __int64 g_nJoyCntrResetCycle = 0; // Abs cycle that joystick counters were reset
|
||||||
|
const double PDL_CNTR_INTERVAL = 2816.0 / 255.0; // 11.04 (From KEGS)
|
||||||
|
|
||||||
|
Paddle::Paddle()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Paddle::getButton(int i) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Paddle::getAxis(int i) const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const Paddle> & Paddle::instance()
|
||||||
|
{
|
||||||
|
static std::shared_ptr<const Paddle> singleton = std::make_shared<Paddle>();
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
Paddle::~Paddle()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BYTE __stdcall JoyReadButton(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft)
|
||||||
|
{
|
||||||
|
addr &= 0xFF;
|
||||||
|
BOOL pressed = 0;
|
||||||
|
|
||||||
|
const std::shared_ptr<const Paddle> & paddle = Paddle::instance();
|
||||||
|
|
||||||
|
if (paddle)
|
||||||
|
{
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0x61:
|
||||||
|
pressed = paddle->getButton(0);
|
||||||
|
break;
|
||||||
|
case 0x62:
|
||||||
|
pressed = paddle->getButton(1);
|
||||||
|
break;
|
||||||
|
case 0x63:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MemReadFloatingBus(pressed, nCyclesLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
BYTE __stdcall JoyReadPosition(WORD pc, WORD address, BYTE bWrite, BYTE d, ULONG nCyclesLeft)
|
||||||
|
{
|
||||||
|
const int nJoyNum = (address & 2) ? 1 : 0; // $C064..$C067
|
||||||
|
|
||||||
|
CpuCalcCycles(nCyclesLeft);
|
||||||
|
BOOL nPdlCntrActive = 0;
|
||||||
|
|
||||||
|
const std::shared_ptr<const Paddle> & paddle = Paddle::instance();
|
||||||
|
|
||||||
|
if (paddle)
|
||||||
|
{
|
||||||
|
if (nJoyNum == 0)
|
||||||
|
{
|
||||||
|
int axis = address & 1;
|
||||||
|
int pdl = paddle->getAxis(axis);
|
||||||
|
// This is from KEGS. It helps games like Championship Lode Runner & Boulderdash
|
||||||
|
if (pdl >= 255)
|
||||||
|
pdl = 280;
|
||||||
|
|
||||||
|
nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)pdl * PDL_CNTR_INTERVAL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MemReadFloatingBus(nPdlCntrActive, nCyclesLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
BYTE __stdcall JoyResetPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft)
|
||||||
|
{
|
||||||
|
CpuCalcCycles(nCyclesLeft);
|
||||||
|
g_nJoyCntrResetCycle = g_nCumulativeCycles;
|
||||||
|
|
||||||
|
return MemReadFloatingBus(nCyclesLeft);
|
||||||
|
}
|
16
source/linux/paddle.h
Normal file
16
source/linux/paddle.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Paddle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Paddle();
|
||||||
|
|
||||||
|
virtual ~Paddle();
|
||||||
|
|
||||||
|
virtual bool getButton(int i) const;
|
||||||
|
virtual int getAxis(int i) const;
|
||||||
|
|
||||||
|
static std::shared_ptr<const Paddle> & instance();
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue