summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2022-09-02 08:55:16 +1000
committer Vas Crabb <vas@vastheman.com>2022-09-02 08:55:16 +1000
commit051c380fd14040c83a0d5b919e6289e70fef9df8 (patch)
treee247a309f4d1c66c07803c02d67ac89837211bd1 /src
parent67f129e31518a50a801413f732991972d2c3538a (diff)
Patched up some gaps in functionality and fixed some bugs.
ui: Added some missing functionality: * Added an option to copy input device IDs to the relevant menus. * Added an item for setting the software lists files path (-hashpath) to the folder setup menu. * Allow pasting text from clipboard in most places that allow typing (searching, entering filenames, entering barcodes). * Changed the software selection menu heading to be a bit less misleading. * Made barcode menu less eager to rebuild itself unnecessarily, and removed some confusing and apparently pointless code. Exposed more Lua bindings: * Added low-level palette objects. * Added indexed bitmap types. * Added a bitmap method for extracting pixels from a rectangular area as a packed binary string. * Changed screen device pixels method to return width and height in addition to the pixels. osd: Added some functionality and cleaned up a little: * Added a function for copying text to the clipboard. * Moved function for converting Windows error codes to standard error conditions to winutil.cpp so it can be used from more places. * Removed duplicate declaration of osd_get_clipboard_text and made the function noexcept (including fixing implementations). * Made macOS implementation of osd_get_clipboard_text skip the encoding conversion if it finds UTF-8 text first. * Changed the default -uimodekey setting so it doesn't lose the "not shift" that stops the default from interfering with UI paste. Various bug fixes: * util/unicode.cpp: Fixed the version of utf8_from_uchar that returns std::string blowing up on invalid codepoints. * util/bitmap.h: Fixed wrapping constructors for indexed bitmaps taking the wrong parameter type (nothing was using them before). * util/bitmap.cpp: Fixed potential use-after-free issues with bitmap palettes. * emu/input.cpp, emu/inputdev.cpp: Log 1-based device numbers, matching what's shown in the internal UI and used in tokens in CFG files. * emu/emumem.cpp: Added the bank tag to a fatal error message where it was missing. docs: Reworked and expanded documentation on configuring stable controller IDs. For translators, the changes are quite minor: * There's a menu item for copying a device ID to the clipboard, and associated success/failure messages. * There's the menu item for setting the software list file search path. * One of the lines in the software selection menu heading has changes as it could be interpreted as implying it showed a software list name.
Diffstat (limited to 'src')
-rw-r--r--src/emu/emumem.cpp2
-rw-r--r--src/emu/inpttype.ipp4
-rw-r--r--src/emu/input.cpp2
-rw-r--r--src/emu/inputdev.cpp4
-rw-r--r--src/emu/natkeyboard.cpp3
-rw-r--r--src/emu/render.cpp2
-rw-r--r--src/frontend/mame/luaengine.cpp152
-rw-r--r--src/frontend/mame/luaengine.h2
-rw-r--r--src/frontend/mame/luaengine.ipp45
-rw-r--r--src/frontend/mame/luaengine_render.cpp532
-rw-r--r--src/frontend/mame/ui/barcode.cpp25
-rw-r--r--src/frontend/mame/ui/dirmenu.cpp110
-rw-r--r--src/frontend/mame/ui/filecreate.cpp13
-rw-r--r--src/frontend/mame/ui/filesel.cpp62
-rw-r--r--src/frontend/mame/ui/filesel.h2
-rw-r--r--src/frontend/mame/ui/inputdevices.cpp15
-rw-r--r--src/frontend/mame/ui/selector.cpp5
-rw-r--r--src/frontend/mame/ui/selmenu.cpp10
-rw-r--r--src/frontend/mame/ui/selsoft.cpp2
-rw-r--r--src/frontend/mame/ui/simpleselgame.cpp6
-rw-r--r--src/frontend/mame/ui/swlist.cpp97
-rw-r--r--src/frontend/mame/ui/swlist.h1
-rw-r--r--src/frontend/mame/ui/ui.cpp3
-rw-r--r--src/frontend/mame/ui/utils.h84
-rw-r--r--src/lib/util/bitmap.cpp22
-rw-r--r--src/lib/util/bitmap.h8
-rw-r--r--src/lib/util/unicode.cpp4
-rw-r--r--src/osd/modules/file/winfile.cpp88
-rw-r--r--src/osd/modules/file/winfile.h2
-rw-r--r--src/osd/modules/file/winptty.cpp10
-rw-r--r--src/osd/modules/font/font_dwrite.cpp14
-rw-r--r--src/osd/modules/input/input_sdlcommon.cpp34
-rw-r--r--src/osd/modules/input/input_windows.cpp20
-rw-r--r--src/osd/modules/lib/osdlib.h30
-rw-r--r--src/osd/modules/lib/osdlib_macosx.cpp83
-rw-r--r--src/osd/modules/lib/osdlib_unix.cpp48
-rw-r--r--src/osd/modules/lib/osdlib_win32.cpp81
-rw-r--r--src/osd/modules/lib/osdobj_common.cpp2
-rw-r--r--src/osd/osdcore.h9
-rw-r--r--src/osd/windows/winutil.cpp65
-rw-r--r--src/osd/windows/winutil.h4
41 files changed, 1141 insertions, 566 deletions
diff --git a/src/emu/emumem.cpp b/src/emu/emumem.cpp
index b08657c9087..0d20a1bda79 100644
--- a/src/emu/emumem.cpp
+++ b/src/emu/emumem.cpp
@@ -984,7 +984,7 @@ void memory_bank::set_entry(int entrynum)
// validate
if (entrynum < 0 || entrynum >= int(m_entries.size()))
- throw emu_fatalerror("memory_bank::set_entry called with out-of-range entry %d", entrynum);
+ throw emu_fatalerror("memory_bank::set_entry called for bank '%s' with out-of-range entry %d", m_tag, entrynum);
if (m_entries[entrynum] == nullptr)
throw emu_fatalerror("memory_bank::set_entry called for bank '%s' with invalid bank entry %d", m_tag, entrynum);
diff --git a/src/emu/inpttype.ipp b/src/emu/inpttype.ipp
index 03f6e3e1dab..fc4ca40b8d4 100644
--- a/src/emu/inpttype.ipp
+++ b/src/emu/inpttype.ipp
@@ -910,9 +910,9 @@ namespace {
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_NEXT_GROUP, N_p("input-name", "UI Next Group"), input_seq(KEYCODE_CLOSEBRACE) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_ROTATE, N_p("input-name", "UI Rotate"), input_seq(KEYCODE_R) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SHOW_PROFILER, N_p("input-name", "Show Profiler"), input_seq(KEYCODE_F11, KEYCODE_LSHIFT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_UI, N_p("input-name", "UI Toggle"), input_seq(KEYCODE_SCRLOCK, input_seq::not_code, KEYCODE_LSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TOGGLE_UI, N_p("input-name", "UI Toggle"), input_seq(KEYCODE_SCRLOCK, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_RELEASE_POINTER, N_p("input-name", "UI Release Pointer"), input_seq(KEYCODE_RCONTROL, KEYCODE_RALT) ) \
- INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PASTE, N_p("input-name", "UI Paste Text"), input_seq(KEYCODE_SCRLOCK, KEYCODE_LSHIFT) ) \
+ INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_PASTE, N_p("input-name", "UI Paste Text"), input_seq(KEYCODE_SCRLOCK, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_SCRLOCK, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_SAVE_STATE, N_p("input-name", "Save State"), input_seq(KEYCODE_F7, KEYCODE_LSHIFT, input_seq::or_code, KEYCODE_F7, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_LOAD_STATE, N_p("input-name", "Load State"), input_seq(KEYCODE_F7, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
INPUT_PORT_DIGITAL_TYPE( 0, UI, UI_TAPE_START, N_p("input-name", "UI (First) Tape Start"), input_seq(KEYCODE_F2, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_RSHIFT) ) \
diff --git a/src/emu/input.cpp b/src/emu/input.cpp
index 6368c4ee4a9..6c3699a833a 100644
--- a/src/emu/input.cpp
+++ b/src/emu/input.cpp
@@ -1194,7 +1194,7 @@ bool input_manager::map_device_to_controller(const devicemap_table &table)
{
// remap devindex
input_devclass->remap_device_index(device->devindex(), devindex);
- osd_printf_verbose("Input: Remapped %s #%d: %s (device id: %s)\n", input_devclass->name(), devindex, device->name(), device->id());
+ osd_printf_verbose("Input: Remapped %s #%d: %s (device id: %s)\n", input_devclass->name(), devindex + 1, device->name(), device->id());
break;
}
diff --git a/src/emu/inputdev.cpp b/src/emu/inputdev.cpp
index dacffbc2e56..2ce5720cf9b 100644
--- a/src/emu/inputdev.cpp
+++ b/src/emu/inputdev.cpp
@@ -519,9 +519,9 @@ input_device &input_class::add_device(std::unique_ptr<input_device> &&new_device
m_maxindex = std::max(m_maxindex, devindex);
if (new_device->id()[0] == 0)
- osd_printf_verbose("Input: Adding %s #%d: %s\n", m_name, devindex, new_device->name());
+ osd_printf_verbose("Input: Adding %s #%d: %s\n", m_name, devindex + 1, new_device->name());
else
- osd_printf_verbose("Input: Adding %s #%d: %s (device id: %s)\n", m_name, devindex, new_device->name(), new_device->id());
+ osd_printf_verbose("Input: Adding %s #%d: %s (device id: %s)\n", m_name, devindex + 1, new_device->name(), new_device->id());
m_device[devindex] = std::move(new_device);
return *m_device[devindex];
diff --git a/src/emu/natkeyboard.cpp b/src/emu/natkeyboard.cpp
index cac2e2a717a..681f64cd263 100644
--- a/src/emu/natkeyboard.cpp
+++ b/src/emu/natkeyboard.cpp
@@ -15,6 +15,9 @@
#include "emuopts.h"
#include "unicode.h"
+// FIXME: allow OSD module headers to be included in a less ugly way
+#include "../osd/modules/lib/osdlib.h"
+
#include <algorithm>
#include <cstring>
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index 6946a8de57d..32aebcf8eb7 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -691,7 +691,7 @@ const rgb_t *render_container::bcg_lookup_table(int texformat, u32 &out_length,
m_bcglookup.resize(palette->max_index());
recompute_lookups();
}
- assert (palette == &m_palclient->palette());
+ assert(palette == &m_palclient->palette());
out_length = palette->max_index();
return &m_bcglookup[0];
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 1d0bfca5e76..386d6dc841d 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -1475,6 +1475,13 @@ void lua_engine::initialize()
dipalette_type.set_function("set_shadow_factor", &device_palette_interface::set_shadow_factor);
dipalette_type.set_function("set_highlight_factor", &device_palette_interface::set_highlight_factor);
dipalette_type.set_function("set_shadow_mode", &device_palette_interface::set_shadow_mode);
+ dipalette_type["palette"] = sol::property(
+ [] (device_palette_interface &pal)
+ {
+ return pal.palette()
+ ? std::optional<palette_wrapper>(std::in_place, *pal.palette())
+ : std::optional<palette_wrapper>();
+ });
dipalette_type["entries"] = sol::property(&device_palette_interface::entries);
dipalette_type["indirect_entries"] = sol::property(&device_palette_interface::indirect_entries);
dipalette_type["black_pen"] = sol::property(&device_palette_interface::black_pen);
@@ -1488,7 +1495,8 @@ void lua_engine::initialize()
"screen_dev",
sol::no_constructor,
sol::base_classes, sol::bases<device_t>());
- screen_dev_type["draw_box"] =
+ screen_dev_type.set_function(
+ "draw_box",
[] (screen_device &sdev, float x1, float y1, float x2, float y2, std::optional<uint32_t> fgcolor, std::optional<uint32_t> bgcolor)
{
float const sc_width(sdev.visible_area().width());
@@ -1503,8 +1511,9 @@ void lua_engine::initialize()
if (!bgcolor)
bgcolor = ui.colors().background_color();
ui.draw_outlined_box(sdev.container(), x1, y1, x2, y2, *fgcolor, *bgcolor);
- };
- screen_dev_type["draw_line"] =
+ });
+ screen_dev_type.set_function(
+ "draw_line",
[] (screen_device &sdev, float x1, float y1, float x2, float y2, std::optional<uint32_t> color)
{
float const sc_width(sdev.visible_area().width());
@@ -1516,8 +1525,9 @@ void lua_engine::initialize()
if (!color)
color = mame_machine_manager::instance()->ui().colors().text_color();
sdev.container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(*color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
- };
- screen_dev_type["draw_text"] =
+ });
+ screen_dev_type.set_function(
+ "draw_text",
[this] (screen_device &sdev, sol::object xobj, float y, char const *msg, std::optional<uint32_t> fgcolor, std::optional<uint32_t> bgcolor)
{
float const sc_width(sdev.visible_area().width());
@@ -1555,78 +1565,80 @@ void lua_engine::initialize()
x, y, (1.0f - x),
justify, ui::text_layout::word_wrapping::WORD,
mame_ui_manager::OPAQUE_, *fgcolor, *bgcolor);
- };
- screen_dev_type["orientation"] =
- [] (screen_device &sdev)
- {
- uint32_t flags = sdev.orientation();
- int rotation_angle = 0;
- switch (flags)
+ });
+ screen_dev_type.set_function(
+ "orientation",
+ [] (screen_device &sdev)
{
- case ORIENTATION_SWAP_XY:
- case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X:
- rotation_angle = 90;
- flags ^= ORIENTATION_FLIP_X;
- break;
- case ORIENTATION_FLIP_Y:
- case ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y:
- rotation_angle = 180;
- flags ^= ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y;
- break;
- case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y:
- case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y:
- rotation_angle = 270;
- flags ^= ORIENTATION_FLIP_Y;
- break;
- }
- return std::tuple<int, bool, bool>(rotation_angle, flags & ORIENTATION_FLIP_X, flags & ORIENTATION_FLIP_Y);
- };
+ uint32_t flags = sdev.orientation();
+ int rotation_angle = 0;
+ switch (flags)
+ {
+ case ORIENTATION_SWAP_XY:
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X:
+ rotation_angle = 90;
+ flags ^= ORIENTATION_FLIP_X;
+ break;
+ case ORIENTATION_FLIP_Y:
+ case ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y:
+ rotation_angle = 180;
+ flags ^= ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y;
+ break;
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y:
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y:
+ rotation_angle = 270;
+ flags ^= ORIENTATION_FLIP_Y;
+ break;
+ }
+ return std::tuple<int, bool, bool>(rotation_angle, flags & ORIENTATION_FLIP_X, flags & ORIENTATION_FLIP_Y);
+ });
screen_dev_type["time_until_pos"] = sol::overload(
[] (screen_device &sdev, int vpos) { return sdev.time_until_pos(vpos).as_double(); },
[] (screen_device &sdev, int vpos, int hpos) { return sdev.time_until_pos(vpos, hpos).as_double(); });
- screen_dev_type["time_until_vblank_start"] = &screen_device::time_until_vblank_start;
- screen_dev_type["time_until_vblank_end"] = &screen_device::time_until_vblank_end;
- screen_dev_type["snapshot"] =
- [this] (screen_device &sdev, char const *filename) -> sol::object
- {
- // FIXME: this shouldn't be a member of the screen device
- // the screen is only used as a hint when configured for native snapshots and may be ignored
- std::string snapstr;
- bool is_absolute_path = false;
- if (filename)
+ screen_dev_type.set_function("time_until_vblank_start", &screen_device::time_until_vblank_start);
+ screen_dev_type.set_function("time_until_vblank_end", &screen_device::time_until_vblank_end);
+ screen_dev_type.set_function(
+ "snapshot",
+ [this] (screen_device &sdev, char const *filename) -> sol::object
{
- // a filename was specified; if it isn't absolute post-process it
- snapstr = process_snapshot_filename(machine(), filename);
- is_absolute_path = osd_is_absolute_path(snapstr);
- }
+ // FIXME: this shouldn't be a member of the screen device
+ // the screen is only used as a hint when configured for native snapshots and may be ignored
+ std::string snapstr;
+ bool is_absolute_path = false;
+ if (filename)
+ {
+ // a filename was specified; if it isn't absolute post-process it
+ snapstr = process_snapshot_filename(machine(), filename);
+ is_absolute_path = osd_is_absolute_path(snapstr);
+ }
- // open the file
- emu_file file(is_absolute_path ? "" : machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- std::error_condition filerr;
- if (!snapstr.empty())
- filerr = file.open(snapstr);
- else
- filerr = machine().video().open_next(file, "png");
- if (filerr)
- return sol::make_object(sol(), filerr);
+ // open the file
+ emu_file file(is_absolute_path ? "" : machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ std::error_condition filerr;
+ if (!snapstr.empty())
+ filerr = file.open(snapstr);
+ else
+ filerr = machine().video().open_next(file, "png");
+ if (filerr)
+ return sol::make_object(sol(), filerr);
- // and save the snapshot
- machine().video().save_snapshot(&sdev, file);
- return sol::lua_nil;
- };
- screen_dev_type["pixel"] = [] (screen_device &sdev, s32 x, s32 y) { return sdev.pixel(x, y); };
- screen_dev_type["pixels"] =
- [] (screen_device &sdev, sol::this_state s)
- {
- // TODO: would be better if this could return a tuple of (buffer, width, height)
- const rectangle &visarea = sdev.visible_area();
- luaL_Buffer buff;
- int size = visarea.height() * visarea.width() * 4;
- u32 *ptr = (u32 *)luaL_buffinitsize(s, &buff, size);
- sdev.pixels(ptr);
- luaL_pushresultsize(&buff, size);
- return sol::make_reference(s, sol::stack_reference(s, -1));
- };
+ // and save the snapshot
+ machine().video().save_snapshot(&sdev, file);
+ return sol::lua_nil;
+ });
+ screen_dev_type.set_function("pixel", &screen_device::pixel);
+ screen_dev_type.set_function(
+ "pixels",
+ [] (screen_device &sdev, sol::this_state s)
+ {
+ const rectangle &visarea = sdev.visible_area();
+ luaL_Buffer buff;
+ int size = visarea.height() * visarea.width() * 4;
+ u32 *const ptr = reinterpret_cast<u32 *>(luaL_buffinitsize(s, &buff, size));
+ sdev.pixels(ptr);
+ luaL_pushresultsize(&buff, size);
+ return std::make_tuple(sol::make_reference(s, sol::stack_reference(s, -1)), visarea.width(), visarea.height());
+ });
screen_dev_type["screen_type"] = sol::property(&screen_device::screen_type);
screen_dev_type["width"] = sol::property([] (screen_device &sdev) { return sdev.visible_area().width(); });
screen_dev_type["height"] = sol::property([] (screen_device &sdev) { return sdev.visible_area().height(); });
diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h
index 27761eb85b5..e188c186e11 100644
--- a/src/frontend/mame/luaengine.h
+++ b/src/frontend/mame/luaengine.h
@@ -144,6 +144,8 @@ private:
class buffer_helper;
struct addr_space;
+ class palette_wrapper;
+ template <typename T> class bitmap_helper;
class tap_helper;
class addr_space_change_notif;
class symbol_table_wrapper;
diff --git a/src/frontend/mame/luaengine.ipp b/src/frontend/mame/luaengine.ipp
index 91e4b9d0b4f..4b20e39cdb1 100644
--- a/src/frontend/mame/luaengine.ipp
+++ b/src/frontend/mame/luaengine.ipp
@@ -128,6 +128,51 @@ public:
};
+class lua_engine::palette_wrapper
+{
+public:
+ palette_wrapper(uint32_t numcolors, uint32_t numgroups) : m_palette(palette_t::alloc(numcolors, numgroups))
+ {
+ }
+
+ palette_wrapper(palette_t &pal) : m_palette(&pal)
+ {
+ m_palette->ref();
+ }
+
+ palette_wrapper(palette_wrapper const &that) : m_palette(that.m_palette)
+ {
+ m_palette->ref();
+ }
+
+ ~palette_wrapper()
+ {
+ m_palette->deref();
+ }
+
+ palette_wrapper &operator=(palette_wrapper const &that)
+ {
+ that.m_palette->ref();
+ m_palette->deref();
+ m_palette = that.m_palette;
+ return *this;
+ }
+
+ palette_t const &palette() const
+ {
+ return *m_palette;
+ }
+
+ palette_t &palette()
+ {
+ return *m_palette;
+ }
+
+private:
+ palette_t *m_palette;
+};
+
+
namespace sol {
// don't convert core_options to a table directly
diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp
index ed56d7470b2..d6369b27bc3 100644
--- a/src/frontend/mame/luaengine_render.cpp
+++ b/src/frontend/mame/luaengine_render.cpp
@@ -17,110 +17,13 @@
#include "render.h"
#include "rendlay.h"
+#include <algorithm>
#include <atomic>
#include <iterator>
namespace {
-template <typename T>
-class bitmap_helper : public T
-{
-public:
- using ptr = std::shared_ptr<bitmap_helper>;
-
- bitmap_helper(bitmap_helper const &) = delete;
- bitmap_helper(bitmap_helper &&) = delete;
- bitmap_helper &operator=(bitmap_helper const &) = delete;
- bitmap_helper &operator=(bitmap_helper &&) = delete;
-
- bitmap_helper(sol::this_state s, int width, int height, int xslop, int yslop)
- : T(width, height, xslop, yslop)
- , lock_count(0)
- , storage()
- {
- if ((0 < width) && (0 < height) && !this->valid())
- luaL_error(s, "Error allocating bitmap storage");
- }
-
- bitmap_helper(ptr const &source, rectangle const &subrect)
- : T(*source, subrect)
- , lock_count(0)
- , storage(source->storage ? source->storage : source)
- {
- ++storage->lock_count;
- }
-
- ~bitmap_helper()
- {
- assert(!lock_count);
- release_storage();
- }
-
- bool locked() const
- {
- return bool(lock_count);
- }
-
- void reset(sol::this_state s)
- {
- if (lock_count)
- luaL_error(s, "Cannot reset bitmap while in use");
- T::reset();
- release_storage();
- }
-
- void allocate(sol::this_state s, int width, int height, int xslop, int yslop)
- {
- if (lock_count)
- luaL_error(s, "Cannot reallocate bitmap while in use");
- T::allocate(width, height, xslop, yslop);
- release_storage();
- if ((0 < width) && (0 < height) && !this->valid())
- luaL_error(s, "Error allocating bitmap storage");
- }
-
- void resize(sol::this_state s, int width, int height, int xslop, int yslop)
- {
- if (lock_count)
- luaL_error(s, "Cannot resize bitmap while in use");
- T::resize(width, height, xslop, yslop);
- release_storage();
- if ((0 < width) && (0 < height) && !this->valid())
- luaL_error(s, "Error allocating bitmap storage");
- }
-
- void wrap(sol::this_state s, ptr const &source, rectangle const &subrect)
- {
- if (source.get() == this)
- luaL_error(s, "Bitmap cannot wrap itself");
- if (lock_count)
- luaL_error(s, "Cannot free bitmap storage while in use");
- if (!source->cliprect().contains(subrect))
- luaL_error(s, "Bounds exceed source clipping rectangle");
- T::wrap(*source, subrect);
- release_storage();
- storage = source->storage ? source->storage : source;
- ++storage->lock_count;
- }
-
- std::atomic<unsigned> lock_count;
-
-private:
- void release_storage()
- {
- if (storage)
- {
- assert(storage->lock_count);
- --storage->lock_count;
- storage.reset();
- }
- }
-
- ptr storage;
-};
-
-
class render_texture_helper
{
public:
@@ -130,7 +33,8 @@ public:
: texture(that.texture)
, bitmap(that.bitmap)
, manager(that.manager)
- , lock_count(that.lock_count)
+ , storage_lock_count(that.storage_lock_count)
+ , palette_lock_count(that.palette_lock_count)
{
that.texture = nullptr;
that.bitmap.reset();
@@ -141,14 +45,16 @@ public:
: texture(nullptr)
, bitmap(b)
, manager(m)
- , lock_count(b->lock_count)
+ , storage_lock_count(b->storage_lock_count)
+ , palette_lock_count(b->palette_lock_count)
{
if (bitmap)
{
texture = manager.texture_alloc();
if (texture)
{
- ++lock_count;
+ ++storage_lock_count;
+ ++palette_lock_count;
texture->set_bitmap(*bitmap, bitmap->cliprect(), f);
}
else
@@ -177,8 +83,10 @@ public:
}
if (bitmap)
{
- assert(lock_count);
- --lock_count;
+ assert(storage_lock_count);
+ assert(palette_lock_count);
+ --storage_lock_count;
+ --palette_lock_count;
bitmap.reset();
}
}
@@ -188,7 +96,8 @@ public:
private:
render_manager &manager;
- std::atomic<unsigned> &lock_count;
+ std::atomic<unsigned> &storage_lock_count;
+ std::atomic<unsigned> &palette_lock_count;
};
@@ -226,6 +135,21 @@ struct render_target_view_names
template <typename T>
+auto get_bitmap_pixels(T const &bitmap, sol::this_state s, rectangle const &bounds)
+{
+ if (!bitmap.cliprect().contains(bounds))
+ luaL_error(s, "Bounds exceed source clipping rectangle");
+ luaL_Buffer buff;
+ size_t const size(bounds.width() * bounds.height() * sizeof(typename T::pixel_t));
+ auto ptr = reinterpret_cast<typename T::pixel_t *>(luaL_buffinitsize(s, &buff, size));
+ for (auto y = bounds.top(); bounds.bottom() >= y; ++y, ptr += bounds.width())
+ std::copy_n(&bitmap.pix(y, bounds.left()), bounds.width(), ptr);
+ luaL_pushresultsize(&buff, size);
+ return std::make_tuple(sol::make_reference(s, sol::stack_reference(s, -1)), bounds.width(), bounds.height());
+}
+
+
+template <typename T>
auto make_bitmap_specific_type(sol::table registry, char const *name)
{
auto result = registry.new_usertype<T>(
@@ -233,6 +157,15 @@ auto make_bitmap_specific_type(sol::table registry, char const *name)
sol::no_constructor,
sol::base_classes, sol::bases<bitmap_t>());
result.set_function("pix", [] (T &bitmap, int32_t x, int32_t y) { return bitmap.pix(y, x); });
+ result["pixels"] = sol::overload(
+ [] (T const &bitmap, sol::this_state s)
+ {
+ return get_bitmap_pixels(bitmap, s, bitmap.cliprect());
+ },
+ [] (T const &bitmap, sol::this_state s, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
+ {
+ return get_bitmap_pixels(bitmap, s, rectangle(minx, maxx, miny, maxy));
+ });
result["fill"] = sol::overload(
static_cast<void (T::*)(typename T::pixel_t)>(&T::fill),
[] (T &bitmap, typename T::pixel_t color, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
@@ -251,57 +184,6 @@ auto make_bitmap_specific_type(sol::table registry, char const *name)
return result;
}
-
-template <typename T, typename B>
-auto make_bitmap_type(sol::table &registry, char const *name)
-{
- auto result = registry.new_usertype<T>(
- name,
- sol::call_constructor, sol::factories(
- [] (sol::this_state s)
- {
- return std::make_shared<T>(s, 0, 0, 0, 0);
- },
- [] (sol::this_state s, int width, int height)
- {
- return std::make_shared<T>(s, width, height, 0, 0);
- },
- [] (sol::this_state s, int width, int height, int xslop, int yslop)
- {
- return std::make_shared<T>(s, width, height, xslop, yslop);
- },
- [] (typename T::ptr const &source)
- {
- return std::make_shared<T>(source, source->cliprect());
- },
- [] (sol::this_state s, typename T::ptr const &source, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
- {
- rectangle const subrect(minx, maxx, miny, maxy);
- if (!source->cliprect().contains(subrect))
- luaL_error(s, "Bounds exceed source clipping rectangle");
- return std::make_shared<T>(source, subrect);
- }),
- sol::base_classes, sol::bases<B, bitmap_t>());
- result.set_function("reset", &T::reset);
- result["allocate"] = sol::overload(
- &T::allocate,
- [] (T &bitmap, sol::this_state s, int width, int height) { bitmap.allocate(s, width, height, 0, 0); });
- result["resize"] = sol::overload(
- &T::resize,
- [] (T &bitmap, sol::this_state s, int width, int height) { bitmap.resize(s, width, height, 0, 0); });
- result["wrap"] = sol::overload(
- [] (T &bitmap, sol::this_state s, typename T::ptr const &source)
- {
- bitmap.wrap(s, source, source->cliprect());
- },
- [] (T &bitmap, sol::this_state s, typename T::ptr const &source, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
- {
- bitmap.wrap(s, source, rectangle(minx, maxx, miny, maxy));
- });
- result["locked"] = sol::property(&T::locked);
- return result;
-}
-
} // anonymous namespace
@@ -462,6 +344,231 @@ public:
} // namespace sol
+template <typename T>
+class lua_engine::bitmap_helper : public T
+{
+public:
+ using ptr = std::shared_ptr<bitmap_helper>;
+
+ bitmap_helper(bitmap_helper const &) = delete;
+ bitmap_helper(bitmap_helper &&) = delete;
+ bitmap_helper &operator=(bitmap_helper const &) = delete;
+ bitmap_helper &operator=(bitmap_helper &&) = delete;
+
+ bitmap_helper(sol::this_state s, int width, int height, int xslop, int yslop)
+ : T(width, height, xslop, yslop)
+ , storage_lock_count(0)
+ , palette_lock_count(0)
+ , storage()
+ {
+ if ((0 < width) && (0 < height) && !this->valid())
+ luaL_error(s, "Error allocating bitmap storage");
+ }
+
+ bitmap_helper(ptr const &source, rectangle const &subrect)
+ : T(*source, subrect)
+ , storage_lock_count(0)
+ , palette_lock_count(0)
+ , storage(source->storage ? source->storage : source)
+ {
+ ++storage->storage_lock_count;
+ this->set_palette(source->palette());
+ }
+
+ ~bitmap_helper()
+ {
+ assert(!storage_lock_count);
+ assert(!palette_lock_count);
+ release_storage();
+ }
+
+ void reset(sol::this_state s)
+ {
+ if (storage_lock_count)
+ luaL_error(s, "Cannot reset bitmap while in use");
+ palette_t *const p(this->palette());
+ if (p)
+ p->ref();
+ T::reset();
+ this->set_palette(p);
+ if (p)
+ p->deref();
+ release_storage();
+ }
+
+ void allocate(sol::this_state s, int width, int height, int xslop, int yslop)
+ {
+ if (storage_lock_count)
+ luaL_error(s, "Cannot reallocate bitmap while in use");
+ palette_t *const p(this->palette());
+ if (p)
+ p->ref();
+ T::allocate(width, height, xslop, yslop);
+ this->set_palette(p);
+ if (p)
+ p->deref();
+ release_storage();
+ if ((0 < width) && (0 < height) && !this->valid())
+ luaL_error(s, "Error allocating bitmap storage");
+ }
+
+ void resize(sol::this_state s, int width, int height, int xslop, int yslop)
+ {
+ if (storage_lock_count)
+ luaL_error(s, "Cannot resize bitmap while in use");
+ T::resize(width, height, xslop, yslop);
+ release_storage();
+ if ((0 < width) && (0 < height) && !this->valid())
+ luaL_error(s, "Error allocating bitmap storage");
+ }
+
+ void wrap(sol::this_state s, ptr const &source, rectangle const &subrect)
+ {
+ if (source.get() == this)
+ luaL_error(s, "Bitmap cannot wrap itself");
+ if (storage_lock_count)
+ luaL_error(s, "Cannot free bitmap storage while in use");
+ if (!source->cliprect().contains(subrect))
+ luaL_error(s, "Bounds exceed source clipping rectangle");
+ palette_t *const p(this->palette());
+ if (p)
+ p->ref();
+ T::wrap(*source, subrect);
+ this->set_palette(p);
+ if (p)
+ p->deref();
+ release_storage();
+ storage = source->storage ? source->storage : source;
+ ++storage->storage_lock_count;
+ }
+
+ std::atomic<unsigned> storage_lock_count;
+ std::atomic<unsigned> palette_lock_count;
+
+ template <typename B>
+ static auto make_type(sol::table &registry, char const *name)
+ {
+ auto result = registry.new_usertype<bitmap_helper>(
+ name,
+ sol::call_constructor, sol::factories(
+ [] (sol::this_state s)
+ {
+ return std::make_shared<bitmap_helper>(s, 0, 0, 0, 0);
+ },
+ [] (sol::this_state s, int width, int height)
+ {
+ return std::make_shared<bitmap_helper>(s, width, height, 0, 0);
+ },
+ [] (sol::this_state s, int width, int height, int xslop, int yslop)
+ {
+ return std::make_shared<bitmap_helper>(s, width, height, xslop, yslop);
+ },
+ [] (ptr const &source)
+ {
+ return std::make_shared<bitmap_helper>(source, source->cliprect());
+ },
+ [] (sol::this_state s, ptr const &source, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
+ {
+ rectangle const subrect(minx, maxx, miny, maxy);
+ if (!source->cliprect().contains(subrect))
+ luaL_error(s, "Bounds exceed source clipping rectangle");
+ return std::make_shared<bitmap_helper>(source, subrect);
+ }),
+ sol::base_classes, sol::bases<B, bitmap_t>());
+ add_bitmap_members(result);
+ return result;
+ }
+
+ template <typename B>
+ static auto make_indexed_type(sol::table &registry, char const *name)
+ {
+ auto result = registry.new_usertype<bitmap_helper>(
+ name,
+ sol::call_constructor, sol::factories(
+ [] (sol::this_state s, palette_wrapper &p)
+ {
+ ptr result = std::make_shared<bitmap_helper>(s, 0, 0, 0, 0);
+ result->set_palette(&p.palette());
+ return result;
+ },
+ [] (sol::this_state s, palette_wrapper &p, int width, int height)
+ {
+ ptr result = std::make_shared<bitmap_helper>(s, width, height, 0, 0);
+ result->set_palette(&p.palette());
+ return result;
+ },
+ [] (sol::this_state s, palette_wrapper &p, int width, int height, int xslop, int yslop)
+ {
+ ptr result = std::make_shared<bitmap_helper>(s, width, height, xslop, yslop);
+ result->set_palette(&p.palette());
+ return result;
+ },
+ [] (ptr const &source)
+ {
+ return std::make_shared<bitmap_helper>(source, source->cliprect());
+ },
+ [] (sol::this_state s, ptr const &source, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
+ {
+ rectangle const subrect(minx, maxx, miny, maxy);
+ if (!source->cliprect().contains(subrect))
+ luaL_error(s, "Bounds exceed source clipping rectangle");
+ return std::make_shared<bitmap_helper>(source, subrect);
+ }),
+ sol::base_classes, sol::bases<B, bitmap_t>());
+ result["palette"] = sol::property(
+ [] (bitmap_helper const &b)
+ {
+ return b.palette()
+ ? std::optional<palette_wrapper>(std::in_place, *b.palette())
+ : std::optional<palette_wrapper>();
+ },
+ [] (bitmap_helper &b, sol::this_state s, palette_wrapper &p)
+ {
+ if (b.palette_lock_count)
+ luaL_error(s, "Cannot set palette while in use");
+ b.set_palette(&p.palette());
+ });
+ add_bitmap_members(result);
+ return result;
+ }
+
+private:
+ void release_storage()
+ {
+ if (storage)
+ {
+ assert(storage->storage_lock_count);
+ --storage->storage_lock_count;
+ storage.reset();
+ }
+ }
+
+ template <typename U>
+ static void add_bitmap_members(U &type)
+ {
+ type.set_function("reset", &bitmap_helper::reset);
+ type["allocate"] = sol::overload(
+ &bitmap_helper::allocate,
+ [] (bitmap_helper &bitmap, sol::this_state s, int width, int height) { bitmap.allocate(s, width, height, 0, 0); });
+ type["resize"] = sol::overload(
+ &bitmap_helper::resize,
+ [] (bitmap_helper &bitmap, sol::this_state s, int width, int height) { bitmap.resize(s, width, height, 0, 0); });
+ type["wrap"] = sol::overload(
+ [] (bitmap_helper &bitmap, sol::this_state s, ptr const &source)
+ {
+ bitmap.wrap(s, source, source->cliprect());
+ },
+ [] (bitmap_helper &bitmap, sol::this_state s, ptr const &source, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
+ {
+ bitmap.wrap(s, source, rectangle(minx, maxx, miny, maxy));
+ });
+ type["locked"] = sol::property([] (bitmap_helper const &b) { return bool(b.storage_lock_count); });
+ }
+
+ ptr storage;
+};
+
+
//-------------------------------------------------
// initialize_render - register render user types
//-------------------------------------------------
@@ -498,7 +605,108 @@ void lua_engine::initialize_render(sol::table &emu)
color_type["b"] = &render_color::b;
+ auto palette_type = emu.new_usertype<palette_wrapper>(
+ "palette",
+ sol::call_constructor, sol::initializers(
+ [] (palette_wrapper &pal, uint32_t colors) { new (&pal) palette_wrapper(colors, 1); },
+ [] (palette_wrapper &pal, uint64_t colors, uint32_t groups) { new (&pal) palette_wrapper(colors, groups); }));
+ palette_type.set_function(
+ "entry_color",
+ [] (palette_wrapper const &pal, uint32_t index) { return uint32_t(pal.palette().entry_color(index)); });
+ palette_type.set_function(
+ "entry_contrast",
+ [] (palette_wrapper const &pal, uint32_t index) { return pal.palette().entry_contrast(index); });
+ palette_type.set_function(
+ "entry_adjusted_color",
+ [] (palette_wrapper const &pal, uint32_t index, std::optional<uint32_t> group)
+ {
+ if (group)
+ {
+ if ((pal.palette().num_colors() <= index) || (pal.palette().num_groups() <= *group))
+ return uint32_t(rgb_t::black());
+ index += *group * pal.palette().num_colors();
+ }
+ return uint32_t(pal.palette().entry_adjusted_color(index));
+ });
+ palette_type["entry_set_color"] = sol::overload(
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, uint32_t color)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_color(index, rgb_t(color));
+ },
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, uint8_t red, uint8_t green, uint8_t blue)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_color(index, rgb_t(red, green, blue));
+ });
+ palette_type.set_function(
+ "entry_set_red_level",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, uint8_t level)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_red_level(index, level);
+ });
+ palette_type.set_function(
+ "entry_set_green_level",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, uint8_t level)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_green_level(index, level);
+ });
+ palette_type.set_function(
+ "entry_set_blue_level",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, uint8_t level)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_blue_level(index, level);
+ });
+ palette_type.set_function(
+ "entry_set_contrast",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, float contrast)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_contrast(index, contrast);
+ });
+ palette_type.set_function(
+ "group_set_brightness",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t group, float brightness)
+ {
+ if (pal.palette().num_colors() <= group)
+ luaL_error(s, "Group index out of range");
+ pal.palette().group_set_brightness(group, brightness);
+ });
+ palette_type.set_function(
+ "group_set_contrast",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t group, float contrast)
+ {
+ if (pal.palette().num_colors() <= group)
+ luaL_error(s, "Group index out of range");
+ pal.palette().group_set_contrast(group, contrast);
+ });
+ palette_type["colors"] = sol::property([] (palette_wrapper const &pal) { return pal.palette().num_colors(); });
+ palette_type["groups"] = sol::property([] (palette_wrapper const &pal) { return pal.palette().num_groups(); });
+ palette_type["max_index"] = sol::property([] (palette_wrapper const &pal) { return pal.palette().max_index(); });
+ palette_type["black_entry"] = sol::property([] (palette_wrapper const &pal) { return pal.palette().black_entry(); });
+ palette_type["white_entry"] = sol::property([] (palette_wrapper const &pal) { return pal.palette().white_entry(); });
+ palette_type["brightness"] = sol::property([] (palette_wrapper &pal, float brightness) { pal.palette().set_brightness(brightness); });
+ palette_type["contrast"] = sol::property([] (palette_wrapper &pal, float contrast) { pal.palette().set_contrast(contrast); });
+ palette_type["gamma"] = sol::property([] (palette_wrapper &pal, float gamma) { pal.palette().set_gamma(gamma); });
+
+
auto bitmap_type = sol().registry().new_usertype<bitmap_t>("bitmap", sol::no_constructor);
+ bitmap_type.set_function(
+ "cliprect",
+ [] (bitmap_t const &bitmap)
+ {
+ rectangle const &result(bitmap.cliprect());
+ return std::make_tuple(result.left(), result.top(), result.right(), result.bottom());
+ });
bitmap_type["fill"] = sol::overload(
static_cast<void (bitmap_t::*)(uint64_t)>(&bitmap_t::fill),
[] (bitmap_t &bitmap, uint64_t color, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
@@ -518,10 +726,14 @@ void lua_engine::initialize_render(sol::table &emu)
make_bitmap_specific_type<bitmap32_t>(sol().registry(), "bitmap32");
make_bitmap_specific_type<bitmap64_t>(sol().registry(), "bitmap64");
- make_bitmap_type<bitmap_helper<bitmap_yuy16>, bitmap16_t>(emu, "bitmap_yuy16");
- make_bitmap_type<bitmap_helper<bitmap_rgb32>, bitmap32_t>(emu, "bitmap_rgb32");
- make_bitmap_type<bitmap_helper<bitmap_argb32>, bitmap32_t>(emu, "bitmap_argb32");
+ bitmap_helper<bitmap_ind8>::make_indexed_type<bitmap8_t>(emu, "bitmap_ind8");
+ bitmap_helper<bitmap_ind16>::make_indexed_type<bitmap16_t>(emu, "bitmap_ind16");
+ bitmap_helper<bitmap_ind32>::make_indexed_type<bitmap32_t>(emu, "bitmap_ind32");
+ bitmap_helper<bitmap_ind64>::make_indexed_type<bitmap64_t>(emu, "bitmap_ind64");
+ bitmap_helper<bitmap_yuy16>::make_type<bitmap16_t>(emu, "bitmap_yuy16");
+ bitmap_helper<bitmap_rgb32>::make_type<bitmap32_t>(emu, "bitmap_rgb32");
+ bitmap_helper<bitmap_argb32>::make_type<bitmap32_t>(emu, "bitmap_argb32");
auto render_texture_type = emu.new_usertype<render_texture_helper>("render_texture", sol::no_constructor);
render_texture_type.set_function("free", &render_texture_helper::free);
@@ -798,6 +1010,10 @@ void lua_engine::initialize_render(sol::table &emu)
auto render_type = sol().registry().new_usertype<render_manager>("render", sol::no_constructor);
render_type["texture_alloc"] = sol::overload(
+ [] (render_manager &manager, sol::this_state s, bitmap_helper<bitmap_ind16>::ptr const &bitmap)
+ {
+ return render_texture_helper(s, manager, bitmap, TEXFORMAT_PALETTE16);
+ },
[] (render_manager &manager, sol::this_state s, bitmap_helper<bitmap_yuy16>::ptr const &bitmap)
{
return render_texture_helper(s, manager, bitmap, TEXFORMAT_YUY16);
diff --git a/src/frontend/mame/ui/barcode.cpp b/src/frontend/mame/ui/barcode.cpp
index a06e4b99673..a0e4791dfb6 100644
--- a/src/frontend/mame/ui/barcode.cpp
+++ b/src/frontend/mame/ui/barcode.cpp
@@ -58,24 +58,11 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom)
{
if (current_device())
{
- std::string buffer;
- const char *new_barcode;
-
// selected device
item_append(std::string(current_display_name()), std::string(current_device()->tag() + 1), current_display_flags(), ITEMREF_SELECT_READER);
// append the "New Barcode" item
- if (get_selection_ref() == ITEMREF_NEW_BARCODE)
- {
- buffer.append(m_barcode_buffer);
- new_barcode = buffer.c_str();
- }
- else
- {
- new_barcode = m_barcode_buffer.c_str();
- }
-
- item_append(_("New Barcode:"), new_barcode, 0, ITEMREF_NEW_BARCODE);
+ item_append(_("New Barcode:"), m_barcode_buffer, 0, ITEMREF_NEW_BARCODE);
// finish up the menu
item_append(_("Enter Code"), 0, ITEMREF_ENTER_BARCODE);
@@ -131,11 +118,19 @@ void menu_barcode_reader::handle(event const *ev)
}
break;
+ case IPT_UI_PASTE:
+ if (get_selection_ref() == ITEMREF_NEW_BARCODE)
+ {
+ if (paste_text(m_barcode_buffer, uchar_is_digit))
+ ev->item->set_subtext(m_barcode_buffer);
+ }
+ break;
+
case IPT_SPECIAL:
if (get_selection_ref() == ITEMREF_NEW_BARCODE)
{
if (input_character(m_barcode_buffer, ev->unichar, uchar_is_digit))
- reset(reset_options::REMEMBER_POSITION);
+ ev->item->set_subtext(m_barcode_buffer);
}
break;
}
diff --git a/src/frontend/mame/ui/dirmenu.cpp b/src/frontend/mame/ui/dirmenu.cpp
index 1aa4cb6a8fe..ab55b742054 100644
--- a/src/frontend/mame/ui/dirmenu.cpp
+++ b/src/frontend/mame/ui/dirmenu.cpp
@@ -49,6 +49,7 @@ const folders_entry f_folders[] =
{ N_p("path-option", "Cheat Files"), OPTION_CHEATPATH, ADDING },
{ N_p("path-option", "Plugins"), OPTION_PLUGINSPATH, ADDING },
{ N_p("path-option", "UI Translations"), OPTION_LANGUAGEPATH, CHANGE },
+ { N_p("path-option", "Software Lists"), OPTION_HASHPATH, ADDING },
{ N_p("path-option", "INIs"), OPTION_INIPATH, ADDING },
{ N_p("path-option", "UI Settings"), OPTION_UI_PATH, CHANGE },
{ N_p("path-option", "Plugin Data"), OPTION_PLUGINDATAPATH, CHANGE },
@@ -176,6 +177,8 @@ private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
+ void update_search();
+
int const m_ref;
std::string m_current_path;
std::string m_search;
@@ -241,10 +244,13 @@ void menu_add_change_folder::handle(event const *ev)
m_search.clear();
reset(reset_options::SELECT_FIRST);
}
+ else if (ev->iptkey == IPT_UI_PASTE)
+ {
+ if (paste_text(m_search, uchar_is_printable))
+ update_search();
+ }
else if (ev->iptkey == IPT_SPECIAL)
{
- bool update_selected = false;
-
if (ev->unichar == 0x09)
{
// Tab key, save current path
@@ -276,56 +282,10 @@ void menu_add_change_folder::handle(event const *ev)
reset_parent(reset_options::SELECT_FIRST);
stack_pop();
}
- else
+ else if (input_character(m_search, ev->unichar, uchar_is_printable))
{
// if it's any other key and we're not maxed out, update
- update_selected = input_character(m_search, ev->unichar, uchar_is_printable);
- }
-
- // check for entries which matches our search buffer
- if (update_selected)
- {
- const int cur_selected = selected_index();
- int entry, bestmatch = 0;
-
- // from current item to the end
- for (entry = cur_selected; entry < item_count(); entry++)
- if (item(entry).ref() && !m_search.empty())
- {
- int match = 0;
- for (int i = 0; i < m_search.size() + 1; i++)
- {
- if (core_strnicmp(item(entry).text().c_str(), m_search.data(), i) == 0)
- match = i;
- }
-
- if (match > bestmatch)
- {
- bestmatch = match;
- set_selected_index(entry);
- }
- }
-
- // and from the first item to current one
- for (entry = 0; entry < cur_selected; entry++)
- {
- if (item(entry).ref() && !m_search.empty())
- {
- int match = 0;
- for (int i = 0; i < m_search.size() + 1; i++)
- {
- if (core_strnicmp(item(entry).text().c_str(), m_search.data(), i) == 0)
- match = i;
- }
-
- if (match > bestmatch)
- {
- bestmatch = match;
- set_selected_index(entry);
- }
- }
- }
- centre_selection();
+ update_search();
}
}
else if (ev->iptkey == IPT_UI_CANCEL)
@@ -408,6 +368,56 @@ void menu_add_change_folder::custom_render(void *selectedref, float top, float b
ui().colors().text_color(), ui().colors().background_color(), 1.0f);
}
+//-------------------------------------------------
+// update search
+//-------------------------------------------------
+
+void menu_add_change_folder::update_search()
+{
+ // check for entries which matches our search buffer
+ const int cur_selected = selected_index();
+ int entry, bestmatch = 0;
+
+ // from current item to the end
+ for (entry = cur_selected; entry < item_count(); entry++)
+ if (item(entry).ref() && !m_search.empty())
+ {
+ int match = 0;
+ for (int i = 0; i < m_search.size() + 1; i++)
+ {
+ if (core_strnicmp(item(entry).text().c_str(), m_search.data(), i) == 0)
+ match = i;
+ }
+
+ if (match > bestmatch)
+ {
+ bestmatch = match;
+ set_selected_index(entry);
+ }
+ }
+
+ // and from the first item to current one
+ for (entry = 0; entry < cur_selected; entry++)
+ {
+ if (item(entry).ref() && !m_search.empty())
+ {
+ int match = 0;
+ for (int i = 0; i < m_search.size() + 1; i++)
+ {
+ if (core_strnicmp(item(entry).text().c_str(), m_search.data(), i) == 0)
+ match = i;
+ }
+
+ if (match > bestmatch)
+ {
+ bestmatch = match;
+ set_selected_index(entry);
+ }
+ }
+ }
+ centre_selection();
+}
+
/**************************************************
MENU DISPLAY PATH
diff --git a/src/frontend/mame/ui/filecreate.cpp b/src/frontend/mame/ui/filecreate.cpp
index 3ecb44f9b62..44d50108b8c 100644
--- a/src/frontend/mame/ui/filecreate.cpp
+++ b/src/frontend/mame/ui/filecreate.cpp
@@ -208,13 +208,22 @@ void menu_file_create::handle(event const *ev)
}
break;
+ case IPT_UI_PASTE:
+ if (get_selection_ref() == ITEMREF_NEW_IMAGE_NAME)
+ {
+ if (paste_text(m_filename, &osd_is_valid_filename_char))
+ reset(reset_options::REMEMBER_POSITION);
+ }
+ break;
+
case IPT_SPECIAL:
if (get_selection_ref() == ITEMREF_NEW_IMAGE_NAME)
{
- input_character(m_filename, ev->unichar, &osd_is_valid_filename_char);
- reset(reset_options::REMEMBER_POSITION);
+ if (input_character(m_filename, ev->unichar, &osd_is_valid_filename_char))
+ reset(reset_options::REMEMBER_POSITION);
}
break;
+
case IPT_UI_CANCEL:
m_ok = false;
break;
diff --git a/src/frontend/mame/ui/filesel.cpp b/src/frontend/mame/ui/filesel.cpp
index 36f18005409..704aaba3686 100644
--- a/src/frontend/mame/ui/filesel.cpp
+++ b/src/frontend/mame/ui/filesel.cpp
@@ -304,45 +304,41 @@ void menu_file_selector::select_item(const file_selector_entry &entry)
// type_search_char
//-------------------------------------------------
-void menu_file_selector::type_search_char(char32_t ch)
+void menu_file_selector::update_search()
{
- std::string const current(m_filename);
- if (input_character(m_filename, ch, uchar_is_printable))
- {
- ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename);
+ ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename);
- file_selector_entry const *const cur_selected(reinterpret_cast<file_selector_entry const *>(get_selection_ref()));
+ file_selector_entry const *const cur_selected(reinterpret_cast<file_selector_entry const *>(get_selection_ref()));
- // if it's a perfect match for the current selection, don't move it
- if (!cur_selected || core_strnicmp(cur_selected->basename.c_str(), m_filename.c_str(), m_filename.size()))
+ // if it's a perfect match for the current selection, don't move it
+ if (!cur_selected || core_strnicmp(cur_selected->basename.c_str(), m_filename.c_str(), m_filename.size()))
+ {
+ std::string::size_type bestmatch(0);
+ file_selector_entry const *selected_entry(cur_selected);
+ for (auto &entry : m_entrylist)
{
- std::string::size_type bestmatch(0);
- file_selector_entry const *selected_entry(cur_selected);
- for (auto &entry : m_entrylist)
+ // TODO: more efficient "common prefix" code
+ std::string::size_type match(0);
+ for (std::string::size_type i = 1; m_filename.size() >= i; ++i)
{
- // TODO: more efficient "common prefix" code
- std::string::size_type match(0);
- for (std::string::size_type i = 1; m_filename.size() >= i; ++i)
- {
- if (!core_strnicmp(entry.basename.c_str(), m_filename.c_str(), i))
- match = i;
- else
- break;
- }
-
- if (match > bestmatch)
- {
- bestmatch = match;
- selected_entry = &entry;
- }
+ if (!core_strnicmp(entry.basename.c_str(), m_filename.c_str(), i))
+ match = i;
+ else
+ break;
}
- if (selected_entry && (selected_entry != cur_selected))
+ if (match > bestmatch)
{
- set_selection((void *)selected_entry);
- centre_selection();
+ bestmatch = match;
+ selected_entry = &entry;
}
}
+
+ if (selected_entry && (selected_entry != cur_selected))
+ {
+ set_selection((void *)selected_entry);
+ centre_selection();
+ }
}
}
@@ -448,7 +444,13 @@ void menu_file_selector::handle(event const *ev)
if (ev->iptkey == IPT_SPECIAL)
{
// if it's any other key and we're not maxed out, update
- type_search_char(ev->unichar);
+ if (input_character(m_filename, ev->unichar, uchar_is_printable))
+ update_search();
+ }
+ else if (ev->iptkey == IPT_UI_PASTE)
+ {
+ if (paste_text(m_filename, uchar_is_printable))
+ update_search();
}
else if (ev->iptkey == IPT_UI_CANCEL)
{
diff --git a/src/frontend/mame/ui/filesel.h b/src/frontend/mame/ui/filesel.h
index 3b09244ca20..8fa309c2fb9 100644
--- a/src/frontend/mame/ui/filesel.h
+++ b/src/frontend/mame/ui/filesel.h
@@ -91,7 +91,7 @@ private:
file_selector_entry *append_dirent_entry(const osd::directory::entry *dirent);
void append_entry_menu_item(const file_selector_entry *entry);
void select_item(const file_selector_entry &entry);
- void type_search_char(char32_t ch);
+ void update_search();
};
diff --git a/src/frontend/mame/ui/inputdevices.cpp b/src/frontend/mame/ui/inputdevices.cpp
index 6dba1d49f92..d5c993bd075 100644
--- a/src/frontend/mame/ui/inputdevices.cpp
+++ b/src/frontend/mame/ui/inputdevices.cpp
@@ -13,6 +13,9 @@
#include "inputdev.h"
+// FIXME: allow OSD module headers to be included in a less ugly way
+#include "../osd/modules/lib/osdlib.h"
+
namespace ui {
@@ -82,6 +85,9 @@ protected:
private:
virtual void populate(float &customtop, float &custombottom) override
{
+ item_append(_("menu-inputdev", "Copy Device ID"), 0U, nullptr);
+ item_append(menu_item_type::SEPARATOR);
+
bool haveanalog = false;
for (input_item_id itemid = ITEM_ID_FIRST_VALID; m_device.maxitem() >= itemid; ++itemid)
{
@@ -109,6 +115,15 @@ private:
virtual void handle(event const *ev) override
{
+ // FIXME: hacky, depending on first item being "copy ID", but need a better model for item reference values
+ if (ev && ev->item && (IPT_UI_SELECT == ev->iptkey) && (&item(0) == ev->item))
+ {
+ if (!osd_set_clipboard_text(m_device.id()))
+ machine().popmessage(_("menu-inputdev", "Copied device ID to clipboard"));
+ else
+ machine().popmessage(_("menu-inputdev", "Error copying device ID to clipboard"));
+ }
+
for (int i = 0; item_count() > i; ++i)
{
void *const ref(item(i).ref());
diff --git a/src/frontend/mame/ui/selector.cpp b/src/frontend/mame/ui/selector.cpp
index f8791a37887..93e3ce326d3 100644
--- a/src/frontend/mame/ui/selector.cpp
+++ b/src/frontend/mame/ui/selector.cpp
@@ -69,6 +69,11 @@ void menu_selector::handle(event const *ev)
}
break;
+ case IPT_UI_PASTE:
+ if (paste_text(m_search, uchar_is_printable))
+ reset(reset_options::SELECT_FIRST);
+ break;
+
case IPT_SPECIAL:
if (input_character(m_search, ev->unichar, uchar_is_printable))
reset(reset_options::SELECT_FIRST);
diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp
index bc43ee4b4b8..9b1b3f1e74d 100644
--- a/src/frontend/mame/ui/selmenu.cpp
+++ b/src/frontend/mame/ui/selmenu.cpp
@@ -1583,6 +1583,16 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey)
if (!m_ui_error && machine().ui_input().pressed_repeat(IPT_UI_TOGGLE_CHEAT, 0))
mame_machine_manager::instance()->cheat().set_enable(!mame_machine_manager::instance()->cheat().enabled());
+ // handle pasting text into the search
+ if (exclusive_input_pressed(iptkey, IPT_UI_PASTE, 0))
+ {
+ if (!m_ui_error && accept_search())
+ {
+ if (paste_text(m_search, uchar_is_printable))
+ reset(reset_options::SELECT_FIRST);
+ }
+ }
+
// see if any other UI keys are pressed
if (iptkey == IPT_INVALID)
{
diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp
index 051b09b4fcf..c15fcff7a26 100644
--- a/src/frontend/mame/ui/selsoft.cpp
+++ b/src/frontend/mame/ui/selsoft.cpp
@@ -704,7 +704,7 @@ void menu_select_software::make_topbox_text(std::string &line0, std::string &lin
// determine the text for the header
int vis_item = !m_search.empty() ? m_available_items : (m_available_items - 1);
line0 = string_format(_("%1$s %2$s ( %3$d / %4$d software packages )"), emulator_info::get_appname(), bare_build_version, vis_item, m_data->swinfo().size() - 1);
- line1 = string_format(_("System: \"%1$s\" software list "), m_system.description);
+ line1 = string_format(_("%1$s - select software"), m_system.description);
software_filter const *const it(m_data->current_filter());
char const *const filter(it ? it->filter_text() : nullptr);
diff --git a/src/frontend/mame/ui/simpleselgame.cpp b/src/frontend/mame/ui/simpleselgame.cpp
index 9cd8dd26fbe..9db5ac2218d 100644
--- a/src/frontend/mame/ui/simpleselgame.cpp
+++ b/src/frontend/mame/ui/simpleselgame.cpp
@@ -132,6 +132,10 @@ void simple_menu_select_game::handle(event const *ev)
case IPT_UI_CANCEL:
inkey_cancel();
break;
+ case IPT_UI_PASTE:
+ if (paste_text(m_search, uchar_is_printable))
+ reset(reset_options::SELECT_FIRST);
+ break;
case IPT_SPECIAL:
inkey_special(*ev);
break;
@@ -218,7 +222,7 @@ void simple_menu_select_game::inkey_cancel()
void simple_menu_select_game::inkey_special(const event &menu_event)
{
// typed characters append to the buffer
- size_t old_size = m_search.size();
+ size_t const old_size = m_search.size();
if (input_character(m_search, menu_event.unichar, uchar_is_printable))
{
if (m_search.size() < old_size)
diff --git a/src/frontend/mame/ui/swlist.cpp b/src/frontend/mame/ui/swlist.cpp
index 70c9471da56..5d3c74f8676 100644
--- a/src/frontend/mame/ui/swlist.cpp
+++ b/src/frontend/mame/ui/swlist.cpp
@@ -192,6 +192,54 @@ void menu_software_list::append_software_entry(const software_info &swinfo)
//-------------------------------------------------
+// update_search - update meunu for new search text
+//-------------------------------------------------
+
+void menu_software_list::update_search(void *selectedref)
+{
+ // display the popup
+ ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_search);
+
+ // identify the selected entry
+ entry_info const *const cur_selected = (uintptr_t(selectedref) != 1)
+ ? reinterpret_cast<entry_info const *>(get_selection_ref())
+ : nullptr;
+
+ // if it's a perfect match for the current selection, don't move it
+ if (!cur_selected || core_strnicmp((m_ordered_by_shortname ? cur_selected->short_name : cur_selected->long_name).c_str(), m_search.c_str(), m_search.size()))
+ {
+ std::string::size_type bestmatch(0);
+ entry_info const *selected_entry(cur_selected);
+ for (auto &entry : m_entrylist)
+ {
+ // TODO: more efficient "common prefix" code
+ auto const &compare_name = m_ordered_by_shortname ? entry.short_name : entry.long_name;
+ std::string::size_type match(0);
+ for (std::string::size_type i = 1; m_search.size() >= i; ++i)
+ {
+ if (!core_strnicmp(compare_name.c_str(), m_search.c_str(), i))
+ match = i;
+ else
+ break;
+ }
+
+ if (match > bestmatch)
+ {
+ bestmatch = match;
+ selected_entry = &entry;
+ }
+ }
+
+ if (selected_entry && (selected_entry != cur_selected))
+ {
+ set_selection((void *)selected_entry);
+ centre_selection();
+ }
+ }
+}
+
+
+//-------------------------------------------------
// populate
//-------------------------------------------------
@@ -267,50 +315,15 @@ void menu_software_list::handle(event const *ev)
stack_pop();
}
}
+ else if (ev->iptkey == IPT_UI_PASTE)
+ {
+ if (paste_text(m_search, m_ordered_by_shortname ? is_valid_softlist_part_char : uchar_is_printable))
+ update_search(ev->itemref);
+ }
else if (ev->iptkey == IPT_SPECIAL)
{
- if (input_character(m_search, ev->unichar, m_ordered_by_shortname ? is_valid_softlist_part_char : [] (char32_t ch) { return true; }))
- {
- // display the popup
- ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_search);
-
- // identify the selected entry
- entry_info const *const cur_selected = (uintptr_t(ev->itemref) != 1)
- ? reinterpret_cast<entry_info const *>(get_selection_ref())
- : nullptr;
-
- // if it's a perfect match for the current selection, don't move it
- if (!cur_selected || core_strnicmp((m_ordered_by_shortname ? cur_selected->short_name : cur_selected->long_name).c_str(), m_search.c_str(), m_search.size()))
- {
- std::string::size_type bestmatch(0);
- entry_info const *selected_entry(cur_selected);
- for (auto &entry : m_entrylist)
- {
- // TODO: more efficient "common prefix" code
- auto const &compare_name = m_ordered_by_shortname ? entry.short_name : entry.long_name;
- std::string::size_type match(0);
- for (std::string::size_type i = 1; m_search.size() >= i; ++i)
- {
- if (!core_strnicmp(compare_name.c_str(), m_search.c_str(), i))
- match = i;
- else
- break;
- }
-
- if (match > bestmatch)
- {
- bestmatch = match;
- selected_entry = &entry;
- }
- }
-
- if (selected_entry && (selected_entry != cur_selected))
- {
- set_selection((void *)selected_entry);
- centre_selection();
- }
- }
- }
+ if (input_character(m_search, ev->unichar, m_ordered_by_shortname ? is_valid_softlist_part_char : uchar_is_printable))
+ update_search(ev->itemref);
}
else if (ev->iptkey == IPT_UI_CANCEL)
{
diff --git a/src/frontend/mame/ui/swlist.h b/src/frontend/mame/ui/swlist.h
index 36e5d3c6eaf..b77d8090d7b 100644
--- a/src/frontend/mame/ui/swlist.h
+++ b/src/frontend/mame/ui/swlist.h
@@ -93,6 +93,7 @@ private:
// functions
void append_software_entry(const software_info &swinfo);
+ void update_search(void *selectedref);
};
diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp
index e0c0de0d4ab..3299448a1f4 100644
--- a/src/frontend/mame/ui/ui.cpp
+++ b/src/frontend/mame/ui/ui.cpp
@@ -42,6 +42,8 @@
#include "screen.h"
#include "uiinput.h"
+// FIXME: allow OSD module headers to be included in a less ugly way
+#include "../osd/modules/lib/osdlib.h"
#include "../osd/modules/lib/osdobj_common.h"
#include <chrono>
@@ -1116,6 +1118,7 @@ void mame_ui_manager::decrease_frameskip()
bool mame_ui_manager::can_paste()
{
// check to see if the clipboard is not empty
+ // FIXME: this is expensive - need a cheaper way to check if clipboard contains suitable content
return !osd_get_clipboard_text().empty();
}
diff --git a/src/frontend/mame/ui/utils.h b/src/frontend/mame/ui/utils.h
index 098588086f2..02e88a73b65 100644
--- a/src/frontend/mame/ui/utils.h
+++ b/src/frontend/mame/ui/utils.h
@@ -15,12 +15,17 @@
#include "softlist.h"
#include "unicode.h"
+// FIXME: allow OSD module headers to be included in a less ugly way
+#include "../osd/modules/lib/osdlib.h"
+
#include <algorithm>
#include <functional>
#include <limits>
#include <memory>
#include <string>
+#include <string_view>
#include <unordered_map>
+#include <utility>
#include <vector>
@@ -406,6 +411,8 @@ int getprecisionchr(const char* s);
std::vector<std::string> tokenize(const std::string &text, char sep);
+namespace ui {
+
//-------------------------------------------------
// input_character - inputs a typed character
// into a buffer
@@ -414,31 +421,30 @@ std::vector<std::string> tokenize(const std::string &text, char sep);
template <typename F>
bool input_character(std::string &buffer, std::string::size_type size, char32_t unichar, F &&filter)
{
- bool result = false;
- auto buflen = buffer.size();
-
+ auto const buflen(buffer.length());
if ((unichar == 8) || (unichar == 0x7f))
{
// backspace
if (0 < buflen)
{
- auto buffer_oldend = buffer.c_str() + buflen;
- auto buffer_newend = utf8_previous_char(buffer_oldend);
+ auto const buffer_oldend(buffer.c_str() + buflen);
+ auto const buffer_newend(utf8_previous_char(buffer_oldend));
buffer.resize(buffer_newend - buffer.c_str());
- result = true;
+ return true;
}
}
else if ((unichar >= ' ') && filter(unichar))
{
// append this character - check against the size first
- std::string utf8_char = utf8_from_uchar(unichar);
- if ((buffer.size() + utf8_char.size()) <= size)
+ char utf8char[UTF8_CHAR_MAX];
+ auto const utf8len(utf8_from_uchar(utf8char, std::size(utf8char), unichar));
+ if ((0 < utf8len) && (size >= utf8len) && ((size - utf8len) >= buflen))
{
- buffer += utf8_char;
- result = true;
+ buffer.append(utf8char, utf8len);
+ return true;
}
}
- return result;
+ return false;
}
@@ -450,9 +456,61 @@ bool input_character(std::string &buffer, std::string::size_type size, char32_t
template <typename F>
bool input_character(std::string &buffer, char32_t unichar, F &&filter)
{
- auto size = std::numeric_limits<std::string::size_type>::max();
- return input_character(buffer, size, unichar, filter);
+ auto const size(std::numeric_limits<std::string::size_type>::max());
+ return input_character(buffer, size, unichar, std::forward<F>(filter));
}
+//-------------------------------------------------
+// paste_text - paste text from clipboard into a
+// buffer, ignoring invalid characters
+//-------------------------------------------------
+
+template <typename F>
+bool paste_text(std::string &buffer, std::string::size_type size, F &&filter)
+{
+ std::string const clip(osd_get_clipboard_text());
+ std::string_view text(clip);
+ bool updated(false);
+ int codelength;
+ char32_t unichar;
+ while ((codelength = uchar_from_utf8(&unichar, text)) != 0)
+ {
+ text.remove_prefix((0 < codelength) ? codelength : 1);
+ if ((0 < codelength) && filter(unichar))
+ {
+ char utf8char[UTF8_CHAR_MAX];
+ auto const utf8len(utf8_from_uchar(utf8char, std::size(utf8char), unichar));
+ if (0 < utf8len)
+ {
+ if ((size < utf8len) || ((size - utf8len) < buffer.length()))
+ {
+ return updated;
+ }
+ else
+ {
+ buffer.append(utf8char, utf8len);
+ updated = true;
+ }
+ }
+ }
+ }
+ return updated;
+}
+
+
+//-------------------------------------------------
+// paste_text - paste text from clipboard into a
+// buffer, ignoring invalid characters
+//-------------------------------------------------
+
+template <typename F>
+bool paste_text(std::string &buffer, F &&filter)
+{
+ auto const size(std::numeric_limits<std::string::size_type>::max());
+ return paste_text(buffer, size, std::forward<F>(filter));
+}
+
+} // namespace ui
+
#endif // MAME_FRONTEND_UI_UTILS_H
diff --git a/src/lib/util/bitmap.cpp b/src/lib/util/bitmap.cpp
index 5f4d2adfacb..76eb764e129 100644
--- a/src/lib/util/bitmap.cpp
+++ b/src/lib/util/bitmap.cpp
@@ -289,8 +289,12 @@ void bitmap_t::resize(int width, int height, int xslop, int yslop)
{
// if we need more memory, just realloc
palette_t *const palette = m_palette;
+ if (palette)
+ palette->ref();
allocate(width, height, xslop, yslop);
set_palette(palette);
+ if (palette)
+ palette->deref();
}
else
{
@@ -400,19 +404,15 @@ void bitmap_t::wrap(bitmap_t &source, const rectangle &subrect)
void bitmap_t::set_palette(palette_t *palette)
{
- // first dereference any existing palette
- if (m_palette != nullptr)
- {
+ // first reference the new palette
+ if (palette)
+ palette->ref();
+
+ // then dereference any existing palette
+ if (m_palette)
m_palette->deref();
- m_palette = nullptr;
- }
- // then reference any new palette
- if (palette != nullptr)
- {
- palette->ref();
- m_palette = palette;
- }
+ m_palette = palette;
}
/**
diff --git a/src/lib/util/bitmap.h b/src/lib/util/bitmap.h
index 1b8dee3b5b5..6fe08c0b7d6 100644
--- a/src/lib/util/bitmap.h
+++ b/src/lib/util/bitmap.h
@@ -26,7 +26,7 @@
// bitmap_format describes the various bitmap formats we use
enum bitmap_format
{
- BITMAP_FORMAT_INVALID = 0, // invalid forma
+ BITMAP_FORMAT_INVALID = 0, // invalid format
BITMAP_FORMAT_IND8, // 8bpp indexed
BITMAP_FORMAT_IND16, // 16bpp indexed
BITMAP_FORMAT_IND32, // 32bpp indexed
@@ -301,7 +301,7 @@ public:
bitmap_ind16(uint16_t *base, int width, int height, int rowpixels) : bitmap16_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind16(bitmap_ind16 &source, const rectangle &subrect) : bitmap16_t(k_bitmap_format, source, subrect) { }
void wrap(uint16_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
- void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
+ void wrap(bitmap_ind16 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
@@ -321,7 +321,7 @@ public:
bitmap_ind32(uint32_t *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind32(bitmap_ind32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { }
void wrap(uint32_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
- void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
+ void wrap(bitmap_ind32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
@@ -341,7 +341,7 @@ public:
bitmap_ind64(uint64_t *base, int width, int height, int rowpixels) : bitmap64_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind64(bitmap_ind64 &source, const rectangle &subrect) : bitmap64_t(k_bitmap_format, source, subrect) { }
void wrap(uint64_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
- void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
+ void wrap(bitmap_ind64 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
diff --git a/src/lib/util/unicode.cpp b/src/lib/util/unicode.cpp
index e07984d05b2..a07da6c7759 100644
--- a/src/lib/util/unicode.cpp
+++ b/src/lib/util/unicode.cpp
@@ -386,8 +386,8 @@ int utf8_from_uchar(char *utf8string, size_t count, char32_t uchar)
std::string utf8_from_uchar(char32_t uchar)
{
char buffer[UTF8_CHAR_MAX];
- auto len = utf8_from_uchar(buffer, std::size(buffer), uchar);
- return std::string(buffer, len);
+ auto const len = utf8_from_uchar(buffer, std::size(buffer), uchar);
+ return std::string(buffer, std::max<decltype(len)>(len, 0));
}
diff --git a/src/osd/modules/file/winfile.cpp b/src/osd/modules/file/winfile.cpp
index 199537bbdee..173021121f1 100644
--- a/src/osd/modules/file/winfile.cpp
+++ b/src/osd/modules/file/winfile.cpp
@@ -62,12 +62,12 @@ public:
LARGE_INTEGER largeOffset;
largeOffset.QuadPart = offset;
if (!SetFilePointerEx(m_handle, largeOffset, nullptr, FILE_BEGIN))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
// then perform the read
DWORD result = 0;
if (!ReadFile(m_handle, buffer, length, &result, nullptr))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
actual = result;
return std::error_condition();
@@ -79,12 +79,12 @@ public:
LARGE_INTEGER largeOffset;
largeOffset.QuadPart = offset;
if (!SetFilePointerEx(m_handle, largeOffset, nullptr, FILE_BEGIN))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
// then perform the write
DWORD result = 0;
if (!WriteFile(m_handle, buffer, length, &result, nullptr))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
actual = result;
return std::error_condition();
@@ -96,11 +96,11 @@ public:
LARGE_INTEGER largeOffset;
largeOffset.QuadPart = offset;
if (!SetFilePointerEx(m_handle, largeOffset, nullptr, FILE_BEGIN))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
// then perform the truncation
if (!SetEndOfFile(m_handle))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
else
return std::error_condition();
}
@@ -229,7 +229,7 @@ std::error_condition osd_file::open(std::string const &orig_path, uint32_t openf
// if we still failed, clean up and free
if (INVALID_HANDLE_VALUE == h)
- return win_error_to_file_error(err);
+ return win_error_to_error_condition(err);
}
// get the file size
@@ -259,7 +259,7 @@ std::error_condition osd_file::open(std::string const &orig_path, uint32_t openf
if (NO_ERROR != err)
{
CloseHandle(h);
- return win_error_to_file_error(err);
+ return win_error_to_error_condition(err);
}
}
@@ -299,7 +299,7 @@ std::error_condition osd_file::remove(std::string const &filename) noexcept
std::error_condition filerr;
if (!DeleteFile(tempstr.c_str()))
- filerr = win_error_to_file_error(GetLastError());
+ filerr = win_error_to_error_condition(GetLastError());
return filerr;
}
@@ -415,12 +415,12 @@ std::error_condition osd_get_full_path(std::string &dst, std::string const &path
std::wstring const w_path(osd::text::to_wstring(path));
DWORD const length(GetFullPathNameW(w_path.c_str(), 0, nullptr, nullptr));
if (!length)
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
// allocate a buffer and get the canonical path
std::unique_ptr<wchar_t []> buffer(std::make_unique<wchar_t []>(length));
if (!GetFullPathNameW(w_path.c_str(), length, buffer.get(), nullptr))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
// convert the result back to UTF-8
osd::text::from_wstring(dst, buffer.get());
@@ -534,69 +534,3 @@ bool osd_is_valid_filepath_char(char32_t uchar) noexcept
&& !(uchar >= '\x7F' && uchar <= '\x9F')
&& uchar_isvalid(uchar);
}
-
-
-
-//============================================================
-// win_error_to_file_error
-//============================================================
-
-std::error_condition win_error_to_file_error(DWORD error) noexcept
-{
- // TODO: work out if there's a better way to do this
- switch (error)
- {
- case ERROR_SUCCESS:
- return std::error_condition();
-
- case ERROR_INVALID_HANDLE:
- return std::errc::bad_file_descriptor;
-
- case ERROR_OUTOFMEMORY:
- return std::errc::not_enough_memory;
-
- case ERROR_NOT_SUPPORTED:
- return std::errc::not_supported;
-
- case ERROR_FILE_NOT_FOUND:
- case ERROR_PATH_NOT_FOUND:
- case ERROR_INVALID_NAME:
- return std::errc::no_such_file_or_directory;
-
- case ERROR_FILENAME_EXCED_RANGE:
- return std::errc::filename_too_long;
-
- case ERROR_ACCESS_DENIED:
- case ERROR_SHARING_VIOLATION:
- return std::errc::permission_denied;
-
- case ERROR_ALREADY_EXISTS:
- return std::errc::file_exists;
-
- case ERROR_TOO_MANY_OPEN_FILES:
- return std::errc::too_many_files_open;
-
- case ERROR_WRITE_FAULT:
- case ERROR_READ_FAULT:
- return std::errc::io_error;
-
- case ERROR_HANDLE_DISK_FULL:
- case ERROR_DISK_FULL:
- return std::errc::no_space_on_device;
-
- case ERROR_PATH_BUSY:
- case ERROR_BUSY:
- return std::errc::device_or_resource_busy;
-
- case ERROR_FILE_TOO_LARGE:
- return std::errc::file_too_large;
-
- case ERROR_INVALID_ACCESS:
- case ERROR_NEGATIVE_SEEK:
- case ERROR_BAD_ARGUMENTS:
- return std::errc::invalid_argument;
-
- default:
- return std::error_condition(error, std::system_category());
- }
-}
diff --git a/src/osd/modules/file/winfile.h b/src/osd/modules/file/winfile.h
index 83f0814733d..90cf6e69a60 100644
--- a/src/osd/modules/file/winfile.h
+++ b/src/osd/modules/file/winfile.h
@@ -32,6 +32,4 @@ std::error_condition win_open_socket(std::string const &path, std::uint32_t open
bool win_check_ptty_path(std::string const &path) noexcept;
std::error_condition win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
-std::error_condition win_error_to_file_error(DWORD error) noexcept;
-
#endif // MAME_OSD_MODULES_FILE_WINFILE_H
diff --git a/src/osd/modules/file/winptty.cpp b/src/osd/modules/file/winptty.cpp
index 7feeacce137..9aac0c5a990 100644
--- a/src/osd/modules/file/winptty.cpp
+++ b/src/osd/modules/file/winptty.cpp
@@ -8,11 +8,11 @@
#include "winutil.h"
#include <cassert>
-
-#include <windows.h>
#include <cstdlib>
#include <cstring>
+#include <windows.h>
+
namespace {
@@ -44,7 +44,7 @@ public:
{
DWORD bytes_read;
if (!ReadFile(m_handle, buffer, count, &bytes_read, nullptr))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
actual = bytes_read;
return std::error_condition();
@@ -54,7 +54,7 @@ public:
{
DWORD bytes_written;
if (!WriteFile(m_handle, buffer, count, &bytes_written, nullptr))
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
actual = bytes_written;
return std::error_condition();
@@ -99,7 +99,7 @@ std::error_condition win_open_ptty(std::string const &path, std::uint32_t openfl
if (openflags & OPEN_FLAG_CREATE)
pipe = CreateNamedPipe(t_name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, nullptr);
if (INVALID_HANDLE_VALUE == pipe)
- return win_error_to_file_error(GetLastError());
+ return win_error_to_error_condition(GetLastError());
}
else
{
diff --git a/src/osd/modules/font/font_dwrite.cpp b/src/osd/modules/font/font_dwrite.cpp
index 70edc24c0f1..47a52dbd197 100644
--- a/src/osd/modules/font/font_dwrite.cpp
+++ b/src/osd/modules/font/font_dwrite.cpp
@@ -11,12 +11,19 @@
#if defined(OSD_WINDOWS)
-#include <windows.h>
+#include "corestr.h"
+
+#include "winutil.h"
+
+#include "osdcore.h"
+#include "strconv.h"
#include <cmath>
#include <memory>
#include <stdexcept>
+#include <windows.h>
+
// Windows Imaging Components
#include <wincodec.h>
@@ -34,11 +41,6 @@ DEFINE_GUID(GUID_WICPixelFormat8bppAlpha, 0xe6cd0116, 0xeeba, 0x4161, 0xaa, 0x85
#include <wrl/client.h>
#undef interface
-#include "strconv.h"
-#include "corestr.h"
-#include "winutil.h"
-#include "osdcore.h"
-
using namespace Microsoft::WRL;
//-------------------------------------------------
diff --git a/src/osd/modules/input/input_sdlcommon.cpp b/src/osd/modules/input/input_sdlcommon.cpp
index 659add8dc79..f0d8a8632f6 100644
--- a/src/osd/modules/input/input_sdlcommon.cpp
+++ b/src/osd/modules/input/input_sdlcommon.cpp
@@ -139,11 +139,6 @@ void sdl_event_manager::process_window_event(running_machine &machine, SDL_Event
void sdl_osd_interface::customize_input_type_list(std::vector<input_type_entry> &typelist)
{
- input_item_id mameid_code;
- input_code ui_code;
- const char* uimode;
- char fullmode[64];
-
// loop over the defaults
for (input_type_entry &entry : typelist)
{
@@ -151,22 +146,27 @@ void sdl_osd_interface::customize_input_type_list(std::vector<input_type_entry>
{
// configurable UI mode switch
case IPT_UI_TOGGLE_UI:
- uimode = options().ui_mode_key();
- if (!strcmp(uimode, "auto"))
{
+ char const *const uimode = options().ui_mode_key();
+ input_item_id mameid_code = ITEM_ID_INVALID;
+ if (!uimode || !*uimode || !strcmp(uimode, "auto"))
+ {
#if defined(__APPLE__) && defined(__MACH__)
- mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_INSERT");
-#else
- mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_SCRLOCK");
+ mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_INSERT");
#endif
+ }
+ else
+ {
+ std::string fullmode("ITEM_ID_");
+ fullmode.append(uimode);
+ mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode.c_str());
+ }
+ if (ITEM_ID_INVALID != mameid_code)
+ {
+ input_code const ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
+ entry.defseq(SEQ_TYPE_STANDARD).set(ui_code);
+ }
}
- else
- {
- snprintf(fullmode, 63, "ITEM_ID_%s", uimode);
- mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode);
- }
- ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
- entry.defseq(SEQ_TYPE_STANDARD).set(ui_code);
break;
// alt-enter for fullscreen
case IPT_OSD_1:
diff --git a/src/osd/modules/input/input_windows.cpp b/src/osd/modules/input/input_windows.cpp
index 60306765f72..3b3765ce19e 100644
--- a/src/osd/modules/input/input_windows.cpp
+++ b/src/osd/modules/input/input_windows.cpp
@@ -78,8 +78,6 @@ void windows_osd_interface::poll_input(running_machine &machine) const
void windows_osd_interface::customize_input_type_list(std::vector<input_type_entry> &typelist)
{
- const char* uimode;
-
// loop over the defaults
for (input_type_entry &entry : typelist)
switch (entry.type())
@@ -91,16 +89,18 @@ void windows_osd_interface::customize_input_type_list(std::vector<input_type_ent
break;
// configurable UI mode switch
case IPT_UI_TOGGLE_UI:
- uimode = options().ui_mode_key();
- if (strcmp(uimode, "auto"))
{
- std::string fullmode = "ITEM_ID_";
- fullmode += uimode;
- input_item_id const mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode.c_str());
- if (ITEM_ID_INVALID != mameid_code)
+ char const *const uimode = options().ui_mode_key();
+ if (uimode && *uimode && strcmp(uimode, "auto"))
{
- input_code const ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
- entry.defseq(SEQ_TYPE_STANDARD).set(ui_code);
+ std::string fullmode("ITEM_ID_");
+ fullmode.append(uimode);
+ input_item_id const mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode.c_str());
+ if (ITEM_ID_INVALID != mameid_code)
+ {
+ input_code const ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
+ entry.defseq(SEQ_TYPE_STANDARD).set(ui_code);
+ }
}
}
break;
diff --git a/src/osd/modules/lib/osdlib.h b/src/osd/modules/lib/osdlib.h
index 8ca4762a111..c84901002ad 100644
--- a/src/osd/modules/lib/osdlib.h
+++ b/src/osd/modules/lib/osdlib.h
@@ -12,16 +12,20 @@
// - osd_ticks
// - osd_sleep
//============================================================
+#ifndef MAME_OSD_LIB_OSDLIB_H
+#define MAME_OSD_LIB_OSDLIB_H
-#ifndef __OSDLIB__
-#define __OSDLIB__
+#pragma once
#include <initializer_list>
#include <string>
+#include <string_view>
+#include <system_error>
#include <type_traits>
#include <vector>
#include <memory>
+
/*-----------------------------------------------------------------------------
osd_process_kill: kill the current process
@@ -54,10 +58,22 @@ void osd_process_kill();
int osd_setenv(const char *name, const char *value, int overwrite);
-/*-----------------------------------------------------------------------------
- osd_get_clipboard_text: retrieves text from the clipboard
------------------------------------------------------------------------------*/
-std::string osd_get_clipboard_text();
+/// \brief Get clipboard text
+///
+/// Gets current clipboard content as UTF-8 text. Returns an empty
+/// string if the clipboard contents cannot be converted to plain text.
+/// \return Clipboard contents or an empty string.
+std::string osd_get_clipboard_text() noexcept;
+
+
+/// \brief Set clipboard text
+///
+/// Sets the desktop environment's clipboard contents to the supplied
+/// UTF-8 text. The contents of the clipboard may be changed on error.
+/// \param [in] text The text to copy to the clipboard.
+/// \return An error condition if the operation failed or is
+/// unsupported.
+std::error_condition osd_set_clipboard_text(std::string_view text) noexcept;
namespace osd {
@@ -193,4 +209,4 @@ protected:
#define OSD_DYNAMIC_CALL(fname, ...) (*m_##fname##_pfn) ( __VA_ARGS__ )
#define OSD_DYNAMIC_API_TEST(fname) (m_##fname##_pfn != nullptr)
-#endif /* __OSDLIB__ */
+#endif // MAME_OSD_LIB_OSDLIB_H
diff --git a/src/osd/modules/lib/osdlib_macosx.cpp b/src/osd/modules/lib/osdlib_macosx.cpp
index 19b228b6369..8f61bb4e998 100644
--- a/src/osd/modules/lib/osdlib_macosx.cpp
+++ b/src/osd/modules/lib/osdlib_macosx.cpp
@@ -85,7 +85,7 @@ void osd_break_into_debugger(const char *message)
// osd_get_clipboard_text
//============================================================
-std::string osd_get_clipboard_text()
+std::string osd_get_clipboard_text() noexcept
{
std::string result;
bool has_result = false;
@@ -121,31 +121,48 @@ std::string osd_get_clipboard_text()
CFStringEncoding encoding;
if (UTTypeConformsTo(flavor_type, kUTTypeUTF16PlainText))
encoding = kCFStringEncodingUTF16;
- else if (UTTypeConformsTo (flavor_type, kUTTypeUTF8PlainText))
+ else if (UTTypeConformsTo(flavor_type, kUTTypeUTF8PlainText))
encoding = kCFStringEncodingUTF8;
- else if (UTTypeConformsTo (flavor_type, kUTTypePlainText))
+ else if (UTTypeConformsTo(flavor_type, kUTTypePlainText))
encoding = kCFStringEncodingMacRoman;
else
continue;
CFDataRef flavor_data;
err = PasteboardCopyItemFlavorData(pasteboard_ref, item_id, flavor_type, &flavor_data);
+ if (err)
+ continue;
- if (!err)
+ CFDataRef utf8_data;
+ if (kCFStringEncodingUTF8 == encoding)
+ {
+ utf8_data = flavor_data;
+ }
+ else
{
CFStringRef string_ref = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, flavor_data, encoding);
- CFDataRef data_ref = CFStringCreateExternalRepresentation (kCFAllocatorDefault, string_ref, kCFStringEncodingUTF8, '?');
- CFRelease(string_ref);
CFRelease(flavor_data);
+ if (!string_ref)
+ continue;
- CFIndex const length = CFDataGetLength(data_ref);
- CFRange const range = CFRangeMake(0, length);
-
- result.resize(length);
- CFDataGetBytes(data_ref, range, reinterpret_cast<unsigned char *>(&result[0]));
- has_result = true;
+ utf8_data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, string_ref, kCFStringEncodingUTF8, '?');
+ CFRelease(string_ref);
+ }
- CFRelease(data_ref);
+ if (utf8_data)
+ {
+ CFIndex const length = CFDataGetLength(utf8_data);
+ CFRange const range = CFRangeMake(0, length);
+ try
+ {
+ result.resize(length);
+ CFDataGetBytes(utf8_data, range, reinterpret_cast<UInt8 *>(result.data()));
+ has_result = true;
+ }
+ catch (std::bad_alloc const &)
+ {
+ }
+ CFRelease(utf8_data);
}
}
@@ -157,6 +174,46 @@ std::string osd_get_clipboard_text()
return result;
}
+
+//============================================================
+// osd_set_clipboard_text
+//============================================================
+
+std::error_condition osd_set_clipboard_text(std::string_view text) noexcept
+{
+ // FIXME: better conversion of OSStatus to std::error_condition
+ OSStatus err;
+
+ CFDataRef const data = CFDataCreate(kCFAllocatorDefault, reinterpret_cast<UInt8 const *>(text.data()), text.length());
+ if (!data)
+ return std::errc::not_enough_memory;
+
+ PasteboardRef pasteboard_ref;
+ err = PasteboardCreate(kPasteboardClipboard, &pasteboard_ref);
+ if (err)
+ {
+ CFRelease(data);
+ return std::errc::io_error;
+ }
+
+ err = PasteboardClear(pasteboard_ref);
+ if (err)
+ {
+ CFRelease(data);
+ CFRelease(pasteboard_ref);
+ return std::errc::io_error;
+ }
+
+ err = PasteboardPutItemFlavor(pasteboard_ref, PasteboardItemID(1), kUTTypeUTF8PlainText, data, kPasteboardFlavorNoFlags);
+ CFRelease(data);
+ CFRelease(pasteboard_ref);
+ if (err)
+ return std::errc::io_error;
+
+ return std::error_condition();
+}
+
+
//============================================================
// osd_getpid
//============================================================
diff --git a/src/osd/modules/lib/osdlib_unix.cpp b/src/osd/modules/lib/osdlib_unix.cpp
index 4b091450116..0c6eb8622ab 100644
--- a/src/osd/modules/lib/osdlib_unix.cpp
+++ b/src/osd/modules/lib/osdlib_unix.cpp
@@ -69,28 +69,66 @@ void osd_break_into_debugger(const char *message)
}
#ifdef SDLMAME_ANDROID
-std::string osd_get_clipboard_text()
+std::string osd_get_clipboard_text() noexcept
{
return std::string();
}
+
+std::error_condition osd_set_clipboard_text(std::string_view text) noexcept
+{
+ return std::errc::io_error; // TODO: better error code?
+}
#else
//============================================================
// osd_get_clipboard_text
//============================================================
-std::string osd_get_clipboard_text()
+std::string osd_get_clipboard_text() noexcept
{
+ // TODO: better error handling
std::string result;
if (SDL_HasClipboardText())
{
- char *temp = SDL_GetClipboardText();
- result.assign(temp);
- SDL_free(temp);
+ char *const temp = SDL_GetClipboardText();
+ if (temp)
+ {
+ try
+ {
+ result.assign(temp);
+ }
+ catch (std::bad_alloc const &)
+ {
+ }
+ SDL_free(temp);
+ }
}
return result;
}
+
+//============================================================
+// osd_set_clipboard_text
+//============================================================
+
+std::error_condition osd_set_clipboard_text(std::string_view text) noexcept
+{
+ try
+ {
+ std::string const clip(text); // need to do this to ensure there's a terminating NUL for SDL
+ if (0 > SDL_SetClipboardText(clip.c_str()))
+ {
+ // SDL_GetError returns a message, can't really convert it to an error condition
+ return std::errc::io_error; // TODO: better error code?
+ }
+
+ return std::error_condition();
+ }
+ catch (std::bad_alloc const &)
+ {
+ return std::errc::not_enough_memory;
+ }
+}
#endif
//============================================================
diff --git a/src/osd/modules/lib/osdlib_win32.cpp b/src/osd/modules/lib/osdlib_win32.cpp
index 174dc769760..d209e98c474 100644
--- a/src/osd/modules/lib/osdlib_win32.cpp
+++ b/src/osd/modules/lib/osdlib_win32.cpp
@@ -14,10 +14,10 @@
#include "osdcore.h"
#include "strconv.h"
-#ifdef OSD_WINDOWS
#include "winutf8.h"
-#endif
+#include "winutil.h"
+#include <algorithm>
#include <cstdio>
#include <cstdlib>
@@ -168,21 +168,88 @@ static std::string convert_ansi(LPCVOID data)
// osd_get_clipboard_text
//============================================================
-std::string osd_get_clipboard_text()
+std::string osd_get_clipboard_text() noexcept
{
std::string result;
- // try to access unicode text
- if (!get_clipboard_text_by_format(result, CF_UNICODETEXT, convert_wide))
+ // TODO: better error handling
+ try
+ {
+ // try to access unicode text
+ if (!get_clipboard_text_by_format(result, CF_UNICODETEXT, convert_wide))
+ {
+ // try to access ANSI text
+ get_clipboard_text_by_format(result, CF_TEXT, convert_ansi);
+ }
+ }
+ catch (...)
{
- // try to access ANSI text
- get_clipboard_text_by_format(result, CF_TEXT, convert_ansi);
}
return result;
}
//============================================================
+// osd_set_clipboard_text
+//============================================================
+
+std::error_condition osd_set_clipboard_text(std::string_view text) noexcept
+{
+ try
+ {
+ // convert the text to a wide char string and create a moveable global block
+ std::wstring const wtext = osd::text::to_wstring(text);
+ HGLOBAL const clip = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(wchar_t));
+ if (!clip)
+ return win_error_to_error_condition(GetLastError());
+ LPWSTR const lock = reinterpret_cast<LPWSTR>(GlobalLock(clip));
+ if (!lock)
+ {
+ DWORD const err(GetLastError());
+ GlobalFree(clip);
+ return win_error_to_error_condition(err);
+ }
+
+ // clear current clipboard contents
+ if (!OpenClipboard(nullptr))
+ {
+ DWORD const err(GetLastError());
+ GlobalUnlock(clip);
+ GlobalFree(clip);
+ return win_error_to_error_condition(err);
+ }
+ if (!OpenClipboard(nullptr))
+ {
+ DWORD const err(GetLastError());
+ CloseClipboard();
+ GlobalUnlock(clip);
+ GlobalFree(clip);
+ return win_error_to_error_condition(err);
+ }
+
+ // copy the text (plus NUL terminator) to the moveable block and put it on the clipboard
+ std::copy_n(wtext.c_str(), wtext.length() + 1, lock);
+ GlobalUnlock(clip);
+ if (!SetClipboardData(CF_UNICODETEXT, clip))
+ {
+ DWORD const err(GetLastError());
+ CloseClipboard();
+ GlobalFree(clip);
+ return win_error_to_error_condition(err);
+ }
+
+ // clean up
+ if (!CloseClipboard())
+ return win_error_to_error_condition(GetLastError());
+ return std::error_condition();
+ }
+ catch (std::bad_alloc const &)
+ {
+ return std::errc::not_enough_memory;
+ }
+}
+
+//============================================================
// osd_getpid
//============================================================
diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp
index 1019bc4f766..09254f32042 100644
--- a/src/osd/modules/lib/osdobj_common.cpp
+++ b/src/osd/modules/lib/osdobj_common.cpp
@@ -32,7 +32,7 @@ const options_entry osd_options::s_option_entries[] =
#if defined(SDLMAME_MACOSX) || defined(OSD_MAC)
{ OSDOPTION_UIMODEKEY, "DEL", core_options::option_type::STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" },
#else
- { OSDOPTION_UIMODEKEY, "SCRLOCK", core_options::option_type::STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" },
+ { OSDOPTION_UIMODEKEY, "auto", core_options::option_type::STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" },
#endif // SDLMAME_MACOSX
{ nullptr, nullptr, core_options::option_type::HEADER, "OSD FONT OPTIONS" },
diff --git a/src/osd/osdcore.h b/src/osd/osdcore.h
index d9f61c22a5a..489343f35b4 100644
--- a/src/osd/osdcore.h
+++ b/src/osd/osdcore.h
@@ -11,7 +11,6 @@
#pragma once
-
#include "osdcomm.h"
#include "strformat.h"
@@ -19,6 +18,7 @@
#include <cstdint>
#include <iosfwd>
#include <string>
+#include <string_view>
#include <utility>
#include <vector>
@@ -350,13 +350,6 @@ void osd_work_item_release(osd_work_item *item);
void osd_break_into_debugger(const char *message);
-/// \brief Get clipboard text
-///
-/// Gets current clipboard content as UTF-8 text. Returns an empty
-/// string if the clipboard contents cannot be converted to plain text.
-/// \return Clipboard contents or an empty string.
-std::string osd_get_clipboard_text();
-
/***************************************************************************
UNCATEGORIZED INTERFACES
diff --git a/src/osd/windows/winutil.cpp b/src/osd/windows/winutil.cpp
index 3a344386a12..3ee4ffde376 100644
--- a/src/osd/windows/winutil.cpp
+++ b/src/osd/windows/winutil.cpp
@@ -129,3 +129,68 @@ HMODULE WINAPI GetModuleHandleUni()
VirtualQuery((LPCVOID)GetModuleHandleUni, &mbi, sizeof(mbi));
return (HMODULE)mbi.AllocationBase;
}
+
+
+//============================================================
+// win_error_to_error_condition
+//============================================================
+
+std::error_condition win_error_to_error_condition(DWORD error) noexcept
+{
+ // TODO: work out if there's a better way to do this
+ switch (error)
+ {
+ case ERROR_SUCCESS:
+ return std::error_condition();
+
+ case ERROR_INVALID_HANDLE:
+ return std::errc::bad_file_descriptor;
+
+ case ERROR_OUTOFMEMORY:
+ return std::errc::not_enough_memory;
+
+ case ERROR_NOT_SUPPORTED:
+ return std::errc::not_supported;
+
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_INVALID_NAME:
+ return std::errc::no_such_file_or_directory;
+
+ case ERROR_FILENAME_EXCED_RANGE:
+ return std::errc::filename_too_long;
+
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ return std::errc::permission_denied;
+
+ case ERROR_ALREADY_EXISTS:
+ return std::errc::file_exists;
+
+ case ERROR_TOO_MANY_OPEN_FILES:
+ return std::errc::too_many_files_open;
+
+ case ERROR_WRITE_FAULT:
+ case ERROR_READ_FAULT:
+ return std::errc::io_error;
+
+ case ERROR_HANDLE_DISK_FULL:
+ case ERROR_DISK_FULL:
+ return std::errc::no_space_on_device;
+
+ case ERROR_PATH_BUSY:
+ case ERROR_BUSY:
+ return std::errc::device_or_resource_busy;
+
+ case ERROR_FILE_TOO_LARGE:
+ return std::errc::file_too_large;
+
+ case ERROR_INVALID_ACCESS:
+ case ERROR_NEGATIVE_SEEK:
+ case ERROR_BAD_ARGUMENTS:
+ return std::errc::invalid_argument;
+
+ default:
+ return std::error_condition(error, std::system_category());
+ }
+}
diff --git a/src/osd/windows/winutil.h b/src/osd/windows/winutil.h
index 0a5952b5279..85393b6b930 100644
--- a/src/osd/windows/winutil.h
+++ b/src/osd/windows/winutil.h
@@ -13,8 +13,8 @@
#include "osdfile.h"
-#include <algorithm>
#include <chrono>
+#include <system_error>
#include <windows.h>
@@ -25,4 +25,6 @@ std::chrono::system_clock::time_point win_time_point_from_filetime(LPFILETIME fi
BOOL win_is_gui_application();
HMODULE WINAPI GetModuleHandleUni();
+std::error_condition win_error_to_error_condition(DWORD error) noexcept;
+
#endif // MAME_OSD_WINDOWS_WINUTIL_H