1 #include "core/dispatch.hpp"
2 #include "core/instance.hpp"
3 #include "core/memorymanip.hpp"
4 #include "core/memorywatch.hpp"
5 #include "core/project.hpp"
6 #include "library/hex.hpp"
7 #include "library/string.hpp"
8 #include "library/memorysearch.hpp"
9 #include "library/int24.hpp"
10 #include "library/zip.hpp"
12 #include "platform/wxwidgets/loadsave.hpp"
13 #include "platform/wxwidgets/platform.hpp"
14 #include "platform/wxwidgets/scrollbar.hpp"
15 #include "platform/wxwidgets/textrender.hpp"
23 #include <wx/control.h>
24 #include <wx/combobox.h>
26 #define wxID_RESET (wxID_HIGHEST + 1)
27 #define wxID_UPDATE (wxID_HIGHEST + 2)
28 #define wxID_TYPESELECT (wxID_HIGHEST + 3)
29 #define wxID_HEX_SELECT (wxID_HIGHEST + 4)
30 #define wxID_ADD (wxID_HIGHEST + 5)
31 #define wxID_SET_REGIONS (wxID_HIGHEST + 6)
32 #define wxID_AUTOUPDATE (wxID_HIGHEST + 7)
33 #define wxID_DISQUALIFY (wxID_HIGHEST + 8)
34 #define wxID_POKE (wxID_HIGHEST + 9)
35 #define wxID_SHOW_HEXEDITOR (wxID_HIGHEST + 10)
36 #define wxID_MENU_SAVE_PREVMEM (wxID_HIGHEST + 11)
37 #define wxID_MENU_SAVE_SET (wxID_HIGHEST + 12)
38 #define wxID_MENU_SAVE_ALL (wxID_HIGHEST + 13)
39 #define wxID_MENU_LOAD (wxID_HIGHEST + 14)
40 #define wxID_MENU_UNDO (wxID_HIGHEST + 15)
41 #define wxID_MENU_REDO (wxID_HIGHEST + 16)
42 #define wxID_MENU_DUMP_CANDIDATES (wxID_HIGHEST + 17)
43 #define wxID_BUTTONS_BASE (wxID_HIGHEST + 128)
46 #define CANDIDATE_LIMIT 512
48 class wxwindow_memorysearch
;
49 memory_search
* wxwindow_memorysearch_active();
53 unsigned UNDOHISTORY_MAXSIZE
= 48;
54 struct _watch_properties
{
56 int type
; //0 => Unsigned, 1 => Signed, 2 => Float.
58 } watch_properties
[] = {
73 wxwindow_memorysearch
* mwatch
;
75 const char* datatypes
[] = {
90 typedef void (wxwindow_memorysearch::*search_fn_t
)();
95 search_fn_t searches
[DATATYPES
];
98 template<typename T
> std::string
format_number_signed(T val
, bool hex
);
99 template<typename T
> std::string
format_number_unsigned(T val
, bool hex
);
101 template<typename T
> std::string
format_number_signedh(T val
, unsigned hwidth
, bool hex
)
103 std::ostringstream x
;
106 x
<< "+" << std::setfill('0') << std::setw(hwidth
) << std::hex
<<
107 static_cast<uint64_t>(val
);
110 uint64_t y
= static_cast<uint64_t>(y2
);
111 x
<< "-" << std::setfill('0') << std::setw(hwidth
) << std::hex
<< (~y
+ 1);
114 x
<< static_cast<int64_t>(val
);
118 template<typename T
> std::string
format_number_unsignedh(T val
, unsigned hwidth
, bool hex
)
120 std::ostringstream x
;
122 x
<< std::setfill('0') << std::setw(hwidth
) << std::hex
<< static_cast<uint64_t>(val
);
124 x
<< static_cast<uint64_t>(val
);
128 template<> std::string format_number_signed
<uint8_t>(uint8_t val
, bool hex
)
130 return format_number_signedh(static_cast<int8_t>(val
), 2, hex
);
133 template<> std::string format_number_signed
<uint16_t>(uint16_t val
, bool hex
)
135 return format_number_signedh(static_cast<int16_t>(val
), 4, hex
);
138 template<> std::string format_number_signed
<ss_uint24_t
>(ss_uint24_t val
, bool hex
)
140 return format_number_signedh((int32_t)(uint32_t)(val
), 6, hex
);
143 template<> std::string format_number_signed
<uint32_t>(uint32_t val
, bool hex
)
145 return format_number_signedh(static_cast<int32_t>(val
), 8, hex
);
148 template<> std::string format_number_signed
<uint64_t>(uint64_t val
, bool hex
)
150 return format_number_signedh(static_cast<int64_t>(val
), 16, hex
);
153 template<> std::string format_number_unsigned
<uint8_t>(uint8_t val
, bool hex
)
155 return format_number_unsignedh(val
, 2, hex
);
158 template<> std::string format_number_unsigned
<uint16_t>(uint16_t val
, bool hex
)
160 return format_number_unsignedh(val
, 4, hex
);
163 template<> std::string format_number_unsigned
<ss_uint24_t
>(ss_uint24_t val
, bool hex
)
165 return format_number_unsignedh(val
, 6, hex
);
168 template<> std::string format_number_unsigned
<uint32_t>(uint32_t val
, bool hex
)
170 return format_number_unsignedh(val
, 8, hex
);
173 template<> std::string format_number_unsigned
<uint64_t>(uint64_t val
, bool hex
)
175 return format_number_unsignedh(val
, 16, hex
);
178 std::string
format_number_float(double val
)
180 return (stringfmt() << val
).str();
184 class wxwindow_memorysearch_vmasel
: public wxDialog
187 wxwindow_memorysearch_vmasel(wxWindow
* p
, const std::set
<std::string
>& enabled
);
188 bool ShouldPreventAppExit() const;
189 std::set
<std::string
> get_vmas();
190 void on_ok(wxCommandEvent
& e
);
191 void on_cancel(wxCommandEvent
& e
);
193 std::set
<std::string
> vmas
;
194 std::vector
<wxCheckBox
*> checkboxes
;
199 wxwindow_memorysearch_vmasel::wxwindow_memorysearch_vmasel(wxWindow
* p
, const std::set
<std::string
>& enabled
)
200 : wxDialog(p
, wxID_ANY
, towxstring("lsnes: Select enabled regions"), wxDefaultPosition
, wxSize(300, -1))
202 auto i
= lsnes_instance
.memory
.get_regions();
204 wxFlexGridSizer
* top_s
= new wxFlexGridSizer(i
.size() + 1, 1, 0, 0);
207 if(j
->readonly
|| j
->special
)
210 top_s
->Add(t
= new wxCheckBox(this, wxID_ANY
, towxstring(j
->name
)), 0, wxGROW
);
211 if(enabled
.count(j
->name
))
213 checkboxes
.push_back(t
);
215 wxBoxSizer
* pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
216 pbutton_s
->AddStretchSpacer();
217 pbutton_s
->Add(ok
= new wxButton(this, wxID_ANY
, wxT("Ok")), 0, wxGROW
);
218 pbutton_s
->Add(cancel
= new wxButton(this, wxID_ANY
, wxT("Cancel")), 0, wxGROW
);
219 ok
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
220 wxCommandEventHandler(wxwindow_memorysearch_vmasel::on_ok
), NULL
, this);
221 cancel
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
222 wxCommandEventHandler(wxwindow_memorysearch_vmasel::on_cancel
), NULL
, this);
223 top_s
->Add(pbutton_s
);
225 pbutton_s
->SetSizeHints(this);
226 top_s
->SetSizeHints(this);
230 bool wxwindow_memorysearch_vmasel::ShouldPreventAppExit() const
235 std::set
<std::string
> wxwindow_memorysearch_vmasel::get_vmas()
240 void wxwindow_memorysearch_vmasel::on_ok(wxCommandEvent
& e
)
242 for(auto i
: checkboxes
)
244 vmas
.insert(tostdstring(i
->GetLabel()));
248 void wxwindow_memorysearch_vmasel::on_cancel(wxCommandEvent
& e
)
250 EndModal(wxID_CANCEL
);
254 class wxwindow_memorysearch
: public wxFrame
257 class panel
: public text_framebuffer_panel
260 panel(wxwindow_memorysearch
* parent
);
261 void set_selection(uint64_t first
, uint64_t last
);
262 void get_selection(uint64_t& first
, uint64_t& last
);
264 void prepare_paint();
266 wxwindow_memorysearch
* parent
;
270 wxwindow_memorysearch();
271 ~wxwindow_memorysearch();
272 bool ShouldPreventAppExit() const;
273 void on_close(wxCloseEvent
& e
);
274 void on_button_click(wxCommandEvent
& e
);
276 void on_mousedrag(wxMouseEvent
& e
);
277 void on_mouse(wxMouseEvent
& e
);
279 template<void(memory_search::*sfn
)()> void search_0();
280 template<typename T
, typename T2
, void(memory_search::*sfn
)(T2 val
)> void search_1();
281 template<typename T
> void _do_poke_addr(uint64_t addr
);
282 template<typename T
> std::string
_do_format_signed(uint64_t addr
, bool hex
, bool old
)
285 return format_number_signed
<T
>(msearch
->v_readold
<T
>(addr
), hex
);
287 return format_number_signed
<T
>(lsnes_instance
.memory
.read
<T
>(addr
), hex
);
289 template<typename T
> std::string
_do_format_unsigned(uint64_t addr
, bool hex
, bool old
)
292 return format_number_unsigned
<T
>(msearch
->v_readold
<T
>(addr
), hex
);
294 return format_number_unsigned
<T
>(lsnes_instance
.memory
.read
<T
>(addr
), hex
);
296 template<typename T
> std::string
_do_format_float(uint64_t addr
, bool hex
, bool old
)
299 return format_number_float(msearch
->v_readold
<T
>(addr
));
301 return format_number_float(lsnes_instance
.memory
.read
<T
>(addr
));
303 void dump_candidates_text();
305 friend memory_search
* wxwindow_memorysearch_active();
307 template<typename T
> T
promptvalue(bool& bad
);
309 memory_search
* msearch
;
310 void on_mouse0(wxMouseEvent
& e
, bool polarity
);
312 void on_mouse2(wxMouseEvent
& e
);
313 void handle_undo_redo(bool redo
);
315 void handle_save(memory_search::savestate_type type
);
317 std::string
format_address(uint64_t addr
);
322 wxCheckBox
* hexmode2
;
323 wxCheckBox
* autoupdate
;
324 std::map
<uint64_t, uint64_t> addresses
;
326 uint64_t drag_startline
;
333 std::set
<std::string
> vmas_enabled
;
334 std::map
<std::string
, std::pair
<uint64_t, uint64_t>> vma_info
;
335 wxMenuItem
* undoitem
;
336 wxMenuItem
* redoitem
;
337 std::list
<std::vector
<char>> undohistory
;
338 std::list
<std::vector
<char>> redohistory
;
341 std::string
wxwindow_memorysearch::format_address(uint64_t addr
)
343 for(auto i
: vma_info
) {
344 if(i
.second
.first
<= addr
&& i
.second
.first
+ i
.second
.second
> addr
) {
347 uint64_t t
= i
.second
.second
;
348 while(t
> 0x10) { hcount
++; t
>>= 4; }
349 return (stringfmt() << i
.first
<< "+" << std::hex
<< std::setw(hcount
) << std::setfill('0')
350 << (addr
- i
.second
.first
)).str();
354 return hex::to(addr
);
359 typedef void (wxwindow_memorysearch::*pokefn_t
)(uint64_t);
361 &wxwindow_memorysearch::_do_poke_addr
<int8_t>,
362 &wxwindow_memorysearch::_do_poke_addr
<uint8_t>,
363 &wxwindow_memorysearch::_do_poke_addr
<int16_t>,
364 &wxwindow_memorysearch::_do_poke_addr
<uint16_t>,
365 &wxwindow_memorysearch::_do_poke_addr
<ss_int24_t
>,
366 &wxwindow_memorysearch::_do_poke_addr
<ss_uint24_t
>,
367 &wxwindow_memorysearch::_do_poke_addr
<int32_t>,
368 &wxwindow_memorysearch::_do_poke_addr
<uint32_t>,
369 &wxwindow_memorysearch::_do_poke_addr
<int64_t>,
370 &wxwindow_memorysearch::_do_poke_addr
<uint64_t>,
371 &wxwindow_memorysearch::_do_poke_addr
<float>,
372 &wxwindow_memorysearch::_do_poke_addr
<double>,
375 typedef std::string (wxwindow_memorysearch::*displayfn_t
)(uint64_t, bool hexmode
, bool old
);
376 displayfn_t displays
[] = {
377 &wxwindow_memorysearch::_do_format_signed
<uint8_t>,
378 &wxwindow_memorysearch::_do_format_unsigned
<uint8_t>,
379 &wxwindow_memorysearch::_do_format_signed
<uint16_t>,
380 &wxwindow_memorysearch::_do_format_unsigned
<uint16_t>,
381 &wxwindow_memorysearch::_do_format_signed
<ss_uint24_t
>,
382 &wxwindow_memorysearch::_do_format_unsigned
<ss_uint24_t
>,
383 &wxwindow_memorysearch::_do_format_signed
<uint32_t>,
384 &wxwindow_memorysearch::_do_format_unsigned
<uint32_t>,
385 &wxwindow_memorysearch::_do_format_signed
<uint64_t>,
386 &wxwindow_memorysearch::_do_format_unsigned
<uint64_t>,
387 &wxwindow_memorysearch::_do_format_float
<float>,
388 &wxwindow_memorysearch::_do_format_float
<double>,
391 struct searchtype searchtbl
[] = {
394 &wxwindow_memorysearch::search_1
<int8_t, uint8_t,
395 &memory_search::s_value
<uint8_t>>,
396 &wxwindow_memorysearch::search_1
<uint8_t, uint8_t,
397 &memory_search::s_value
<uint8_t>>,
398 &wxwindow_memorysearch::search_1
<int16_t, uint16_t,
399 &memory_search::s_value
<uint16_t>>,
400 &wxwindow_memorysearch::search_1
<uint16_t, uint16_t,
401 &memory_search::s_value
<uint16_t>>,
402 &wxwindow_memorysearch::search_1
<ss_int24_t
, ss_uint24_t
,
403 &memory_search::s_value
<ss_uint24_t
>>,
404 &wxwindow_memorysearch::search_1
<ss_uint24_t
, ss_uint24_t
,
405 &memory_search::s_value
<ss_uint24_t
>>,
406 &wxwindow_memorysearch::search_1
<int32_t, uint32_t,
407 &memory_search::s_value
<uint32_t>>,
408 &wxwindow_memorysearch::search_1
<uint32_t, uint32_t,
409 &memory_search::s_value
<uint32_t>>,
410 &wxwindow_memorysearch::search_1
<int64_t, uint64_t,
411 &memory_search::s_value
<uint64_t>>,
412 &wxwindow_memorysearch::search_1
<uint64_t, uint64_t,
413 &memory_search::s_value
<uint64_t>>,
414 &wxwindow_memorysearch::search_1
<float, float,
415 &memory_search::s_value
<float>>,
416 &wxwindow_memorysearch::search_1
<double, double,
417 &memory_search::s_value
<double>>
421 &wxwindow_memorysearch::search_1
<int8_t, uint8_t,
422 &memory_search::s_difference
<uint8_t>>,
423 &wxwindow_memorysearch::search_1
<uint8_t, uint8_t,
424 &memory_search::s_difference
<uint8_t>>,
425 &wxwindow_memorysearch::search_1
<int16_t, uint16_t,
426 &memory_search::s_difference
<uint16_t>>,
427 &wxwindow_memorysearch::search_1
<uint16_t, uint16_t,
428 &memory_search::s_difference
<uint16_t>>,
429 &wxwindow_memorysearch::search_1
<ss_int24_t
, ss_uint24_t
,
430 &memory_search::s_difference
<ss_uint24_t
>>,
431 &wxwindow_memorysearch::search_1
<ss_uint24_t
, ss_uint24_t
,
432 &memory_search::s_difference
<ss_uint24_t
>>,
433 &wxwindow_memorysearch::search_1
<int32_t, uint32_t,
434 &memory_search::s_difference
<uint32_t>>,
435 &wxwindow_memorysearch::search_1
<uint32_t, uint32_t,
436 &memory_search::s_difference
<uint32_t>>,
437 &wxwindow_memorysearch::search_1
<int64_t, uint64_t,
438 &memory_search::s_difference
<uint64_t>>,
439 &wxwindow_memorysearch::search_1
<uint64_t, uint64_t,
440 &memory_search::s_difference
<uint64_t>>,
441 &wxwindow_memorysearch::search_1
<float, float,
442 &memory_search::s_difference
<float>>,
443 &wxwindow_memorysearch::search_1
<double, double,
444 &memory_search::s_difference
<double>>
448 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<int8_t>>,
449 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<uint8_t>>,
450 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<int16_t>>,
451 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<uint16_t>>,
452 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<ss_int24_t
>>,
453 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<ss_uint24_t
>>,
454 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<int32_t>>,
455 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<uint32_t>>,
456 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<int64_t>>,
457 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<uint64_t>>,
458 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<float>>,
459 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<double>>
463 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<int8_t>>,
464 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<uint8_t>>,
465 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<int16_t>>,
466 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<uint16_t>>,
467 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<ss_int24_t
>>,
468 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<ss_uint24_t
>>,
469 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<int32_t>>,
470 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<uint32_t>>,
471 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<int64_t>>,
472 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<uint64_t>>,
473 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<float>>,
474 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<double>>
478 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<int8_t>>,
479 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<uint8_t>>,
480 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<int16_t>>,
481 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<uint16_t>>,
482 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<ss_int24_t
>>,
483 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<ss_uint24_t
>>,
484 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<int32_t>>,
485 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<uint32_t>>,
486 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<int64_t>>,
487 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<uint64_t>>,
488 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<float>>,
489 &wxwindow_memorysearch::search_0
<&memory_search::s_eq
<double>>
493 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<int8_t>>,
494 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<uint8_t>>,
495 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<int16_t>>,
496 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<uint16_t>>,
497 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<ss_int24_t
>>,
498 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<ss_uint24_t
>>,
499 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<int32_t>>,
500 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<uint32_t>>,
501 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<int64_t>>,
502 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<uint64_t>>,
503 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<float>>,
504 &wxwindow_memorysearch::search_0
<&memory_search::s_ne
<double>>
508 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<int8_t>>,
509 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<uint8_t>>,
510 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<int16_t>>,
511 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<uint16_t>>,
512 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<ss_int24_t
>>,
513 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<ss_uint24_t
>>,
514 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<int32_t>>,
515 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<uint32_t>>,
516 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<int64_t>>,
517 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<uint64_t>>,
518 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<float>>,
519 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<double>>
523 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<int8_t>>,
524 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<uint8_t>>,
525 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<int16_t>>,
526 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<uint16_t>>,
527 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<ss_int24_t
>>,
528 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<ss_uint24_t
>>,
529 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<int32_t>>,
530 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<uint32_t>>,
531 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<int64_t>>,
532 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<uint64_t>>,
533 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<float>>,
534 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<double>>
538 &wxwindow_memorysearch::search_0
<&memory_search::s_seqlt
<uint8_t>>,
539 &wxwindow_memorysearch::search_0
<&memory_search::s_seqlt
<uint8_t>>,
540 &wxwindow_memorysearch::search_0
<&memory_search::s_seqlt
<uint16_t>>,
541 &wxwindow_memorysearch::search_0
<&memory_search::s_seqlt
<uint16_t>>,
542 &wxwindow_memorysearch::search_0
<&memory_search::s_seqlt
<ss_int24_t
>>,
543 &wxwindow_memorysearch::search_0
<&memory_search::s_seqlt
<ss_uint24_t
>>,
544 &wxwindow_memorysearch::search_0
<&memory_search::s_seqlt
<uint32_t>>,
545 &wxwindow_memorysearch::search_0
<&memory_search::s_seqlt
<uint32_t>>,
546 &wxwindow_memorysearch::search_0
<&memory_search::s_seqlt
<uint64_t>>,
547 &wxwindow_memorysearch::search_0
<&memory_search::s_seqlt
<uint64_t>>,
548 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<float>>,
549 &wxwindow_memorysearch::search_0
<&memory_search::s_lt
<double>>
553 &wxwindow_memorysearch::search_0
<&memory_search::s_seqle
<uint8_t>>,
554 &wxwindow_memorysearch::search_0
<&memory_search::s_seqle
<uint8_t>>,
555 &wxwindow_memorysearch::search_0
<&memory_search::s_seqle
<uint16_t>>,
556 &wxwindow_memorysearch::search_0
<&memory_search::s_seqle
<uint16_t>>,
557 &wxwindow_memorysearch::search_0
<&memory_search::s_seqle
<ss_int24_t
>>,
558 &wxwindow_memorysearch::search_0
<&memory_search::s_seqle
<ss_uint24_t
>>,
559 &wxwindow_memorysearch::search_0
<&memory_search::s_seqle
<uint32_t>>,
560 &wxwindow_memorysearch::search_0
<&memory_search::s_seqle
<uint32_t>>,
561 &wxwindow_memorysearch::search_0
<&memory_search::s_seqle
<uint64_t>>,
562 &wxwindow_memorysearch::search_0
<&memory_search::s_seqle
<uint64_t>>,
563 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<float>>,
564 &wxwindow_memorysearch::search_0
<&memory_search::s_le
<double>>
568 &wxwindow_memorysearch::search_0
<&memory_search::s_seqge
<uint8_t>>,
569 &wxwindow_memorysearch::search_0
<&memory_search::s_seqge
<uint8_t>>,
570 &wxwindow_memorysearch::search_0
<&memory_search::s_seqge
<uint16_t>>,
571 &wxwindow_memorysearch::search_0
<&memory_search::s_seqge
<uint16_t>>,
572 &wxwindow_memorysearch::search_0
<&memory_search::s_seqge
<ss_int24_t
>>,
573 &wxwindow_memorysearch::search_0
<&memory_search::s_seqge
<ss_uint24_t
>>,
574 &wxwindow_memorysearch::search_0
<&memory_search::s_seqge
<uint32_t>>,
575 &wxwindow_memorysearch::search_0
<&memory_search::s_seqge
<uint32_t>>,
576 &wxwindow_memorysearch::search_0
<&memory_search::s_seqge
<uint64_t>>,
577 &wxwindow_memorysearch::search_0
<&memory_search::s_seqge
<uint64_t>>,
578 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<float>>,
579 &wxwindow_memorysearch::search_0
<&memory_search::s_ge
<double>>
583 &wxwindow_memorysearch::search_0
<&memory_search::s_seqgt
<uint8_t>>,
584 &wxwindow_memorysearch::search_0
<&memory_search::s_seqgt
<uint8_t>>,
585 &wxwindow_memorysearch::search_0
<&memory_search::s_seqgt
<uint16_t>>,
586 &wxwindow_memorysearch::search_0
<&memory_search::s_seqgt
<uint16_t>>,
587 &wxwindow_memorysearch::search_0
<&memory_search::s_seqgt
<ss_int24_t
>>,
588 &wxwindow_memorysearch::search_0
<&memory_search::s_seqgt
<ss_uint24_t
>>,
589 &wxwindow_memorysearch::search_0
<&memory_search::s_seqgt
<uint32_t>>,
590 &wxwindow_memorysearch::search_0
<&memory_search::s_seqgt
<uint32_t>>,
591 &wxwindow_memorysearch::search_0
<&memory_search::s_seqgt
<uint64_t>>,
592 &wxwindow_memorysearch::search_0
<&memory_search::s_seqgt
<uint64_t>>,
593 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<float>>,
594 &wxwindow_memorysearch::search_0
<&memory_search::s_gt
<double>>
598 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
599 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
600 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
601 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
602 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
603 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
604 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
605 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
606 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
607 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
608 &wxwindow_memorysearch::search_0
<&memory_search::update
>,
609 &wxwindow_memorysearch::search_0
<&memory_search::update
>
615 wxwindow_memorysearch::wxwindow_memorysearch()
616 : wxFrame(NULL
, wxID_ANY
, wxT("lsnes: Memory Search"), wxDefaultPosition
, wxSize(-1, -1),
617 wxMINIMIZE_BOX
| wxSYSTEM_MENU
| wxCAPTION
| wxCLIP_CHILDREN
| wxCLOSE_BOX
)
622 Connect(wxEVT_CLOSE_WINDOW
, wxCloseEventHandler(wxwindow_memorysearch::on_close
));
623 msearch
= new memory_search(lsnes_instance
.memory
);
625 wxFlexGridSizer
* toplevel
= new wxFlexGridSizer(4, 1, 0, 0);
628 wxBoxSizer
* buttons
= new wxBoxSizer(wxHORIZONTAL
);
629 buttons
->Add(tmp
= new wxButton(this, wxID_RESET
, wxT("Reset")), 0, wxGROW
);
630 tmp
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
, wxCommandEventHandler(wxwindow_memorysearch::on_button_click
),
632 buttons
->Add(new wxStaticText(this, wxID_ANY
, wxT("Data type:")), 0, wxGROW
);
633 wxString _datatypes
[DATATYPES
];
634 for(size_t i
= 0; i
< DATATYPES
; i
++)
635 _datatypes
[i
] = towxstring(datatypes
[i
]);
636 buttons
->Add(type
= new wxComboBox(this, wxID_TYPESELECT
, _datatypes
[typecode
], wxDefaultPosition
,
637 wxDefaultSize
, DATATYPES
, _datatypes
, wxCB_READONLY
), 0,
639 type
->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED
,
640 wxCommandEventHandler(wxwindow_memorysearch::on_button_click
), NULL
, this);
641 buttons
->Add(hexmode2
= new wxCheckBox(this, wxID_HEX_SELECT
, wxT("Hex display")), 0, wxGROW
);
642 buttons
->Add(autoupdate
= new wxCheckBox(this, wxID_AUTOUPDATE
, wxT("Update automatically")), 0, wxGROW
);
643 autoupdate
->SetValue(true);
644 hexmode2
->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED
,
645 wxCommandEventHandler(wxwindow_memorysearch::on_button_click
), NULL
, this);
646 toplevel
->Add(buttons
);
648 wxFlexGridSizer
* searches
= new wxFlexGridSizer(0, 6, 0, 0);
649 for(unsigned j
= 0; j
< sizeof(searchtbl
)/sizeof(searchtbl
[0]); j
++) {
650 std::string name
= searchtbl
[j
].name
;
651 searches
->Add(tmp
= new wxButton(this, wxID_BUTTONS_BASE
+ j
, towxstring(name
)), 1, wxGROW
);
652 tmp
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
653 wxCommandEventHandler(wxwindow_memorysearch::on_button_click
), NULL
, this);
655 toplevel
->Add(searches
);
657 toplevel
->Add(count
= new wxStaticText(this, wxID_ANY
, wxT("XXXXXX candidates")), 0, wxGROW
);
658 wxBoxSizer
* matchesb
= new wxBoxSizer(wxHORIZONTAL
);
659 matchesb
->Add(matches
= new panel(this), 1, wxGROW
);
660 matchesb
->Add(scroll
= new scroll_bar(this, wxID_ANY
, true), 0, wxGROW
);
661 toplevel
->Add(matchesb
, 1, wxGROW
);
663 scroll
->set_page_size(matches
->get_characters().second
);
665 for(auto i
: lsnes_instance
.memory
.get_regions()) {
666 if(memory_search::searchable_region(i
))
667 vmas_enabled
.insert(i
->name
);
668 vma_info
[i
->name
] = std::make_pair(i
->base
, i
->size
);
671 wxMenuBar
* menubar
= new wxMenuBar();
673 wxMenu
* filemenu
= new wxMenu();
674 filemenu
->Append(wxID_MENU_DUMP_CANDIDATES
, wxT("Dump candidates..."));
675 filemenu
->AppendSeparator();
676 filemenu
->Append(wxID_MENU_SAVE_PREVMEM
, wxT("Save previous memory..."));
677 filemenu
->Append(wxID_MENU_SAVE_SET
, wxT("Save set of addresses..."));
678 filemenu
->Append(wxID_MENU_SAVE_ALL
, wxT("Save previous memory and set of addresses..."));
679 filemenu
->AppendSeparator();
680 filemenu
->Append(wxID_MENU_LOAD
, wxT("Load save..."));
681 menubar
->Append(filemenu
, wxT("File"));
682 wxMenu
* editmenu
= new wxMenu();
683 undoitem
= editmenu
->Append(wxID_UNDO
, wxT("Undo"));
684 redoitem
= editmenu
->Append(wxID_REDO
, wxT("Redo"));
685 undoitem
->Enable(false);
686 redoitem
->Enable(false);
687 menubar
->Append(editmenu
, wxT("Edit"));
688 Connect(wxID_MENU_DUMP_CANDIDATES
, wxEVT_COMMAND_MENU_SELECTED
,
689 wxCommandEventHandler(wxwindow_memorysearch::on_button_click
));
690 Connect(wxID_MENU_SAVE_PREVMEM
, wxEVT_COMMAND_MENU_SELECTED
,
691 wxCommandEventHandler(wxwindow_memorysearch::on_button_click
));
692 Connect(wxID_MENU_SAVE_SET
, wxEVT_COMMAND_MENU_SELECTED
,
693 wxCommandEventHandler(wxwindow_memorysearch::on_button_click
));
694 Connect(wxID_MENU_SAVE_ALL
, wxEVT_COMMAND_MENU_SELECTED
,
695 wxCommandEventHandler(wxwindow_memorysearch::on_button_click
));
696 Connect(wxID_MENU_LOAD
, wxEVT_COMMAND_MENU_SELECTED
,
697 wxCommandEventHandler(wxwindow_memorysearch::on_button_click
));
698 Connect(wxID_UNDO
, wxEVT_COMMAND_MENU_SELECTED
,
699 wxCommandEventHandler(wxwindow_memorysearch::on_button_click
));
700 Connect(wxID_REDO
, wxEVT_COMMAND_MENU_SELECTED
,
701 wxCommandEventHandler(wxwindow_memorysearch::on_button_click
));
705 matches
->Connect(wxEVT_LEFT_DOWN
, wxMouseEventHandler(wxwindow_memorysearch::on_mouse
), NULL
, this);
706 matches
->Connect(wxEVT_LEFT_UP
, wxMouseEventHandler(wxwindow_memorysearch::on_mouse
), NULL
, this);
707 matches
->Connect(wxEVT_MIDDLE_DOWN
, wxMouseEventHandler(wxwindow_memorysearch::on_mouse
), NULL
, this);
708 matches
->Connect(wxEVT_MIDDLE_UP
, wxMouseEventHandler(wxwindow_memorysearch::on_mouse
), NULL
, this);
709 matches
->Connect(wxEVT_RIGHT_DOWN
, wxMouseEventHandler(wxwindow_memorysearch::on_mouse
), NULL
, this);
710 matches
->Connect(wxEVT_RIGHT_UP
, wxMouseEventHandler(wxwindow_memorysearch::on_mouse
), NULL
, this);
711 matches
->Connect(wxEVT_MOTION
, wxMouseEventHandler(wxwindow_memorysearch::on_mousedrag
), NULL
, this);
712 matches
->Connect(wxEVT_MOUSEWHEEL
, wxMouseEventHandler(wxwindow_memorysearch::on_mouse
), NULL
, this);
713 scroll
->set_handler([this](scroll_bar
& s
) { this->matches
->request_paint(); });
715 toplevel
->SetSizeHints(this);
722 wxwindow_memorysearch::panel::panel(wxwindow_memorysearch
* _parent
)
723 : text_framebuffer_panel(_parent
, 40, 25, wxID_ANY
, NULL
)
730 void wxwindow_memorysearch::panel::prepare_paint()
732 uint64_t first
= parent
->scroll
->get_position();
733 auto ssize
= get_characters();
734 uint64_t last
= first
+ ssize
.second
;
735 std::vector
<std::string
> lines
;
736 lines
.reserve(ssize
.second
);
737 std::map
<uint64_t, uint64_t> addrs
;
738 auto* ms
= parent
->msearch
;
740 bool toomany
= false;
741 auto _parent
= parent
;
742 lsnes_instance
.iqueue
.run([&toomany
, &first
, &last
, ms
, &lines
, &addrs
, &addr_count
, _parent
]() {
743 addr_count
= ms
->get_candidate_count();
744 if(last
> addr_count
) {
745 uint64_t delta
= last
- addr_count
;
754 if(addr_count
<= CANDIDATE_LIMIT
) {
755 std::list
<uint64_t> addrs2
= ms
->get_candidates();
757 for(auto i
: addrs2
) {
758 std::string row
= _parent
->format_address(i
) + " ";
759 row
+= (_parent
->*displays
[_parent
->typecode
])(i
, _parent
->hexmode
, false);
761 row
+= (_parent
->*displays
[_parent
->typecode
])(i
, _parent
->hexmode
, true);
763 if(j
>= first
&& j
< last
)
764 lines
.push_back(row
);
768 lines
.push_back("Too many candidates to display");
772 std::swap(parent
->addresses
, addrs
);
774 std::ostringstream x
;
775 x
<< addr_count
<< " " << ((addr_count
!= 1) ? "candidates" : "candidate");
776 parent
->count
->SetLabel(towxstring(x
.str()));
779 for(unsigned i
= 0; i
< lines
.size(); i
++) {
780 bool sel
= (first
+ i
) >= first_sel
&& (first
+ i
) < last_sel
;
781 write(lines
[i
], 0, 0, i
, sel
? 0xFFFFFF : 0, sel
? 0 : 0xFFFFFF);
789 parent
->toomany
= toomany
;
790 parent
->scroll
->set_range(toomany
? 0 : addr_count
);
793 void wxwindow_memorysearch::panel::set_selection(uint64_t first
, uint64_t last
)
800 void wxwindow_memorysearch::panel::get_selection(uint64_t& first
, uint64_t& last
)
806 wxwindow_memorysearch::~wxwindow_memorysearch()
812 bool wxwindow_memorysearch::ShouldPreventAppExit() const
817 void wxwindow_memorysearch::dump_candidates_text()
820 std::string filename
= choose_file_save(this, "Dump memory search",
821 lsnes_instance
.project
.otherpath(), filetype_textfile
);
822 std::ofstream
out(filename
);
824 lsnes_instance
.iqueue
.run([ms
, this, &out
]() {
825 std::list
<uint64_t> addrs2
= ms
->get_candidates();
826 for(auto i
: addrs2
) {
827 std::string row
= format_address(i
) + " ";
828 row
+= (this->*displays
[this->typecode
])(i
, this->hexmode
, false);
830 row
+= (this->*displays
[this->typecode
])(i
, this->hexmode
, true);
832 out
<< row
<< std::endl
;
836 throw std::runtime_error("Can't write save file");
837 } catch(canceled_exception
& e
) {
838 } catch(std::exception
& e
) {
839 show_message_ok(this, "Save error", std::string(e
.what()), wxICON_WARNING
);
844 void wxwindow_memorysearch::handle_save(memory_search::savestate_type type
)
847 std::vector
<char> state
;
848 msearch
->savestate(state
, type
);
849 std::string filename
= choose_file_save(this, "Save memory search",
850 lsnes_instance
.project
.otherpath(), filetype_memorysearch
);
851 std::ofstream
out(filename
, std::ios::binary
);
852 out
.write(&state
[0], state
.size());
854 throw std::runtime_error("Can't write save file");
855 } catch(canceled_exception
& e
) {
856 } catch(std::exception
& e
) {
857 show_message_ok(this, "Save error", std::string(e
.what()), wxICON_WARNING
);
862 void wxwindow_memorysearch::handle_load()
865 std::string filename
= choose_file_load(this, "Load memory search",
866 lsnes_instance
.project
.otherpath(), filetype_memorysearch
);
867 std::vector
<char> state
= zip::readrel(filename
, "");
869 msearch
->loadstate(state
);
871 } catch(canceled_exception
& e
) {
872 } catch(std::exception
& e
) {
873 show_message_ok(this, "Load error", std::string(e
.what()), wxICON_WARNING
);
878 void wxwindow_memorysearch::handle_undo_redo(bool redo
)
880 std::list
<std::vector
<char>>& a
= *(redo
? &redohistory
: &undohistory
);
881 std::list
<std::vector
<char>>& b
= *(redo
? &undohistory
: &redohistory
);
883 show_message_ok(this, "Undo/Redo error", "Can't find state to undo/redo to", wxICON_WARNING
);
888 std::vector
<char> state
;
889 msearch
->savestate(state
, memory_search::ST_SET
);
892 msearch
->loadstate(a
.back());
894 } catch(std::exception
& e
) {
897 show_message_ok(this, "Undo/Redo error", std::string(e
.what()), wxICON_WARNING
);
900 undoitem
->Enable(undohistory
.size());
901 redoitem
->Enable(redohistory
.size());
905 void wxwindow_memorysearch::push_undo()
908 std::vector
<char> state
;
909 msearch
->savestate(state
, memory_search::ST_SET
);
910 undohistory
.push_back(state
);
911 if(undohistory
.size() > UNDOHISTORY_MAXSIZE
)
912 undohistory
.pop_front();
914 undoitem
->Enable(undohistory
.size());
915 redoitem
->Enable(redohistory
.size());
920 void wxwindow_memorysearch::on_mouse(wxMouseEvent
& e
)
922 if(e
.RightUp() || (e
.LeftUp() && e
.ControlDown()))
924 else if(e
.LeftDown())
931 if(e
.ShiftDown() && e
.ControlDown())
933 scroll
->apply_wheel(e
.GetWheelRotation(), e
.GetWheelDelta(), speed
);
936 void wxwindow_memorysearch::on_mouse0(wxMouseEvent
& e
, bool polarity
)
938 dragging
= polarity
&& !toomany
;
942 uint64_t first
= scroll
->get_position();
943 drag_startline
= first
+ e
.GetY() / matches
->get_cell().second
;
944 } else if(mpx
== e
.GetX() && mpy
== e
.GetY()) {
945 matches
->set_selection(0, 0);
949 void wxwindow_memorysearch::on_mousedrag(wxMouseEvent
& e
)
953 uint64_t first
= scroll
->get_position();
954 uint64_t linenow
= first
+ e
.GetY() / matches
->get_cell().second
;
955 if(drag_startline
< linenow
)
956 matches
->set_selection(drag_startline
, linenow
+ 1);
958 matches
->set_selection(linenow
, drag_startline
+ 1);
961 void wxwindow_memorysearch::on_mouse2(wxMouseEvent
& e
)
965 uint64_t selcount
= 0;
967 matches
->get_selection(start
, end
);
968 some_selected
= (start
< end
);
970 uint64_t first
= scroll
->get_position();
971 act_line
= first
+ e
.GetY() / matches
->get_cell().second
;
972 if(addresses
.count(act_line
)) {
973 some_selected
= true;
977 menu
.Append(wxID_ADD
, wxT("Add watch..."))->Enable(some_selected
);
978 menu
.Append(wxID_SHOW_HEXEDITOR
, wxT("Select in hex editor"))->Enable(selcount
== 1 &&
979 wxeditor_hexeditor_available());
980 menu
.Append(wxID_POKE
, wxT("Poke..."))->Enable(selcount
== 1);
981 menu
.AppendSeparator();
982 menu
.Append(wxID_DISQUALIFY
, wxT("Disqualify"))->Enable(some_selected
);
983 menu
.AppendSeparator();
984 menu
.Append(wxID_UPDATE
, wxT("Update"));
985 menu
.Append(wxID_SET_REGIONS
, wxT("Enabled VMAs"));
986 menu
.Connect(wxEVT_COMMAND_MENU_SELECTED
, wxCommandEventHandler(wxwindow_memorysearch::on_button_click
),
991 void wxwindow_memorysearch::on_close(wxCloseEvent
& e
)
997 void wxwindow_memorysearch::auto_update()
999 if(autoupdate
->GetValue())
1003 void wxwindow_memorysearch::update()
1005 matches
->request_paint();
1008 void wxwindow_memorysearch::on_button_click(wxCommandEvent
& e
)
1011 if(id
== wxID_RESET
) {
1014 //Update all VMA info too.
1015 for(auto i
: lsnes_instance
.memory
.get_regions()) {
1016 if(memory_search::searchable_region(i
) && !vmas_enabled
.count(i
->name
))
1017 msearch
->dq_range(i
->base
, i
->last_address());
1018 vma_info
[i
->name
] = std::make_pair(i
->base
, i
->size
);
1020 wxeditor_hexeditor_update();
1021 } else if(id
== wxID_UPDATE
) {
1023 } else if(id
== wxID_TYPESELECT
) {
1024 wxString c
= type
->GetValue();
1025 for(unsigned i
= 0; i
< DATATYPES
; i
++)
1026 if(c
== towxstring(datatypes
[i
]))
1028 } else if(id
== wxID_HEX_SELECT
) {
1029 hexmode
= hexmode2
->GetValue();
1030 } else if(id
== wxID_ADD
) {
1031 uint64_t start
, end
;
1032 matches
->get_selection(start
, end
);
1037 for(uint64_t r
= start
; r
< end
; r
++) {
1038 if(!addresses
.count(r
))
1040 uint64_t addr
= addresses
[r
];
1042 std::string n
= pick_text(this, "Name for watch", (stringfmt()
1043 << "Enter name for watch at 0x" << std::hex
<< addr
<< ":").str());
1046 memwatch_item
e(lsnes_instance
.memory
);
1047 e
.expr
= (stringfmt() << addr
).str();
1048 bool is_hex
= hexmode2
->GetValue();
1049 e
.bytes
= watch_properties
[typecode
].len
;
1050 e
.signed_flag
= !is_hex
&& (watch_properties
[typecode
].type
== 1);
1051 e
.float_flag
= (watch_properties
[typecode
].type
== 2);
1052 if(e
.float_flag
) is_hex
= false;
1053 e
.format
= is_hex
? watch_properties
[typecode
].hformat
: "";
1054 auto i
= lsnes_instance
.memory
.get_regions();
1057 if(addr
>= j
->base
&& addr
< j
->base
+ j
->size
)
1058 endianess
= j
->endian
;
1060 e
.endianess
= endianess
;
1061 lsnes_instance
.iqueue
.run([n
, &e
]() { lsnes_instance
.mwatch
.set(n
, e
); });
1062 } catch(canceled_exception
& e
) {
1065 matches
->set_selection(0, 0);
1066 } else if(id
== wxID_DISQUALIFY
) {
1067 uint64_t start
, end
;
1068 matches
->get_selection(start
, end
);
1074 for(uint64_t r
= start
; r
< end
; r
++) {
1075 if(!addresses
.count(r
))
1077 uint64_t addr
= addresses
[r
];
1079 lsnes_instance
.iqueue
.run([addr
, ms
]() { ms
->dq_range(addr
, addr
); });
1081 matches
->set_selection(0, 0);
1082 wxeditor_hexeditor_update();
1083 } else if(id
== wxID_SET_REGIONS
) {
1084 wxwindow_memorysearch_vmasel
* d
= new wxwindow_memorysearch_vmasel(this, vmas_enabled
);
1085 if(d
->ShowModal() == wxID_OK
)
1086 vmas_enabled
= d
->get_vmas();
1093 for(auto i
: lsnes_instance
.memory
.get_regions())
1094 if(memory_search::searchable_region(i
) && !vmas_enabled
.count(i
->name
))
1095 msearch
->dq_range(i
->base
, i
->last_address());
1096 wxeditor_hexeditor_update();
1097 } else if(id
== wxID_POKE
) {
1098 uint64_t start
, end
;
1099 matches
->get_selection(start
, end
);
1104 for(uint64_t r
= start
; r
< end
; r
++) {
1105 if(!addresses
.count(r
))
1107 uint64_t addr
= addresses
[r
];
1109 (this->*(pokes
[typecode
]))(addr
);
1110 } catch(canceled_exception
& e
) {
1114 } else if(id
== wxID_SHOW_HEXEDITOR
) {
1115 uint64_t start
, end
;
1116 matches
->get_selection(start
, end
);
1121 for(uint64_t r
= start
; r
< end
; r
++) {
1122 if(!addresses
.count(r
))
1124 wxeditor_hexeditor_jumpto(addresses
[r
]);
1127 } else if(id
>= wxID_BUTTONS_BASE
&& id
< wxID_BUTTONS_BASE
+
1128 (ssize_t
)(sizeof(searchtbl
)/sizeof(searchtbl
[0]))) {
1129 int button
= id
- wxID_BUTTONS_BASE
;
1131 uint64_t old_count
= msearch
->get_candidate_count();
1132 (this->*(searchtbl
[button
].searches
[typecode
]))();
1133 uint64_t new_count
= msearch
->get_candidate_count();
1134 if(old_count
== new_count
) {
1135 undohistory
.pop_back(); //Shouldn't be undoable.
1136 undoitem
->Enable(undohistory
.size());
1138 wxeditor_hexeditor_update();
1139 } else if(id
== wxID_MENU_DUMP_CANDIDATES
) {
1140 dump_candidates_text();
1141 } else if(id
== wxID_MENU_SAVE_PREVMEM
) {
1142 handle_save(memory_search::ST_PREVMEM
);
1143 } else if(id
== wxID_MENU_SAVE_SET
) {
1144 handle_save(memory_search::ST_SET
);
1145 } else if(id
== wxID_MENU_SAVE_ALL
) {
1146 handle_save(memory_search::ST_ALL
);
1147 } else if(id
== wxID_MENU_LOAD
) {
1149 } else if(id
== wxID_UNDO
) {
1150 handle_undo_redo(false);
1151 } else if(id
== wxID_REDO
) {
1152 handle_undo_redo(true);
1157 template<typename T
> void wxwindow_memorysearch::_do_poke_addr(uint64_t addr
)
1159 T val
= msearch
->v_read
<T
>(addr
);
1162 v
= pick_text(this, "Poke value", (stringfmt() << "Enter value to poke to " << std::hex
<< "0x"
1163 << addr
).str(), (stringfmt() << val
).str(), false);
1164 val
= parse_value
<T
>(v
);
1165 } catch(canceled_exception
& e
) {
1168 wxMessageBox(towxstring("Bad value '" + v
+ "'"), _T("Error"), wxICON_WARNING
| wxOK
, this);
1171 msearch
->v_write
<T
>(addr
, val
);
1174 template<void(memory_search::*sfn
)()> void wxwindow_memorysearch::search_0()
1179 template<typename T
, typename T2
, void(memory_search::*sfn
)(T2 val
)> void wxwindow_memorysearch::search_1()
1182 T val
= promptvalue
<T
>(bad
);
1185 (msearch
->*sfn
)(static_cast<T2
>(val
));
1188 template<typename T
> T
wxwindow_memorysearch::promptvalue(bool& bad
)
1191 wxTextEntryDialog
* d
= new wxTextEntryDialog(this, wxT("Enter value to search for:"), wxT("Memory search"),
1193 if(d
->ShowModal() == wxID_CANCEL
) {
1197 v
= tostdstring(d
->GetValue());
1201 val2
= parse_value
<T
>(v
);
1203 wxMessageBox(towxstring("Bad value '" + v
+ "'"), _T("Error"), wxICON_WARNING
| wxOK
, this);
1210 void wxwindow_memorysearch_display()
1216 mwatch
= new wxwindow_memorysearch();
1220 void wxwindow_memorysearch_update()
1223 mwatch
->auto_update();
1226 memory_search
* wxwindow_memorysearch_active()
1229 return mwatch
->msearch
;