Refactor internal interfaces to support arbitrary number of controllers
This commit is contained in:
parent
4f9dfd513c
commit
07ecfd7dc4
16 changed files with 396 additions and 309 deletions
|
@ -37,18 +37,6 @@
|
|||
* Maximum number of ports.
|
||||
*/
|
||||
#define MAX_PORTS 2
|
||||
/**
|
||||
* Maximum number of controllers per one port.
|
||||
*/
|
||||
#define MAX_CONTROLLERS_PER_PORT 4
|
||||
/**
|
||||
* Maximum numbers of controls per one controller.
|
||||
*/
|
||||
#define MAX_CONTROLS_PER_CONTROLLER 12
|
||||
/**
|
||||
* Number of button controls.
|
||||
*/
|
||||
#define MAX_BUTTONS MAX_PORTS * MAX_CONTROLLERS_PER_PORT * MAX_CONTROLS_PER_CONTROLLER
|
||||
/**
|
||||
* Size of controller page.
|
||||
*/
|
||||
|
@ -403,28 +391,20 @@ public:
|
|||
/**
|
||||
* Clear specified DRDY bit.
|
||||
*
|
||||
* Parameter port: The port ID.
|
||||
* Parameter pcid: The physical controller id.
|
||||
* Parameter ctrl: The control id.
|
||||
*/
|
||||
void clear_DRDY(unsigned pcid, unsigned ctrl) throw();
|
||||
void clear_DRDY(unsigned port, unsigned pcid, unsigned ctrl) throw();
|
||||
/**
|
||||
* Get state of DRDY bit.
|
||||
*
|
||||
* Parameter port: The port ID.
|
||||
* Parameter pcid: The physical controller id.
|
||||
* Parameter ctrl: The control id.
|
||||
* Returns: The DRDY state.
|
||||
*/
|
||||
bool get_DRDY(unsigned pcid, unsigned ctrl) throw();
|
||||
/**
|
||||
* Get state of DRDY bit.
|
||||
*
|
||||
* Parameter idx: The control index.
|
||||
* Returns: The DRDY state.
|
||||
*/
|
||||
bool get_DRDY(unsigned idx) throw()
|
||||
{
|
||||
return get_DRDY(idx / MAX_CONTROLS_PER_CONTROLLER, idx % MAX_CONTROLS_PER_CONTROLLER);
|
||||
}
|
||||
bool get_DRDY(unsigned port, unsigned pcid, unsigned ctrl) throw();
|
||||
/**
|
||||
* Is any poll count nonzero or is system flag set?
|
||||
*
|
||||
|
@ -434,29 +414,34 @@ public:
|
|||
/**
|
||||
* Read the actual poll count on specified control.
|
||||
*
|
||||
* Parameter port: The port ID.
|
||||
* Parameter pcid: The physical controller id.
|
||||
* Parameter ctrl: The control id.
|
||||
* Return: The poll count.
|
||||
*/
|
||||
uint32_t get_polls(unsigned pcid, unsigned ctrl) throw();
|
||||
uint32_t get_polls(unsigned port, unsigned pcid, unsigned ctrl) throw();
|
||||
/**
|
||||
* Get number of controls.
|
||||
*
|
||||
* Returns: The control count.
|
||||
*/
|
||||
unsigned maxbuttons() throw();
|
||||
/**
|
||||
* Read the actual poll count on specified control.
|
||||
*
|
||||
* Parameter idx: The control index.
|
||||
* Return: The poll count.
|
||||
*/
|
||||
uint32_t get_polls(unsigned idx) throw()
|
||||
{
|
||||
return get_polls(idx / MAX_CONTROLS_PER_CONTROLLER, idx % MAX_CONTROLS_PER_CONTROLLER);
|
||||
}
|
||||
uint32_t get_polls(unsigned idx) throw();
|
||||
/**
|
||||
* Increment poll count on specified control.
|
||||
*
|
||||
* Parameter port: The port ID.
|
||||
* Parameter pcid: The physical controller id.
|
||||
* Parameter ctrl: The control id.
|
||||
* Return: The poll count pre-increment.
|
||||
*/
|
||||
uint32_t increment_polls(unsigned pcid, unsigned ctrl) throw();
|
||||
uint32_t increment_polls(unsigned port, unsigned pcid, unsigned ctrl) throw();
|
||||
/**
|
||||
* Set the system flag.
|
||||
*/
|
||||
|
@ -495,7 +480,7 @@ public:
|
|||
*/
|
||||
bool check(const std::vector<uint32_t>& mem) throw();
|
||||
private:
|
||||
uint32_t ctrs[MAX_BUTTONS];
|
||||
std::vector<uint32_t> ctrs;
|
||||
bool system_flag;
|
||||
};
|
||||
|
||||
|
@ -684,17 +669,31 @@ public:
|
|||
{
|
||||
return totalsize;
|
||||
}
|
||||
/**
|
||||
* Get number of controls.
|
||||
*
|
||||
* Returns: The control count.
|
||||
*/
|
||||
unsigned maxbuttons() throw();
|
||||
/**
|
||||
* Do the types match?
|
||||
*
|
||||
* Parameter a: Another controller frame.
|
||||
* Returns: True if types match, false if not.
|
||||
*/
|
||||
bool type_matches(const controller_frame& a);
|
||||
/**
|
||||
* Set axis/button value.
|
||||
*
|
||||
* Parameter port: The port to set.
|
||||
* Parameter pcid: Physical controller id.
|
||||
* Parameter ctrl: The control id.
|
||||
* Parameter x: The new value.
|
||||
*/
|
||||
void axis(unsigned pcid, unsigned ctrl, short x) throw()
|
||||
void axis(unsigned port, unsigned pcid, unsigned ctrl, short x) throw()
|
||||
{
|
||||
unsigned port = (pcid / MAX_CONTROLLERS_PER_PORT) % MAX_PORTS;
|
||||
pinfo[port]->write(backing + offsets[port], pcid % MAX_CONTROLLERS_PER_PORT, ctrl, x);
|
||||
if(port < MAX_PORTS)
|
||||
pinfo[port]->write(backing + offsets[port], pcid, ctrl, x);
|
||||
}
|
||||
/**
|
||||
* Set axis/button value.
|
||||
|
@ -702,21 +701,21 @@ public:
|
|||
* Parameter idx: Control index.
|
||||
* Parameter x: The new value.
|
||||
*/
|
||||
void axis2(unsigned idx, short x) throw()
|
||||
{
|
||||
axis(idx / MAX_CONTROLS_PER_CONTROLLER, idx % MAX_CONTROLS_PER_CONTROLLER, x);
|
||||
}
|
||||
void axis2(unsigned idx, short x) throw();
|
||||
/**
|
||||
* Get axis/button value.
|
||||
*
|
||||
* Parameter port: The port to get.
|
||||
* Parameter pcid: Physical controller id.
|
||||
* Parameter ctrl: The control id.
|
||||
* Return value: The axis value.
|
||||
*/
|
||||
short axis(unsigned pcid, unsigned ctrl) throw()
|
||||
short axis(unsigned port, unsigned pcid, unsigned ctrl) throw()
|
||||
{
|
||||
unsigned port = (pcid / MAX_CONTROLLERS_PER_PORT) % MAX_PORTS;
|
||||
return pinfo[port]->read(backing + offsets[port], pcid % MAX_CONTROLLERS_PER_PORT, ctrl);
|
||||
if(port < MAX_PORTS)
|
||||
return pinfo[port]->read(backing + offsets[port], pcid, ctrl);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -725,31 +724,34 @@ public:
|
|||
* Parameter idx: Index of control.
|
||||
* Return value: The axis value.
|
||||
*/
|
||||
short axis2(unsigned idx) throw()
|
||||
{
|
||||
return axis(idx / MAX_CONTROLS_PER_CONTROLLER, idx % MAX_CONTROLS_PER_CONTROLLER);
|
||||
}
|
||||
short axis2(unsigned idx) throw();
|
||||
/**
|
||||
* Get controller display.
|
||||
*
|
||||
* Parameter port: The port to get.
|
||||
* Parameter pcid: Physical controller id.
|
||||
* Parameter buf: Buffer to write nul-terminated display to.
|
||||
*/
|
||||
void display(unsigned pcid, char* buf) throw()
|
||||
void display(unsigned port, unsigned pcid, char* buf) throw()
|
||||
{
|
||||
unsigned port = (pcid / MAX_CONTROLLERS_PER_PORT) % MAX_PORTS;
|
||||
return pinfo[port]->display(backing + offsets[port], pcid % MAX_CONTROLLERS_PER_PORT, buf);
|
||||
if(port < MAX_PORTS)
|
||||
return pinfo[port]->display(backing + offsets[port], pcid, buf);
|
||||
else
|
||||
strcpy(buf, "");
|
||||
}
|
||||
/**
|
||||
* Get device type.
|
||||
*
|
||||
* Parameter port: The port to get.
|
||||
* Parameter pcid: Physical controller id.
|
||||
* Returns: Device type.
|
||||
*/
|
||||
devicetype_t devicetype(unsigned pcid) throw()
|
||||
devicetype_t devicetype(unsigned port, unsigned pcid) throw()
|
||||
{
|
||||
unsigned port = (pcid / MAX_CONTROLLERS_PER_PORT) % MAX_PORTS;
|
||||
return pinfo[port]->devicetype(pcid % MAX_CONTROLLERS_PER_PORT);
|
||||
if(port < MAX_PORTS)
|
||||
return pinfo[port]->devicetype(pcid);
|
||||
else
|
||||
return DT_NONE;
|
||||
}
|
||||
/**
|
||||
* Deserialize frame from text format.
|
||||
|
@ -822,35 +824,39 @@ public:
|
|||
/**
|
||||
* Get physical button ID for physical controller ID and logical button ID.
|
||||
*
|
||||
* Parameter port: The port to get.
|
||||
* Parameter pcid: Physical controller id.
|
||||
* Parameter lbid: Logical button id.
|
||||
* Returns: The physical button id, or -1 if no such button.
|
||||
*/
|
||||
int button_id(unsigned pcid, unsigned lbid)
|
||||
int button_id(unsigned port, unsigned pcid, unsigned lbid)
|
||||
{
|
||||
unsigned port = (pcid / MAX_CONTROLLERS_PER_PORT) % MAX_PORTS;
|
||||
return pinfo[port]->button_id(pcid % MAX_CONTROLLERS_PER_PORT, lbid);
|
||||
return pinfo[port]->button_id(pcid, lbid);
|
||||
}
|
||||
/**
|
||||
* Does the specified controller have analog function.
|
||||
*
|
||||
* Parameter port: The port to get.
|
||||
* Parameter pcid: Physical controller id.
|
||||
*/
|
||||
bool is_analog(unsigned pcid)
|
||||
bool is_analog(unsigned port, unsigned pcid)
|
||||
{
|
||||
unsigned port = (pcid / MAX_CONTROLLERS_PER_PORT) % MAX_PORTS;
|
||||
return pinfo[port]->is_analog(pcid % MAX_CONTROLLERS_PER_PORT);
|
||||
return pinfo[port]->is_analog(pcid);
|
||||
}
|
||||
/**
|
||||
* Does the specified controller have mouse-type function.
|
||||
*
|
||||
* Parameter port: The port to get.
|
||||
* Parameter pcid: Physical controller id.
|
||||
*/
|
||||
bool is_mouse(unsigned pcid)
|
||||
bool is_mouse(unsigned port, unsigned pcid)
|
||||
{
|
||||
unsigned port = (pcid / MAX_CONTROLLERS_PER_PORT) % MAX_PORTS;
|
||||
return pinfo[port]->is_mouse(pcid % MAX_CONTROLLERS_PER_PORT);
|
||||
return pinfo[port]->is_mouse(pcid);
|
||||
}
|
||||
/**
|
||||
* Get max number of controls in port.
|
||||
*/
|
||||
unsigned control_count();
|
||||
private:
|
||||
size_t totalsize;
|
||||
unsigned char memory[MAXIMUM_CONTROLLER_FRAME_SIZE];
|
||||
|
@ -1034,34 +1040,25 @@ public:
|
|||
* Constructor.
|
||||
*/
|
||||
controller_state() throw();
|
||||
/**
|
||||
* Get upper bound for number of lcids.
|
||||
*/
|
||||
unsigned lcid_count() throw();
|
||||
/**
|
||||
* Convert lcid (Logical Controller ID) into pcid (Physical Controler ID).
|
||||
*
|
||||
* Parameter lcid: The logical controller ID.
|
||||
* Return: The physical controller ID, or -1 if no such controller exists.
|
||||
* Return: The physical controller (port, ID), or (-1, -1) if no such controller exists.
|
||||
*/
|
||||
int lcid_to_pcid(unsigned lcid) throw();
|
||||
/**
|
||||
* Convert acid (Analog Controller ID) into pcid.
|
||||
*
|
||||
* Parameter acid: The analog controller ID.
|
||||
* Return: The physical controller ID, or -1 if no such controller exists.
|
||||
*/
|
||||
int acid_to_pcid(unsigned acid) throw();
|
||||
/**
|
||||
* Is given acid a mouse?
|
||||
*
|
||||
* Parameter acid: The analog controller ID.
|
||||
* Returns: True if given acid is mouse, false otherwise.
|
||||
*/
|
||||
bool acid_is_mouse(unsigned acid) throw();
|
||||
std::pair<int, int> lcid_to_pcid(unsigned lcid) throw();
|
||||
/**
|
||||
* Look up device type type of given pcid.
|
||||
*
|
||||
* Parameter port: The port number.
|
||||
* Parameter pcid: The physical controller id.
|
||||
* Returns: The type of device.
|
||||
*/
|
||||
devicetype_t pcid_to_type(unsigned pcid) throw();
|
||||
devicetype_t pcid_to_type(unsigned port, unsigned pcid) throw();
|
||||
/**
|
||||
* Set type of port.
|
||||
*
|
||||
|
@ -1102,13 +1099,14 @@ public:
|
|||
*/
|
||||
controller_frame get_blank() throw();
|
||||
/**
|
||||
* Send analog input to given acid.
|
||||
* Send analog input to given pcid.
|
||||
*
|
||||
* Parameter acid: The acid to send input to.
|
||||
* Parameter port: The port to send input to.
|
||||
* Parameter pcid: The pcid to send input to.
|
||||
* Parameter x: The x coordinate to send.
|
||||
* Parameter y: The x coordinate to send.
|
||||
*/
|
||||
void analog(unsigned acid, int x, int y) throw();
|
||||
void analog(unsigned port, unsigned pcid, int x, int y) throw();
|
||||
/**
|
||||
* Manipulate the reset flag.
|
||||
*
|
||||
|
@ -1118,35 +1116,39 @@ public:
|
|||
/**
|
||||
* Manipulate autohold.
|
||||
*
|
||||
* Parameter port: The port number.
|
||||
* Parameter pcid: The physical controller ID to manipulate.
|
||||
* Parameter pbid: The physical button ID to manipulate.
|
||||
* Parameter newstate: The new state for autohold.
|
||||
*/
|
||||
void autohold(unsigned pcid, unsigned pbid, bool newstate) throw();
|
||||
void autohold(unsigned port, unsigned pcid, unsigned pbid, bool newstate) throw();
|
||||
/**
|
||||
* Query autohold.
|
||||
*
|
||||
* Parameter port: The port number to query.
|
||||
* Parameter pcid: The physical controller ID to query.
|
||||
* Parameter pbid: The physical button ID to query.
|
||||
* Returns: The state of autohold.
|
||||
*/
|
||||
bool autohold(unsigned pcid, unsigned pbid) throw();
|
||||
bool autohold(unsigned port, unsigned pcid, unsigned pbid) throw();
|
||||
/**
|
||||
* Manipulate button.
|
||||
*
|
||||
* Parameter port: The port number to manipulate.
|
||||
* Parameter pcid: The physical controller ID to manipulate.
|
||||
* Parameter pbid: The physical button ID to manipulate.
|
||||
* Parameter newstate: The new state for button.
|
||||
*/
|
||||
void button(unsigned pcid, unsigned pbid, bool newstate) throw();
|
||||
void button(unsigned port, unsigned pcid, unsigned pbid, bool newstate) throw();
|
||||
/**
|
||||
* Query button.
|
||||
*
|
||||
* Parameter port: The port number to query.
|
||||
* Parameter pcid: The physical controller ID to query.
|
||||
* Parameter pbid: The physical button ID to query.
|
||||
* Returns: The state of button.
|
||||
*/
|
||||
bool button(unsigned pcid, unsigned pbid) throw();
|
||||
bool button(unsigned port, unsigned pcid, unsigned pbid) throw();
|
||||
/**
|
||||
* Set autofire pattern.
|
||||
*
|
||||
|
@ -1157,24 +1159,23 @@ public:
|
|||
/**
|
||||
* Get physical button ID for physical controller ID and logical button ID.
|
||||
*
|
||||
* Parameter port: The port number to query.
|
||||
* Parameter pcid: Physical controller id.
|
||||
* Parameter lbid: Logical button id.
|
||||
* Returns: The physical button id, or -1 if no such button.
|
||||
*/
|
||||
int button_id(unsigned pcid, unsigned lbid) throw();
|
||||
int button_id(unsigned port, unsigned pcid, unsigned lbid) throw();
|
||||
/**
|
||||
* TODO: Document.
|
||||
*/
|
||||
bool is_analog(unsigned pcid) throw();
|
||||
bool is_analog(unsigned port, unsigned pcid) throw();
|
||||
/**
|
||||
* TODO: Document.
|
||||
*/
|
||||
bool is_mouse(unsigned pcid) throw();
|
||||
bool is_mouse(unsigned port, unsigned pcid) throw();
|
||||
private:
|
||||
const porttype_info* porttypeinfo[MAX_PORTS];
|
||||
porttype_t porttypes[MAX_PORTS];
|
||||
int analog_indices[MAX_ANALOG];
|
||||
bool analog_mouse[MAX_ANALOG];
|
||||
controller_frame _input;
|
||||
controller_frame _autohold;
|
||||
controller_frame _committed;
|
||||
|
|
|
@ -152,15 +152,16 @@ public:
|
|||
*
|
||||
* The default handler does nothing.
|
||||
*
|
||||
* Parameter pid: The physical ID of controller (0-7).
|
||||
* Parameter ctrlnum: Physical control number (0-15).
|
||||
* Parameter port: The port number.
|
||||
* Parameter pid: The physical ID of controller.
|
||||
* Parameter ctrlnum: Physical control number.
|
||||
* Parameter newstate: True if autohold is now active, false if autohold is now inactive.
|
||||
*/
|
||||
virtual void on_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate);
|
||||
virtual void on_autohold_update(unsigned port, unsigned pid, unsigned ctrlnum, bool newstate);
|
||||
/**
|
||||
* Call all on_autohold_update() handlers.
|
||||
*/
|
||||
static void do_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate) throw();
|
||||
static void do_autohold_update(unsigned port, unsigned pid, unsigned ctrlnum, bool newstate) throw();
|
||||
/**
|
||||
* Controller configuration may have been changed.
|
||||
*
|
||||
|
|
|
@ -101,12 +101,13 @@ public:
|
|||
* Reads the data ready flag. On new frame, all data ready flags are unset. On reading control, its data ready
|
||||
* flag is unset.
|
||||
*
|
||||
* parameter port: The port ID.
|
||||
* parameter pid: Physical controller id.
|
||||
* parameter index: Control ID.
|
||||
* returns: The read value.
|
||||
* throws std::logic_error: Invalid control index.
|
||||
*/
|
||||
bool get_DRDY(unsigned pid, unsigned index) throw(std::logic_error);
|
||||
bool get_DRDY(unsigned port, unsigned pid, unsigned index) throw(std::logic_error);
|
||||
|
||||
/**
|
||||
* Set all data ready flags
|
||||
|
@ -116,13 +117,14 @@ public:
|
|||
/**
|
||||
* Poll a control by (port, controller, index) tuple.
|
||||
*
|
||||
* parameter port: The port ID.
|
||||
* parameter pid: Physical controller ID.
|
||||
* parameter index: The index of control in controller (0 to 11)
|
||||
* returns: The read value
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::logic_error: Invalid port, controller or index or before movie start.
|
||||
*/
|
||||
short next_input(unsigned pid, unsigned index) throw(std::bad_alloc, std::logic_error);
|
||||
short next_input(unsigned port, unsigned pid, unsigned index) throw(std::bad_alloc, std::logic_error);
|
||||
|
||||
/**
|
||||
* Set current control values. These are read in readwrite mode.
|
||||
|
@ -292,7 +294,7 @@ public:
|
|||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Error polling for input.
|
||||
*/
|
||||
short input_poll(bool port, unsigned dev, unsigned id) throw(std::bad_alloc, std::runtime_error);
|
||||
short input_poll(unsigned port, unsigned dev, unsigned id) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* Called when movie code needs new controls snapshot.
|
||||
|
|
|
@ -563,5 +563,7 @@ void runemufn(T fn)
|
|||
* If set, queueing synchronous function produces a warning.
|
||||
*/
|
||||
extern volatile bool queue_synchronous_fn_warning;
|
||||
extern void* queue_synchronous_fn_stack[512];
|
||||
extern size_t queue_synchronous_fn_stacksize;
|
||||
|
||||
#endif
|
||||
|
|
7
include/library/backtrace.hpp
Normal file
7
include/library/backtrace.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef _library__backtrace__hpp__included__
|
||||
#define _library__backtrace__hpp__included__
|
||||
|
||||
int lsnes_backtrace(void** buffer, int size);
|
||||
void lsnes_backtrace_symbols_stderr(void* const* buffer, int size);
|
||||
|
||||
#endif
|
|
@ -32,39 +32,41 @@ namespace
|
|||
//Do button action.
|
||||
void do_button_action(unsigned ui_id, unsigned button, short newstate, bool autoh)
|
||||
{
|
||||
int x = controls.lcid_to_pcid(ui_id);
|
||||
if(x < 0) {
|
||||
auto x = controls.lcid_to_pcid(ui_id);
|
||||
if(x.first < 0) {
|
||||
messages << "No such controller #" << (ui_id + 1) << std::endl;
|
||||
return;
|
||||
}
|
||||
int bid = controls.button_id(x, button);
|
||||
int bid = controls.button_id(x.first, x.second, button);
|
||||
if(bid < 0) {
|
||||
messages << "Invalid button for controller type" << std::endl;
|
||||
return;
|
||||
}
|
||||
if(autoh) {
|
||||
controls.autohold(x, bid, controls.autohold(x, bid) ^ newstate);
|
||||
information_dispatch::do_autohold_update(x, bid, controls.autohold(x, bid));
|
||||
controls.autohold(x.first, x.second, bid, controls.autohold(x.first, x.second, bid) ^
|
||||
newstate);
|
||||
information_dispatch::do_autohold_update(x.first, x.second, bid, controls.autohold(x.first,
|
||||
x.second, bid));
|
||||
} else
|
||||
controls.button(x, bid, newstate);
|
||||
controls.button(x.first, x.second, bid, newstate);
|
||||
}
|
||||
|
||||
void send_analog(unsigned lcid, int32_t x, int32_t y)
|
||||
{
|
||||
int pcid = controls.lcid_to_pcid(lcid);
|
||||
if(pcid < 0) {
|
||||
auto pcid = controls.lcid_to_pcid(lcid);
|
||||
if(pcid.first < 0) {
|
||||
messages << "Controller #" << (lcid + 1) << " not present" << std::endl;
|
||||
return;
|
||||
}
|
||||
if(controls.is_analog(pcid) < 0) {
|
||||
if(controls.is_analog(pcid.first, pcid.second) < 0) {
|
||||
messages << "Controller #" << (lcid + 1) << " is not analog" << std::endl;
|
||||
return;
|
||||
}
|
||||
auto g2 = get_framebuffer_size();
|
||||
if(controls.is_mouse(pcid)) {
|
||||
controls.analog(pcid, x - g2.first / 2, y - g2.second / 2);
|
||||
if(controls.is_mouse(pcid.first, pcid.second)) {
|
||||
controls.analog(pcid.first, pcid.second, x - g2.first / 2, y - g2.second / 2);
|
||||
} else
|
||||
controls.analog(pcid, x / 2 , y / 2);
|
||||
controls.analog(pcid.first, pcid.second, x / 2 , y / 2);
|
||||
}
|
||||
|
||||
function_ptr_command<const std::string&> autofire("autofire", "Set autofire pattern",
|
||||
|
@ -92,15 +94,15 @@ namespace
|
|||
if(!buttonmap.count(button))
|
||||
(stringfmt() << "Invalid button '" << button << "'").throwex();
|
||||
auto g = buttonmap[button];
|
||||
int x = controls.lcid_to_pcid(g.first);
|
||||
if(x < 0)
|
||||
auto x = controls.lcid_to_pcid(g.first);
|
||||
if(x.first < 0)
|
||||
(stringfmt() << "No such controller #" << (g.first + 1)).
|
||||
throwex();
|
||||
int bid = controls.button_id(x, g.second);
|
||||
int bid = controls.button_id(x.first, x.second, g.second);
|
||||
if(bid < 0)
|
||||
(stringfmt() << "Invalid button for controller type").
|
||||
throwex();
|
||||
c.axis(x, bid, true);
|
||||
c.axis(x.first, x.second, bid, true);
|
||||
fpattern = rest;
|
||||
}
|
||||
new_autofire_pattern.push_back(c);
|
||||
|
|
|
@ -341,48 +341,85 @@ pollcounter_vector::pollcounter_vector() throw()
|
|||
void pollcounter_vector::clear() throw()
|
||||
{
|
||||
system_flag = false;
|
||||
memset(ctrs, 0, sizeof(ctrs));
|
||||
//FIXME: Support more controllers/ports
|
||||
ctrs.resize(96);
|
||||
memset(&ctrs[0], 0, sizeof(uint32_t) * ctrs.size());
|
||||
}
|
||||
|
||||
void pollcounter_vector::set_all_DRDY() throw()
|
||||
{
|
||||
for(size_t i = 0; i < MAX_BUTTONS ; i++)
|
||||
for(size_t i = 0; i < ctrs.size() ; i++)
|
||||
ctrs[i] |= 0x80000000UL;
|
||||
}
|
||||
|
||||
#define INDEXOF(pcid, ctrl) ((pcid) * MAX_CONTROLS_PER_CONTROLLER + (ctrl))
|
||||
|
||||
void pollcounter_vector::clear_DRDY(unsigned pcid, unsigned ctrl) throw()
|
||||
namespace
|
||||
{
|
||||
ctrs[INDEXOF(pcid, ctrl)] &= 0x7FFFFFFFUL;
|
||||
inline size_t INDEXOF(unsigned port, unsigned pcid, unsigned ctrl)
|
||||
{
|
||||
//FIXME: Support more controls.
|
||||
return port * 48 + pcid * 12 + ctrl;
|
||||
}
|
||||
|
||||
bool pollcounter_vector::get_DRDY(unsigned pcid, unsigned ctrl) throw()
|
||||
inline unsigned IINDEXOF_PORT(unsigned c)
|
||||
{
|
||||
return ((ctrs[INDEXOF(pcid, ctrl)] & 0x80000000UL) != 0);
|
||||
//FIXME: Support more controls.
|
||||
return c / 48;
|
||||
}
|
||||
|
||||
inline unsigned IINDEXOF_PCID(unsigned c)
|
||||
{
|
||||
//FIXME: Support more controls.
|
||||
return c / 12 % 4;
|
||||
}
|
||||
|
||||
inline unsigned IINDEXOF_CTRL(unsigned c)
|
||||
{
|
||||
//FIXME: Support more controls.
|
||||
return c % 12;
|
||||
}
|
||||
}
|
||||
|
||||
void pollcounter_vector::clear_DRDY(unsigned port, unsigned pcid, unsigned ctrl) throw()
|
||||
{
|
||||
ctrs[INDEXOF(port, pcid, ctrl)] &= 0x7FFFFFFFUL;
|
||||
}
|
||||
|
||||
bool pollcounter_vector::get_DRDY(unsigned port, unsigned pcid, unsigned ctrl) throw()
|
||||
{
|
||||
return ((ctrs[INDEXOF(port, pcid, ctrl)] & 0x80000000UL) != 0);
|
||||
}
|
||||
|
||||
bool pollcounter_vector::has_polled() throw()
|
||||
{
|
||||
uint32_t res = system_flag ? 1 : 0;
|
||||
for(size_t i = 0; i < MAX_BUTTONS ; i++)
|
||||
for(size_t i = 0; i < ctrs.size(); i++)
|
||||
res |= ctrs[i];
|
||||
return ((res & 0x7FFFFFFFUL) != 0);
|
||||
}
|
||||
|
||||
uint32_t pollcounter_vector::get_polls(unsigned pcid, unsigned ctrl) throw()
|
||||
uint32_t pollcounter_vector::get_polls(unsigned port, unsigned pcid, unsigned ctrl) throw()
|
||||
{
|
||||
return ctrs[INDEXOF(pcid, ctrl)] & 0x7FFFFFFFUL;
|
||||
return ctrs[INDEXOF(port, pcid, ctrl)] & 0x7FFFFFFFUL;
|
||||
}
|
||||
|
||||
uint32_t pollcounter_vector::increment_polls(unsigned pcid, unsigned ctrl) throw()
|
||||
uint32_t pollcounter_vector::get_polls(unsigned ctrl) throw()
|
||||
{
|
||||
size_t i = INDEXOF(pcid, ctrl);
|
||||
return get_polls(IINDEXOF_PORT(ctrl), IINDEXOF_PCID(ctrl), IINDEXOF_CTRL(ctrl));
|
||||
}
|
||||
|
||||
uint32_t pollcounter_vector::increment_polls(unsigned port, unsigned pcid, unsigned ctrl) throw()
|
||||
{
|
||||
size_t i = INDEXOF(port, pcid, ctrl);
|
||||
uint32_t x = ctrs[i] & 0x7FFFFFFFUL;
|
||||
++ctrs[i];
|
||||
return x;
|
||||
}
|
||||
|
||||
unsigned pollcounter_vector::maxbuttons() throw()
|
||||
{
|
||||
return ctrs.size();
|
||||
}
|
||||
|
||||
void pollcounter_vector::set_system() throw()
|
||||
{
|
||||
system_flag = true;
|
||||
|
@ -396,7 +433,7 @@ bool pollcounter_vector::get_system() throw()
|
|||
uint32_t pollcounter_vector::max_polls() throw()
|
||||
{
|
||||
uint32_t max = system_flag ? 1 : 0;
|
||||
for(unsigned i = 0; i < MAX_BUTTONS; i++) {
|
||||
for(unsigned i = 0; i < ctrs.size(); i++) {
|
||||
uint32_t tmp = ctrs[i] & 0x7FFFFFFFUL;
|
||||
max = (max < tmp) ? tmp : max;
|
||||
}
|
||||
|
@ -405,29 +442,28 @@ uint32_t pollcounter_vector::max_polls() throw()
|
|||
|
||||
void pollcounter_vector::save_state(std::vector<uint32_t>& mem) throw(std::bad_alloc)
|
||||
{
|
||||
mem.resize(4 + MAX_BUTTONS );
|
||||
mem.resize(4 + ctrs.size());
|
||||
//Compatiblity fun.
|
||||
mem[0] = 0x80000000UL;
|
||||
mem[1] = system_flag ? 1 : 0x80000000UL;
|
||||
mem[2] = system_flag ? 1 : 0x80000000UL;
|
||||
mem[3] = system_flag ? 1 : 0x80000000UL;
|
||||
for(size_t i = 0; i < MAX_BUTTONS ; i++)
|
||||
for(size_t i = 0; i < ctrs.size(); i++)
|
||||
mem[4 + i] = ctrs[i];
|
||||
}
|
||||
|
||||
void pollcounter_vector::load_state(const std::vector<uint32_t>& mem) throw()
|
||||
{
|
||||
system_flag = (mem[1] | mem[2] | mem[3]) & 0x7FFFFFFFUL;
|
||||
for(size_t i = 0; i < MAX_BUTTONS ; i++)
|
||||
for(size_t i = 0; i < ctrs.size(); i++)
|
||||
ctrs[i] = mem[i + 4];
|
||||
}
|
||||
|
||||
bool pollcounter_vector::check(const std::vector<uint32_t>& mem) throw()
|
||||
{
|
||||
return (mem.size() == MAX_BUTTONS + 4);
|
||||
return (mem.size() == ctrs.size() + 4);
|
||||
}
|
||||
|
||||
|
||||
controller_frame::controller_frame(porttype_t p1, porttype_t p2) throw(std::runtime_error)
|
||||
{
|
||||
memset(memory, 0, sizeof(memory));
|
||||
|
@ -480,6 +516,30 @@ void controller_frame::set_types(const porttype_t* tarr)
|
|||
totalsize = offset;
|
||||
}
|
||||
|
||||
void controller_frame::axis2(unsigned ctrl, short value) throw()
|
||||
{
|
||||
axis(IINDEXOF_PORT(ctrl), IINDEXOF_PCID(ctrl), IINDEXOF_CTRL(ctrl), value);
|
||||
}
|
||||
|
||||
short controller_frame::axis2(unsigned ctrl) throw()
|
||||
{
|
||||
return axis(IINDEXOF_PORT(ctrl), IINDEXOF_PCID(ctrl), IINDEXOF_CTRL(ctrl));
|
||||
}
|
||||
|
||||
unsigned controller_frame::maxbuttons() throw()
|
||||
{
|
||||
//FIXME: Fix for more ports/controllers/controls
|
||||
return 96;
|
||||
}
|
||||
|
||||
bool controller_frame::type_matches(const controller_frame& a)
|
||||
{
|
||||
for(unsigned i = 0; i < MAX_PORTS; i++)
|
||||
if(a.types[i] != types[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t controller_frame_vector::walk_helper(size_t frame, bool sflag) throw()
|
||||
{
|
||||
size_t ret = sflag ? frame : 0;
|
||||
|
@ -717,6 +777,12 @@ controller_frame::controller_frame() throw()
|
|||
totalsize = SYSTEM_BYTES;
|
||||
}
|
||||
|
||||
unsigned controller_frame::control_count()
|
||||
{
|
||||
//FIXME: More controls.
|
||||
return 12;
|
||||
}
|
||||
|
||||
void controller_frame::set_port_type(unsigned port, porttype_t ptype) throw(std::runtime_error)
|
||||
{
|
||||
char tmp[MAXIMUM_CONTROLLER_FRAME_SIZE] = {0};
|
||||
|
@ -750,59 +816,46 @@ void controller_frame::set_port_type(unsigned port, porttype_t ptype) throw(std:
|
|||
|
||||
controller_state::controller_state() throw()
|
||||
{
|
||||
for(size_t i = 0; i < MAX_ANALOG; i++) {
|
||||
analog_indices[i] = -1;
|
||||
analog_mouse[i] = false;
|
||||
}
|
||||
for(size_t i = 0; i < MAX_PORTS; i++) {
|
||||
porttypes[i] = PT_INVALID;
|
||||
porttypeinfo[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int controller_state::lcid_to_pcid(unsigned lcid) throw()
|
||||
unsigned controller_state::lcid_count() throw()
|
||||
{
|
||||
//FIXME: Support more ports/controllers.
|
||||
return 8;
|
||||
}
|
||||
|
||||
std::pair<int, int> controller_state::lcid_to_pcid(unsigned lcid) throw()
|
||||
{
|
||||
if(!porttypeinfo[0] || !porttypeinfo[1])
|
||||
return -1;
|
||||
return std::make_pair(-1, -1);
|
||||
//FIXME: Support more ports/controllers.
|
||||
unsigned p1devs = porttypeinfo[0]->controllers;
|
||||
unsigned p2devs = porttypeinfo[1]->controllers;
|
||||
if(lcid >= p1devs + p2devs)
|
||||
return -1;
|
||||
return std::make_pair(-1, -1);
|
||||
//Exceptional: If p1 is none, map all to p2.
|
||||
if(!p1devs)
|
||||
return lcid + MAX_CONTROLLERS_PER_PORT;
|
||||
return std::make_pair(1, lcid);
|
||||
//LID 0 Is always PID 0 unless out of range.
|
||||
if(lcid == 0)
|
||||
return 0;
|
||||
return std::make_pair(0, 0);
|
||||
//LID 1-n are on port 2.
|
||||
else if(lcid < 1 + p2devs)
|
||||
return lcid - 1 + MAX_CONTROLLERS_PER_PORT;
|
||||
return std::make_pair(1, lcid- 1);
|
||||
//From there, those are on port 1 (except for the first).
|
||||
else
|
||||
return lcid - p2devs;
|
||||
return std::make_pair(0, lcid - p2devs);
|
||||
}
|
||||
|
||||
int controller_state::acid_to_pcid(unsigned acid) throw()
|
||||
devicetype_t controller_state::pcid_to_type(unsigned port, unsigned pcid) throw()
|
||||
{
|
||||
if(acid > MAX_ANALOG)
|
||||
return -1;
|
||||
return analog_indices[acid];
|
||||
}
|
||||
|
||||
bool controller_state::acid_is_mouse(unsigned acid) throw()
|
||||
{
|
||||
if(acid > MAX_ANALOG)
|
||||
return -1;
|
||||
return analog_mouse[acid];
|
||||
|
||||
}
|
||||
|
||||
devicetype_t controller_state::pcid_to_type(unsigned pcid) throw()
|
||||
{
|
||||
size_t port = pcid / MAX_CONTROLLERS_PER_PORT;
|
||||
if(port >= MAX_PORTS)
|
||||
return DT_NONE;
|
||||
return porttypeinfo[port]->devicetype(pcid % MAX_CONTROLLERS_PER_PORT);
|
||||
return porttypeinfo[port]->devicetype(pcid);
|
||||
}
|
||||
|
||||
controller_frame controller_state::get(uint64_t framenum) throw()
|
||||
|
@ -813,14 +866,10 @@ controller_frame controller_state::get(uint64_t framenum) throw()
|
|||
return _input ^ _autohold;
|
||||
}
|
||||
|
||||
void controller_state::analog(unsigned acid, int x, int y) throw()
|
||||
void controller_state::analog(unsigned port, unsigned pcid, int x, int y) throw()
|
||||
{
|
||||
if(acid >= MAX_ANALOG || analog_indices[acid] < 0) {
|
||||
messages << "No analog controller #" << acid << std::endl;
|
||||
return;
|
||||
}
|
||||
_input.axis(analog_indices[acid], 0, x);
|
||||
_input.axis(analog_indices[acid], 1, y);
|
||||
_input.axis(port, pcid, 0, x);
|
||||
_input.axis(port, pcid, 1, y);
|
||||
}
|
||||
|
||||
void controller_state::reset(int32_t delay) throw()
|
||||
|
@ -834,25 +883,25 @@ void controller_state::reset(int32_t delay) throw()
|
|||
}
|
||||
}
|
||||
|
||||
void controller_state::autohold(unsigned pcid, unsigned pbid, bool newstate) throw()
|
||||
void controller_state::autohold(unsigned port, unsigned pcid, unsigned pbid, bool newstate) throw()
|
||||
{
|
||||
_autohold.axis(pcid, pbid, newstate ? 1 : 0);
|
||||
information_dispatch::do_autohold_update(pcid, pbid, newstate);
|
||||
_autohold.axis(port, pcid, pbid, newstate ? 1 : 0);
|
||||
information_dispatch::do_autohold_update(port, pcid, pbid, newstate);
|
||||
}
|
||||
|
||||
bool controller_state::autohold(unsigned pcid, unsigned pbid) throw()
|
||||
bool controller_state::autohold(unsigned port, unsigned pcid, unsigned pbid) throw()
|
||||
{
|
||||
return (_autohold.axis(pcid, pbid) != 0);
|
||||
return (_autohold.axis(port, pcid, pbid) != 0);
|
||||
}
|
||||
|
||||
void controller_state::button(unsigned pcid, unsigned pbid, bool newstate) throw()
|
||||
void controller_state::button(unsigned port, unsigned pcid, unsigned pbid, bool newstate) throw()
|
||||
{
|
||||
_input.axis(pcid, pbid, newstate ? 1 : 0);
|
||||
_input.axis(port, pcid, pbid, newstate ? 1 : 0);
|
||||
}
|
||||
|
||||
bool controller_state::button(unsigned pcid, unsigned pbid) throw()
|
||||
bool controller_state::button(unsigned port, unsigned pcid, unsigned pbid) throw()
|
||||
{
|
||||
return (_input.axis(pcid, pbid) != 0);
|
||||
return (_input.axis(port, pcid, pbid) != 0);
|
||||
}
|
||||
|
||||
void controller_state::autofire(std::vector<controller_frame> pattern) throw(std::bad_alloc)
|
||||
|
@ -860,12 +909,11 @@ void controller_state::autofire(std::vector<controller_frame> pattern) throw(std
|
|||
_autofire = pattern;
|
||||
}
|
||||
|
||||
int controller_state::button_id(unsigned pcid, unsigned lbid) throw()
|
||||
int controller_state::button_id(unsigned port, unsigned pcid, unsigned lbid) throw()
|
||||
{
|
||||
size_t port = pcid / MAX_CONTROLLERS_PER_PORT;
|
||||
if(port >= MAX_PORTS)
|
||||
return -1;
|
||||
return porttypeinfo[port]->button_id(pcid % MAX_CONTROLLERS_PER_PORT, lbid);
|
||||
return porttypeinfo[port]->button_id(pcid, lbid);
|
||||
}
|
||||
|
||||
void controller_state::set_port(unsigned port, porttype_t ptype, bool set_core) throw(std::runtime_error)
|
||||
|
@ -887,29 +935,6 @@ void controller_state::set_port(unsigned port, porttype_t ptype, bool set_core)
|
|||
}
|
||||
porttypes[port] = ptype;
|
||||
porttypeinfo[port] = info;
|
||||
int i = 0;
|
||||
for(unsigned j = 0; j < MAX_ANALOG; j++)
|
||||
analog_indices[j] = -1;
|
||||
for(unsigned j = 0; j < MAX_PORTS * MAX_CONTROLLERS_PER_PORT; j++) {
|
||||
if(!porttypeinfo[j / MAX_CONTROLLERS_PER_PORT])
|
||||
continue;
|
||||
devicetype_t d = porttypeinfo[j / MAX_CONTROLLERS_PER_PORT]->devicetype(j % MAX_CONTROLLERS_PER_PORT);
|
||||
switch(d) {
|
||||
case DT_NONE:
|
||||
case DT_GAMEPAD:
|
||||
break;
|
||||
case DT_MOUSE:
|
||||
analog_mouse[i] = true;
|
||||
analog_indices[i++] = j;
|
||||
break;
|
||||
case DT_LIGHTGUN:
|
||||
analog_mouse[i] = false;
|
||||
analog_indices[i++] = j;
|
||||
break;
|
||||
}
|
||||
if(i == MAX_ANALOG)
|
||||
break;
|
||||
}
|
||||
information_dispatch::do_autohold_reconfigure();
|
||||
}
|
||||
|
||||
|
@ -936,12 +961,12 @@ controller_frame controller_state::commit(controller_frame controls) throw()
|
|||
return _committed;
|
||||
}
|
||||
|
||||
bool controller_state::is_analog(unsigned pcid) throw()
|
||||
bool controller_state::is_analog(unsigned port, unsigned pcid) throw()
|
||||
{
|
||||
return _input.is_analog(pcid);
|
||||
return _input.is_analog(port, pcid);
|
||||
}
|
||||
|
||||
bool controller_state::is_mouse(unsigned pcid) throw()
|
||||
bool controller_state::is_mouse(unsigned port, unsigned pcid) throw()
|
||||
{
|
||||
return _input.is_mouse(pcid);
|
||||
return _input.is_mouse(port, pcid);
|
||||
}
|
||||
|
|
|
@ -188,16 +188,16 @@ void information_dispatch::do_mode_change(bool readonly) throw()
|
|||
}
|
||||
}
|
||||
|
||||
void information_dispatch::on_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate)
|
||||
void information_dispatch::on_autohold_update(unsigned port, unsigned pid, unsigned ctrlnum, bool newstate)
|
||||
{
|
||||
//Do nothing.
|
||||
}
|
||||
|
||||
void information_dispatch::do_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate) throw()
|
||||
void information_dispatch::do_autohold_update(unsigned port, unsigned pid, unsigned ctrlnum, bool newstate) throw()
|
||||
{
|
||||
for(auto& i : dispatch()) {
|
||||
START_EH_BLOCK
|
||||
i->on_autohold_update(pid, ctrlnum, newstate);
|
||||
i->on_autohold_update(port, pid, ctrlnum, newstate);
|
||||
END_EH_BLOCK(i, "on_autohold_update");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -259,13 +259,13 @@ void update_movie_state()
|
|||
c = movb.get_movie().get_controls();
|
||||
else
|
||||
c = controls.get_committed();
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
unsigned pindex = controls.lcid_to_pcid(i);
|
||||
devicetype_t dtype = controls.pcid_to_type(pindex);
|
||||
for(unsigned i = 0; i < controls.lcid_count(); i++) {
|
||||
auto pindex = controls.lcid_to_pcid(i);
|
||||
devicetype_t dtype = controls.pcid_to_type(pindex.first, pindex.second);
|
||||
if(dtype == DT_NONE)
|
||||
continue;
|
||||
char buffer[MAX_DISPLAY_LENGTH];
|
||||
c.display(pindex, buffer);
|
||||
c.display(pindex.first, pindex.second, buffer);
|
||||
char y[3] = {'P', 0, 0};
|
||||
y[1] = 49 + i;
|
||||
_status.set(y, buffer);
|
||||
|
@ -340,7 +340,7 @@ class my_interface : public SNES::Interface
|
|||
int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id)
|
||||
{
|
||||
int16_t x;
|
||||
x = movb.input_poll(port, index, id);
|
||||
x = movb.input_poll(port ? 1 : 0, index, id);
|
||||
lua_callback_snoop_input(port ? 1 : 0, index, id, x);
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ namespace
|
|||
//Project IDs have to match.
|
||||
if(old_projectid != new_projectid)
|
||||
return false;
|
||||
//The controller types have to match.
|
||||
if(!old_movie.blank_frame(false).type_matches(new_movie.blank_frame(false)))
|
||||
return false;
|
||||
//If new movie is before first frame, anything with same project_id is compatible.
|
||||
if(frame == 0)
|
||||
return true;
|
||||
|
@ -64,7 +67,8 @@ namespace
|
|||
if(old_reset != new_reset || old_delay != new_delay)
|
||||
return false;
|
||||
//Then rest of the stuff.
|
||||
for(unsigned i = 0; i < MAX_BUTTONS; i++) {
|
||||
unsigned buttons = old_movie.blank_frame(false).maxbuttons();
|
||||
for(unsigned i = 0; i < buttons; i++) {
|
||||
uint32_t p = polls[i + 4] & 0x7FFFFFFFUL;
|
||||
short ov = 0, nv = 0;
|
||||
for(uint32_t j = 0; j < p; j++) {
|
||||
|
@ -136,7 +140,7 @@ controller_frame movie::get_controls() throw()
|
|||
c.reset(movie_data[current_frame_first_subframe].reset());
|
||||
c.delay(movie_data[current_frame_first_subframe].delay());
|
||||
}
|
||||
for(size_t i = 0; i < MAX_BUTTONS; i++) {
|
||||
for(size_t i = 0; i < c.maxbuttons(); i++) {
|
||||
uint32_t polls = pollcounters.get_polls(i);
|
||||
uint32_t index = (changes > polls) ? polls : changes - 1;
|
||||
c.axis2(i, movie_data[current_frame_first_subframe + index].axis2(i));
|
||||
|
@ -188,20 +192,20 @@ void movie::next_frame() throw(std::bad_alloc)
|
|||
current_frame++;
|
||||
}
|
||||
|
||||
bool movie::get_DRDY(unsigned pid, unsigned ctrl) throw(std::logic_error)
|
||||
bool movie::get_DRDY(unsigned port, unsigned pid, unsigned ctrl) throw(std::logic_error)
|
||||
{
|
||||
return pollcounters.get_DRDY(pid, ctrl);
|
||||
return pollcounters.get_DRDY(port, pid, ctrl);
|
||||
}
|
||||
|
||||
short movie::next_input(unsigned pid, unsigned ctrl) throw(std::bad_alloc, std::logic_error)
|
||||
short movie::next_input(unsigned port, unsigned pid, unsigned ctrl) throw(std::bad_alloc, std::logic_error)
|
||||
{
|
||||
pollcounters.clear_DRDY(pid, ctrl);
|
||||
pollcounters.clear_DRDY(port, pid, ctrl);
|
||||
|
||||
if(readonly) {
|
||||
//In readonly mode...
|
||||
//If at the end of the movie, return released / neutral (but also record the poll)...
|
||||
if(current_frame_first_subframe >= movie_data.size()) {
|
||||
pollcounters.increment_polls(pid, ctrl);
|
||||
pollcounters.increment_polls(port, pid, ctrl);
|
||||
return 0;
|
||||
}
|
||||
//Before the beginning? Somebody screwed up (but return released / neutral anyway)...
|
||||
|
@ -209,10 +213,10 @@ short movie::next_input(unsigned pid, unsigned ctrl) throw(std::bad_alloc, std::
|
|||
return 0;
|
||||
//Otherwise find the last valid frame of input.
|
||||
uint32_t changes = count_changes(current_frame_first_subframe);
|
||||
uint32_t polls = pollcounters.increment_polls(pid, ctrl);
|
||||
uint32_t polls = pollcounters.increment_polls(port, pid, ctrl);
|
||||
uint32_t index = (changes > polls) ? polls : changes - 1;
|
||||
//debuglog << "Frame=" << current_frame << " Subframe=" << polls << " control=" << controlindex << " value=" << movie_data[current_frame_first_subframe + index](controlindex) << " fetchrow=" << current_frame_first_subframe + index << std::endl << std::flush;
|
||||
return movie_data[current_frame_first_subframe + index].axis(pid, ctrl);
|
||||
return movie_data[current_frame_first_subframe + index].axis(port, pid, ctrl);
|
||||
} else {
|
||||
//Readwrite mode.
|
||||
//Before the beginning? Somebody screwed up (but return released / neutral anyway)...
|
||||
|
@ -223,30 +227,30 @@ short movie::next_input(unsigned pid, unsigned ctrl) throw(std::bad_alloc, std::
|
|||
if(current_frame_first_subframe >= movie_data.size()) {
|
||||
movie_data.append(current_controls.copy(true));
|
||||
//current_frame_first_subframe should be movie_data.size(), so it is right.
|
||||
pollcounters.increment_polls(pid, ctrl);
|
||||
pollcounters.increment_polls(port, pid, ctrl);
|
||||
frames_in_movie++;
|
||||
//debuglog << "Frame=" << current_frame << " Subframe=" << (pollcounters[controlindex] - 1) << " control=" << controlindex << " value=" << movie_data[current_frame_first_subframe](controlindex) << " fetchrow=" << current_frame_first_subframe << std::endl << std::flush;
|
||||
return movie_data[current_frame_first_subframe].axis(pid, ctrl);
|
||||
return movie_data[current_frame_first_subframe].axis(port, pid, ctrl);
|
||||
}
|
||||
short new_value = current_controls.axis(pid, ctrl);
|
||||
short new_value = current_controls.axis(port, pid, ctrl);
|
||||
//Fortunately, we know this frame is the last one in movie_data.
|
||||
uint32_t pollcounter = pollcounters.get_polls(pid, ctrl);
|
||||
uint32_t pollcounter = pollcounters.get_polls(port, pid, ctrl);
|
||||
uint64_t fetchrow = movie_data.size() - 1;
|
||||
if(current_frame_first_subframe + pollcounter < movie_data.size()) {
|
||||
//The index is within existing size. Change the value and propagate to all subsequent
|
||||
//subframes.
|
||||
for(uint64_t i = current_frame_first_subframe + pollcounter; i < movie_data.size(); i++)
|
||||
movie_data[i].axis(pid, ctrl, new_value);
|
||||
movie_data[i].axis(port, pid, ctrl, new_value);
|
||||
fetchrow = current_frame_first_subframe + pollcounter;
|
||||
} else if(new_value != movie_data[movie_data.size() - 1].axis(pid, ctrl)) {
|
||||
} else if(new_value != movie_data[movie_data.size() - 1].axis(port, pid, ctrl)) {
|
||||
//The index is not within existing size and value does not match. We need to create a new
|
||||
//subframes(s), copying the last subframe.
|
||||
while(current_frame_first_subframe + pollcounter >= movie_data.size())
|
||||
movie_data.append(movie_data[movie_data.size() - 1].copy(false));
|
||||
fetchrow = current_frame_first_subframe + pollcounter;
|
||||
movie_data[current_frame_first_subframe + pollcounter].axis(pid, ctrl, new_value);
|
||||
movie_data[current_frame_first_subframe + pollcounter].axis(port, pid, ctrl, new_value);
|
||||
}
|
||||
pollcounters.increment_polls(pid, ctrl);
|
||||
pollcounters.increment_polls(port, pid, ctrl);
|
||||
//debuglog << "Frame=" << current_frame << " Subframe=" << (pollcounters[controlindex] - 1) << " control=" << controlindex << " value=" << new_value << " fetchrow=" << fetchrow << std::endl << std::flush;
|
||||
return new_value;
|
||||
}
|
||||
|
@ -353,7 +357,7 @@ void movie::readonly_mode(bool enable) throw(std::bad_alloc)
|
|||
movie_data[j].delay(movie_data[current_frame_first_subframe].delay());
|
||||
}
|
||||
//Then the other buttons.
|
||||
for(size_t i = 0; i < MAX_BUTTONS; i++) {
|
||||
for(size_t i = 0; i < pollcounters.maxbuttons(); i++) {
|
||||
uint32_t polls = pollcounters.get_polls(i);
|
||||
polls = polls ? polls : 1;
|
||||
for(uint64_t j = current_frame_first_subframe + polls; j < next_frame_first_subframe; j++)
|
||||
|
@ -482,14 +486,13 @@ long movie_logic::new_frame_starting(bool dont_poll) throw(std::bad_alloc, std::
|
|||
return mov.get_reset_status();
|
||||
}
|
||||
|
||||
short movie_logic::input_poll(bool port, unsigned dev, unsigned id) throw(std::bad_alloc, std::runtime_error)
|
||||
short movie_logic::input_poll(unsigned port, unsigned dev, unsigned id) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
unsigned pid = port ? (dev + MAX_CONTROLLERS_PER_PORT) : dev;
|
||||
if(!mov.get_DRDY(pid, id)) {
|
||||
if(!mov.get_DRDY(port, dev, id)) {
|
||||
mov.set_controls(update_controls(true));
|
||||
mov.set_all_DRDY();
|
||||
}
|
||||
int16_t in = mov.next_input(pid, id);
|
||||
int16_t in = mov.next_input(port, dev, id);
|
||||
//debuglog << "BSNES asking for (" << port << "," << dev << "," << id << ") (frame " << mov.get_current_frame()
|
||||
// << ") giving " << in << std::endl;
|
||||
//debuglog.flush();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "core/window.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
#include "library/backtrace.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
@ -575,8 +576,16 @@ void platform::queue(const std::string& c) throw(std::bad_alloc)
|
|||
|
||||
void platform::queue(void (*f)(void* arg), void* arg, bool sync) throw(std::bad_alloc)
|
||||
{
|
||||
if(sync && queue_synchronous_fn_warning)
|
||||
if(sync && queue_synchronous_fn_warning) {
|
||||
void* buffer[512];
|
||||
int ss = lsnes_backtrace(buffer, 512);
|
||||
std::cerr << "WARNING: Synchronous queue in callback to UI, this may deadlock!" << std::endl;
|
||||
std::cerr << "UI called from:" << std::endl;
|
||||
lsnes_backtrace_symbols_stderr(queue_synchronous_fn_stack, queue_synchronous_fn_stacksize);
|
||||
std::cerr << "Queue called from:" << std::endl;
|
||||
lsnes_backtrace_symbols_stderr(buffer, ss);
|
||||
std::cerr << "----------------------------------" << std::endl;
|
||||
}
|
||||
init_threading();
|
||||
mutex::holder h(*queue_lock);
|
||||
++next_function;
|
||||
|
@ -659,3 +668,5 @@ modal_pause_holder::~modal_pause_holder()
|
|||
bool platform::pausing_allowed = true;
|
||||
double platform::global_volume = 1.0;
|
||||
volatile bool queue_synchronous_fn_warning;
|
||||
void* queue_synchronous_fn_stack[512];
|
||||
size_t queue_synchronous_fn_stacksize;
|
||||
|
|
25
src/library/backtrace.cpp
Normal file
25
src/library/backtrace.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "library/backtrace.hpp"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <execinfo.h>
|
||||
|
||||
int lsnes_backtrace(void** buffer, int size)
|
||||
{
|
||||
return backtrace(buffer, size);
|
||||
}
|
||||
|
||||
void lsnes_backtrace_symbols_stderr(void* const* buffer, int size)
|
||||
{
|
||||
backtrace_symbols_fd(buffer, size, 2);
|
||||
}
|
||||
#else
|
||||
int lsnes_backtrace(void** buffer, int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lsnes_backtrace_symbols_stderr(void* const* buffer, int size)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
|
@ -8,23 +8,21 @@ namespace
|
|||
function_ptr_luafun iset("input.set", [](lua_State* LS, const std::string& fname) -> int {
|
||||
if(!lua_input_controllerdata)
|
||||
return 0;
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
unsigned index = get_numeric_argument<unsigned>(LS, 2, fname.c_str());
|
||||
short value = get_numeric_argument<short>(LS, 3, fname.c_str());
|
||||
if(controller >= MAX_PORTS * MAX_CONTROLLERS_PER_PORT || index > MAX_CONTROLS_PER_CONTROLLER)
|
||||
return 0;
|
||||
lua_input_controllerdata->axis(controller, index, value);
|
||||
unsigned port = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 2, fname.c_str());
|
||||
unsigned index = get_numeric_argument<unsigned>(LS, 3, fname.c_str());
|
||||
short value = get_numeric_argument<short>(LS, 4, fname.c_str());
|
||||
lua_input_controllerdata->axis(port, controller, index, value);
|
||||
return 0;
|
||||
});
|
||||
|
||||
function_ptr_luafun iget("input.get", [](lua_State* LS, const std::string& fname) -> int {
|
||||
if(!lua_input_controllerdata)
|
||||
return 0;
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
unsigned index = get_numeric_argument<unsigned>(LS, 2, fname.c_str());
|
||||
if(controller >= MAX_PORTS * MAX_CONTROLLERS_PER_PORT || index > MAX_CONTROLS_PER_CONTROLLER)
|
||||
return 0;
|
||||
lua_pushnumber(LS, lua_input_controllerdata->axis(controller, index));
|
||||
unsigned port = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 2, fname.c_str());
|
||||
unsigned index = get_numeric_argument<unsigned>(LS, 3, fname.c_str());
|
||||
lua_pushnumber(LS, lua_input_controllerdata->axis(port, controller, index));
|
||||
return 1;
|
||||
});
|
||||
|
||||
|
@ -32,14 +30,13 @@ namespace
|
|||
if(!lua_input_controllerdata)
|
||||
return 0;
|
||||
short val;
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
if(controller >= MAX_PORTS * MAX_CONTROLLERS_PER_PORT)
|
||||
return 0;
|
||||
uint64_t base = get_numeric_argument<uint64_t>(LS, 2, fname.c_str());
|
||||
for(unsigned i = 0; i < MAX_CONTROLS_PER_CONTROLLER; i++) {
|
||||
unsigned port = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 2, fname.c_str());
|
||||
uint64_t base = get_numeric_argument<uint64_t>(LS, 3, fname.c_str());
|
||||
for(unsigned i = 0; i < lua_input_controllerdata->control_count(); i++) {
|
||||
val = (base >> i) & 1;
|
||||
get_numeric_argument<short>(LS, i + 3, val, fname.c_str());
|
||||
lua_input_controllerdata->axis(controller, i, val);
|
||||
get_numeric_argument<short>(LS, i + 4, val, fname.c_str());
|
||||
lua_input_controllerdata->axis(port, controller, i, val);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
@ -47,26 +44,26 @@ namespace
|
|||
function_ptr_luafun igeta("input.geta", [](lua_State* LS, const std::string& fname) -> int {
|
||||
if(!lua_input_controllerdata)
|
||||
return 0;
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
if(controller >= MAX_PORTS * MAX_CONTROLLERS_PER_PORT)
|
||||
return 0;
|
||||
unsigned port = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 2, fname.c_str());
|
||||
uint64_t fret = 0;
|
||||
for(unsigned i = 0; i < MAX_CONTROLS_PER_CONTROLLER; i++)
|
||||
if(lua_input_controllerdata->axis(controller, i))
|
||||
for(unsigned i = 0; i < lua_input_controllerdata->control_count(); i++)
|
||||
if(lua_input_controllerdata->axis(port, controller, i))
|
||||
fret |= (1ULL << i);
|
||||
lua_pushnumber(LS, fret);
|
||||
for(unsigned i = 0; i < MAX_CONTROLS_PER_CONTROLLER; i++)
|
||||
lua_pushnumber(LS, lua_input_controllerdata->axis(controller, i));
|
||||
return MAX_CONTROLS_PER_CONTROLLER + 1;
|
||||
for(unsigned i = 0; i < lua_input_controllerdata->control_count(); i++)
|
||||
lua_pushnumber(LS, lua_input_controllerdata->axis(port, controller, i));
|
||||
return lua_input_controllerdata->control_count() + 1;
|
||||
});
|
||||
|
||||
function_ptr_luafun igett("input.controllertype", [](lua_State* LS, const std::string& fname) -> int {
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
unsigned port = get_numeric_argument<unsigned>(LS, 1, fname.c_str());
|
||||
unsigned controller = get_numeric_argument<unsigned>(LS, 2, fname.c_str());
|
||||
auto& m = get_movie();
|
||||
controller_frame f = m.read_subframe(m.get_current_frame(), 0);
|
||||
porttype_t p = f.get_port_type(controller / MAX_CONTROLLERS_PER_PORT);
|
||||
porttype_t p = f.get_port_type(port);
|
||||
const porttype_info& i = porttype_info::lookup(p);
|
||||
if(i.controllers <= controller % MAX_CONTROLLERS_PER_PORT)
|
||||
if(i.controllers <= controller)
|
||||
lua_pushnil(LS);
|
||||
else if(p == PT_NONE)
|
||||
lua_pushnil(LS);
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace
|
|||
lua_pushnumber(LS, r.delay().second);
|
||||
lua_settable(LS, -3);
|
||||
|
||||
for(size_t i = 0; i < MAX_BUTTONS; i++) {
|
||||
for(size_t i = 0; i < r.maxbuttons(); i++) {
|
||||
lua_pushnumber(LS, i + 4);
|
||||
lua_pushnumber(LS, r.axis2(i));
|
||||
lua_settable(LS, -3);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "core/settings.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "interface/core.hpp"
|
||||
#include "library/backtrace.hpp"
|
||||
#include "library/zip.hpp"
|
||||
|
||||
#include "platform/wxwidgets/platform.hpp"
|
||||
|
@ -81,6 +82,8 @@ namespace
|
|||
{
|
||||
void(*fn)(void*);
|
||||
void* arg;
|
||||
int stacksize;
|
||||
void* stack[512];
|
||||
};
|
||||
|
||||
std::list<ui_queue_entry> ui_queue;
|
||||
|
@ -139,6 +142,8 @@ back:
|
|||
if(ui_queue.empty())
|
||||
goto end;
|
||||
i = ui_queue.begin();
|
||||
memcpy(queue_synchronous_fn_stack, i->stack, i->stacksize * sizeof(void*));
|
||||
queue_synchronous_fn_stacksize = i->stacksize;
|
||||
}
|
||||
i->fn(i->arg);
|
||||
{
|
||||
|
@ -389,6 +394,7 @@ void _runuifun_async(void (*fn)(void*), void* arg)
|
|||
ui_queue_entry e;
|
||||
e.fn = fn;
|
||||
e.arg = arg;
|
||||
e.stacksize = lsnes_backtrace(e.stack, 512);
|
||||
ui_queue.push_back(e);
|
||||
auto i = ui_queue.insert(ui_queue.end(), e);
|
||||
post_ui_event(UISERV_UIFUN);
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
#include "platform/wxwidgets/window_mainwindow.hpp"
|
||||
#include "platform/wxwidgets/window_status.hpp"
|
||||
|
||||
#define MAXCONTROLLERS MAX_PORTS * MAX_CONTROLLERS_PER_PORT
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#ifndef UINT64_C
|
||||
|
@ -38,6 +36,9 @@ extern "C"
|
|||
#include <libswscale/swscale.h>
|
||||
}
|
||||
|
||||
//FIXME: Support more ports/controllers.
|
||||
#define MAXCONTROLLERS 8
|
||||
|
||||
enum
|
||||
{
|
||||
wxID_PAUSE = wxID_HIGHEST + 1,
|
||||
|
@ -179,29 +180,29 @@ namespace
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool UI_get_autohold(unsigned pid, unsigned idx)
|
||||
bool UI_get_autohold(unsigned port, unsigned pid, unsigned idx)
|
||||
{
|
||||
bool ret;
|
||||
runemufn([&ret, pid, idx]() { ret = controls.autohold(pid, idx); });
|
||||
runemufn([&ret, port, pid, idx]() { ret = controls.autohold(port, pid, idx); });
|
||||
return ret;
|
||||
}
|
||||
|
||||
void UI_change_autohold(unsigned pid, unsigned idx, bool newstate)
|
||||
void UI_change_autohold(unsigned port, unsigned pid, unsigned idx, bool newstate)
|
||||
{
|
||||
runemufn([pid, idx, newstate]() { controls.autohold(pid, idx, newstate); });
|
||||
runemufn([port, pid, idx, newstate]() { controls.autohold(port, pid, idx, newstate); });
|
||||
}
|
||||
|
||||
int UI_controller_index_by_logical(unsigned lid)
|
||||
std::pair<int, int> UI_controller_index_by_logical(unsigned lid)
|
||||
{
|
||||
int ret;
|
||||
std::pair<int, int> ret;
|
||||
runemufn([&ret, lid]() { ret = controls.lcid_to_pcid(lid); });
|
||||
return ret;
|
||||
}
|
||||
|
||||
int UI_button_id(unsigned pcid, unsigned lidx)
|
||||
int UI_button_id(unsigned port, unsigned pcid, unsigned lidx)
|
||||
{
|
||||
int ret;
|
||||
runemufn([&ret, pcid, lidx]() { ret = controls.button_id(pcid, lidx); });
|
||||
runemufn([&ret, port, pcid, lidx]() { ret = controls.button_id(port, pcid, lidx); });
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -221,7 +222,7 @@ namespace
|
|||
void change_type();
|
||||
bool is_dummy();
|
||||
void on_select(wxCommandEvent& e);
|
||||
void update(unsigned pid, unsigned ctrlnum, bool newstate);
|
||||
void update(std::pair<int, int> pid, unsigned ctrlnum, bool newstate);
|
||||
private:
|
||||
unsigned our_lid;
|
||||
wxMenuItem* entries[MAX_LOGICAL_BUTTONS];
|
||||
|
@ -234,10 +235,10 @@ namespace
|
|||
autohold_menu(wxwin_mainwindow* win);
|
||||
void reconfigure();
|
||||
void on_select(wxCommandEvent& e);
|
||||
void update(unsigned pid, unsigned ctrlnum, bool newstate);
|
||||
void update(unsigned port, unsigned pid, unsigned ctrlnum, bool newstate);
|
||||
private:
|
||||
controller_autohold_menu* menus[MAXCONTROLLERS];
|
||||
wxMenuItem* entries[MAXCONTROLLERS];
|
||||
std::vector<controller_autohold_menu*> menus;
|
||||
std::vector<wxMenuItem*> entries;
|
||||
};
|
||||
|
||||
class sound_select_menu : public wxMenu
|
||||
|
@ -262,7 +263,7 @@ namespace
|
|||
void on_sound_unmute(bool unmute) throw();
|
||||
void on_sound_change(const std::string& dev) throw();
|
||||
void on_mode_change(bool readonly) throw();
|
||||
void on_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate);
|
||||
void on_autohold_update(unsigned port, unsigned pid, unsigned ctrlnum, bool newstate);
|
||||
void on_autohold_reconfigure();
|
||||
private:
|
||||
wxwin_mainwindow* mainw;
|
||||
|
@ -284,13 +285,13 @@ namespace
|
|||
void controller_autohold_menu::change_type()
|
||||
{
|
||||
enabled_entries = 0;
|
||||
int pid = controls.lcid_to_pcid(our_lid);
|
||||
auto pid = controls.lcid_to_pcid(our_lid);
|
||||
for(unsigned i = 0; i < MAX_LOGICAL_BUTTONS; i++) {
|
||||
int pidx = -1;
|
||||
if(pid >= 0)
|
||||
pidx = controls.button_id(pid, i);
|
||||
if(pid.first >= 0)
|
||||
pidx = controls.button_id(pid.first, pid.second, i);
|
||||
if(pidx >= 0) {
|
||||
entries[i]->Check(pid > 0 && UI_get_autohold(pid, pidx));
|
||||
entries[i]->Check(pid.first > 0 && UI_get_autohold(pid.first, pid.second, pidx));
|
||||
entries[i]->Enable();
|
||||
enabled_entries++;
|
||||
} else {
|
||||
|
@ -314,41 +315,33 @@ namespace
|
|||
}
|
||||
unsigned lidx = (x - wxID_AUTOHOLD_FIRST) % MAX_LOGICAL_BUTTONS;
|
||||
modal_pause_holder hld;
|
||||
int pid = controls.lcid_to_pcid(our_lid);
|
||||
if(pid < 0 || !entries[lidx])
|
||||
auto pid = controls.lcid_to_pcid(our_lid);
|
||||
if(pid.first < 0 || !entries[lidx])
|
||||
return;
|
||||
int pidx = controls.button_id(pid, lidx);
|
||||
int pidx = controls.button_id(pid.first, pid.second, lidx);
|
||||
if(pidx < 0)
|
||||
return;
|
||||
//Autohold change on pid=pid, ctrlindx=idx, state
|
||||
bool newstate = entries[lidx]->IsChecked();
|
||||
UI_change_autohold(pid, pidx, newstate);
|
||||
UI_change_autohold(pid.first, pid.second, pidx, newstate);
|
||||
}
|
||||
|
||||
void controller_autohold_menu::update(unsigned pid, unsigned ctrlnum, bool newstate)
|
||||
void controller_autohold_menu::update(std::pair<int, int> pid, unsigned ctrlnum, bool newstate)
|
||||
{
|
||||
modal_pause_holder hld;
|
||||
int pid2 = UI_controller_index_by_logical(our_lid);
|
||||
if(pid2 < 0 || static_cast<unsigned>(pid) != pid2)
|
||||
auto pid2 = UI_controller_index_by_logical(our_lid);
|
||||
if(pid2.first < 0 || pid != pid2)
|
||||
return;
|
||||
for(unsigned i = 0; i < MAX_LOGICAL_BUTTONS; i++) {
|
||||
int idx = UI_button_id(pid2, i);
|
||||
int idx = UI_button_id(pid2.first, pid2.second, i);
|
||||
if(idx < 0 || static_cast<unsigned>(idx) != ctrlnum)
|
||||
continue;
|
||||
entries[i]->Check(newstate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
autohold_menu::autohold_menu(wxwin_mainwindow* win)
|
||||
{
|
||||
for(unsigned i = 0; i < MAXCONTROLLERS; i++) {
|
||||
std::ostringstream str;
|
||||
str << "Controller #&" << (i + 1);
|
||||
menus[i] = new controller_autohold_menu(i, DT_NONE);
|
||||
entries[i] = AppendSubMenu(menus[i], towxstring(str.str()));
|
||||
entries[i]->Enable(!menus[i]->is_dummy());
|
||||
}
|
||||
win->Connect(wxID_AUTOHOLD_FIRST, wxID_AUTOHOLD_LAST, wxEVT_COMMAND_MENU_SELECTED,
|
||||
wxCommandEventHandler(autohold_menu::on_select), NULL, this);
|
||||
reconfigure();
|
||||
|
@ -357,7 +350,19 @@ namespace
|
|||
void autohold_menu::reconfigure()
|
||||
{
|
||||
modal_pause_holder hld;
|
||||
for(unsigned i = 0; i < MAXCONTROLLERS; i++) {
|
||||
unsigned idx;
|
||||
for(idx = menus.size(); controls.lcid_to_pcid(idx).first >= 0; idx++);
|
||||
unsigned osize = menus.size();
|
||||
menus.resize(idx);
|
||||
entries.resize(idx);
|
||||
for(unsigned i = osize; i < menus.size(); i++) {
|
||||
std::ostringstream str;
|
||||
str << "Controller #&" << (i + 1);
|
||||
menus[i] = new controller_autohold_menu(i, DT_NONE);
|
||||
entries[i] = AppendSubMenu(menus[i], towxstring(str.str()));
|
||||
entries[i]->Enable(!menus[i]->is_dummy());
|
||||
}
|
||||
for(unsigned i = 0; i < menus.size(); i++) {
|
||||
menus[i]->change_type();
|
||||
entries[i]->Enable(!menus[i]->is_dummy());
|
||||
}
|
||||
|
@ -365,14 +370,14 @@ namespace
|
|||
|
||||
void autohold_menu::on_select(wxCommandEvent& e)
|
||||
{
|
||||
for(unsigned i = 0; i < MAXCONTROLLERS; i++)
|
||||
for(unsigned i = 0; i < menus.size(); i++)
|
||||
menus[i]->on_select(e);
|
||||
}
|
||||
|
||||
void autohold_menu::update(unsigned pid, unsigned ctrlnum, bool newstate)
|
||||
void autohold_menu::update(unsigned port, unsigned pid, unsigned ctrlnum, bool newstate)
|
||||
{
|
||||
for(unsigned i = 0; i < MAXCONTROLLERS; i++)
|
||||
menus[i]->update(pid, ctrlnum, newstate);
|
||||
for(unsigned i = 0; i < menus.size(); i++)
|
||||
menus[i]->update(std::make_pair(port, pid), ctrlnum, newstate);
|
||||
}
|
||||
|
||||
sound_select_menu::sound_select_menu(wxwin_mainwindow* win)
|
||||
|
@ -433,9 +438,9 @@ namespace
|
|||
runuifun([readonly, mainw]() { mainw->menu_check(wxID_READONLY_MODE, readonly); });
|
||||
}
|
||||
|
||||
void broadcast_listener::on_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate)
|
||||
void broadcast_listener::on_autohold_update(unsigned port, unsigned pid, unsigned ctrlnum, bool newstate)
|
||||
{
|
||||
runuifun([pid, ctrlnum, newstate, ahmenu]() { ahmenu->update(pid, ctrlnum, newstate); });
|
||||
runuifun([port, pid, ctrlnum, newstate, ahmenu]() { ahmenu->update(port, pid, ctrlnum, newstate); });
|
||||
}
|
||||
|
||||
void broadcast_listener::on_autohold_reconfigure()
|
||||
|
|
Loading…
Add table
Reference in a new issue