diff --git a/include/core/controllerframe.hpp b/include/core/controllerframe.hpp index 5d60f197..5e01f0df 100644 --- a/include/core/controllerframe.hpp +++ b/include/core/controllerframe.hpp @@ -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& mem) throw(); private: - uint32_t ctrs[MAX_BUTTONS]; + std::vector 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 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; diff --git a/include/core/dispatch.hpp b/include/core/dispatch.hpp index 0ad3ac14..7ba4d5a4 100644 --- a/include/core/dispatch.hpp +++ b/include/core/dispatch.hpp @@ -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. * diff --git a/include/core/movie.hpp b/include/core/movie.hpp index 5fbae63f..05fbcf3b 100644 --- a/include/core/movie.hpp +++ b/include/core/movie.hpp @@ -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. diff --git a/include/core/window.hpp b/include/core/window.hpp index ab6d2c5e..ed225466 100644 --- a/include/core/window.hpp +++ b/include/core/window.hpp @@ -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 diff --git a/include/library/backtrace.hpp b/include/library/backtrace.hpp new file mode 100644 index 00000000..29d5ed36 --- /dev/null +++ b/include/library/backtrace.hpp @@ -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 diff --git a/src/core/controller.cpp b/src/core/controller.cpp index 7614e50c..d92f4730 100644 --- a/src/core/controller.cpp +++ b/src/core/controller.cpp @@ -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 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); diff --git a/src/core/controllerframe.cpp b/src/core/controllerframe.cpp index fee74909..c5c62d42 100644 --- a/src/core/controllerframe.cpp +++ b/src/core/controllerframe.cpp @@ -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; + } + + inline unsigned IINDEXOF_PORT(unsigned c) + { + //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; + } } -bool pollcounter_vector::get_DRDY(unsigned pcid, unsigned ctrl) throw() +void pollcounter_vector::clear_DRDY(unsigned port, unsigned pcid, unsigned ctrl) throw() { - return ((ctrs[INDEXOF(pcid, ctrl)] & 0x80000000UL) != 0); + 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& 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& 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& 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 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 pattern) throw(std::bad_alloc) @@ -860,12 +909,11 @@ void controller_state::autofire(std::vector 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); } diff --git a/src/core/dispatch.cpp b/src/core/dispatch.cpp index 89657801..10be306a 100644 --- a/src/core/dispatch.cpp +++ b/src/core/dispatch.cpp @@ -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"); } } diff --git a/src/core/mainloop.cpp b/src/core/mainloop.cpp index 83198695..5a62601e 100644 --- a/src/core/mainloop.cpp +++ b/src/core/mainloop.cpp @@ -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; } diff --git a/src/core/movie.cpp b/src/core/movie.cpp index 96402d16..d4e8db3f 100644 --- a/src/core/movie.cpp +++ b/src/core/movie.cpp @@ -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(); diff --git a/src/core/window.cpp b/src/core/window.cpp index 615e66ab..e2837b08 100644 --- a/src/core/window.cpp +++ b/src/core/window.cpp @@ -7,6 +7,7 @@ #include "core/window.hpp" #include "library/string.hpp" #include "library/minmax.hpp" +#include "library/backtrace.hpp" #include #include @@ -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; diff --git a/src/library/backtrace.cpp b/src/library/backtrace.cpp new file mode 100644 index 00000000..7e9c5818 --- /dev/null +++ b/src/library/backtrace.cpp @@ -0,0 +1,25 @@ +#include "library/backtrace.hpp" + +#ifdef __linux__ +#include + +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 diff --git a/src/lua/input.cpp b/src/lua/input.cpp index e39251fa..b39837d3 100644 --- a/src/lua/input.cpp +++ b/src/lua/input.cpp @@ -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(LS, 1, fname.c_str()); - unsigned index = get_numeric_argument(LS, 2, fname.c_str()); - short value = get_numeric_argument(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(LS, 1, fname.c_str()); + unsigned controller = get_numeric_argument(LS, 2, fname.c_str()); + unsigned index = get_numeric_argument(LS, 3, fname.c_str()); + short value = get_numeric_argument(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(LS, 1, fname.c_str()); - unsigned index = get_numeric_argument(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(LS, 1, fname.c_str()); + unsigned controller = get_numeric_argument(LS, 2, fname.c_str()); + unsigned index = get_numeric_argument(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(LS, 1, fname.c_str()); - if(controller >= MAX_PORTS * MAX_CONTROLLERS_PER_PORT) - return 0; - uint64_t base = get_numeric_argument(LS, 2, fname.c_str()); - for(unsigned i = 0; i < MAX_CONTROLS_PER_CONTROLLER; i++) { + unsigned port = get_numeric_argument(LS, 1, fname.c_str()); + unsigned controller = get_numeric_argument(LS, 2, fname.c_str()); + uint64_t base = get_numeric_argument(LS, 3, fname.c_str()); + for(unsigned i = 0; i < lua_input_controllerdata->control_count(); i++) { val = (base >> i) & 1; - get_numeric_argument(LS, i + 3, val, fname.c_str()); - lua_input_controllerdata->axis(controller, i, val); + get_numeric_argument(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(LS, 1, fname.c_str()); - if(controller >= MAX_PORTS * MAX_CONTROLLERS_PER_PORT) - return 0; + unsigned port = get_numeric_argument(LS, 1, fname.c_str()); + unsigned controller = get_numeric_argument(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(LS, 1, fname.c_str()); + unsigned port = get_numeric_argument(LS, 1, fname.c_str()); + unsigned controller = get_numeric_argument(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); diff --git a/src/lua/movie.cpp b/src/lua/movie.cpp index 8cac05b7..c7540f76 100644 --- a/src/lua/movie.cpp +++ b/src/lua/movie.cpp @@ -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); diff --git a/src/platform/wxwidgets/main.cpp b/src/platform/wxwidgets/main.cpp index 37bf39c7..451bd169 100644 --- a/src/platform/wxwidgets/main.cpp +++ b/src/platform/wxwidgets/main.cpp @@ -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; @@ -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); diff --git a/src/platform/wxwidgets/mainwindow.cpp b/src/platform/wxwidgets/mainwindow.cpp index 1036aae4..88ddb48a 100644 --- a/src/platform/wxwidgets/mainwindow.cpp +++ b/src/platform/wxwidgets/mainwindow.cpp @@ -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 } +//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 UI_controller_index_by_logical(unsigned lid) { - int ret; + std::pair 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 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 menus; + std::vector 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 pid, unsigned ctrlnum, bool newstate) { modal_pause_holder hld; - int pid2 = UI_controller_index_by_logical(our_lid); - if(pid2 < 0 || static_cast(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(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()