Merge branch 'rr1-maint'

This commit is contained in:
Ilari Liusvaara 2012-04-11 22:50:34 +03:00
commit 213d32c427
10 changed files with 416 additions and 48 deletions

View file

@ -1 +1 @@
1-Δ5ε2 1-Δ6

View file

@ -0,0 +1,41 @@
#ifndef _library__joyfun__hpp__included__
#define _library__joyfun__hpp__included__
#include <cstdint>
/**
* Perform axis calibration correction.
*
* Parameter v: The raw value read.
* Parameter low: The low limit.
* Parameter high: The high limit.
* Returns: The calibrated read value.
*/
short calibration_correction(int64_t v, int64_t low, int64_t high);
/**
* Translate hundredths of degree position into hat bitmask.
*
* 0 is assumed to be up, and values are assumed to be clockwise. Negative values are centered.
*
* Parameter angle: The angle.
* Returns: The hat bitmask.
*/
short angle_to_bitmask(int angle);
/**
* If a != b, a <- b and return true. Otherwise return false.
*
* Parameter a: The target.
* Parameter b: The source.
* Returns: a was not equal to b?
*/
template<typename T> bool make_equal(T& a, const T& b)
{
bool r = (a != b);
if(r)
a = b;
return r;
}
#endif

View file

@ -387,6 +387,10 @@ EVDEV: Use EVDEV for joystick (Linux only).
WIN32MM: Use Win32mm for joystick (Windows only). WIN32MM: Use Win32mm for joystick (Windows only).
\end_layout \end_layout
\begin_layout Itemize
WXWIDGETS: Use Wxwidgets for joystick (requires WXWIDGETS graphics)
\end_layout
\begin_layout Itemize \begin_layout Itemize
DUMMY: Disable joystick support. DUMMY: Disable joystick support.
\end_layout \end_layout
@ -6036,5 +6040,81 @@ Fix writing port2 data to movie.
Fix SRAM handling with Bsnes v087. Fix SRAM handling with Bsnes v087.
\end_layout \end_layout
\begin_layout Subsection
rr1-delta6
\end_layout
\begin_layout Itemize
Library loading support
\end_layout
\begin_layout Itemize
Built-in TSCC encoder
\end_layout
\begin_layout Itemize
Hi-color (256T colors) dumping.
\end_layout
\begin_layout Itemize
Dump over TCP/IP(v6)
\end_layout
\begin_layout Itemize
Hidable status panel
\end_layout
\begin_layout Itemize
Turbo toggle/hold
\end_layout
\begin_layout Itemize
Adjustable sound volume
\end_layout
\begin_layout Itemize
Screen scaling
\end_layout
\begin_layout Itemize
Allow DnD into filename boxes
\end_layout
\begin_layout Itemize
Configurable paths
\end_layout
\begin_layout Itemize
Portaudio: Fix speaker popping at start
\end_layout
\begin_layout Itemize
Lots of UI changes
\end_layout
\begin_layout Itemize
Speed adjustment menu
\end_layout
\begin_layout Itemize
Win32 joystick support
\end_layout
\begin_layout Itemize
Lua: gui.rainbow and gui.box
\end_layout
\begin_layout Itemize
Split key lists into classes (the key list was large!)
\end_layout
\begin_layout Itemize
More save slots support
\end_layout
\begin_layout Itemize
Wxwidgets (wxJoystick) joystick support
\end_layout
\end_body \end_body
\end_document \end_document

View file

@ -154,6 +154,9 @@ Building is via makefile, the following options are available:
WIN32MM: Use Win32mm for joystick (Windows only). WIN32MM: Use Win32mm for joystick (Windows only).
WXWIDGETS: Use Wxwidgets for joystick (requires WXWIDGETS
graphics)
DUMMY: Disable joystick support. DUMMY: Disable joystick support.
Default is SDL. Default is SDL.
@ -2976,3 +2979,41 @@ set-axis joystick0axis19 disabled
• Fix SRAM handling with Bsnes v087. • Fix SRAM handling with Bsnes v087.
15.56 rr1-delta6
• Library loading support
• Built-in TSCC encoder
• Hi-color (256T colors) dumping.
• Dump over TCP/IP(v6)
• Hidable status panel
• Turbo toggle/hold
• Adjustable sound volume
• Screen scaling
• Allow DnD into filename boxes
• Configurable paths
• Portaudio: Fix speaker popping at start
• Lots of UI changes
• Speed adjustment menu
• Win32 joystick support
• Lua: gui.rainbow and gui.box
• Split key lists into classes (the key list was large!)
• More save slots support
• Wxwidgets (wxJoystick) joystick support

30
src/library/joyfun.cpp Normal file
View file

@ -0,0 +1,30 @@
#include "library/joyfun.hpp"
short calibration_correction(int64_t v, int64_t low, int64_t high)
{
double _v = v;
double _low = low;
double _high = high;
double _pos = 65535 * (_v - _low) / (_high - _low) - 32768;
if(_pos < -32768)
return -32768;
else if(_pos > 32767)
return 32767;
else
return static_cast<short>(_pos);
}
short angle_to_bitmask(int pov)
{
short m = 0;
if((pov >= 0 && pov <= 6000) || (pov >= 30000 && pov <= 36000))
m |= 1;
if(pov >= 3000 && pov <= 15000)
m |= 2;
if(pov >= 12000 && pov <= 24000)
m |= 4;
if(pov >= 21000 && pov <= 33000)
m |= 8;
return m;
}

View file

@ -1,6 +1,7 @@
#include "core/command.hpp" #include "core/command.hpp"
#include "core/keymapper.hpp" #include "core/keymapper.hpp"
#include "core/window.hpp" #include "core/window.hpp"
#include "library/joyfun.hpp"
#include <unistd.h> #include <unistd.h>
#include <map> #include <map>
@ -202,8 +203,7 @@ namespace
v = (e.current_status != 0); v = (e.current_status != 0);
break; break;
case ET_AXIS: case ET_AXIS:
v = -32768 + 65535 * (static_cast<double>(e.current_status) - e.axis_min) / v = calibration_correction(e.current_status, e.axis_min, e.axis_max);
(static_cast<double>(e.axis_max) - e.axis_min);
break; break;
case ET_HAT_X: case ET_HAT_X:
case ET_HAT_Y: { case ET_HAT_Y: {

View file

@ -4,6 +4,7 @@
#include "core/window.hpp" #include "core/window.hpp"
#include "library/minmax.hpp" #include "library/minmax.hpp"
#include "library/string.hpp" #include "library/string.hpp"
#include "library/joyfun.hpp"
#include <windows.h> #include <windows.h>
#include <mmsystem.h> #include <mmsystem.h>
@ -30,9 +31,9 @@ namespace
volatile bool quit_signaled; volatile bool quit_signaled;
volatile bool quit_ack; volatile bool quit_ack;
void create_hat(unsigned i) void create_hat(unsigned i, unsigned j = 0)
{ {
std::string n = (stringfmt() << "joystick" << i << "hat").str(); std::string n = (stringfmt() << "joystick" << i << "hat" << j).str();
keygroup* k = new keygroup(n, "joystick", keygroup::KT_HAT); keygroup* k = new keygroup(n, "joystick", keygroup::KT_HAT);
hats[i] = k; hats[i] = k;
} }
@ -57,21 +58,8 @@ namespace
auto key = std::make_pair(i, j); auto key = std::make_pair(i, j);
if(!axes.count(key)) if(!axes.count(key))
return; return;
short cpos; if(make_equal(laxes[key], calibration_correction(pos, pmin, pmax)))
double _pos = pos; platform::queue(keypress(modifier_set(), *axes[key], laxes[key]));
double _pmin = pmin;
double _pmax = pmax;
_pos = 65535 * (_pos - _pmin) / (_pmax - _pmin) - 32768;
if(_pos < -32768)
cpos = -32768;
else if(_pos > 32767)
cpos = 32767;
else
cpos = _pos;
if(laxes[key] != cpos) {
platform::queue(keypress(modifier_set(), *axes[key], cpos));
laxes[key] = cpos;
}
} }
void init_joysticks() void init_joysticks()
@ -144,31 +132,15 @@ namespace
info.dwFlags = JOY_RETURNALL; info.dwFlags = JOY_RETURNALL;
if(joyGetPosEx(jnum, &info) != JOYERR_NOERROR) if(joyGetPosEx(jnum, &info) != JOYERR_NOERROR)
continue; //Not usable. continue; //Not usable.
if(caps.wCaps & JOYCAPS_HASPOV) { if(caps.wCaps & JOYCAPS_HASPOV)
//Read POV hat. if(make_equal(lhats[jnum], angle_to_bitmask(info.dwPOV)))
short m = 0; platform::queue(keypress(modifier_set(), *hats[jnum], lhats[jnum]));
int pov = info.dwPOV;
if((pov >= 0 && pov <= 6000) || (pov >= 30000 && pov <= 36000))
m |= 1;
if(pov >= 3000 && pov <= 15000)
m |= 2;
if(pov >= 12000 && pov <= 24000)
m |= 4;
if(pov >= 21000 && pov <= 33000)
m |= 8;
if(lhats[jnum] != m) {
platform::queue(keypress(modifier_set(), *hats[jnum], m));
lhats[jnum] = m;
}
}
for(unsigned j = 0; j < caps.wMaxButtons; j++) { for(unsigned j = 0; j < caps.wMaxButtons; j++) {
//Read buttons //Read buttons
auto key = std::make_pair(jnum, j); auto key = std::make_pair(jnum, j);
short x = (info.dwButtons >> j) & 1; if(buttons.count(key) && make_equal(lbuttons[key],
if(buttons.count(key) && lbuttons[key] != x) { static_cast<short>((info.dwButtons >> j) & 1)))
platform::queue(keypress(modifier_set(), *buttons[key], x)); platform::queue(keypress(modifier_set(), *buttons[key], lbuttons[key]));
lbuttons[key] = x;
}
} }
read_axis(jnum, 0, info.dwXpos, caps.wXmin, caps.wXmax); read_axis(jnum, 0, info.dwXpos, caps.wXmin, caps.wXmax);
read_axis(jnum, 1, info.dwYpos, caps.wYmin, caps.wYmax); read_axis(jnum, 1, info.dwYpos, caps.wYmin, caps.wYmax);

View file

@ -6,6 +6,13 @@ else
OBJECTS = dummy.$(OBJECT_SUFFIX) OBJECTS = dummy.$(OBJECT_SUFFIX)
endif endif
ifeq ($(JOYSTICK), WXWIDGETS)
ifneq ($(GRAPHICS), WXWIDGETS)
$(error "WXWIDGETS joystick requires WXWIDGETS graphics")
endif
WXW_CFLAGS += -DWXWIDGETS_JOYSTICK_SUPPORT
endif
.PRECIOUS: %.$(OBJECT_SUFFIX) .PRECIOUS: %.$(OBJECT_SUFFIX)

View file

@ -0,0 +1,189 @@
#ifdef WXWIDGETS_JOYSTICK_SUPPORT
#include "core/command.hpp"
#include "core/framerate.hpp"
#include "core/keymapper.hpp"
#include "core/window.hpp"
#include "library/minmax.hpp"
#include "library/string.hpp"
#include "library/joyfun.hpp"
#include <wx/timer.h>
#include <wx/joystick.h>
#define POLL_WAIT 20000
#include <cstdlib>
#include <string>
#include <sstream>
#include <iostream>
#include <stdexcept>
#include <sys/time.h>
#include <unistd.h>
namespace
{
std::set<keygroup*> keygroups;
std::map<std::pair<unsigned, unsigned>, keygroup*> buttons;
std::map<std::pair<unsigned, unsigned>, keygroup*> axes;
std::map<unsigned, keygroup*> hats;
std::map<std::pair<unsigned, unsigned>, short> lbuttons;
std::map<std::pair<unsigned, unsigned>, short> laxes;
std::map<unsigned, short> lhats;
std::map<unsigned, wxJoystick*> joysticks;
volatile bool ready = false;
void create_hat(unsigned i, unsigned j = 0)
{
std::string n = (stringfmt() << "joystick" << i << "hat" << j).str();
keygroup* k = new keygroup(n, "joystick", keygroup::KT_HAT);
hats[i] = k;
}
void create_button(unsigned i, unsigned j)
{
std::string n = (stringfmt() << "joystick" << i << "button" << j).str();
keygroup* k = new keygroup(n, "joystick", keygroup::KT_KEY);
buttons[std::make_pair(i, j)] = k;
}
void create_axis(unsigned i, unsigned j, int min, int max)
{
messages << "axis #" << j << ": " << min << " " << max << std::endl;
std::string n = (stringfmt() << "joystick" << i << "axis" << j).str();
keygroup* k;
k = new keygroup(n, "joystick", keygroup::KT_AXIS_PAIR);
axes[std::make_pair(i, j)] = k;
}
void read_axis(unsigned i, unsigned j, int pos, int pmin, int pmax)
{
auto key = std::make_pair(i, j);
if(!axes.count(key))
return;
if(make_equal(laxes[key], calibration_correction(pos, pmin, pmax)))
platform::queue(keypress(modifier_set(), *axes[key], laxes[key]));
}
void init_joysticks()
{
unsigned max_joysticks = wxJoystick::GetNumberJoysticks();
if(!max_joysticks)
return; //No joystick support.
for(unsigned i = 0; i < max_joysticks; i++) {
wxJoystick* joy = new wxJoystick(i);
if(!joy->IsOk()) {
//Not usable.
delete joy;
continue;
}
joysticks[i] = joy;
messages << "Joystick #" << i << ": " << joy->GetProductName() << std::endl;
if(joy->HasPOV())
create_hat(i);
for(unsigned j = 0; j < joy->GetNumberButtons() && j < 32; j++)
create_button(i, j);
unsigned axcount = 2;
create_axis(i, 0, joy->GetXMin(), joy->GetXMax());
create_axis(i, 1, joy->GetYMin(), joy->GetYMax());
if(joy->HasZ()) {
create_axis(i, 2, joy->GetZMin(), joy->GetZMax());
axcount++;
}
if(joy->HasRudder()) {
create_axis(i, 3, joy->GetRudderMin(), joy->GetRudderMax());
axcount++;
}
if(joy->HasU()) {
create_axis(i, 4, joy->GetUMin(), joy->GetUMax());
axcount++;
}
if(joy->HasV()) {
create_axis(i, 5, joy->GetVMin(), joy->GetVMax());
axcount++;
}
if(joy->HasPOV())
messages << "1 hat, ";
messages << axcount << " axes, " << min((int)joy->GetNumberButtons(), 32) << " buttons"
<< std::endl;
}
ready = true;
}
void poll_joysticks()
{
if(!ready)
return;
modifier_set mod;
for(auto i : joysticks) {
unsigned jnum = i.first;
wxJoystick* joy = i.second;
if(joy->HasPOV())
if(make_equal(lhats[jnum], angle_to_bitmask(joy->GetPOVCTSPosition())))
platform::queue(keypress(modifier_set(), *hats[jnum], lhats[jnum]));
uint32_t bmask = joy->GetButtonState();
for(unsigned j = 0; j < 32; j++) {
//Read buttons
auto key = std::make_pair(jnum, j);
if(buttons.count(key) && make_equal(lbuttons[key], static_cast<short>((bmask >> j) &
1)))
platform::queue(keypress(modifier_set(), *buttons[key], lbuttons[key]));
}
wxPoint xy = joy->GetPosition();
read_axis(jnum, 0, xy.x, joy->GetXMin(), joy->GetXMax());
read_axis(jnum, 1, xy.y, joy->GetYMin(), joy->GetYMax());
if(joy->HasZ())
read_axis(jnum, 2, joy->GetZPosition(), joy->GetZMin(), joy->GetZMax());
if(joy->HasRudder())
read_axis(jnum, 3, joy->GetRudderPosition(), joy->GetRudderMin(), joy->GetRudderMax());
if(joy->HasU())
read_axis(jnum, 4, joy->GetUPosition(), joy->GetUMin(), joy->GetUMax());
if(joy->HasV())
read_axis(jnum, 5, joy->GetVPosition(), joy->GetUMin(), joy->GetUMax());
}
}
struct joystick_timer : public wxTimer
{
joystick_timer() { start(); }
void start() { Start(POLL_WAIT / 1000); }
void stop() { Stop(); }
void Notify() { poll_joysticks(); }
}* jtimer;
}
void joystick_plugin::init() throw()
{
init_joysticks();
jtimer = new joystick_timer();
}
void joystick_plugin::quit() throw()
{
jtimer->stop();
delete jtimer;
jtimer = NULL;
ready = false;
usleep(50000);
for(auto i : keygroups)
delete i;
for(auto i : joysticks)
delete i.second;
usleep(500000);
buttons.clear();
axes.clear();
hats.clear();
keygroups.clear();
joysticks.clear();
}
void joystick_plugin::thread_fn() throw()
{
//We don't poll in this thread, so just quit instantly.
}
void joystick_plugin::signal() throw()
{
//We don't poll in dedicated thread, so nothing to do.
}
const char* joystick_plugin::name = "Wxwidgets joystick plugin";
#endif

View file

@ -74,6 +74,8 @@ namespace
std::map<std::string, keyentry_mod_data> modifiers; std::map<std::string, keyentry_mod_data> modifiers;
std::map<std::string, std::set<std::string>> classes; std::map<std::string, std::set<std::string>> classes;
std::string currentclass; std::string currentclass;
wxFlexGridSizer* top_s;
wxFlexGridSizer* t_s;
wxComboBox* mainclass; wxComboBox* mainclass;
wxComboBox* mainkey; wxComboBox* mainkey;
wxButton* ok; wxButton* ok;
@ -105,15 +107,15 @@ namespace
}); });
Centre(); Centre();
wxFlexGridSizer* top_s = new wxFlexGridSizer(2, 1, 0, 0); top_s = new wxFlexGridSizer(2, 1, 0, 0);
SetSizer(top_s); SetSizer(top_s);
wxFlexGridSizer* t_s = new wxFlexGridSizer(mods.size() + 1, 3, 0, 0); t_s = new wxFlexGridSizer(mods.size() + 1, 3, 0, 0);
for(auto i : mods) { for(auto i : mods) {
t_s->Add(new wxStaticText(this, wxID_ANY, towxstring(i)), 0, wxGROW); t_s->Add(new wxStaticText(this, wxID_ANY, towxstring(i)), 0, wxGROW);
keyentry_mod_data m; keyentry_mod_data m;
t_s->Add(m.pressed = new wxCheckBox(this, wxID_ANY, wxT("Pressed")), 0, wxGROW); t_s->Add(m.pressed = new wxCheckBox(this, wxID_ANY, wxT("Pressed")), 0, wxGROW);
t_s->Add(m.unmasked = new wxCheckBox(this, wxID_ANY, wxT("Unmasked")), 0, wxGROW); t_s->Add(m.unmasked = new wxCheckBox(this, wxID_ANY, wxT("Unmasked")), 1, wxGROW);
m.pressed->Disable(); m.pressed->Disable();
modifiers[i] = m; modifiers[i] = m;
m.pressed->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, m.pressed->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
@ -123,7 +125,7 @@ namespace
} }
t_s->Add(new wxStaticText(this, wxID_ANY, wxT("Key")), 0, wxGROW); t_s->Add(new wxStaticText(this, wxID_ANY, wxT("Key")), 0, wxGROW);
t_s->Add(mainclass = new wxComboBox(this, wxID_ANY, classeslist[0], wxDefaultPosition, wxDefaultSize, t_s->Add(mainclass = new wxComboBox(this, wxID_ANY, classeslist[0], wxDefaultPosition, wxDefaultSize,
classeslist.size(), &classeslist[0], wxCB_READONLY), 1, wxGROW); classeslist.size(), &classeslist[0], wxCB_READONLY), 0, wxGROW);
mainclass->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED, mainclass->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
wxCommandEventHandler(wxdialog_keyentry::on_classchange), NULL, this); wxCommandEventHandler(wxdialog_keyentry::on_classchange), NULL, this);
t_s->Add(mainkey = new wxComboBox(this, wxID_ANY, emptystring, wxDefaultPosition, wxDefaultSize, t_s->Add(mainkey = new wxComboBox(this, wxID_ANY, emptystring, wxDefaultPosition, wxDefaultSize,
@ -135,9 +137,9 @@ namespace
wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
if(clearable) if(clearable)
pbutton_s->Add(clear = new wxButton(this, wxID_OK, wxT("Clear")), 0, wxGROW); pbutton_s->Add(clear = new wxButton(this, wxID_OK, wxT("Clear")), 0, wxGROW);
pbutton_s->AddStretchSpacer();
pbutton_s->Add(ok = new wxButton(this, wxID_OK, wxT("OK")), 0, wxGROW); pbutton_s->Add(ok = new wxButton(this, wxID_OK, wxT("OK")), 0, wxGROW);
pbutton_s->Add(cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW); pbutton_s->Add(cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
pbutton_s->AddStretchSpacer();
ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED, ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_ok), NULL, this); wxCommandEventHandler(wxdialog_keyentry::on_ok), NULL, this);
cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
@ -223,7 +225,10 @@ namespace
set_class(_class); set_class(_class);
mainclass->SetValue(towxstring(_class)); mainclass->SetValue(towxstring(_class));
mainkey->SetValue(towxstring(key)); mainkey->SetValue(towxstring(key));
} t_s->Layout();
top_s->Layout();
Fit();
}
void wxdialog_keyentry::on_change_setting(wxCommandEvent& e) void wxdialog_keyentry::on_change_setting(wxCommandEvent& e)
{ {
@ -303,6 +308,9 @@ namespace
mainkey->Append(towxstring(i)); mainkey->Append(towxstring(i));
currentclass = _class; currentclass = _class;
mainkey->SetSelection(0); mainkey->SetSelection(0);
t_s->Layout();
top_s->Layout();
Fit();
} }
void wxdialog_keyentry::on_classchange(wxCommandEvent& e) void wxdialog_keyentry::on_classchange(wxCommandEvent& e)