Allow binding commands to class instance

This commit is contained in:
Ilari Liusvaara 2014-11-17 15:55:14 +02:00
parent 5ee7962cb9
commit 3b2298180a
43 changed files with 1221 additions and 650 deletions

2
.gitignore vendored
View file

@ -15,3 +15,5 @@ lsnes
/gambatte
src/fonts/font.cpp
src/core/version.cpp
src/cmdhelp/*.cpp
include/cmdhelp/*.hpp

View file

@ -0,0 +1,2 @@
#pragma once
namespace STUBS { extern const char* inverse_cmd_list[]; }

View file

@ -4,6 +4,7 @@
#include <string>
#include <map>
#include "library/dispatch.hpp"
#include "library/command.hpp"
struct project_info;
struct controller_state;
@ -65,7 +66,7 @@ public:
* Ctor.
*/
button_mapping(controller_state& _controls, keyboard::mapper& mapper, keyboard::keyboard& keyboard,
emu_framebuffer& fbuf, emulator_dispatch& _dispatch, lua_state& _lua2);
emu_framebuffer& fbuf, emulator_dispatch& _dispatch, lua_state& _lua2, command::group& _cmd);
/**
* Dtor.
*/
@ -98,13 +99,10 @@ public:
* Map of button keys.
*/
std::map<std::string, std::string> button_keys;
/**
* Do button/axis action.
*/
void do_action(const std::string& name, short state, int mode);
private:
void do_analog_action(const std::string& a);
void do_autofire_action(const std::string& a, int mode);
private:
void do_action(const std::string& name, short state, int mode);
void promote_key(keyboard::ctrlrkey& k);
void add_button(const std::string& name, const controller_bind& binding);
void process_controller(portctrl::controller& controller, unsigned number);
@ -129,7 +127,17 @@ private:
emu_framebuffer& fbuf;
emulator_dispatch& edispatch;
lua_state& lua2;
command::group& cmd;
struct dispatch::target<> ncore;
command::_fnptr<const std::string&> button_p;
command::_fnptr<const std::string&> button_r;
command::_fnptr<const std::string&> button_h;
command::_fnptr<const std::string&> button_t;
command::_fnptr<const std::string&> button_d;
command::_fnptr<const std::string&> button_ap;
command::_fnptr<const std::string&> button_ar;
command::_fnptr<const std::string&> button_at;
command::_fnptr<const std::string&> button_a;
};

View file

@ -16,6 +16,7 @@
#include <map>
#include <list>
#include "library/portctrl-data.hpp"
#include "library/command.hpp"
#include "library/threads.hpp"
class project_state;
@ -34,7 +35,7 @@ public:
* Constructor.
*/
controller_state(project_state& _project, movie_logic& _mlogic, button_mapping& _buttons,
emulator_dispatch& _dispatch, status_updater& _supdater) throw();
emulator_dispatch& _dispatch, status_updater& _supdater, command::group& _cmd) throw();
/**
* Convert lcid (Logical Controller ID) into pcid (Physical Controler ID).
*
@ -205,12 +206,12 @@ public:
void set_macro(const std::string& macro, const portctrl::macro& m);
void apply_macro(portctrl::frame& f);
void rename_macro(const std::string& old, const std::string& newn);
void do_macro(const std::string& a, int mode);
std::set<std::string> active_macro_set();
void advance_macros();
std::map<std::string, uint64_t> get_macro_frames();
void set_macro_frames(const std::map<std::string, uint64_t>& f);
private:
void do_macro(const std::string& a, int mode);
struct autofire_info
{
uint64_t first_frame;
@ -240,6 +241,10 @@ private:
button_mapping& buttons;
emulator_dispatch& edispatch;
status_updater& supdater;
command::group& cmd;
command::_fnptr<const std::string&> macro_p;
command::_fnptr<const std::string&> macro_r;
command::_fnptr<const std::string&> macro_t;
};
#endif

View file

@ -4,6 +4,7 @@
#include <functional>
#include <fstream>
#include <cstdint>
#include "library/command.hpp"
#include "library/dispatch.hpp"
class emulator_dispatch;
@ -15,7 +16,7 @@ class loaded_rom;
class debug_context
{
public:
debug_context(emulator_dispatch& _dispatch, loaded_rom& _rom);
debug_context(emulator_dispatch& _dispatch, loaded_rom& _rom, command::group& _cmd);
/**
* Type of event.
*/
@ -154,14 +155,21 @@ public:
std::map<uint64_t, cb_list> trace_cb;
std::map<uint64_t, cb_list> frame_cb;
private:
void do_showhooks();
void do_genevent(const std::string& a);
void do_tracecmd(const std::string& a);
cb_list dummy_cb; //Always empty.
uint64_t xmask = 1;
std::function<void()> tracelog_change_cb;
emulator_dispatch& edispatch;
loaded_rom& rom;
command::group& cmd;
struct dispatch::target<> corechange;
bool corechange_r = false;
bool requesting_break = false;
command::_fnptr<> showhooks;
command::_fnptr<const std::string&> genevent;
command::_fnptr<const std::string&> tracecmd;
struct tracelog_file : public callback_base
{

View file

@ -2,6 +2,7 @@
#define _framebuffer__hpp__included__
#include "core/window.hpp"
#include "library/command.hpp"
#include "library/framebuffer.hpp"
#include "library/triplebuffer.hpp"
@ -30,7 +31,7 @@ class emu_framebuffer
public:
emu_framebuffer(subtitle_commentary& _subtitles, settingvar::group& _settings, memwatch_set& _mwatch,
keyboard::keyboard& _keyboard, emulator_dispatch& _dispatch, lua_state& _lua2, loaded_rom& _rom,
status_updater& _supdater);
status_updater& _supdater, command::group& _cmd);
/**
* The main framebuffer.
*/
@ -83,6 +84,7 @@ public:
framebuffer::raw& render_get_latest_screen();
void render_get_latest_screen_end();
private:
void do_screenshot(command::arg_filename a);
struct render_info
{
framebuffer::raw fbuf;
@ -107,6 +109,8 @@ private:
lua_state& lua2;
loaded_rom& rom;
status_updater& supdater;
command::group& cmd;
command::_fnptr<command::arg_filename> screenshot;
};
#endif

View file

@ -3,6 +3,7 @@
#include <cstdint>
#include "library/threads.hpp"
#include "library/command.hpp"
#define FRAMERATE_HISTORY_FRAMES 10
@ -12,7 +13,7 @@
class framerate_regulator
{
public:
framerate_regulator();
framerate_regulator(command::group& _cmd);
/**
* Set the target speed multiplier.
*
@ -96,7 +97,10 @@ private:
double nominal_framerate;
double multiplier_framerate;
threads::lock framerate_lock;
command::group& cmd;
command::_fnptr<> turbo_p;
command::_fnptr<> turbo_r;
command::_fnptr<> turbo_t;
};
#endif

View file

@ -4,6 +4,7 @@
#include <list>
#include <cstdint>
#include <string>
#include "library/command.hpp"
class emulator_dispatch;
@ -28,7 +29,8 @@ public:
uint64_t length;
};
voice_commentary(settingvar::group& _settings, emulator_dispatch& _dispatch, audioapi_instance& _audio);
voice_commentary(settingvar::group& _settings, emulator_dispatch& _dispatch, audioapi_instance& _audio,
command::group& _cmd);
~voice_commentary();
void init();
void kill();
@ -53,6 +55,9 @@ private:
settingvar::group& settings;
emulator_dispatch& edispatch;
audioapi_instance& audio;
command::group& cmd;
command::_fnptr<> tangentp;
command::_fnptr<> tangentr;
};
#endif

View file

@ -18,7 +18,7 @@ public:
/**
* Ctor.
*/
save_jukebox(settingvar::group& _settings);
save_jukebox(settingvar::group& _settings, command::group& _cmd);
/**
* Dtor.
*/
@ -73,11 +73,16 @@ public:
*/
void unset_update();
private:
void do_slotsel(const std::string& arg);
settingvar::group& settings;
size_t current_slot;
size_t current_size;
std::function<void()> update;
save_jukebox_listener* listener;
command::group& cmd;
command::_fnptr<const std::string&> slotsel;
command::_fnptr<> cycleprev;
command::_fnptr<> cyclenext;
};
#endif

View file

@ -19,7 +19,7 @@ public:
MT_XOR
};
multitrack_edit(movie_logic& _mlogic, controller_state& _controls, emulator_dispatch& _dispatch,
status_updater& _supdater);
status_updater& _supdater, button_mapping& _buttons, command::group& _cmd);
void enable(bool state);
void set(unsigned port, unsigned controller, state s);
void set_and_notify(unsigned port, unsigned controller, state s);
@ -30,6 +30,9 @@ public:
void process_frame(portctrl::frame& input);
bool any_records();
private:
void do_mt_fwd();
void do_mt_bw();
void do_mt_set(const std::string& args);
threads::lock mlock;
bool enabled;
std::map<std::pair<unsigned, unsigned>, state> controllerstate;
@ -37,6 +40,11 @@ private:
controller_state& controls;
emulator_dispatch& edispatch;
status_updater& supdater;
button_mapping& buttons;
command::group& cmd;
command::_fnptr<> mt_f;
command::_fnptr<> mt_b;
command::_fnptr<const std::string&> mt_s;
};
#endif

View file

@ -6,6 +6,7 @@
#include <list>
#include <vector>
#include "core/rom-small.hpp"
#include "library/command.hpp"
#include "library/json.hpp"
class voice_commentary;
@ -15,14 +16,7 @@ class button_mapping;
class emulator_dispatch;
class input_queue;
class status_updater;
namespace command
{
class group;
}
namespace settingvar
{
class cache;
}
namespace settingvar { class cache; }
//A branch.
struct project_branch_info
@ -226,6 +220,13 @@ public:
*/
void copy_macros(project_info& p, controller_state& s);
private:
void recursive_list_branch(uint64_t bid, std::set<unsigned>& dset, unsigned depth, bool last_of);
void do_branch_ls();
void do_branch_mk(const std::string& a);
void do_branch_rm(const std::string& a);
void do_branch_set(const std::string& a);
void do_branch_rp(const std::string& a);
void do_branch_mv(const std::string& a);
project_info* active_project;
voice_commentary& commentary;
memwatch_set& mwatch;
@ -237,6 +238,12 @@ private:
input_queue& iqueue;
loaded_rom& rom;
status_updater& supdater;
command::_fnptr<> branch_ls;
command::_fnptr<const std::string&> branch_mk;
command::_fnptr<const std::string&> branch_rm;
command::_fnptr<const std::string&> branch_set;
command::_fnptr<const std::string&> branch_rp;
command::_fnptr<const std::string&> branch_mv;
};
#endif

View file

@ -4,6 +4,7 @@
#include <cstdint>
#include <set>
#include <string>
#include "library/command.hpp"
namespace lua { class render_context; }
@ -30,7 +31,8 @@ class emulator_dispatch;
struct subtitle_commentary
{
public:
subtitle_commentary(movie_logic& _mlogic, emu_framebuffer& _fbuf, emulator_dispatch& _dispatch);
subtitle_commentary(movie_logic& _mlogic, emu_framebuffer& _fbuf, emulator_dispatch& _dispatch,
command::group& _cmd);
std::set<std::pair<uint64_t, uint64_t>> get_all();
std::string get(uint64_t f, uint64_t l);
void set(uint64_t f, uint64_t l, const std::string& x);
@ -38,9 +40,16 @@ public:
static std::string s_escape(std::string x);
void render(lua::render_context& ctx);
private:
void do_editsub(const std::string& a);
void do_listsub();
void do_savesub(const std::string& a);
movie_logic& mlogic;
emu_framebuffer& fbuf;
emulator_dispatch& edispatch;
command::group& cmd;
command::_fnptr<const std::string&> editsub;
command::_fnptr<> listsub;
command::_fnptr<command::arg_filename> savesub;
};
#endif

View file

@ -3,6 +3,7 @@
#include <stdexcept>
#include <string>
#include <functional>
#include <set>
#include <map>
#include <list>
@ -245,6 +246,25 @@ private:
set* in_set;
};
/**
* Name, Description and help for command.
*/
struct stub
{
/**
* The command name.
*/
const char* name;
/**
* The short description.
*/
const char* desc;
/**
* The long help.
*/
const char* help;
};
/**
* Mandatory filename
*/
@ -269,7 +289,7 @@ struct arg_filename
* parameter a: The arguments to pass.
*/
template<typename... args>
void invoke_fn(void (*fn)(args... arguments), const std::string& a);
void invoke_fn(std::function<void(args... arguments)> fn, const std::string& a);
/**
* Warp function pointer as command.
@ -292,10 +312,25 @@ public:
const std::string& _help, void (*_fn)(args... arguments), bool dynamic = false) throw(std::bad_alloc)
: base(group, name, dynamic)
{
description = _description;
shorthelp = _description;
help = _help;
fn = _fn;
}
/**
* Create a new command.
*
* parameter _set: The set command will be part of.
* parameter name: Name of the command
* parameter fn: Function to call on command.
* parameter description Description&Help for the command
*/
_fnptr(group& _group, stub _name, std::function<void(args... arguments)> _fn) throw(std::bad_alloc)
: base(_group, _name.name, false)
{
shorthelp = _name.desc;
help = _name.help;
fn = _fn;
}
/**
* Destroy a commnad.
*/
@ -319,7 +354,7 @@ public:
*/
std::string get_short_help() throw(std::bad_alloc)
{
return description;
return shorthelp;
}
/**
* Get long help.
@ -332,8 +367,8 @@ public:
return help;
}
private:
void (*fn)(args... arguments);
std::string description;
std::function<void(args... arguments)> fn;
std::string shorthelp;
std::string help;
};
@ -344,6 +379,21 @@ template<typename... args>
class fnptr : public factory_base
{
public:
/**
* Create a new command.
*
* parameter _set: The set command will be part of.
* parameter desc: Command descriptor.
* parameter fn: Function to call on command.
*/
fnptr(set& _set, stub _name, void (*_fn)(args... arguments)) throw(std::bad_alloc)
{
shorthelp = _name.desc;
name = _name.name;
help = _name.help;
fn = _fn;
_factory_base(_set, name);
}
/**
* Create a new command.
*
@ -356,7 +406,7 @@ public:
fnptr(set& _set, const std::string& _name, const std::string& _description,
const std::string& _help, void (*_fn)(args... arguments)) throw(std::bad_alloc)
{
description = _description;
shorthelp = _description;
name = _name;
help = _help;
fn = _fn;
@ -373,11 +423,11 @@ public:
*/
base* make(group& grp) throw(std::bad_alloc)
{
return new _fnptr<args...>(grp, name, description, help, fn, true);
return new _fnptr<args...>(grp, name, shorthelp, help, fn, true);
}
private:
void (*fn)(args... arguments);
std::string description;
std::string shorthelp;
std::string help;
std::string name;
};

View file

@ -23,7 +23,7 @@ CFLAGS += -DOPUS_SUPPORTS_SURROUND
endif
endif
COMMON_LIBRARY=core lua fonts library interface video emulation
COMMON_LIBRARY=core lua fonts library interface video emulation cmdhelp
ALLFILES=__all__.files
ALLFLAGS=__all__.ldflags
COMMON_LIBRARY_FILES=$(patsubst %,%/$(ALLFILES),$(COMMON_LIBRARY))
@ -37,7 +37,7 @@ __all_common__.files: $(COMMON_LIBRARY_FILES)
__all_platform__.files: $(PLATFORM_LIBRARY_FILES)
lua genfilelist.lua $^ >$@
core/$(ALLFILES): forcelook
core/$(ALLFILES): forcelook cmdhelp/$(ALLFILES)
$(MAKE) -C core
emulation/$(ALLFILES): forcelook
@ -58,6 +58,9 @@ lua/$(ALLFILES): forcelook
platform/$(ALLFILES): forcelook
$(MAKE) -C platform
cmdhelp/$(ALLFILES): forcelook
$(MAKE) -C cmdhelp
util/__all_files__: forcelook
$(MAKE) -C util
@ -85,6 +88,7 @@ precheck:
$(MAKE) -C platform precheck
$(MAKE) -C util precheck
$(MAKE) -C video precheck
$(MAKE) -C cmdhelp precheck
platclean:
$(MAKE) -C emulation clean
@ -101,6 +105,7 @@ clean:
$(MAKE) -C platform clean
$(MAKE) -C util clean
$(MAKE) -C video clean
$(MAKE) -C cmdhelp clean
forcelook:
@true

39
src/cmdhelp/Makefile Normal file
View file

@ -0,0 +1,39 @@
ALLFILES=__all__.files
ALLFLAGS=__all__.ldflags
JSON_FILES=$(wildcard *.json)
JSON_SRC=$(patsubst %.json,%.cpp,$(JSON_FILES))
JSON_OBJECTS=$(patsubst %.json,%.$(OBJECT_SUFFIX),$(JSON_FILES))
__all__.files: $(JSON_OBJECTS) inverselist.$(OBJECT_SUFFIX)
lua ../genfilelist.lua $^ >$@
touch $(ALLFLAGS)
mkstubs.exe: mkstubs.cpp ../library/json.cpp ../library/utf8.cpp ../library/string.cpp ../library/hex.cpp ../library/eatarg.cpp ../library/int24.cpp
$(HOSTCC) -g -std=gnu++0x -I../../include/library -o $@ $^ -lboost_regex$(HOST_BOOST_POSTFIX) -lboost_system$(HOST_BOOST_POSTFIX) -Wall
mkstubsi.exe: mkstubsi.cpp ../library/json.cpp ../library/utf8.cpp ../library/string.cpp ../library/hex.cpp ../library/eatarg.cpp ../library/int24.cpp
$(HOSTCC) -g -std=gnu++0x -I../../include/library -o $@ $^ -lboost_regex$(HOST_BOOST_POSTFIX) -lboost_system$(HOST_BOOST_POSTFIX) -Wall
inverselist.cpp: $(JSON_FILES) mkstubsi.exe
./mkstubsi.exe $^
%.cpp: %.json mkstubs.exe
./mkstubs.exe $<
mv *.hpp ../../include/cmdhelp
%.$(OBJECT_SUFFIX): %.cpp
$(REALCC) $(CFLAGS) -c -o $@ $< -I../../include -Wall
.PRECIOUS: %.$(OBJECT_SUFFIX) %.files
precheck:
@true
clean:
rm -f *.$(OBJECT_SUFFIX) $(JSON_SRC) inverselist.cpp __all__.ldflags __all__.files
rm -f mkstubs.exe
forcelook:
@true

56
src/cmdhelp/button.json Normal file
View file

@ -0,0 +1,56 @@
{
"btnp":{
"__class":"button",
"__name":"+controller",
"__description":"Press a button",
"<button>":"Press button <button>"
},
"btnr":{
"__class":"button",
"__name":"-controller",
"__description":"Release a button",
"<button>":"Release button <button>"
},
"btnh":{
"__class":"button",
"__name":"hold-controller",
"__description":"Autohold a button",
"<button>":"Autohold button <button>"
},
"btnt":{
"__class":"button",
"__name":"type-controller",
"__description":"Type a button",
"<button>":"Type button <button>"
},
"btnd":{
"__class":"button",
"__name":"designate-position",
"__description":"Set postion",
"<button>":"Designate position for an axis"
},
"btnap":{
"__class":"button",
"__name":"+autofire-controller",
"__description":"Start autofire",
"<button> [[<duty> ]<cyclelen>]":"Autofire button <button> with duty <duty> out of <cyclelen>"
},
"btnar":{
"__class":"button",
"__name":"-autofire-controller",
"__description":"End autofire",
"<button> [[<duty> ]<cyclelen>]":"End Autofire on button <button>"
},
"btnat":{
"__class":"button",
"__name":"autofire-controller",
"__description":"Toggle autofire",
"<button> [[<duty> ]<cyclelen>]":"Toggle Autofire on button <button> with duty <duty> out of <cyclelen>"
},
"btna":{
"__class":"button",
"__name":"controller-analog",
"__description":"Analog action",
"<button> <axisvalue>":"Analog action on <button> with value <axisvalue>"
}
}

View file

@ -0,0 +1,15 @@
{
"tangentp":{
"__class":"commentary",
"__name":"+tangent",
"__description":"Voice tangent",
"":"Voice tangent",
"__inverse":{"":"Movie‣Voice tangent"}
},
"tangentr":{
"__class":"commentary",
"__name":"-tangent",
"__description":"Voice tangent",
"":"Voice tangent."
}
}

21
src/cmdhelp/debug.json Normal file
View file

@ -0,0 +1,21 @@
{
"showhooks":{
"__class":"debug",
"__name":"show-callbacks",
"__description":"Show debug callbacks",
"":"Shows debugging callbacks"
},
"genevent":{
"__class":"debug",
"__name":"generate-memory-event",
"__description":"Inject a debugging event",
"<type> <addr> <value>":"Inject a debugging event with given <type>, <addr> and <value>"
},
"trace":{
"__class":"debug",
"__name":"tracelog",
"__description":"Trace log control",
"<cpuid> <file>":"Start tracing <cpuid> to <file>",
"<cpuid>":"End tracing <cpuid>"
}
}

View file

@ -0,0 +1,7 @@
{
"screenshot":{
"__name":"take-screenshot",
"__description":"Takes a screenshot",
"<file>":"Save a screenshot to PNG file <file>"
}
}

56
src/cmdhelp/jukebox.json Normal file
View file

@ -0,0 +1,56 @@
{
"slotselect":{
"__class":"jukebox",
"__name":"set-jukebox-slot",
"__description":"Set jukebox slot",
"<slot>":"Set jukebox slot to <slot>\n",
"__inverse":{
"1":"Slot select‣Slot 1",
"2":"Slot select‣Slot 2",
"3":"Slot select‣Slot 3",
"4":"Slot select‣Slot 4",
"5":"Slot select‣Slot 5",
"6":"Slot select‣Slot 6",
"7":"Slot select‣Slot 7",
"8":"Slot select‣Slot 8",
"9":"Slot select‣Slot 9",
"10":"Slot select‣Slot 10",
"11":"Slot select‣Slot 11",
"12":"Slot select‣Slot 12",
"13":"Slot select‣Slot 13",
"14":"Slot select‣Slot 14",
"15":"Slot select‣Slot 15",
"16":"Slot select‣Slot 16",
"17":"Slot select‣Slot 17",
"18":"Slot select‣Slot 18",
"19":"Slot select‣Slot 19",
"20":"Slot select‣Slot 20",
"21":"Slot select‣Slot 21",
"22":"Slot select‣Slot 22",
"23":"Slot select‣Slot 23",
"24":"Slot select‣Slot 24",
"25":"Slot select‣Slot 25",
"26":"Slot select‣Slot 26",
"27":"Slot select‣Slot 27",
"28":"Slot select‣Slot 28",
"29":"Slot select‣Slot 29",
"30":"Slot select‣Slot 30",
"31":"Slot select‣Slot 31",
"32":"Slot select‣Slot 32"
}
},
"slotprev":{
"__class":"jukebox",
"__name":"cycle-jukebox-backward",
"__description":"Cycle save jukebox backwards",
"":"Cycle save jukebox backwards",
"__inverse":{"":"Slot select‣Cycle backwards"}
},
"slotnext":{
"__class":"jukebox",
"__name":"cycle-jukebox-forward",
"__description":"Cycle save jukebox forwards",
"":"Cycle save jukebox forwards",
"__inverse":{"":"Slot select‣Cycle forwards"}
}
}

82
src/cmdhelp/loadsave.json Normal file
View file

@ -0,0 +1,82 @@
{
"load":{
"__class":"loadsave",
"__name":"load",
"__description":"Load savestate (current mode)",
"<file>":"Loads SNES state from <file> in current mode",
"__inverse":{
"$SLOT:1":"Load‣Slot 1",
"$SLOT:2":"Load‣Slot 2",
"$SLOT:3":"Load‣Slot 3",
"$SLOT:4":"Load‣Slot 4",
"$SLOT:5":"Load‣Slot 5",
"$SLOT:6":"Load‣Slot 6",
"$SLOT:7":"Load‣Slot 7",
"$SLOT:8":"Load‣Slot 8",
"$SLOT:9":"Load‣Slot 9",
"$SLOT:10":"Load‣Slot 10",
"$SLOT:11":"Load‣Slot 11",
"$SLOT:12":"Load‣Slot 12",
"$SLOT:13":"Load‣Slot 13",
"$SLOT:14":"Load‣Slot 14",
"$SLOT:15":"Load‣Slot 15",
"$SLOT:16":"Load‣Slot 16",
"$SLOT:17":"Load‣Slot 17",
"$SLOT:18":"Load‣Slot 18",
"$SLOT:19":"Load‣Slot 19",
"$SLOT:20":"Load‣Slot 20",
"$SLOT:21":"Load‣Slot 21",
"$SLOT:22":"Load‣Slot 22",
"$SLOT:23":"Load‣Slot 23",
"$SLOT:24":"Load‣Slot 24",
"$SLOT:25":"Load‣Slot 25",
"$SLOT:26":"Load‣Slot 26",
"$SLOT:27":"Load‣Slot 27",
"$SLOT:28":"Load‣Slot 28",
"$SLOT:29":"Load‣Slot 29",
"$SLOT:30":"Load‣Slot 30",
"$SLOT:31":"Load‣Slot 31",
"$SLOT:32":"Load‣Slot 32"
}
},
"savestate":{
"__class":"loadsave",
"__name":"save-state",
"__description":"Save state",
"<file>":"Saves SNES state to <file>",
"__inverse":{
"$SLOT:1":"Save‣Slot 1",
"$SLOT:2":"Save‣Slot 2",
"$SLOT:3":"Save‣Slot 3",
"$SLOT:4":"Save‣Slot 4",
"$SLOT:5":"Save‣Slot 5",
"$SLOT:6":"Save‣Slot 6",
"$SLOT:7":"Save‣Slot 7",
"$SLOT:8":"Save‣Slot 8",
"$SLOT:9":"Save‣Slot 9",
"$SLOT:10":"Save‣Slot 10",
"$SLOT:11":"Save‣Slot 11",
"$SLOT:12":"Save‣Slot 12",
"$SLOT:13":"Save‣Slot 13",
"$SLOT:14":"Save‣Slot 14",
"$SLOT:15":"Save‣Slot 15",
"$SLOT:16":"Save‣Slot 16",
"$SLOT:17":"Save‣Slot 17",
"$SLOT:18":"Save‣Slot 18",
"$SLOT:19":"Save‣Slot 19",
"$SLOT:20":"Save‣Slot 20",
"$SLOT:21":"Save‣Slot 21",
"$SLOT:22":"Save‣Slot 22",
"$SLOT:23":"Save‣Slot 23",
"$SLOT:24":"Save‣Slot 24",
"$SLOT:25":"Save‣Slot 25",
"$SLOT:26":"Save‣Slot 26",
"$SLOT:27":"Save‣Slot 27",
"$SLOT:28":"Save‣Slot 28",
"$SLOT:29":"Save‣Slot 29",
"$SLOT:30":"Save‣Slot 30",
"$SLOT:31":"Save‣Slot 31",
"$SLOT:32":"Save‣Slot 32"
}
}
}

20
src/cmdhelp/macro.json Normal file
View file

@ -0,0 +1,20 @@
{
"macrot":{
"__class":"macro",
"__name":"macro",
"__description":"Toggle a macro",
"<macroname>":"Toggle macro <macroname>."
},
"macrop":{
"__class":"macro",
"__name":"+macro",
"__description":"Enable a macro",
"<macroname>":"Enable macro <macroname>."
},
"macror":{
"__class":"macro",
"__name":"-macro",
"__description":"Disable a macro",
"<macroname>":"Disable macro <macroname>."
}
}

22
src/cmdhelp/mhold.json Normal file
View file

@ -0,0 +1,22 @@
{
"mholdp":{
"__class":"mhold",
"__name":"+hold-macro",
"__description":"Hold macro (hold)",
"":"Hold macros enable",
"__inverse":{"":"Macro‣Hold all macros"}
},
"mholdr":{
"__class":"mhold",
"__name":"-hold-macro",
"__description":"Hold macro (hold)",
"":"Hold macros disable"
},
"mholdt":{
"__class":"mhold",
"__name":"hold-macro",
"__description":"Hold macro (typed)",
"":"Hold macros typed",
"__inverse":{"":"Macro‣Hold all macros (typed)"}
}
}

144
src/cmdhelp/mkstubs.cpp Normal file
View file

@ -0,0 +1,144 @@
#include "json.hpp"
#include <string>
#include <fstream>
#include <sstream>
#include <set>
const char* hexes = "0123456789abcdef";
std::string quote_c_string(const std::string& raw, bool hiraw = false);
std::string quote_c_string(const std::string& raw, bool hiraw)
{
std::ostringstream out;
out << "\"";
for(auto i : raw) {
unsigned char ch = i;
if(ch == '\n')
out << "\\n";
else if(ch == '\"')
out << "\\\"";
else if(ch == '\\')
out << "\\\\";
else if(ch < 32 || ch == 127 || (ch > 127 && !hiraw))
out << "\\x" << hexes[ch / 16] << hexes[ch % 16];
else
out << ch;
}
out << "\"";
return out.str();
}
std::string quote_help(const std::u32string& raw)
{
const size_t initial_width = 8;
const size_t break_width = 80;
std::ostringstream out;
//Compute split positions.
std::set<size_t> splits;
size_t last_word = 0;
size_t last_word_width = initial_width;
size_t width = initial_width;
for(size_t i = 0; i < raw.length(); i++) {
if(raw[i] == U'\n') {
splits.insert(i);
width = initial_width;
last_word = i;
last_word_width = initial_width;
}
if(raw[i] == U' ') {
width++;
if(width > break_width && last_word_width > initial_width) {
//Wordwrap at last word.
splits.insert(last_word);
width = width - last_word_width + initial_width;
}
last_word = i;
last_word_width = width;
} else {
//FIXME: Handle double-width characters.
width++;
}
}
out << "\t\"\\t";
for(size_t i = 0; i < raw.length(); i++) {
if(splits.count(i)) {
out << "\\n\"\n\t\"";
} else {
char32_t z[2] = {raw[i]};
if(z[0] == U'\"')
out << "\\\"";
else if(z[0] == U'\n')
out << "\\n";
else if(z[0] < 32 || z[0] == 127)
out << "\\x" << hexes[z[0] / 16] << hexes[z[0] % 16];
else
out << utf8::to8(z);
}
}
out << "\\n\"\n";
return out.str();
}
void process_command(const std::string& name, JSON::node& n, std::ostream& hdr, std::ostream& imp)
{
hdr << "extern command::stub " << name << ";" << std::endl;
imp << "command::stub " << name << " = {" << std::endl;
std::string cmdname = n["__name"].as_string8();
std::string desc = n.field_exists("__description") ? n["__description"].as_string8() :
"No description available";
imp << "\t" << quote_c_string(cmdname) << ", " << quote_c_string(desc) << "," << std::endl;
bool first = true;
for(auto i = n.begin(); i != n.end(); i++) {
std::string hleafname = i.key8();
if(hleafname == "__name" || hleafname == "__description" || hleafname == "__inverse" ||
hleafname == "__class")
continue;
std::u32string hleafc = i->as_string();
if(!first)
imp << "\t\"\\n\"" << std::endl;
first = false;
imp << "\t" << quote_c_string(std::string("Syntax: ") + cmdname + " " + hleafname + "\n")
<< std::endl;
imp << quote_help(hleafc);
}
if(first) imp << "\t\"No help available for '" << cmdname << "'\"" << std::endl;
imp << "};" << std::endl;
imp << std::endl;
}
int main(int argc, char** argv)
{
if(argc != 2) {
std::cerr << "Need one filename base" << std::endl;
return 1;
}
std::string fname = argv[1];
if(fname.length() > 5 && fname.substr(fname.length() - 5) == ".json")
fname = fname.substr(0, fname.length() - 5);
std::ifstream infile(fname + std::string(".json"));
std::string in_json;
std::string tmp;
while(infile) {
std::getline(infile, tmp);
in_json = in_json + tmp + "\n";
}
JSON::node n(in_json);
std::ofstream hdr(fname + std::string(".hpp"));
std::ofstream impl(fname + std::string(".cpp"));
impl << "#include \"cmdhelp/" << fname << ".hpp\"" << std::endl;
impl << "namespace STUBS" << std::endl;
impl << "{" << std::endl;
hdr << "#pragma once" << std::endl;
hdr << "#include \"library/command.hpp\"" << std::endl;
hdr << "namespace STUBS" << std::endl;
hdr << "{" << std::endl;
for(auto i = n.begin(); i != n.end(); i++)
process_command(i.key8(), *i, hdr, impl);
impl << "}" << std::endl;
hdr << "}" << std::endl;
return 0;
}

77
src/cmdhelp/mkstubsi.cpp Normal file
View file

@ -0,0 +1,77 @@
#include "json.hpp"
#include <string>
#include <cstring>
#include <fstream>
#include <sstream>
#include <set>
const char* hexes = "0123456789abcdef";
std::string quote_c_string(const std::string& raw, bool hiraw = false);
std::string quote_c_string(const std::string& raw, bool hiraw)
{
std::ostringstream out;
out << "\"";
for(auto i : raw) {
unsigned char ch = i;
if(ch == '\n')
out << "\\n";
else if(ch == '\"')
out << "\\\"";
else if(ch == '\\')
out << "\\\\";
else if(ch < 32 || ch == 127 || (ch > 127 && !hiraw))
out << "\\x" << hexes[ch / 16] << hexes[ch % 16];
else
out << ch;
}
out << "\"";
return out.str();
}
void process_command_inverse(JSON::node& n, std::ostream& imp)
{
if(!n.field_exists("__inverse"))
return;
auto& inv = n["__inverse"];
auto name = n["__name"].as_string8();
for(auto i = inv.begin(); i != inv.end(); i++) {
std::string args = i.key8();
std::string desc = i->as_string8();
if(args != "")
imp << "\t" << quote_c_string(name + " " + args) << ", " << quote_c_string(desc, true) << ","
<< std::endl;
else
imp << "\t" << quote_c_string(name) << ", " << quote_c_string(desc, true) << "," << std::endl;
}
}
int main(int argc, char** argv)
{
std::ofstream impl("inverselist.cpp");
impl << "#include \"cmdhelp/inverselist.hpp\"" << std::endl;
impl << "namespace STUBS" << std::endl;
impl << "{" << std::endl;
impl << "const char* inverse_cmd_list[] = {" << std::endl;
for(int i = 1; i < argc; i++) {
//Hack, skip crap.
if(argv[i][0] == 0 || argv[i][strlen(argv[i])-1] == 'e')
continue;
std::ifstream infile(argv[i]);
std::string in_json;
std::string tmp;
while(infile) {
std::getline(infile, tmp);
in_json = in_json + tmp + "\n";
}
JSON::node n(in_json);
for(auto j = n.begin(); j != n.end(); j++)
process_command_inverse(*j, impl);
}
impl << "\t0\n};" << std::endl;
impl << "}" << std::endl;
return 0;
}

View file

@ -0,0 +1,19 @@
{
"multitrackf":{
"__name":"rotate-multitrack",
"__description":"Rotate multitrack",
"":"Rotate multitrack state",
"__inverse":{"":"Multitrack‣Rotate forward"}
},
"multitrackb":{
"__name":"rotate-multitrack-backwards",
"__description":"Rotate multitrack backwards",
"":"Rotate multitrack state backwards",
"__inverse":{"":"Multitrack‣Rotate backwards"}
},
"multitracks":{
"__name":"set-multitrack",
"__description":"Set multitrack mode",
"<controller> <mode>":"Set multitrack mode for <controller> to <mode>"
}
}

38
src/cmdhelp/project.json Normal file
View file

@ -0,0 +1,38 @@
{
"branch_ls":{
"__class":"project",
"__name":"list-branches",
"__description":"List all slot branches",
"":"List all slot branches."
},
"branch_mk":{
"__class":"project",
"__name":"create-branch",
"__description":"Create a new slot branch",
"<parentid> <name>":"Create new branch named <name> under <parentid>."
},
"branch_rm":{
"__class":"project",
"__name":"delete-branch",
"__description":"Delete a slot branch",
"<id>":"Delete slot branch with id <id>."
},
"branch_set":{
"__class":"project",
"__name":"set-branch",
"__description":"Set current slot branch",
"<id>":"Set current branch to <id>."
},
"branch_rp":{
"__class":"project",
"__name":"reparent-branch",
"__description":"Reparent a slot branch",
"<id> <newpid>":"Reparent branch <id> to be child of <newpid>."
},
"branch_mv":{
"__class":"project",
"__name":"rename-branch",
"__description":"Rename a slot branch",
"<id> <name>":"Rename branch <id> to <name>."
}
}

View file

@ -0,0 +1,18 @@
{
"editsub":{
"__name":"edit-subtitle",
"__description":"Edit a subtitle",
"<first> <length> <text>":"Add/Edit subtitle",
"<first> <length>":"Delete subtitle"
},
"listsub":{
"__name":"list-subtitle",
"__description":"List the subtitles",
"":"List the subtitles."
},
"savesub":{
"__name":"save-subtitle",
"__description":"Save subtitles in .sub format",
"<file>":"Saves subtitles in .sub format to <file>"
}
}

22
src/cmdhelp/turbo.json Normal file
View file

@ -0,0 +1,22 @@
{
"turbot":{
"__class":"turbo",
"__name":"toggle-turbo",
"__description":"Toggle turbo",
"":"Toggle turbo mode.",
"__inverse":{"":"Speed‣Turbo toggle"}
},
"turbop":{
"__class":"turbo",
"__name":"+turbo",
"__description":"Activate turbo",
"":"Activate turbo mode.",
"__inverse":{"":"Speed‣Turbo hold"}
},
"turbor":{
"__class":"turbo",
"__name":"-turbo",
"__description":"Deactivate turbo",
"":"Deactivate turbo mode."
}
}

View file

@ -1,5 +1,7 @@
#include "lsnes.hpp"
#include "cmdhelp/button.hpp"
#include "cmdhelp/macro.hpp"
#include "core/command.hpp"
#include "core/controller.hpp"
#include "core/dispatch.hpp"
@ -27,84 +29,21 @@ namespace
else
return ++map[key];
}
command::fnptr<const std::string&> CMD_button_p(lsnes_cmds, "+controller", "Press a button",
"Syntax: +controller<button>...\nPress a button\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().buttons->do_action(a, 1, 0);
});
command::fnptr<const std::string&> CMD_button_r(lsnes_cmds, "-controller", "Release a button",
"Syntax: -controller<button>...\nRelease a button\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().buttons->do_action(a, 0, 0);
});
command::fnptr<const std::string&> CMD_button_h(lsnes_cmds, "hold-controller", "Autohold a button",
"Syntax: hold-controller<button>...\nAutohold a button\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().buttons->do_action(a, 1, 1);
});
command::fnptr<const std::string&> CMD_button_t(lsnes_cmds, "type-controller", "Type a button",
"Syntax: type-controller<button>...\nType a button\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().buttons->do_action(a, 1, 2);
});
command::fnptr<const std::string&> CMD_button_d(lsnes_cmds, "designate-position", "Set postion",
"Syntax: designate-position <button>...\nDesignate position for an axis\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().buttons->do_action(a, 0, 3);
});
command::fnptr<const std::string&> CMD_button_ap(lsnes_cmds, "+autofire-controller", "Start autofire",
"Syntax: +autofire-controller<button> [[<duty> ]<cyclelen>]...\nAutofire a button\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().buttons->do_autofire_action(a, 1);
});
command::fnptr<const std::string&> CMD_button_an(lsnes_cmds, "-autofire-controller", "End autofire",
"Syntax: -autofire-controller<button> [[<duty> ]<cyclelen>]...\nEnd Autofire on a button\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().buttons->do_autofire_action(a, 0);
});
command::fnptr<const std::string&> CMD_button_at(lsnes_cmds, "autofire-controller", "Toggle autofire",
"Syntax: autofire-controller<button> [[<duty> ]<cyclelen>]...\nToggle Autofire on a button\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().buttons->do_autofire_action(a, -1);
});
command::fnptr<const std::string&> CMD_button_a(lsnes_cmds, "controller-analog", "Analog action",
"Syntax: controller-analog <button> <axis>\nAnalog action\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().buttons->do_analog_action(a);
});
command::fnptr<const std::string&> CMD_macro_t(lsnes_cmds, "macro", "Toggle a macro",
"Syntax: macro <macroname>\nToggle a macro.\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().controls->do_macro(a, 7);
});
command::fnptr<const std::string&> CMD_macro_e(lsnes_cmds, "+macro", "Enable a macro",
"Syntax: +macro <macroname>\nEnable a macro.\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().controls->do_macro(a, 5);
});
command::fnptr<const std::string&> CMD_macro_d(lsnes_cmds, "-macro", "Disable a macro",
"Syntax: -macro <macroname>\nDisable a macro.\n",
[](const std::string& a) throw(std::bad_alloc, std::runtime_error) {
CORE().controls->do_macro(a, 2);
});
}
button_mapping::button_mapping(controller_state& _controls, keyboard::mapper& _mapper, keyboard::keyboard& _keyboard,
emu_framebuffer& _fbuf, emulator_dispatch& _dispatch, lua_state& _lua2)
emu_framebuffer& _fbuf, emulator_dispatch& _dispatch, lua_state& _lua2, command::group& _cmd)
: controls(_controls), mapper(_mapper), keyboard(_keyboard), fbuf(_fbuf), edispatch(_dispatch),
lua2(_lua2)
lua2(_lua2), cmd(_cmd),
button_p(cmd, STUBS::btnp, [this](const std::string& a) { this->do_action(a, 1, 0); }),
button_r(cmd, STUBS::btnr, [this](const std::string& a) { this->do_action(a, 0, 0); }),
button_h(cmd, STUBS::btnh, [this](const std::string& a) { this->do_action(a, 1, 1); }),
button_t(cmd, STUBS::btnt, [this](const std::string& a) { this->do_action(a, 1, 2); }),
button_d(cmd, STUBS::btnd, [this](const std::string& a) { this->do_action(a, 0, 3); }),
button_ap(cmd, STUBS::btnap, [this](const std::string& a) { this->do_autofire_action(a, 1); }),
button_ar(cmd, STUBS::btnar, [this](const std::string& a) { this->do_autofire_action(a, 0); }),
button_at(cmd, STUBS::btnat, [this](const std::string& a) { this->do_autofire_action(a, -1); }),
button_a(cmd, STUBS::btna, [this](const std::string& a) { this->do_analog_action(a); })
{
ncore.set(notify_new_core, [this]() { this->init(); });
}
@ -170,10 +109,10 @@ void button_mapping::load(controller_state& ctrlstate)
for(auto i : s) {
if(!macro_binds.count(i)) {
//New macro, create inverse bind.
macro_binds[i] = new keyboard::invbind(mapper, "macro " + i , "Macro‣" + i +
macro_binds[i] = new keyboard::invbind(mapper, STUBS::macrot.name + (" " + i) , "Macro‣" + i +
" (toggle)");
macro_binds2[i] = new keyboard::invbind(mapper, "+macro " + i , "Macro‣" + i +
" (hold)");
macro_binds2[i] = new keyboard::invbind(mapper, STUBS::macrop.name + (" " + i) , "Macro‣" +
i + " (hold)");
}
}
for(auto i : macro_binds) {
@ -245,33 +184,33 @@ void button_mapping::add_button(const std::string& name, const button_mapping::c
{
keyboard::ctrlrkey* k;
if(binding.mode == 0) {
k = new keyboard::ctrlrkey(mapper, (stringfmt() << "+controller "
k = new keyboard::ctrlrkey(mapper, (stringfmt() << STUBS::btnp.name << " "
<< name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
<< binding.number << "" << binding.name).str());
promote_key(*k);
k = new keyboard::ctrlrkey(mapper, (stringfmt() << "hold-controller "
k = new keyboard::ctrlrkey(mapper, (stringfmt() << STUBS::btnh.name << " "
<< name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
<< binding.number << "" << binding.name << "‣hold").str());
promote_key(*k);
k = new keyboard::ctrlrkey(mapper, (stringfmt() << "type-controller "
k = new keyboard::ctrlrkey(mapper, (stringfmt() << STUBS::btnt.name << " "
<< name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
<< binding.number << "" << binding.name << "‣type").str());
promote_key(*k);
k = new keyboard::ctrlrkey(mapper, (stringfmt() << "+autofire-controller "
k = new keyboard::ctrlrkey(mapper, (stringfmt() << STUBS::btnap.name << " "
<< name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
<< binding.number << "" << binding.name << "‣autofire").str());
promote_key(*k);
k = new keyboard::ctrlrkey(mapper, (stringfmt() << "autofire-controller "
k = new keyboard::ctrlrkey(mapper, (stringfmt() << STUBS::btnat.name << " "
<< name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
<< binding.number << "" << binding.name << "‣autofire toggle").str());
promote_key(*k);
} else if(binding.mode == 1) {
k = new keyboard::ctrlrkey(mapper, (stringfmt() << "designate-position "
k = new keyboard::ctrlrkey(mapper, (stringfmt() << STUBS::btnd.name << " "
<< name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
<< binding.number << "" << binding.name).str());
promote_key(*k);
} else if(binding.mode == 2) {
k = new keyboard::ctrlrkey(mapper, (stringfmt() << "controller-analog "
k = new keyboard::ctrlrkey(mapper, (stringfmt() << STUBS::btna.name << " "
<< name).str(), (stringfmt() << "Controller‣" << binding.cclass << "‣#"
<< binding.number << "" << binding.name << " (axis)").str(), true);
promote_key(*k);

View file

@ -1,3 +1,4 @@
#include "cmdhelp/macro.hpp"
#include "core/controllerframe.hpp"
#include "core/controller.hpp"
#include "core/dispatch.hpp"
@ -15,8 +16,12 @@ namespace
}
controller_state::controller_state(project_state& _project, movie_logic& _mlogic, button_mapping& _buttons,
emulator_dispatch& _dispatch, status_updater& _supdater) throw()
: project(_project), mlogic(_mlogic), buttons(_buttons), edispatch(_dispatch), supdater(_supdater)
emulator_dispatch& _dispatch, status_updater& _supdater, command::group& _cmd) throw()
: project(_project), mlogic(_mlogic), buttons(_buttons), edispatch(_dispatch), supdater(_supdater),
cmd(_cmd),
macro_p(cmd, STUBS::macrop, [this](const std::string& a) { this->do_macro(a, 5); }),
macro_r(cmd, STUBS::macror, [this](const std::string& a) { this->do_macro(a, 2); }),
macro_t(cmd, STUBS::macrot, [this](const std::string& a) { this->do_macro(a, 7); })
{
types = &dummytypes;
tasinput_enaged = false;

View file

@ -1,3 +1,4 @@
#include "cmdhelp/debug.hpp"
#include "core/command.hpp"
#include "core/debug.hpp"
#include "core/dispatch.hpp"
@ -48,8 +49,11 @@ namespace
}
}
debug_context::debug_context(emulator_dispatch& _dispatch, loaded_rom& _rom)
: edispatch(_dispatch), rom(_rom)
debug_context::debug_context(emulator_dispatch& _dispatch, loaded_rom& _rom, command::group& _cmd)
: edispatch(_dispatch), rom(_rom), cmd(_cmd),
showhooks(cmd, STUBS::showhooks, [this]() { this->do_showhooks(); }),
genevent(cmd, STUBS::genevent, [this](const std::string& a) { this->do_genevent(a); }),
tracecmd(cmd, STUBS::trace, [this](const std::string& a) { this->do_tracecmd(a); })
{
}
@ -286,69 +290,62 @@ void debug_context::tracelog(uint64_t proc, const std::string& filename)
if(tracelog_change_cb) tracelog_change_cb();
}
namespace
void debug_context::do_showhooks()
{
command::fnptr<> CMD_callbacks_show(lsnes_cmds, "show-callbacks", "", "",
[]() throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
for(auto& i : core.dbg->read_cb)
for(auto& j : i.second)
messages << "READ addr=" << i.first << " handle=" << &j << std::endl;
for(auto& i : core.dbg->write_cb)
for(auto& j : i.second)
messages << "WRITE addr=" << i.first << " handle=" << &j << std::endl;
for(auto& i : core.dbg->exec_cb)
for(auto& j : i.second)
messages << "EXEC addr=" << i.first << " handle=" << &j << std::endl;
for(auto& i : core.dbg->trace_cb)
for(auto& j : i.second)
messages << "TRACE proc=" << i.first << " handle=" << &j << std::endl;
for(auto& i : core.dbg->frame_cb)
for(auto& j : i.second)
messages << "FRAME handle=" << &j << std::endl;
});
command::fnptr<const std::string&> CMD_generate_event(lsnes_cmds, "generate-memory-event", "", "",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
regex_results r = regex("([^ \t]+) ([^ \t]+) (.+)", args);
if(!r) throw std::runtime_error("generate-memory-event: Bad arguments");
if(r[1] == "r") {
uint64_t addr = parse_value<uint64_t>(r[2]);
uint64_t val = parse_value<uint64_t>(r[3]);
CORE().dbg->do_callback_read(addr, val);
} else if(r[1] == "w") {
uint64_t addr = parse_value<uint64_t>(r[2]);
uint64_t val = parse_value<uint64_t>(r[3]);
CORE().dbg->do_callback_write(addr, val);
} else if(r[1] == "x") {
uint64_t addr = parse_value<uint64_t>(r[2]);
uint64_t val = parse_value<uint64_t>(r[3]);
CORE().dbg->do_callback_exec(addr, val);
} else if(r[1] == "t") {
uint64_t proc = parse_value<uint64_t>(r[2]);
std::string str = r[3];
CORE().dbg->do_callback_trace(proc, str.c_str());
} else
throw std::runtime_error("Invalid operation");
});
command::fnptr<const std::string&> CMD_tracelog(lsnes_cmds, "tracelog", "Trace log control",
"Trace log control\nSyntax: tracelog <cpuid> <file> Start tracing\nSyntax: tracelog <cpuid> "
"End tracing", [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
regex_results r = regex("([^ \t]+)([ \t]+(.+))?", args);
if(!r) throw std::runtime_error("tracelog: Bad arguments");
auto& core = CORE();
std::string cpu = r[1];
std::string filename = r[3];
uint64_t _cpu = 0;
for(auto i : core.rom->get_trace_cpus()) {
if(cpu == i)
goto out;
_cpu++;
}
throw std::runtime_error("tracelog: Invalid CPU");
out:
core.dbg->tracelog(_cpu, filename);
});
for(auto& i : read_cb)
for(auto& j : i.second)
messages << "READ addr=" << i.first << " handle=" << &j << std::endl;
for(auto& i : write_cb)
for(auto& j : i.second)
messages << "WRITE addr=" << i.first << " handle=" << &j << std::endl;
for(auto& i : exec_cb)
for(auto& j : i.second)
messages << "EXEC addr=" << i.first << " handle=" << &j << std::endl;
for(auto& i : trace_cb)
for(auto& j : i.second)
messages << "TRACE proc=" << i.first << " handle=" << &j << std::endl;
for(auto& i : frame_cb)
for(auto& j : i.second)
messages << "FRAME handle=" << &j << std::endl;
}
void debug_context::do_genevent(const std::string& args)
{
regex_results r = regex("([^ \t]+) ([^ \t]+) (.+)", args);
if(!r) throw std::runtime_error("generate-memory-event: Bad arguments");
if(r[1] == "r") {
uint64_t addr = parse_value<uint64_t>(r[2]);
uint64_t val = parse_value<uint64_t>(r[3]);
do_callback_read(addr, val);
} else if(r[1] == "w") {
uint64_t addr = parse_value<uint64_t>(r[2]);
uint64_t val = parse_value<uint64_t>(r[3]);
do_callback_write(addr, val);
} else if(r[1] == "x") {
uint64_t addr = parse_value<uint64_t>(r[2]);
uint64_t val = parse_value<uint64_t>(r[3]);
do_callback_exec(addr, val);
} else if(r[1] == "t") {
uint64_t proc = parse_value<uint64_t>(r[2]);
std::string str = r[3];
do_callback_trace(proc, str.c_str());
} else
throw std::runtime_error("Invalid operation");
}
void debug_context::do_tracecmd(const std::string& args)
{
regex_results r = regex("([^ \t]+)([ \t]+(.+))?", args);
if(!r) throw std::runtime_error("tracelog: Bad arguments");
std::string cpu = r[1];
std::string filename = r[3];
uint64_t _cpu = 0;
for(auto i : rom.get_trace_cpus()) {
if(cpu == i)
goto out;
_cpu++;
}
throw std::runtime_error("tracelog: Invalid CPU");
out:
tracelog(_cpu, filename);
}

View file

@ -1,3 +1,4 @@
#include "cmdhelp/framebuffer.hpp"
#include "core/command.hpp"
#include "core/dispatch.hpp"
#include "core/emustatus.hpp"
@ -77,13 +78,6 @@ namespace
draw_special_screen(target, rl_corrupt);
}
command::fnptr<command::arg_filename> CMD_take_screenshot(lsnes_cmds, "take-screenshot", "Takes a screenshot",
"Syntax: take-screenshot <file>\nSaves screenshot to PNG file <file>\n",
[](command::arg_filename file) throw(std::bad_alloc, std::runtime_error) {
CORE().fbuf->take_screenshot(file);
messages << "Saved PNG screenshot" << std::endl;
});
settingvar::supervariable<settingvar::model_int<0, 8191>> SET_dtb(lsnes_setgrp, "top-border",
"UI‣Top padding", 0);
settingvar::supervariable<settingvar::model_int<0, 8191>> SET_dbb(lsnes_setgrp, "bottom-border",
@ -98,13 +92,21 @@ framebuffer::raw emu_framebuffer::screen_corrupt;
emu_framebuffer::emu_framebuffer(subtitle_commentary& _subtitles, settingvar::group& _settings, memwatch_set& _mwatch,
keyboard::keyboard& _keyboard, emulator_dispatch& _dispatch, lua_state& _lua2, loaded_rom& _rom,
status_updater& _supdater)
status_updater& _supdater, command::group& _cmd)
: buffering(buffer1, buffer2, buffer3), subtitles(_subtitles), settings(_settings), mwatch(_mwatch),
keyboard(_keyboard), edispatch(_dispatch), lua2(_lua2), rom(_rom), supdater(_supdater)
keyboard(_keyboard), edispatch(_dispatch), lua2(_lua2), rom(_rom), supdater(_supdater), cmd(_cmd),
screenshot(cmd, STUBS::screenshot, [this](command::arg_filename a) { this->do_screenshot(a); })
{
last_redraw_no_lua = false;
}
void emu_framebuffer::do_screenshot(command::arg_filename file)
{
std::string fn = file;
take_screenshot(fn);
messages << "Saved PNG screenshot to '" << fn << "'" << std::endl;
}
void emu_framebuffer::take_screenshot(const std::string& file) throw(std::bad_alloc, std::runtime_error)
{
render_info& ri = buffering.get_read();

View file

@ -1,5 +1,6 @@
#include "core/command.hpp"
#include "core/framerate.hpp"
#include "cmdhelp/turbo.hpp"
#include "core/instance.hpp"
#include "core/keymapper.hpp"
#include "core/moviedata.hpp"
@ -16,32 +17,11 @@
bool graphics_driver_is_dummy();
namespace
{
command::fnptr<> CMD_tturbo(lsnes_cmds, "toggle-turbo", "Toggle turbo",
"Syntax: toggle-turbo\nToggle turbo mode.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
CORE().framerate->turboed = !CORE().framerate->turboed;
});
command::fnptr<> CMD_pturbo(lsnes_cmds, "+turbo", "Activate turbo",
"Syntax: +turbo\nActivate turbo mode.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
CORE().framerate->turboed = true;
});
command::fnptr<> CMD_nturbo(lsnes_cmds, "-turbo", "Deactivate turbo",
"Syntax: -turbo\nDeactivate turbo mode.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
CORE().framerate->turboed = false;
});
keyboard::invbind_info IBIND_turboh(lsnes_invbinds, "+turbo", "Speed‣Turbo hold");
keyboard::invbind_info IBIND_turbot(lsnes_invbinds, "toggle-turbo", "Speed‣Turbo toggle");
}
framerate_regulator::framerate_regulator()
framerate_regulator::framerate_regulator(command::group& _cmd)
: cmd(_cmd),
turbo_p(cmd, STUBS::turbop, [this]() { this->turboed = true; }),
turbo_r(cmd, STUBS::turbor, [this]() { this->turboed = false; }),
turbo_t(cmd, STUBS::turbot, [this]() { this->turboed = !this->turboed; })
{
last_time_update = 0;
time_at_last_update = 0;

View file

@ -85,19 +85,19 @@ emulator_instance::emulator_instance()
D.init(lua2, *lua, *command);
D.init(mwatch, *memory, *project, *fbuf, *rom);
D.init(settings);
D.init(jukebox, *settings);
D.init(jukebox, *settings, *command);
D.init(setcache, *settings);
D.init(audio);
D.init(commentary, *settings, *dispatch, *audio);
D.init(subtitles, *mlogic, *fbuf, *dispatch);
D.init(commentary, *settings, *dispatch, *audio, *command);
D.init(subtitles, *mlogic, *fbuf, *dispatch, *command);
D.init(mbranch, *mlogic, *dispatch, *supdater);
D.init(controls, *project, *mlogic, *buttons, *dispatch, *supdater);
D.init(controls, *project, *mlogic, *buttons, *dispatch, *supdater, *command);
D.init(keyboard);
D.init(mapper, *keyboard, *command);
D.init(rom);
D.init(fbuf, *subtitles, *settings, *mwatch, *keyboard, *dispatch, *lua2, *rom, *supdater);
D.init(buttons, *controls, *mapper, *keyboard, *fbuf, *dispatch, *lua2);
D.init(mteditor, *mlogic, *controls, *dispatch, *supdater);
D.init(fbuf, *subtitles, *settings, *mwatch, *keyboard, *dispatch, *lua2, *rom, *supdater, *command);
D.init(buttons, *controls, *mapper, *keyboard, *fbuf, *dispatch, *lua2, *command);
D.init(mteditor, *mlogic, *controls, *dispatch, *supdater, *buttons, *command);
D.init(status_A);
D.init(status_B);
D.init(status_C);
@ -107,8 +107,8 @@ emulator_instance::emulator_instance()
D.init(cmapper, *memory, *mlogic, *rom);
D.init(project, *commentary, *mwatch, *command, *controls, *setcache, *buttons, *dispatch, *iqueue, *rom,
*supdater);
D.init(dbg, *dispatch, *rom);
D.init(framerate);
D.init(dbg, *dispatch, *rom, *command);
D.init(framerate, *command);
D.init(mdumper, *lua2);
D.init(runmode);
D.init(supdater, *project, *mlogic, *commentary, *status, *runmode, *mdumper, *jukebox, *slotcache,

View file

@ -1,5 +1,6 @@
#include "lsnes.hpp"
#include "cmdhelp/commentary.hpp"
#include "core/audioapi.hpp"
#include "core/command.hpp"
#include "core/dispatch.hpp"
@ -1715,24 +1716,13 @@ out:
voicesub_state& internal;
audioapi_instance& audio;
};
//The tangent function.
command::fnptr<> CMD_ptangent(lsnes_cmds, "+tangent", "Voice tangent",
"Syntax: +tangent\nVoice tangent.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
CORE().commentary->set_active_flag(true);
});
command::fnptr<> CMD_ntangent(lsnes_cmds, "-tangent", "Voice tangent",
"Syntax: -tangent\nVoice tangent.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
CORE().commentary->set_active_flag(false);
});
keyboard::invbind_info IBIND_itangent(lsnes_invbinds, "+tangent", "Movie‣Voice tangent");
}
voice_commentary::voice_commentary(settingvar::group& _settings, emulator_dispatch& _dispatch,
audioapi_instance& _audio)
: settings(_settings), edispatch(_dispatch), audio(_audio)
audioapi_instance& _audio, command::group& _cmd)
: settings(_settings), edispatch(_dispatch), audio(_audio), cmd(_cmd),
tangentp(cmd, STUBS::tangentp, [this]() { this->set_active_flag(true); }),
tangentr(cmd, STUBS::tangentr, [this]() { this->set_active_flag(false); })
{
internal = NULL;
}

View file

@ -1,3 +1,4 @@
#include "cmdhelp/jukebox.hpp"
#include "core/jukebox.hpp"
#include "core/settings.hpp"
#include "library/settingvar.hpp"
@ -30,8 +31,11 @@ private:
save_jukebox& jukebox;
};
save_jukebox::save_jukebox(settingvar::group& _settings)
: settings(_settings)
save_jukebox::save_jukebox(settingvar::group& _settings, command::group& _cmd)
: settings(_settings), cmd(_cmd),
slotsel(cmd, STUBS::slotselect, [this](const std::string& a) { this->do_slotsel(a); }),
cycleprev(cmd, STUBS::slotprev, [this]() { this->cycle_prev(); }),
cyclenext(cmd, STUBS::slotnext, [this]() { this->cycle_next(); })
{
listener = new save_jukebox_listener(_settings, *this);
}
@ -104,3 +108,11 @@ void save_jukebox::unset_update()
{
update = std::function<void()>();
}
void save_jukebox::do_slotsel(const std::string& args)
{
if(!regex_match("[1-9][0-9]{0,8}", args))
throw std::runtime_error("Bad slot number");
uint32_t slot = parse_value<uint32_t>(args);
set_slot(slot - 1);
}

View file

@ -1,5 +1,7 @@
#include "lsnes.hpp"
#include "cmdhelp/loadsave.hpp"
#include "cmdhelp/mhold.hpp"
#include "core/advdumper.hpp"
#include "core/command.hpp"
#include "core/controller.hpp"
@ -379,30 +381,6 @@ namespace
}
});
command::fnptr<> CMD_save_jukebox_prev(lsnes_cmds, "cycle-jukebox-backward", "Cycle save jukebox backwards",
"Syntax: cycle-jukebox-backward\nCycle save jukebox backwards\n",
[]() throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
core.jukebox->cycle_prev();
});
command::fnptr<> CMD_save_jukebox_next(lsnes_cmds, "cycle-jukebox-forward", "Cycle save jukebox forwards",
"Syntax: cycle-jukebox-forward\nCycle save jukebox forwards\n",
[]() throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
core.jukebox->cycle_next();
});
command::fnptr<const std::string&> CMD_save_jukebox_set(lsnes_cmds, "set-jukebox-slot", "Set jukebox slot",
"Syntax: set-jukebox-slot\nSet jukebox slot\n", [](const std::string& args)
throw(std::bad_alloc, std::runtime_error) {
if(!regex_match("[1-9][0-9]{0,8}", args))
throw std::runtime_error("Bad slot number");
uint32_t slot = parse_value<uint32_t>(args);
auto& core = CORE();
core.jukebox->set_slot(slot - 1);
});
command::fnptr<> CMD_load_jukebox(lsnes_cmds, "load-jukebox", "Load save from jukebox",
"Syntax: load-jukebox\nLoad save from jukebox\n",
[]() throw(std::bad_alloc, std::runtime_error) {
@ -519,8 +497,7 @@ namespace
core.rom->execute_action(hreset_action, std::vector<interface_action_paramval>());
});
command::fnptr<command::arg_filename> CMD_load_c(lsnes_cmds, "load", "Load savestate (current mode)",
"Syntax: load <file>\nLoads SNES state from <file> in current mode\n",
command::fnptr<command::arg_filename> CMD_load_c(lsnes_cmds, STUBS::load,
[](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
mark_pending_load(args, LOAD_STATE_CURRENT);
});
@ -564,8 +541,7 @@ namespace
mark_pending_load(args, LOAD_STATE_ALLBRANCH);
});
command::fnptr<command::arg_filename> CMD_save_state(lsnes_cmds, "save-state", "Save state",
"Syntax: save-state <file>\nSaves SNES state to <file>\n",
command::fnptr<command::arg_filename> CMD_save_state(lsnes_cmds, STUBS::savestate,
[](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
mark_pending_save(args, SAVE_STATE, -1);
});
@ -679,30 +655,23 @@ namespace
CORE().slotcache->flush();
});
command::fnptr<> CMD_mhold1(lsnes_cmds, "+hold-macro", "Hold macro (hold)",
"Hold macros enable\n", []() throw(std::bad_alloc, std::runtime_error) {
macro_hold_1 = true;
});
command::fnptr<> CMD_mhold1(lsnes_cmds, STUBS::mholdp, []() throw(std::bad_alloc, std::runtime_error) {
macro_hold_1 = true;
});
command::fnptr<> CMD_mhold2(lsnes_cmds, "-hold-macro", "Hold macro (hold)",
"Hold macros disable\n", []() throw(std::bad_alloc, std::runtime_error) {
macro_hold_1 = false;
});
command::fnptr<> CMD_mhold2(lsnes_cmds, STUBS::mholdr, []() throw(std::bad_alloc, std::runtime_error) {
macro_hold_1 = false;
});
command::fnptr<> CMD_mhold3(lsnes_cmds, "hold-macro", "Hold macro (toggle)",
"Hold macros toggle\n", []() throw(std::bad_alloc, std::runtime_error) {
macro_hold_2 = !macro_hold_2;
if(macro_hold_2)
messages << "Macros are held for next frame." << std::endl;
else
messages << "Macros are not held for next frame." << std::endl;
});
command::fnptr<> CMD_mhold3(lsnes_cmds, STUBS::mholdt, []() throw(std::bad_alloc, std::runtime_error) {
macro_hold_2 = !macro_hold_2;
if(macro_hold_2)
messages << "Macros are held for next frame." << std::endl;
else
messages << "Macros are not held for next frame." << std::endl;
});
keyboard::invbind_info IBIND_imhold1(lsnes_invbinds, "+hold-macro", "Macro‣Hold all macros");
keyboard::invbind_info IBIND_imhold2(lsnes_invbinds, "hold-macro", "Macro‣Hold all macros (typed)");
keyboard::invbind_info IBIND_ipause_emulator(lsnes_invbinds, "pause-emulator", "Speed‣(Un)pause");
keyboard::invbind_info IBIND_ijback(lsnes_invbinds, "cycle-jukebox-backward", "Slot select‣Cycle backwards");
keyboard::invbind_info IBIND_ijforward(lsnes_invbinds, "cycle-jukebox-forward", "Slot select‣Cycle forwards");
keyboard::invbind_info IBIND_iloadj(lsnes_invbinds, "load-jukebox", "Load‣Selected slot");
keyboard::invbind_info IBIND_iloadjrw(lsnes_invbinds, "load-jukebox-readwrite",
"Load‣Selected slot (recording mode)");
@ -723,102 +692,6 @@ namespace
keyboard::invbind_info IBIND_itogglepause(lsnes_invbinds, "toggle-pause-on-end", "Movie‣Toggle pause-on-end");
keyboard::invbind_info IBIND_irewind_movie(lsnes_invbinds, "rewind-movie", "Movie‣Rewind movie");
keyboard::invbind_info IBIND_icancel_saves(lsnes_invbinds, "cancel-saves", "Save‣Cancel pending saves");
keyboard::invbind_info IBIND_iload1(lsnes_invbinds, "load $SLOT:1", "Load‣Slot 1");
keyboard::invbind_info IBIND_iload2(lsnes_invbinds, "load $SLOT:2", "Load‣Slot 2");
keyboard::invbind_info IBIND_iload3(lsnes_invbinds, "load $SLOT:3", "Load‣Slot 3");
keyboard::invbind_info IBIND_iload4(lsnes_invbinds, "load $SLOT:4", "Load‣Slot 4");
keyboard::invbind_info IBIND_iload5(lsnes_invbinds, "load $SLOT:5", "Load‣Slot 5");
keyboard::invbind_info IBIND_iload6(lsnes_invbinds, "load $SLOT:6", "Load‣Slot 6");
keyboard::invbind_info IBIND_iload7(lsnes_invbinds, "load $SLOT:7", "Load‣Slot 7");
keyboard::invbind_info IBIND_iload8(lsnes_invbinds, "load $SLOT:8", "Load‣Slot 8");
keyboard::invbind_info IBIND_iload9(lsnes_invbinds, "load $SLOT:9", "Load‣Slot 9");
keyboard::invbind_info IBIND_iload10(lsnes_invbinds, "load $SLOT:10", "Load‣Slot 10");
keyboard::invbind_info IBIND_iload11(lsnes_invbinds, "load $SLOT:11", "Load‣Slot 11");
keyboard::invbind_info IBIND_iload12(lsnes_invbinds, "load $SLOT:12", "Load‣Slot 12");
keyboard::invbind_info IBIND_iload13(lsnes_invbinds, "load $SLOT:13", "Load‣Slot 13");
keyboard::invbind_info IBIND_iload14(lsnes_invbinds, "load $SLOT:14", "Load‣Slot 14");
keyboard::invbind_info IBIND_iload15(lsnes_invbinds, "load $SLOT:15", "Load‣Slot 15");
keyboard::invbind_info IBIND_iload16(lsnes_invbinds, "load $SLOT:16", "Load‣Slot 16");
keyboard::invbind_info IBIND_iload17(lsnes_invbinds, "load $SLOT:17", "Load‣Slot 17");
keyboard::invbind_info IBIND_iload18(lsnes_invbinds, "load $SLOT:18", "Load‣Slot 18");
keyboard::invbind_info IBIND_iload19(lsnes_invbinds, "load $SLOT:19", "Load‣Slot 19");
keyboard::invbind_info IBIND_iload20(lsnes_invbinds, "load $SLOT:20", "Load‣Slot 20");
keyboard::invbind_info IBIND_iload21(lsnes_invbinds, "load $SLOT:21", "Load‣Slot 21");
keyboard::invbind_info IBIND_iload22(lsnes_invbinds, "load $SLOT:22", "Load‣Slot 22");
keyboard::invbind_info IBIND_iload23(lsnes_invbinds, "load $SLOT:23", "Load‣Slot 23");
keyboard::invbind_info IBIND_iload24(lsnes_invbinds, "load $SLOT:24", "Load‣Slot 24");
keyboard::invbind_info IBIND_iload25(lsnes_invbinds, "load $SLOT:25", "Load‣Slot 25");
keyboard::invbind_info IBIND_iload26(lsnes_invbinds, "load $SLOT:26", "Load‣Slot 26");
keyboard::invbind_info IBIND_iload27(lsnes_invbinds, "load $SLOT:27", "Load‣Slot 27");
keyboard::invbind_info IBIND_iload28(lsnes_invbinds, "load $SLOT:28", "Load‣Slot 28");
keyboard::invbind_info IBIND_iload29(lsnes_invbinds, "load $SLOT:29", "Load‣Slot 29");
keyboard::invbind_info IBIND_iload30(lsnes_invbinds, "load $SLOT:30", "Load‣Slot 30");
keyboard::invbind_info IBIND_iload31(lsnes_invbinds, "load $SLOT:31", "Load‣Slot 31");
keyboard::invbind_info IBIND_iload32(lsnes_invbinds, "load $SLOT:32", "Load‣Slot 32");
keyboard::invbind_info IBIND_isave1(lsnes_invbinds, "save-state $SLOT:1", "Save‣Slot 1");
keyboard::invbind_info IBIND_isave2(lsnes_invbinds, "save-state $SLOT:2", "Save‣Slot 2");
keyboard::invbind_info IBIND_isave3(lsnes_invbinds, "save-state $SLOT:3", "Save‣Slot 3");
keyboard::invbind_info IBIND_isave4(lsnes_invbinds, "save-state $SLOT:4", "Save‣Slot 4");
keyboard::invbind_info IBIND_isave5(lsnes_invbinds, "save-state $SLOT:5", "Save‣Slot 5");
keyboard::invbind_info IBIND_isave6(lsnes_invbinds, "save-state $SLOT:6", "Save‣Slot 6");
keyboard::invbind_info IBIND_isave7(lsnes_invbinds, "save-state $SLOT:7", "Save‣Slot 7");
keyboard::invbind_info IBIND_isave8(lsnes_invbinds, "save-state $SLOT:8", "Save‣Slot 8");
keyboard::invbind_info IBIND_isave9(lsnes_invbinds, "save-state $SLOT:9", "Save‣Slot 9");
keyboard::invbind_info IBIND_isave10(lsnes_invbinds, "save-state $SLOT:10", "Save‣Slot 10");
keyboard::invbind_info IBIND_isave11(lsnes_invbinds, "save-state $SLOT:11", "Save‣Slot 11");
keyboard::invbind_info IBIND_isave12(lsnes_invbinds, "save-state $SLOT:12", "Save‣Slot 12");
keyboard::invbind_info IBIND_isave13(lsnes_invbinds, "save-state $SLOT:13", "Save‣Slot 13");
keyboard::invbind_info IBIND_isave14(lsnes_invbinds, "save-state $SLOT:14", "Save‣Slot 14");
keyboard::invbind_info IBIND_isave15(lsnes_invbinds, "save-state $SLOT:15", "Save‣Slot 15");
keyboard::invbind_info IBIND_isave16(lsnes_invbinds, "save-state $SLOT:16", "Save‣Slot 16");
keyboard::invbind_info IBIND_isave17(lsnes_invbinds, "save-state $SLOT:17", "Save‣Slot 17");
keyboard::invbind_info IBIND_isave18(lsnes_invbinds, "save-state $SLOT:18", "Save‣Slot 18");
keyboard::invbind_info IBIND_isave19(lsnes_invbinds, "save-state $SLOT:19", "Save‣Slot 19");
keyboard::invbind_info IBIND_isave20(lsnes_invbinds, "save-state $SLOT:20", "Save‣Slot 20");
keyboard::invbind_info IBIND_isave21(lsnes_invbinds, "save-state $SLOT:21", "Save‣Slot 21");
keyboard::invbind_info IBIND_isave22(lsnes_invbinds, "save-state $SLOT:22", "Save‣Slot 22");
keyboard::invbind_info IBIND_isave23(lsnes_invbinds, "save-state $SLOT:23", "Save‣Slot 23");
keyboard::invbind_info IBIND_isave24(lsnes_invbinds, "save-state $SLOT:24", "Save‣Slot 24");
keyboard::invbind_info IBIND_isave25(lsnes_invbinds, "save-state $SLOT:25", "Save‣Slot 25");
keyboard::invbind_info IBIND_isave26(lsnes_invbinds, "save-state $SLOT:26", "Save‣Slot 26");
keyboard::invbind_info IBIND_isave27(lsnes_invbinds, "save-state $SLOT:27", "Save‣Slot 27");
keyboard::invbind_info IBIND_isave28(lsnes_invbinds, "save-state $SLOT:28", "Save‣Slot 28");
keyboard::invbind_info IBIND_isave29(lsnes_invbinds, "save-state $SLOT:29", "Save‣Slot 29");
keyboard::invbind_info IBIND_isave30(lsnes_invbinds, "save-state $SLOT:30", "Save‣Slot 30");
keyboard::invbind_info IBIND_isave31(lsnes_invbinds, "save-state $SLOT:31", "Save‣Slot 31");
keyboard::invbind_info IBIND_isave32(lsnes_invbinds, "save-state $SLOT:32", "Save‣Slot 32");
keyboard::invbind_info IBIND_islot1(lsnes_invbinds, "set-jukebox-slot 1", "Slot select‣Slot 1");
keyboard::invbind_info IBIND_islot2(lsnes_invbinds, "set-jukebox-slot 2", "Slot select‣Slot 2");
keyboard::invbind_info IBIND_islot3(lsnes_invbinds, "set-jukebox-slot 3", "Slot select‣Slot 3");
keyboard::invbind_info IBIND_islot4(lsnes_invbinds, "set-jukebox-slot 4", "Slot select‣Slot 4");
keyboard::invbind_info IBIND_islot5(lsnes_invbinds, "set-jukebox-slot 5", "Slot select‣Slot 5");
keyboard::invbind_info IBIND_islot6(lsnes_invbinds, "set-jukebox-slot 6", "Slot select‣Slot 6");
keyboard::invbind_info IBIND_islot7(lsnes_invbinds, "set-jukebox-slot 7", "Slot select‣Slot 7");
keyboard::invbind_info IBIND_islot8(lsnes_invbinds, "set-jukebox-slot 8", "Slot select‣Slot 8");
keyboard::invbind_info IBIND_islot9(lsnes_invbinds, "set-jukebox-slot 9", "Slot select‣Slot 9");
keyboard::invbind_info IBIND_islot10(lsnes_invbinds, "set-jukebox-slot 10", "Slot select‣Slot 10");
keyboard::invbind_info IBIND_islot11(lsnes_invbinds, "set-jukebox-slot 11", "Slot select‣Slot 11");
keyboard::invbind_info IBIND_islot12(lsnes_invbinds, "set-jukebox-slot 12", "Slot select‣Slot 12");
keyboard::invbind_info IBIND_islot13(lsnes_invbinds, "set-jukebox-slot 13", "Slot select‣Slot 13");
keyboard::invbind_info IBIND_islot14(lsnes_invbinds, "set-jukebox-slot 14", "Slot select‣Slot 14");
keyboard::invbind_info IBIND_islot15(lsnes_invbinds, "set-jukebox-slot 15", "Slot select‣Slot 15");
keyboard::invbind_info IBIND_islot16(lsnes_invbinds, "set-jukebox-slot 16", "Slot select‣Slot 16");
keyboard::invbind_info IBIND_islot17(lsnes_invbinds, "set-jukebox-slot 17", "Slot select‣Slot 17");
keyboard::invbind_info IBIND_islot18(lsnes_invbinds, "set-jukebox-slot 18", "Slot select‣Slot 18");
keyboard::invbind_info IBIND_islot19(lsnes_invbinds, "set-jukebox-slot 19", "Slot select‣Slot 19");
keyboard::invbind_info IBIND_islot20(lsnes_invbinds, "set-jukebox-slot 20", "Slot select‣Slot 20");
keyboard::invbind_info IBIND_islot21(lsnes_invbinds, "set-jukebox-slot 21", "Slot select‣Slot 21");
keyboard::invbind_info IBIND_islot22(lsnes_invbinds, "set-jukebox-slot 22", "Slot select‣Slot 22");
keyboard::invbind_info IBIND_islot23(lsnes_invbinds, "set-jukebox-slot 23", "Slot select‣Slot 23");
keyboard::invbind_info IBIND_islot24(lsnes_invbinds, "set-jukebox-slot 24", "Slot select‣Slot 24");
keyboard::invbind_info IBIND_islot25(lsnes_invbinds, "set-jukebox-slot 25", "Slot select‣Slot 25");
keyboard::invbind_info IBIND_islot26(lsnes_invbinds, "set-jukebox-slot 26", "Slot select‣Slot 26");
keyboard::invbind_info IBIND_islot27(lsnes_invbinds, "set-jukebox-slot 27", "Slot select‣Slot 27");
keyboard::invbind_info IBIND_islot28(lsnes_invbinds, "set-jukebox-slot 28", "Slot select‣Slot 28");
keyboard::invbind_info IBIND_islot29(lsnes_invbinds, "set-jukebox-slot 29", "Slot select‣Slot 29");
keyboard::invbind_info IBIND_islot30(lsnes_invbinds, "set-jukebox-slot 30", "Slot select‣Slot 30");
keyboard::invbind_info IBIND_islot31(lsnes_invbinds, "set-jukebox-slot 31", "Slot select‣Slot 31");
keyboard::invbind_info IBIND_islot32(lsnes_invbinds, "set-jukebox-slot 32", "Slot select‣Slot 32");
class mywindowcallbacks : public master_dumper::notifier
{

View file

@ -1,3 +1,4 @@
#include "cmdhelp/multitrack.hpp"
#include "core/command.hpp"
#include "core/controller.hpp"
#include "core/dispatch.hpp"
@ -11,8 +12,12 @@
#include <string>
multitrack_edit::multitrack_edit(movie_logic& _mlogic, controller_state& _controls, emulator_dispatch& _dispatch,
status_updater& _supdater)
: mlogic(_mlogic), controls(_controls), edispatch(_dispatch), supdater(_supdater)
status_updater& _supdater, button_mapping& _buttons, command::group& _cmd)
: mlogic(_mlogic), controls(_controls), edispatch(_dispatch), supdater(_supdater), buttons(_buttons),
cmd(_cmd),
mt_f(cmd, STUBS::multitrackf, [this]() { this->do_mt_fwd(); }),
mt_b(cmd, STUBS::multitrackb, [this]() { this->do_mt_bw(); }),
mt_s(cmd, STUBS::multitracks, [this](const std::string& a) { this->do_mt_set(a); })
{
}
@ -172,51 +177,41 @@ bool multitrack_edit::any_records()
return any_need;
}
void multitrack_edit::do_mt_set(const std::string& args)
{
regex_results r = regex("(.*)[ \t]+(.*)", args);
if(!r)
throw std::runtime_error("Bad arguments");
auto c = buttons.byname(r[1]);
if(c.first < 0)
throw std::runtime_error("No such controller");
if(r[2] == "keep")
set_and_notify(c.first, c.second, multitrack_edit::MT_PRESERVE);
else if(r[2] == "rewrite")
set_and_notify(c.first, c.second, multitrack_edit::MT_OVERWRITE);
else if(r[2] == "or")
set_and_notify(c.first, c.second, multitrack_edit::MT_OR);
else if(r[2] == "xor")
set_and_notify(c.first, c.second, multitrack_edit::MT_XOR);
else
throw std::runtime_error("Invalid mode (keep, rewrite, or, xor)");
supdater.update();
}
void multitrack_edit::do_mt_fwd()
{
rotate(true);
supdater.update();
}
void multitrack_edit::do_mt_bw()
{
rotate(false);
supdater.update();
}
namespace
{
command::fnptr<> CMD_rotate_forward(lsnes_cmds, "rotate-multitrack", "Rotate multitrack",
"Syntax: rotate-multitrack\nRotate multitrack\n",
[]() throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
core.mteditor->rotate(true);
core.supdater->update();
});
command::fnptr<> CMD_rotate_backward(lsnes_cmds, "rotate-multitrack-backwards", "Rotate multitrack backwards",
"Syntax: rotate-multitrack-backwards\nRotate multitrack backwards\n",
[]() throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
core.mteditor->rotate(false);
core.supdater->update();
});
command::fnptr<const std::string&> CMD_set_mt(lsnes_cmds, "set-multitrack", "Set multitrack mode",
"Syntax: set-multitrack <controller> <mode>\nSet multitrack mode\n",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
regex_results r = regex("(.*)[ \t]+(.*)", args);
if(!r)
throw std::runtime_error("Bad arguments");
auto c = core.buttons->byname(r[1]);
if(c.first < 0)
throw std::runtime_error("No such controller");
if(r[2] == "keep")
core.mteditor->set_and_notify(c.first, c.second, multitrack_edit::MT_PRESERVE);
else if(r[2] == "rewrite")
core.mteditor->set_and_notify(c.first, c.second, multitrack_edit::MT_OVERWRITE);
else if(r[2] == "or")
core.mteditor->set_and_notify(c.first, c.second, multitrack_edit::MT_OR);
else if(r[2] == "xor")
core.mteditor->set_and_notify(c.first, c.second, multitrack_edit::MT_XOR);
else
throw std::runtime_error("Invalid mode (keep, rewrite, or, xor)");
core.supdater->update();
});
keyboard::invbind_info IBIND_mtback(lsnes_invbinds, "rotate-multitrack-backwards",
"Multitrack‣Rotate backwards");
keyboard::invbind_info IBIND_mtfwd(lsnes_invbinds, "rotate-multitrack", "Multitrack‣Rotate forward");
int multitrack_state(lua::state& L, lua::parameters& P)
{
unsigned port, controller;

View file

@ -1,3 +1,4 @@
#include "cmdhelp/project.hpp"
#include "core/command.hpp"
#include "core/controller.hpp"
#include "core/dispatch.hpp"
@ -193,7 +194,13 @@ project_state::project_state(voice_commentary& _commentary, memwatch_set& _mwatc
controller_state& _controls, settingvar::cache& _setcache, button_mapping& _buttons,
emulator_dispatch& _edispatch, input_queue& _iqueue, loaded_rom& _rom, status_updater& _supdater)
: commentary(_commentary), mwatch(_mwatch), command(_command), controls(_controls), setcache(_setcache),
buttons(_buttons), edispatch(_edispatch), iqueue(_iqueue), rom(_rom), supdater(_supdater)
buttons(_buttons), edispatch(_edispatch), iqueue(_iqueue), rom(_rom), supdater(_supdater),
branch_ls(command, STUBS::branch_ls, [this]() { this->do_branch_ls(); }),
branch_mk(command, STUBS::branch_mk, [this](const std::string& a) { this->do_branch_mk(a); }),
branch_rm(command, STUBS::branch_rm, [this](const std::string& a) { this->do_branch_rm(a); }),
branch_set(command, STUBS::branch_set, [this](const std::string& a) { this->do_branch_set(a); }),
branch_rp(command, STUBS::branch_rp, [this](const std::string& a) { this->do_branch_rp(a); }),
branch_mv(command, STUBS::branch_mv, [this](const std::string& a) { this->do_branch_mv(a); })
{
active_project = NULL;
}
@ -700,150 +707,137 @@ void project_info::write(std::ostream& s)
s << "branchnext=" << next_branch << std::endl;
}
namespace
void project_state::do_branch_mk(const std::string& args)
{
void recursive_list_branch(uint64_t bid, std::set<unsigned>& dset, unsigned depth, bool last_of)
{
auto prj = CORE().project->get();
if(!prj) {
messages << "Not in project context." << std::endl;
return;
}
std::set<uint64_t> children = prj->branch_children(bid);
std::string prefix;
for(unsigned i = 0; i + 1 < depth; i++)
prefix += (dset.count(i) ? "\u2502" : " ");
prefix += (dset.count(depth - 1) ? (last_of ? "\u2514" : "\u251c") : " ");
if(last_of) dset.erase(depth - 1);
messages << prefix
<< ((bid == prj->get_current_branch()) ? "*" : "")
<< bid << ":" << prj->get_branch_name(bid) << std::endl;
dset.insert(depth);
size_t c = 0;
for(auto i : children) {
bool last = (++c == children.size());
recursive_list_branch(i, dset, depth + 1, last);
}
dset.erase(depth);
regex_results r = regex("([0-9]+)[ \t]+(.*)", args);
if(!r) {
messages << "Syntax: create-branch <parentid> <name>" << std::endl;
return;
}
try {
auto prj = get();
uint64_t pbid = parse_value<uint64_t>(r[1]);
if(!prj)
throw std::runtime_error("Not in project context");
uint64_t bid = prj->create_branch(pbid, r[2]);
messages << "Created branch #" << bid << std::endl;
prj->flush();
} catch(std::exception& e) {
messages << "Can't create new branch: " << e.what() << std::endl;
}
command::fnptr<> CMD_list_branches(lsnes_cmds, "list-branches", "List all slot branches",
"Syntax: list-branches\nList all slot branches.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
std::set<unsigned> dset;
recursive_list_branch(0, dset, 0, false);
});
command::fnptr<const std::string&> CMD_create_branch(lsnes_cmds, "create-branch", "Create a new slot branch",
"Syntax: create-branch <parentid> <name>\nCreate new branch named <name> under <parentid>.\n",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
regex_results r = regex("([0-9]+)[ \t]+(.*)", args);
if(!r) {
messages << "Syntax: create-branch <parentid> <name>" << std::endl;
return;
}
try {
auto prj = CORE().project->get();
uint64_t pbid = parse_value<uint64_t>(r[1]);
if(!prj)
throw std::runtime_error("Not in project context");
uint64_t bid = prj->create_branch(pbid, r[2]);
messages << "Created branch #" << bid << std::endl;
prj->flush();
} catch(std::exception& e) {
messages << "Can't create new branch: " << e.what() << std::endl;
}
});
command::fnptr<const std::string&> CMD_delete_branch(lsnes_cmds, "delete-branch", "Delete a slot branch",
"Syntax: delete-branch <id>\nDelete slot branch with id <id>.\n",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
regex_results r = regex("([0-9]+)[ \t]*", args);
if(!r) {
messages << "Syntax: delete-branch <id>" << std::endl;
return;
}
try {
auto prj = CORE().project->get();
uint64_t bid = parse_value<uint64_t>(r[1]);
if(!prj)
throw std::runtime_error("Not in project context");
prj->delete_branch(bid);
messages << "Deleted branch #" << bid << std::endl;
prj->flush();
} catch(std::exception& e) {
messages << "Can't delete branch: " << e.what() << std::endl;
}
});
command::fnptr<const std::string&> CMD_set_branch(lsnes_cmds, "set-branch", "Set current slot branch",
"Syntax: set-branch <id>\nSet current branch to <id>.\n",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
regex_results r = regex("([0-9]+)[ \t]*", args);
if(!r) {
messages << "Syntax: set-branch <id>" << std::endl;
return;
}
try {
auto prj = core.project->get();
uint64_t bid = parse_value<uint64_t>(r[1]);
if(!prj)
throw std::runtime_error("Not in project context");
prj->set_current_branch(bid);
messages << "Set current branch to #" << bid << std::endl;
prj->flush();
core.supdater->update();
} catch(std::exception& e) {
messages << "Can't set branch: " << e.what() << std::endl;
}
});
command::fnptr<const std::string&> CMD_reparent_branch(lsnes_cmds, "reparent-branch",
"Reparent a slot branch",
"Syntax: reparent-branch <id> <newpid>\nReparent branch <id> to be child of <newpid>.\n",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
regex_results r = regex("([0-9]+)[ \t]+([0-9]+)[ \t]*", args);
if(!r) {
messages << "Syntax: reparent-branch <id> <newpid>" << std::endl;
return;
}
try {
auto prj = core.project->get();
uint64_t bid = parse_value<uint64_t>(r[1]);
uint64_t pbid = parse_value<uint64_t>(r[2]);
if(!prj)
throw std::runtime_error("Not in project context");
prj->set_parent_branch(bid, pbid);
messages << "Reparented branch #" << bid << std::endl;
prj->flush();
core.supdater->update();
} catch(std::exception& e) {
messages << "Can't reparent branch: " << e.what() << std::endl;
}
});
command::fnptr<const std::string&> CMD_rename_branch(lsnes_cmds, "rename-branch", "Rename a slot branch",
"Syntax: rename-branch <id> <name>\nRename branch <id> to <name>.\n",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
regex_results r = regex("([0-9]+)[ \t]+(.*)", args);
if(!r) {
messages << "Syntax: rename-branch <id> <name>" << std::endl;
return;
}
try {
auto prj = core.project->get();
uint64_t bid = parse_value<uint64_t>(r[1]);
if(!prj)
throw std::runtime_error("Not in project context");
prj->set_branch_name(bid, r[2]);
messages << "Renamed branch #" << bid << std::endl;
prj->flush();
core.supdater->update();
} catch(std::exception& e) {
messages << "Can't rename branch: " << e.what() << std::endl;
}
});
}
void project_state::do_branch_rm(const std::string& args)
{
regex_results r = regex("([0-9]+)[ \t]*", args);
if(!r) {
messages << "Syntax: delete-branch <id>" << std::endl;
return;
}
try {
auto prj = get();
uint64_t bid = parse_value<uint64_t>(r[1]);
if(!prj)
throw std::runtime_error("Not in project context");
prj->delete_branch(bid);
messages << "Deleted branch #" << bid << std::endl;
prj->flush();
} catch(std::exception& e) {
messages << "Can't delete branch: " << e.what() << std::endl;
}
}
void project_state::do_branch_set(const std::string& args)
{
regex_results r = regex("([0-9]+)[ \t]*", args);
if(!r) {
messages << "Syntax: set-branch <id>" << std::endl;
return;
}
try {
auto prj = get();
uint64_t bid = parse_value<uint64_t>(r[1]);
if(!prj)
throw std::runtime_error("Not in project context");
prj->set_current_branch(bid);
messages << "Set current branch to #" << bid << std::endl;
prj->flush();
supdater.update();
} catch(std::exception& e) {
messages << "Can't set branch: " << e.what() << std::endl;
}
}
void project_state::do_branch_rp(const std::string& args)
{
regex_results r = regex("([0-9]+)[ \t]+([0-9]+)[ \t]*", args);
if(!r) {
messages << "Syntax: reparent-branch <id> <newpid>" << std::endl;
return;
}
try {
auto prj = get();
uint64_t bid = parse_value<uint64_t>(r[1]);
uint64_t pbid = parse_value<uint64_t>(r[2]);
if(!prj)
throw std::runtime_error("Not in project context");
prj->set_parent_branch(bid, pbid);
messages << "Reparented branch #" << bid << std::endl;
prj->flush();
supdater.update();
} catch(std::exception& e) {
messages << "Can't reparent branch: " << e.what() << std::endl;
}
}
void project_state::do_branch_mv(const std::string& args)
{
regex_results r = regex("([0-9]+)[ \t]+(.*)", args);
if(!r) {
messages << "Syntax: rename-branch <id> <name>" << std::endl;
return;
}
try {
auto prj = get();
uint64_t bid = parse_value<uint64_t>(r[1]);
if(!prj)
throw std::runtime_error("Not in project context");
prj->set_branch_name(bid, r[2]);
messages << "Renamed branch #" << bid << std::endl;
prj->flush();
supdater.update();
} catch(std::exception& e) {
messages << "Can't rename branch: " << e.what() << std::endl;
}
}
void project_state::do_branch_ls()
{
std::set<unsigned> dset;
recursive_list_branch(0, dset, 0, false);
}
void project_state::recursive_list_branch(uint64_t bid, std::set<unsigned>& dset, unsigned depth, bool last_of)
{
auto prj = get();
if(!prj) {
messages << "Not in project context." << std::endl;
return;
}
std::set<uint64_t> children = prj->branch_children(bid);
std::string prefix;
for(unsigned i = 0; i + 1 < depth; i++)
prefix += (dset.count(i) ? "\u2502" : " ");
prefix += (dset.count(depth - 1) ? (last_of ? "\u2514" : "\u251c") : " ");
if(last_of) dset.erase(depth - 1);
messages << prefix
<< ((bid == prj->get_current_branch()) ? "*" : "")
<< bid << ":" << prj->get_branch_name(bid) << std::endl;
dset.insert(depth);
size_t c = 0;
for(auto i : children) {
bool last = (++c == children.size());
recursive_list_branch(i, dset, depth + 1, last);
}
dset.erase(depth);
}

29
src/core/reginverse.cpp Normal file
View file

@ -0,0 +1,29 @@
#include "library/keyboard.hpp"
#include "cmdhelp/inverselist.hpp"
#include "core/keymapper.hpp"
namespace
{
class register_command_inverses
{
public:
register_command_inverses()
{
const char** ptr = STUBS::inverse_cmd_list;
while(*ptr) {
ib.insert(new keyboard::invbind_info(lsnes_invbinds, ptr[0], ptr[1]));
ptr += 2;
}
}
~register_command_inverses()
{
for(auto i : ib)
delete i;
ib.clear();
}
private:
std::set<keyboard::invbind_info*> ib;
};
register_command_inverses x;
}

View file

@ -1,3 +1,4 @@
#include "cmdhelp/subtitles.hpp"
#include "core/command.hpp"
#include "core/dispatch.hpp"
#include "core/framebuffer.hpp"
@ -99,74 +100,14 @@ namespace
framebuffer::color fg;
framebuffer::color bg;
};
command::fnptr<const std::string&> CMD_edit_subtitle(lsnes_cmds, "edit-subtitle", "Edit a subtitle",
"Syntax: edit-subtitle <first> <length> <text>\nAdd/Edit subtitle\n"
"Syntax: edit-subtitle <first> <length>\nADelete subtitle\n",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
auto r = regex("([0-9]+)[ \t]+([0-9]+)([ \t]+(.*))?", args, "Bad syntax");
uint64_t frame = parse_value<uint64_t>(r[1]);
uint64_t length = parse_value<uint64_t>(r[2]);
std::string text = r[4];
moviefile_subtiming key(frame, length);
if(text == "")
core.mlogic->get_mfile().subtitles.erase(key);
else
core.mlogic->get_mfile().subtitles[key] =
subtitle_commentary::s_unescape(text);
core.dispatch->subtitle_change();
core.fbuf->redraw_framebuffer();
});
command::fnptr<> CMD_list_subtitle(lsnes_cmds, "list-subtitle", "List the subtitles",
"Syntax: list-subtitle\nList the subtitles.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
for(auto i = core.mlogic->get_mfile().subtitles.rbegin(); i !=
core.mlogic->get_mfile().subtitles.rend();
i++) {
messages << i->first.get_frame() << " " << i->first.get_length() << " "
<< subtitle_commentary::s_escape(i->second) << std::endl;
}
});
command::fnptr<command::arg_filename> CMD_save_s(lsnes_cmds, "save-subtitle", "Save subtitles in .sub format",
"Syntax: save-subtitle <file>\nSaves subtitles in .sub format to <file>\n",
[](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
auto& core = CORE();
if(core.mlogic->get_mfile().subtitles.empty())
return;
auto i = core.mlogic->get_mfile().subtitles.begin();
uint64_t lastframe = i->first.get_frame() + i->first.get_length();
std::ofstream y(std::string(args).c_str());
if(!y)
throw std::runtime_error("Can't open output file");
std::string lasttxt = "";
uint64_t since = 0;
for(uint64_t i = 1; i < lastframe; i++) {
moviefile_subtiming posmarker(i);
auto j = core.mlogic->get_mfile().subtitles.upper_bound(posmarker);
if(j == core.mlogic->get_mfile().subtitles.end())
continue;
if(lasttxt != j->second || !j->first.inrange(i)) {
if(lasttxt != "")
y << "{" << since << "}{" << i - 1 << "}" << s_subescape(lasttxt)
<< std::endl;
since = i;
lasttxt = j->first.inrange(i) ? j->second : "";
}
}
if(lasttxt != "")
y << "{" << since << "}{" << lastframe - 1 << "}" << s_subescape(lasttxt)
<< std::endl;
messages << "Saved subtitles to " << std::string(args) << std::endl;
});
}
subtitle_commentary::subtitle_commentary(movie_logic& _mlogic, emu_framebuffer& _fbuf, emulator_dispatch& _dispatch)
: mlogic(_mlogic), fbuf(_fbuf), edispatch(_dispatch)
subtitle_commentary::subtitle_commentary(movie_logic& _mlogic, emu_framebuffer& _fbuf, emulator_dispatch& _dispatch,
command::group& _cmd)
: mlogic(_mlogic), fbuf(_fbuf), edispatch(_dispatch), cmd(_cmd),
editsub(cmd, STUBS::editsub, [this](const std::string& a) { this->do_editsub(a); }),
listsub(cmd, STUBS::listsub, [this]() { this->do_listsub(); }),
savesub(cmd, STUBS::savesub, [this](command::arg_filename a) { this->do_savesub(a); })
{
}
@ -257,3 +198,59 @@ void subtitle_commentary::set(uint64_t f, uint64_t l, const std::string& x)
edispatch.subtitle_change();
fbuf.redraw_framebuffer();
}
void subtitle_commentary::do_editsub(const std::string& args)
{
auto r = regex("([0-9]+)[ \t]+([0-9]+)([ \t]+(.*))?", args, "Bad syntax");
uint64_t frame = parse_value<uint64_t>(r[1]);
uint64_t length = parse_value<uint64_t>(r[2]);
std::string text = r[4];
moviefile_subtiming key(frame, length);
if(text == "")
mlogic.get_mfile().subtitles.erase(key);
else
mlogic.get_mfile().subtitles[key] =
subtitle_commentary::s_unescape(text);
edispatch.subtitle_change();
fbuf.redraw_framebuffer();
}
void subtitle_commentary::do_listsub()
{
for(auto i = mlogic.get_mfile().subtitles.rbegin(); i !=
mlogic.get_mfile().subtitles.rend();
i++) {
messages << i->first.get_frame() << " " << i->first.get_length() << " "
<< subtitle_commentary::s_escape(i->second) << std::endl;
}
}
void subtitle_commentary::do_savesub(const std::string& args)
{
if(mlogic.get_mfile().subtitles.empty())
return;
auto i = mlogic.get_mfile().subtitles.begin();
uint64_t lastframe = i->first.get_frame() + i->first.get_length();
std::ofstream y(std::string(args).c_str());
if(!y)
throw std::runtime_error("Can't open output file");
std::string lasttxt = "";
uint64_t since = 0;
for(uint64_t i = 1; i < lastframe; i++) {
moviefile_subtiming posmarker(i);
auto j = mlogic.get_mfile().subtitles.upper_bound(posmarker);
if(j == mlogic.get_mfile().subtitles.end())
continue;
if(lasttxt != j->second || !j->first.inrange(i)) {
if(lasttxt != "")
y << "{" << since << "}{" << i - 1 << "}" << s_subescape(lasttxt)
<< std::endl;
since = i;
lasttxt = j->first.inrange(i) ? j->second : "";
}
}
if(lasttxt != "")
y << "{" << since << "}{" << lastframe - 1 << "}" << s_subescape(lasttxt)
<< std::endl;
messages << "Saved subtitles to " << std::string(args) << std::endl;
}

View file

@ -468,13 +468,13 @@ void group::listener::kill(set& s)
}
template<>
void invoke_fn(void (*fn)(const std::string& args), const std::string& args)
void invoke_fn(std::function<void(const std::string& args)> fn, const std::string& args)
{
fn(args);
}
template<>
void invoke_fn(void (*fn)(), const std::string& args)
void invoke_fn(std::function<void()> fn, const std::string& args)
{
if(args != "")
throw std::runtime_error("This command does not take arguments");
@ -482,7 +482,7 @@ void invoke_fn(void (*fn)(), const std::string& args)
}
template<>
void invoke_fn(void (*fn)(struct arg_filename a), const std::string& args)
void invoke_fn(std::function<void(struct arg_filename a)> fn, const std::string& args)
{
if(args == "")
throw std::runtime_error("Filename required");