From ff4d045882aef5298df9a1e1ea8bd1f8c7fde81e Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Wed, 9 Nov 2011 00:05:57 +0200 Subject: [PATCH] =?UTF-8?q?lsnes=20rr0-=CE=B220?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- include/core/dispatch.hpp | 409 +++++++++++++++++++++++++++++++ manual.lyx | 36 +++ src/core/dispatch.cpp | 494 ++++++++++++++++++++++++++++++++++++++ src/core/misc.cpp | 2 +- 5 files changed, 941 insertions(+), 2 deletions(-) create mode 100644 include/core/dispatch.hpp create mode 100644 src/core/dispatch.cpp diff --git a/.gitignore b/.gitignore index 5b5b1dfe..0e500224 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ *.exe docs rom -core +/core diff --git a/include/core/dispatch.hpp b/include/core/dispatch.hpp new file mode 100644 index 00000000..674b3446 --- /dev/null +++ b/include/core/dispatch.hpp @@ -0,0 +1,409 @@ +#ifndef _dispatch__hpp__included__ +#define _dispatch__hpp__included__ + +#include "render.hpp" +#include "keymapper.hpp" + +#include +#include +#include +#include +#include + +/** + * Video data region is NTSC. + */ +#define VIDEO_REGION_NTSC 0 +/** + * Video data region is PAL. + */ +#define VIDEO_REGION_PAL 1 + +/** + * Information about run. + */ +struct gameinfo_struct +{ +public: +/** + * Construct game info. + */ + gameinfo_struct() throw(std::bad_alloc); +/** + * Game name. + */ + std::string gamename; +/** + * Run length in seconds. + */ + double length; +/** + * Rerecord count (base 10 ASCII) + */ + std::string rerecords; +/** + * Authors. The first components are real names, the second components are nicknames. Either (but not both) may be + * blank. + */ + std::vector> authors; +/** + * Format human-redable representation of the length. + * + * Parameter digits: Number of sub-second digits to use. + * Returns: The time formated. + * Throws std::bad_alloc: Not enough memory. + */ + std::string get_readable_time(unsigned digits) const throw(std::bad_alloc); +/** + * Get number of authors. + * + * Returns: Number of authors. + */ + size_t get_author_count() const throw(); +/** + * Get short name of author (nickname if present, otherwise full name). + * + * Parameter idx: Index of author (0-based). + * Returns: The short name. + * Throws std::bad_alloc: Not enough memory. + */ + std::string get_author_short(size_t idx) const throw(std::bad_alloc); +/** + * Get rerecord count as a number. If rerecord count is too high, returns the maximum representatible count. + * + * Returns: The rerecord count. + */ + uint64_t get_rerecords() const throw(); +}; + + +/** + * Information dispatch. + * + * This class handles dispatching information between the components of the emulator. + * + * Each kind of information has virtual method on_foo() which can be overridden to handle events of that type, and + * static method do_foo(), which calls on_foo on all known objects. + * + * The information is delivered to each instance of this class. + */ +class information_dispatch +{ +public: +/** + * Create new object to receive information dispatch events. + * + * Parameter name: The name for the object. + * Throws std::bad_alloc: Not enough memory. + */ + information_dispatch(const std::string& name) throw(std::bad_alloc); +/** + * Destroy object. + */ + ~information_dispatch() throw(); +/** + * Window close event received (this is not emulator close!) + * + * The default handler does nothing. + */ + virtual void on_close(); +/** + * Call all on_close() handlers. + */ + static void do_close() throw(); +/** + * Click or release on window was receivied. + * + * The default handler does nothing. + * + * Parameter x: The x-coordinate of the click. May be negative or otherwise out of screen. + * Parameter y: The y-coordinate of the click. May be negative or otherwise out of screen. + * Parameter buttonmask: Bitfield giving current buttons held: + * Bit 0 => Left button is down/held. + * Bit 1 => Middle button is down/held. + * Bit 2 => Middle button is down/held. + */ + virtual void on_click(int32_t x, int32_t y, uint32_t buttonmask); +/** + * Call all on_click() handlers. + */ + static void do_click(int32_t x, int32_t y, uint32_t buttonmask) throw(); +/** + * Sound mute/unmute status might have been changed. + * + * The default handler does nothing. + * + * Parameter unmuted: If true, the sound is now enabled. If false, the sound is now disabled. + */ + virtual void on_sound_unmute(bool unmuted); +/** + * Call all on_sound_unmute() handlers. + */ + static void do_sound_unmute(bool unmuted) throw(); +/** + * Sound device might have been changed. + * + * The default handler does nothing. + * + * Parameter dev: The device name sound is now playing (if enabled) from. + */ + virtual void on_sound_change(const std::string& dev); +/** + * Call all on_sound_change() handlers. + */ + static void do_sound_change(const std::string& dev) throw(); +/** + * Emulator mode might have been changed. + * + * The default handler does nothing. + * + * Parameter readonly: True if readonly mode is now active, false if now in readwrite mode. + */ + virtual void on_mode_change(bool readonly); +/** + * Call all on_mode_change() handlers. + */ + static void do_mode_change(bool readonly) throw(); +/** + * Autohold on button might have been changed. + * + * The default handler does nothing. + * + * Parameter pid: The physical ID of controller (0-7). + * Parameter ctrlnum: Physical control number (0-15). + * 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); +/** + * Call all on_autohold_update() handlers. + */ + static void do_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate) throw(); +/** + * Controller configuration may have been changed. + * + * The default handler does nothing. + */ + virtual void on_autohold_reconfigure(); +/** + * Call all on_autohold_reconfigure() handlers. + */ + static void do_autohold_reconfigure() throw(); +/** + * A setting may have changed. + * + * The default handler does nothing. + * + * Parameter setting: The setting that has possibly changed. + * Parameter value: The new value for the setting. + */ + virtual void on_setting_change(const std::string& setting, const std::string& value); +/** + * Call all on_setting_change() handlers. + */ + static void do_setting_change(const std::string& setting, const std::string& value) throw(); +/** + * A setting has been cleared (but it might have been cleared already). + * + * The default handler does nothing. + * + * Parameter setting: The setting that is now clear. + */ + virtual void on_setting_clear(const std::string& setting); +/** + * Call all on_setting_clear() handlers + */ + static void do_setting_clear(const std::string& setting) throw(); +/** + * A raw frame has been received. + * + * The default handler does nothing. + * + * Parameter raw: The raw frame data. 512*512 element array. + * Parameter hires: True if in hires mode (512 wide), false if not (256-wide). + * Parameter interlaced: True if in interlaced mode (448/478 high), false if not (224/239 high). + * Parameter overscan: True if overscan is active, false if not. + * Parameter region: One of VIDEO_REGION_* contstants, giving the region this frame is from. + */ + virtual void on_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan, unsigned region); +/** + * Call all on_raw_frame() handlers. + * + * Calls on_new_dumper() on dumpers that had that not yet called. + */ + static void do_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan, unsigned region) + throw(); +/** + * A frame has been received. + * + * The default handler does nothing. + * + * Parameter _frame: The frame object. + * Parameter fps_n: Numerator of current video fps. + * Parameter fps_d: Denominator of current video fps. + */ + virtual void on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d); +/** + * Call all on_frame() handlers. + * + * Calls on_new_dumper() on dumpers that had that not yet called. + */ + static void do_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) throw(); +/** + * A sample has been received. + * + * The default handler does nothing. + * + * Parameter l: The left channel sample (16 bit signed). + * Parameter r: The right channel sample (16 bit signed). + */ + virtual void on_sample(short l, short r); +/** + * Call all on_sample() handlers. + * + * Calls on_new_dumper() on dumpers that had that not yet called. + */ + static void do_sample(short l, short r) throw(); +/** + * Dump is ending. + * + * Calls on_new_dumper() on dumpers that had that not yet called. + * + * The default handler does nothing. + */ + virtual void on_dump_end(); +/** + * Call all on_dump_end() handlers. + */ + static void do_dump_end() throw(); +/** + * Sound sampling rate is changing + * + * The default handler prints warning if dumper flag is set. + * + * Parameter rate_n: Numerator of the new sampling rate in Hz. + * Parameter rate_d: Denominator of the new sampling rate in Hz. + */ + virtual void on_sound_rate(uint32_t rate_n, uint32_t rate_d); +/** + * Call all on_sound_rate() methods and save the parameters. + * + * Calls on_new_dumper() on dumpers that had that not yet called. + */ + static void do_sound_rate(uint32_t rate_n, uint32_t rate_d) throw(); +/** + * Get the sound rate most recently set by on_sound_rate(). + * + * Returns: The first component is the numerator, the second is the denominator. + */ + static std::pair get_sound_rate() throw(); +/** + * Game information is changing. + * + * The default handler does nothing. + * + * Parameter gi: The new game info. + */ + virtual void on_gameinfo(const struct gameinfo_struct& gi); +/** + * Call all on_gameinfo() handlers and save the gameinfo. + */ + static void do_gameinfo(const struct gameinfo_struct& gi) throw(); +/** + * Get the gameinfo most recently set by do_gameinfo(). + * + * Returns: The gameinfo. + */ + static const struct gameinfo_struct& get_gameinfo() throw(); +/** + * Return the dumper flag for this dispatch target. + * + * The default implementation returns false. + * + * If dumper flag is set: + * - on_sound_rate() default handler prints a warning. + * - All dumping related do_* functions triggers calls to to on_new_dumper() on all handlers the next time they + * are called. + * - Destroying the handler triggers calls to on_destroy_dumper() on all handlers (if on_new_dumper() has been + * called). + */ + virtual bool get_dumper_flag() throw(); +/** + * Notify that a new dumper is joining. + * + * Parameter dumper: The name of the dumper object. + */ + virtual void on_new_dumper(const std::string& dumper); +/** + * Notify that a dumper is leaving. + * + * Parameter dumper: The name of the dumper object. + */ + virtual void on_destroy_dumper(const std::string& dumper); +/** + * Get number of active dumpers. + * + * Calls on_new_dumper() on dumpers that had that not yet called. + * + * Returns: The dumper count. + */ + static unsigned get_dumper_count() throw(); +/** + * Get set of active dumpers. + * + * Calls on_new_dumper() on dumpers that had that not yet called. + * + * Returns: The set of dumper names. + * Throws std::bad_alloc: Not enough memory. + */ + static std::set get_dumpers() throw(std::bad_alloc); +/** + * (Pseudo-)key has been pressed or released. + * + * Parameter modifiers: The modifier set currently active. + * Parameter keygroup: The key group the (pseudo-)key is from. + * Parameter subkey: Subkey index within the key group. + * Parameter polarity: True if key is being pressed, false if being released. + * Parameter name: Name of the key being pressed/released. + */ + virtual void on_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey, + bool polarity, const std::string& name); +/** + * Call on_key_event() for all event handlers (or just one if keys are being grabbed). + */ + static void do_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey, + bool polarity, const std::string& name) throw(); +/** + * Grab all key events. + * + * While key events are grabbed, do_key_event() only calls on_key_event() for the grabbing object. + */ + void grab_keys() throw(); +/** + * Ungrab all key events. + * + * While key events are grabbed, do_key_event() only calls on_key_event() for the grabbing object. + */ + void ungrab_keys() throw(); +/** + * Get name of target. + */ + const std::string& get_name() throw(); +/** + * Set window main screen compensation parameters. This is used for mouse click reporting. + * + * parameter xoffset: X coordinate of origin. + * parameter yoffset: Y coordinate of origin. + * parameter hscl: Horizontal scaling factor. + * parameter vscl: Vertical scaling factor. + */ + static void do_click_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl); +private: + static void update_dumpers(bool nocalls = false) throw(); + bool known_if_dumper; + bool marked_as_dumper; + std::string target_name; + bool notified_as_dumper; + bool grabbing_keys; +}; + +#endif diff --git a/manual.lyx b/manual.lyx index a32b9971..f0bba044 100644 --- a/manual.lyx +++ b/manual.lyx @@ -4499,5 +4499,41 @@ Finish pending saves before load/quit. Wxwidgets graphics plugin. \end_layout +\begin_layout Subsection +rr0-beta20 +\end_layout + +\begin_layout Itemize +Get rid of win32-crap.[ch]pp. +\end_layout + +\begin_layout Itemize +Move files around a lot. +\end_layout + +\begin_layout Itemize +Get rid of need for host C++ compiler. +\end_layout + +\begin_layout Itemize +Bsnes v084 core. +\end_layout + +\begin_layout Itemize +Refactor inter-component communication. +\end_layout + +\begin_layout Itemize +Fix zero luma. +\end_layout + +\begin_layout Itemize +Fix crash on multiline aliases. +\end_layout + +\begin_layout Itemize +Load/Save settings in wxwidgets gui. +\end_layout + \end_body \end_document diff --git a/src/core/dispatch.cpp b/src/core/dispatch.cpp new file mode 100644 index 00000000..c0542d6d --- /dev/null +++ b/src/core/dispatch.cpp @@ -0,0 +1,494 @@ +#include "core/dispatch.hpp" +#include "core/globalwrap.hpp" +#include "core/misc.hpp" + +#include +#include +#include + +#define START_EH_BLOCK try { +#define END_EH_BLOCK(obj, call) } catch(std::bad_alloc& e) { \ + OOM_panic(); \ + } catch(std::exception& e) { \ + messages << messages << "[dumper " << obj->get_name() << "] Warning: " call ": " << e.what() \ + << std::endl; \ + } catch(int code) { \ + messages << messages << "[dumper " << obj->get_name() << "] Warning: " call ": Error code #" << code \ + << std::endl; \ + } + +gameinfo_struct::gameinfo_struct() throw(std::bad_alloc) +{ + length = 0; + rerecords = "0"; +} + +std::string gameinfo_struct::get_readable_time(unsigned digits) const throw(std::bad_alloc) +{ + double bias = 0.5 * pow(10, -static_cast(digits)); + double len = length + bias; + std::ostringstream str; + if(length >= 3600) { + double hours = floor(len / 3600); + str << hours << ":"; + len -= hours * 3600; + } + double minutes = floor(len / 60); + len -= minutes * 60; + double seconds = floor(len); + len -= seconds; + str << std::setw(2) << std::setfill('0') << minutes << ":" << seconds; + if(digits > 0) + str << "."; + while(digits > 0) { + len = 10 * len; + str << '0' + static_cast(len); + len -= floor(len); + digits--; + } +} + +size_t gameinfo_struct::get_author_count() const throw() +{ + return authors.size(); +} + +std::string gameinfo_struct::get_author_short(size_t idx) const throw(std::bad_alloc) +{ + if(idx >= authors.size()) + return ""; + const std::pair& x = authors[idx]; + if(x.second != "") + return x.second; + else + return x.first; +} + +uint64_t gameinfo_struct::get_rerecords() const throw() +{ + uint64_t v = 0; + uint64_t max = 0xFFFFFFFFFFFFFFFFULL; + for(size_t i = 0; i < rerecords.length(); i++) { + if(v < max / 10) + //No risk of overflow. + v = v * 10 + static_cast(rerecords[i] - '0'); + else if(v == max / 10) { + //THis may overflow. + v = v * 10; + if(v + static_cast(rerecords[i] - '0') < v) + return max; + v = v + static_cast(rerecords[i] - '0'); + } else + //Definite overflow. + return max; + } + return v; +} + +namespace +{ + globalwrap> dispatch; + uint32_t srate_n = 32000; + uint32_t srate_d = 1; + struct gameinfo_struct sgi; + information_dispatch* exclusive_key = NULL; + int32_t vc_xoffset = 0; + int32_t vc_yoffset = 0; + uint32_t vc_hscl = 1; + uint32_t vc_vscl = 1; + bool recursive = false; +} + +information_dispatch::information_dispatch(const std::string& name) throw(std::bad_alloc) +{ + target_name = name; + dispatch().push_back(this); + known_if_dumper = false; + marked_as_dumper = false; + notified_as_dumper = false; + grabbing_keys = false; +} + +information_dispatch::~information_dispatch() throw() +{ + for(auto i = dispatch().begin(); i != dispatch().end(); ++i) { + if(*i == this) { + dispatch().erase(i); + break; + } + } + if(notified_as_dumper) + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_destroy_dumper(target_name); + END_EH_BLOCK(i, "on_destroy_dumper"); + } +} + +void information_dispatch::on_close() +{ + //Do nothing. +} + +void information_dispatch::do_close() throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_close(); + END_EH_BLOCK(i, "on_close"); + } +} + +void information_dispatch::on_click(int32_t x, int32_t y, uint32_t buttonmask) +{ + //Do nothing. +} + +void information_dispatch::do_click(int32_t x, int32_t y, uint32_t buttonmask) throw() +{ + x = (x - vc_xoffset) / vc_hscl; + y = (y - vc_yoffset) / vc_vscl; + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_click(x, y, buttonmask); + END_EH_BLOCK(i, "on_click"); + } +} + +void information_dispatch::on_sound_unmute(bool unmuted) +{ + //Do nothing. +} + +void information_dispatch::do_sound_unmute(bool unmuted) throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_sound_unmute(unmuted); + END_EH_BLOCK(i, "on_sound_unmute"); + } +} + +void information_dispatch::on_sound_change(const std::string& dev) +{ + //Do nothing. +} + +void information_dispatch::do_sound_change(const std::string& dev) throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_sound_change(dev); + END_EH_BLOCK(i, "on_sound_change"); + } +} + +void information_dispatch::on_mode_change(bool readonly) +{ + //Do nothing. +} + +void information_dispatch::do_mode_change(bool readonly) throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_mode_change(readonly); + END_EH_BLOCK(i, "on_mode_change"); + } +} + +void information_dispatch::on_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate) +{ + //Do nothing. +} + +void information_dispatch::do_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate) throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_autohold_update(pid, ctrlnum, newstate); + END_EH_BLOCK(i, "on_autohold_update"); + } +} + +void information_dispatch::on_autohold_reconfigure() +{ + //Do nothing. +} + +void information_dispatch::do_autohold_reconfigure() throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_autohold_reconfigure(); + END_EH_BLOCK(i, "on_autohold_reconfigure"); + } +} + +void information_dispatch::on_setting_change(const std::string& setting, const std::string& value) +{ + //Do nothing. +} + +void information_dispatch::do_setting_change(const std::string& setting, const std::string& value) throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_setting_change(setting, value); + END_EH_BLOCK(i, "on_setting_change"); + } +} + +void information_dispatch::on_setting_clear(const std::string& setting) +{ + //Do nothing. +} + +void information_dispatch::do_setting_clear(const std::string& setting) throw() +{ + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_setting_clear(setting); + END_EH_BLOCK(i, "on_setting_clear"); + } +} + + +void information_dispatch::on_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan, + unsigned region) +{ + //Do nothing. +} + +void information_dispatch::do_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan, + unsigned region) throw() +{ + update_dumpers(); + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_raw_frame(raw, hires, interlaced, overscan, region); + END_EH_BLOCK(i, "on_raw_frame"); + } +} + +void information_dispatch::on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) +{ + //Do nothing. +} + +void information_dispatch::do_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) throw() +{ + update_dumpers(); + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_frame(_frame, fps_n, fps_d); + END_EH_BLOCK(i, "on_frame"); + } +} + +void information_dispatch::on_sample(short l, short r) +{ + //Do nothing. +} + +void information_dispatch::do_sample(short l, short r) throw() +{ + update_dumpers(); + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_sample(l, r); + END_EH_BLOCK(i, "on_sample"); + } +} + +void information_dispatch::on_dump_end() +{ + //Do nothing. +} + +void information_dispatch::do_dump_end() throw() +{ + update_dumpers(); + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_dump_end(); + END_EH_BLOCK(i, "on_dump_end"); + } +} + +void information_dispatch::on_sound_rate(uint32_t rate_n, uint32_t rate_d) +{ + if(!known_if_dumper) { + marked_as_dumper = get_dumper_flag(); + known_if_dumper = true; + } + if(marked_as_dumper) { + messages << "[dumper " << get_name() << "] Warning: Sound sample rate changing not supported!" + << std::endl; + } +} + +void information_dispatch::do_sound_rate(uint32_t rate_n, uint32_t rate_d) throw() +{ + update_dumpers(); + uint32_t g = gcd(rate_n, rate_d); + rate_n /= g; + rate_d /= g; + if(rate_n == srate_n && rate_d == srate_d) + return; + srate_n = rate_n; + srate_d = rate_d; + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_sound_rate(rate_n, rate_d); + END_EH_BLOCK(i, "on_sound_rate"); + } +} + +std::pair information_dispatch::get_sound_rate() throw() +{ + return std::make_pair(srate_n, srate_d); +} + +void information_dispatch::on_gameinfo(const struct gameinfo_struct& gi) +{ + //Do nothing. +} + +void information_dispatch::do_gameinfo(const struct gameinfo_struct& gi) throw() +{ + update_dumpers(); + try { + sgi = gi; + } catch(...) { + OOM_panic(); + } + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_gameinfo(sgi); + END_EH_BLOCK(i, "on_gameinfo"); + } +} + +const struct gameinfo_struct& information_dispatch::get_gameinfo() throw() +{ + return sgi; +} + +bool information_dispatch::get_dumper_flag() throw() +{ + return false; +} + +void information_dispatch::on_new_dumper(const std::string& dumper) +{ + //Do nothing. +} + +void information_dispatch::on_destroy_dumper(const std::string& dumper) +{ + //Do nothing. +} + +unsigned information_dispatch::get_dumper_count() throw() +{ + update_dumpers(true); + unsigned count = 0; + for(auto& i : dispatch()) + if(i->marked_as_dumper) + count++; + if(!recursive) { + recursive = true; + update_dumpers(); + recursive = false; + } + return count; +} + +std::set information_dispatch::get_dumpers() throw(std::bad_alloc) +{ + update_dumpers(); + std::set r; + try { + for(auto& i : dispatch()) + if(i->notified_as_dumper) + r.insert(i->get_name()); + } catch(...) { + OOM_panic(); + } + return r; +} + +void information_dispatch::on_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey, + bool polarity, const std::string& name) +{ + //Do nothing. +} + +void information_dispatch::do_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey, + bool polarity, const std::string& name) throw() +{ + if(exclusive_key) { + START_EH_BLOCK + exclusive_key->on_key_event(modifiers, keygroup, subkey, polarity, name); + END_EH_BLOCK(exclusive_key, "on_key_event"); + return; + } + for(auto& i : dispatch()) { + START_EH_BLOCK + i->on_key_event(modifiers, keygroup, subkey, polarity, name); + END_EH_BLOCK(i, "on_key_event"); + } +} + +void information_dispatch::grab_keys() throw() +{ + if(grabbing_keys) + return; + exclusive_key = this; + grabbing_keys = true; +} + +void information_dispatch::ungrab_keys() throw() +{ + if(!grabbing_keys) + return; + exclusive_key = NULL; + grabbing_keys = false; + for(auto& i : dispatch()) + if(i->grabbing_keys) { + exclusive_key = i; + break; + } +} + +const std::string& information_dispatch::get_name() throw() +{ + return target_name; +} + +void information_dispatch::update_dumpers(bool nocalls) throw() +{ + for(auto& i : dispatch()) { + if(!i->known_if_dumper) { + i->marked_as_dumper = i->get_dumper_flag(); + i->known_if_dumper = true; + } + if(i->marked_as_dumper && !i->notified_as_dumper && !nocalls) { + for(auto& j : dispatch()) { + START_EH_BLOCK + j->on_new_dumper(i->target_name); + END_EH_BLOCK(j, "on_new_dumper"); + } + i->notified_as_dumper = true; + } + } +} + +void information_dispatch::do_click_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl) +{ + vc_xoffset = xoffset; + vc_yoffset = yoffset; + vc_hscl = hscl; + vc_vscl = vscl; +} diff --git a/src/core/misc.cpp b/src/core/misc.cpp index 51c02967..5a3e0281 100644 --- a/src/core/misc.cpp +++ b/src/core/misc.cpp @@ -306,4 +306,4 @@ uint32_t gcd(uint32_t a, uint32_t b) throw() } std::string bsnes_core_version; -std::string lsnes_version = "0-β19"; +std::string lsnes_version = "0-β20";