diff options
author | 2022-09-02 08:55:16 +1000 | |
---|---|---|
committer | 2022-09-02 08:55:16 +1000 | |
commit | 051c380fd14040c83a0d5b919e6289e70fef9df8 (patch) | |
tree | e247a309f4d1c66c07803c02d67ac89837211bd1 /src | |
parent | 67f129e31518a50a801413f732991972d2c3538a (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')
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 ®istry, 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 ®istry, 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 ®istry, 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 |