mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
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.
This commit is contained in:
parent
67f129e315
commit
051c380fd1
@ -228,3 +228,34 @@ Here’s an example that overrides defaults for 280-ZZZAP:
|
||||
|
||||
This sets the controls to steer left and right to the K and J keys,
|
||||
respectively, and disables the toggle setting for the gear shift input.
|
||||
|
||||
|
||||
.. _ctrlrcfg-mapdevice:
|
||||
|
||||
Assigning input device numbers
|
||||
------------------------------
|
||||
|
||||
Use ``mapdevice`` elements with ``device`` and ``controller`` attributes to
|
||||
assign stable numbers to input devices. Note that all devices explicitly
|
||||
configured in this way must be connected when MAME starts for this to work as
|
||||
expected.
|
||||
|
||||
Set the ``device`` attribute to the device ID of the input device, and set the
|
||||
``controller`` attribute to the desired input device token (device type and
|
||||
number).
|
||||
|
||||
Here’s an example numbering two light guns and two XInput game controllers:
|
||||
|
||||
.. code-block:: XML
|
||||
|
||||
<system name="default">
|
||||
<input>
|
||||
<mapdevice device="VID_D209&PID_1601" controller="GUNCODE_1" />
|
||||
<mapdevice device="VID_D209&PID_1602" controller="GUNCODE_2" />
|
||||
<mapdevice device="XInput Player 1" controller="JOYCODE_1" />
|
||||
<mapdevice device="XInput Player 2" controller="JOYCODE_2" />
|
||||
</input>
|
||||
</system>
|
||||
|
||||
MAME applies ``mapdevice`` elements found inside any applicable ``system``
|
||||
element.
|
||||
|
@ -1,26 +1,52 @@
|
||||
.. _devicemap:
|
||||
|
||||
Stable Controller IDs
|
||||
===============================
|
||||
=====================
|
||||
|
||||
By default, the mapping between devices and controller IDs is not stable. For instance, a gamepad controller may be assigned to "Joy 1" initially, but after a reboot, it may get re-assigned to "Joy 3".
|
||||
By default, MAME does not assign stable numbers to input devices. For instance,
|
||||
a game pad controller may be assigned to “Joy 1” initially, but after
|
||||
restarting, the same game pad may be reassigned to “Joy 3”.
|
||||
|
||||
The reason is that MAME enumerates attached devices and assigns controller IDs based on the enumeration order. Factors that can cause controller IDs to change include plugging / unplugging USB devices, changing ports / hubs and even system reboots.
|
||||
The reason is that MAME assigns numbers to input devices in the based on
|
||||
enumeration order. Factors that can cause this to change include disconnecting
|
||||
and reconnecting USB or Bluetooth devices, changing ports/hubs, and even just
|
||||
restarting the computer. Input device numbers can be quite unpredictable.
|
||||
|
||||
It is quite cumbersome to ensure that controller IDs are always correct.
|
||||
This is where the ``mapdevice`` configuration setting comes into the picture.
|
||||
By adding this setting to a :ref:`controller configuration file <ctrlrcfg>`, you
|
||||
can ensure that a given input device is always assigned the same number in MAME.
|
||||
|
||||
That's where the "mapdevice" configuration setting comes into the picture. This setting allows you to map a device id to a controller ID, ensuring that the specified device always maps to the same controller ID in MAME.
|
||||
|
||||
Usage of mapdevice
|
||||
------------------
|
||||
The "mapdevice" xml element is specified under the input xml element in the controller configuration file. It requires two attributes, "device" and "controller".
|
||||
NOTE: This setting only take effect when added to the **ctrlr** config file.
|
||||
Using mapdevice
|
||||
---------------
|
||||
|
||||
The "device" attribute specifies the id of the device to match. It may also be a substring of the id. To see the list of available devices, enable verbose output and available devices will then be listed to the console at startup (more on this below).
|
||||
The ``mapdevice`` XML element is added to the ``input`` XML element in the
|
||||
controller configuration file. It requires two attributes, ``device`` and
|
||||
``controller``. Note that ``mapdevice`` elements only take effect in the
|
||||
controller configuration file (set using the :ref:`-ctrlr option
|
||||
<mame-commandline-ctrlr>`) – they are ignored in system configuration files and
|
||||
the default configuration file.
|
||||
|
||||
The ``device`` attribute specifies the device ID of the input device to match.
|
||||
It may also be a substring of the device ID. To obtain the device ID for an
|
||||
input device, select it in the :ref:`menus-inputdevices`, and then select **Copy
|
||||
Device ID**. The device ID will be copied to the clipboard. You can also see
|
||||
input device IDs by turning on verbose logging (more on this later). The format
|
||||
of device IDs depends the type of device, selected input provider module and
|
||||
operating system. Your input device IDs may look very different to the examples
|
||||
here.
|
||||
|
||||
The ``controller`` attribute specifies the input token for the input device type
|
||||
(i.e. ``JOYCODE``, ``GUNCODE``, ``MOUSECODE``) and number to assign to the
|
||||
device, separated by an underscore. Numbering starts from 1. For example the
|
||||
token for the first joystick device will be ``JOYCODE_1``, the second will be
|
||||
``JOYCODE_2``, and so on.
|
||||
|
||||
The "controller" attribute specifies the MAME controller ID. It is made up of a controller class (i.e. ``JOYCODE``, ``GUNCODE``, ``MOUSECODE``) and controller index. For example: ``JOYCODE_1``.
|
||||
|
||||
Example
|
||||
-------
|
||||
Here's an example:
|
||||
|
||||
Here’s an example:
|
||||
|
||||
| <mameconfig version="10">
|
||||
| <system name="default">
|
||||
@ -40,37 +66,71 @@ Here's an example:
|
||||
|
||||
In the above example, we have four device mappings specified:
|
||||
|
||||
The first two mapdevice entries map player 1 and 2 lightguns to Gun 1 and Gun 2, respectively. We use a substring of the full raw device names to match each devices. Note that, since this is XML, we needed to escape the ``&`` using ``&``.
|
||||
* The first two ``mapdevice`` elements map player 1 and 2 light guns to Gun 1
|
||||
and Gun 2, respectively. We use a substring of the full device IDs to match
|
||||
each devices. Note that, since this is XML, we needed to escape the
|
||||
ampersands (``&``) as ``&``.
|
||||
* The last two ``mapdevices`` elements map player 1 and player 2 gamepad
|
||||
controllers to Joy 1 and Joy 2, respectively. In this case, these are XInput
|
||||
game controllers.
|
||||
|
||||
The last two mapdevices entries map player 1 and player 2 gamepad controllers to Joy 1 and Joy 2, respectively. In this case, these are XInput devices.
|
||||
|
||||
Listing Available Devices
|
||||
-------------------------
|
||||
How did we obtain the device id's in the above example? Easy!
|
||||
|
||||
Run MAME with -v parameter to enable verbose output. It will then list available devices include the corresponding "device id" to the console.
|
||||
There are two ways to obtain device IDs: by copying them from the
|
||||
:ref:`menus-inputdevices`, or by :ref:`turning on verbose logging
|
||||
<mame-commandline-verbose>` and finding the messages logged when input devices
|
||||
are added.
|
||||
|
||||
To reach the Input Devices menu from the system selection menu, select **General
|
||||
Settings**, and the select **Input Devices**. To reach the input devices menu
|
||||
from the :ref:`main menu <menus-main>`, select **Input Settings**, then select
|
||||
**Input Devices**. From the Input Devices menu, select a device, then select
|
||||
**Copy Device ID** to copy its device ID to the clipboard.
|
||||
|
||||
To use verbose logging, run MAME with the ``-v`` or ``-verbose`` option on the
|
||||
command line. Search the output for messages starting with “Input: Adding…”
|
||||
that show recognised input devices and their respective IDs.
|
||||
|
||||
Here an example:
|
||||
|
||||
| Input: Adding Gun #0:
|
||||
| Input: Adding Gun #1:
|
||||
| Input: Adding Gun #2: HID-compliant mouse (**device id: \\?\HID#VID_045E&PID_0053#7&18297dcb&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}**)
|
||||
| Input: Adding Gun #3: HID-compliant mouse (**device id: \\?\HID#IrDeviceV2&Col08#2&2818a073&0&0007#{378de44c-56ef-11d1-bc8c-00a0c91405dd}**)
|
||||
| Input: Adding Gun #4: HID-compliant mouse (**device id: \\?\HID#VID_D209&PID_1602&MI_02#8&389ab7f3&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}**)
|
||||
| Input: Adding Gun #5: HID-compliant mouse (**device id: \\?\HID#VID_D209&PID_1601&MI_02#9&375eebb1&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}**)
|
||||
| Input: Adding Gun #6: HID-compliant mouse (**device id: \\?\HID#VID_1241&PID_1111#8&198f3adc&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}**)
|
||||
| Input: Adding lightgun #1:
|
||||
| Input: Adding lightgun #2:
|
||||
| Input: Adding lightgun #3: HID-compliant mouse (**device id: \\\\?\\HID#VID_045E&PID_0053#7&18297dcb&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}**)
|
||||
| Input: Adding lightgun #4: HID-compliant mouse (**device id: \\\\?\\HID#IrDeviceV2&Col08#2&2818a073&0&0007#{378de44c-56ef-11d1-bc8c-00a0c91405dd}**)
|
||||
| Input: Adding lightgun #5: HID-compliant mouse (**device id: \\\\?\\HID#VID_D209&PID_1602&MI_02#8&389ab7f3&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}**)
|
||||
| Input: Adding lightgun #6: HID-compliant mouse (**device id: \\\\?\\HID#VID_D209&PID_1601&MI_02#9&375eebb1&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}**)
|
||||
| Input: Adding lightgun #7: HID-compliant mouse (**device id: \\\\?\\HID#VID_1241&PID_1111#8&198f3adc&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}**)
|
||||
| Skipping DirectInput for XInput compatible joystick Controller (XBOX 360 For Windows).
|
||||
| Input: Adding Joy #0: ATRAK Device #1 (**device id: ATRAK Device #1**)
|
||||
| Input: Adding joystick #1: ATRAK Device #1 (**device id: ATRAK Device #1**)
|
||||
| Skipping DirectInput for XInput compatible joystick Controller (XBOX 360 For Windows).
|
||||
| Input: Adding Joy #1: ATRAK Device #2 (**device id: ATRAK Device #2**)
|
||||
| Input: Adding Joy #2: XInput Player 1 (**device id: XInput Player 1**)
|
||||
| Input: Adding Joy #3: XInput Player 2 (**device id: XInput Player 2**)
|
||||
| Input: Adding joystick #2: ATRAK Device #2 (**device id: ATRAK Device #2**)
|
||||
| Input: Adding joystick #3: XInput Player 1 (**device id: XInput Player 1**)
|
||||
| Input: Adding joystick #4: XInput Player 2 (**device id: XInput Player 2**)
|
||||
|
|
||||
|
||||
Furthermore, when devices are mapped using mapdevice, you'll see that in the verbose logging too, such as:
|
||||
Furthermore, when devices are reassigned using ``mapdevice`` elements in the
|
||||
controller configuration file, you’ll see that in the verbose log output, too,
|
||||
such as:
|
||||
|
||||
| Input: Remapped Gun #0: HID-compliant mouse (device id: \\?\HID#VID_D209&PID_1601&MI_02#9&375eebb1&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd})
|
||||
| Input: Remapped Gun #1: HID-compliant mouse (device id: \\?\HID#VID_D209&PID_1602&MI_02#8&389ab7f3&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd})
|
||||
| Input: Remapped Joy #0: XInput Player 1 (device id: XInput Player 1)
|
||||
| Input: Remapped Joy #1: XInput Player 2 (device id: XInput Player 2)
|
||||
| Input: Remapped lightgun #1: HID-compliant mouse (device id: \\\\?\\HID#VID_D209&PID_1601&MI_02#9&375eebb1&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd})
|
||||
| Input: Remapped lightgun #2: HID-compliant mouse (device id: \\\\?\\HID#VID_D209&PID_1602&MI_02#8&389ab7f3&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd})
|
||||
| Input: Remapped joystick #1: XInput Player 1 (device id: XInput Player 1)
|
||||
| Input: Remapped joystick #2: XInput Player 2 (device id: XInput Player 2)
|
||||
|
|
||||
|
||||
Note that the devices numbers in the verbose log output are zero-based, while
|
||||
the device numbers shown in MAME’s user interface and set in configuration files
|
||||
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
You can only assign stable numbers to devices if MAME receives stable, unique
|
||||
device IDs from the input device provider and operating system. This is not
|
||||
always the case. For example the SDL joystick provider is not capable of
|
||||
providing unique IDs for many USB game controllers.
|
||||
|
||||
If not all configured devices are connected when MAME starts, the devices that
|
||||
are connected may not be numbered as expected.
|
||||
|
@ -870,8 +870,8 @@ Palette device
|
||||
Wraps MAME’s ``device_palette_interface`` class, which represents a device that
|
||||
translates pen values to colours.
|
||||
|
||||
Colours are in alpha/red/green/blue (ARGB) format. Channel values are in the
|
||||
range 0 (transparent or off) to 255 (opaque or full intensity), inclusive.
|
||||
Colours are represented in alpha/red/green/blue (ARGB) format. Channel values
|
||||
range from 0 (transparent or off) to 255 (opaque or full intensity), inclusive.
|
||||
Colour channel values are not pre-multiplied by the alpha value. Channel values
|
||||
are packed into the bytes of 32-bit unsigned integers, in the order alpha, red,
|
||||
green, blue from most-significant to least-significant byte.
|
||||
@ -931,6 +931,9 @@ palette:set_shadow_mode(mode)
|
||||
Properties
|
||||
^^^^^^^^^^
|
||||
|
||||
palette.palette (read-only)
|
||||
The underlying :ref:`palette <luareference-render-palette>` managed by the
|
||||
device.
|
||||
palette.entries (read-only)
|
||||
The number of colour entries in the palette.
|
||||
palette.indirect_entries (read-only)
|
||||
@ -1001,10 +1004,12 @@ screen:pixel(x, y)
|
||||
packed into a 32-bit integer. Returns zero (0) if the specified point is
|
||||
outside the visible area.
|
||||
screen:pixels()
|
||||
Returns all visible pixels as 32-bit integers packed into a binary string in
|
||||
host Endian order. Pixels are organised in row-major order, from left to
|
||||
right then top to bottom. Pixels values are either palette indices or
|
||||
colours in RGB format packed into 32-bit integers.
|
||||
Returns all visible pixels, the visible area width and visible area height.
|
||||
|
||||
Pixels are returned as 32-bit integers packed into a binary string in host
|
||||
Endian order. Pixels are organised in row-major order, from left to right
|
||||
then top to bottom. Pixels values are either palette indices or colours in
|
||||
RGB format packed into 32-bit integers.
|
||||
screen:draw_box(left, top, right, bottom, [line], [fill])
|
||||
Draws an outlined rectangle with edges at the specified positions.
|
||||
|
||||
@ -2699,12 +2704,140 @@ color.b (read/write)
|
||||
Blue channel value, in the range of zero (0, off) to one (1, full
|
||||
intensity).
|
||||
|
||||
.. _luareference-render-palette:
|
||||
|
||||
Palette
|
||||
~~~~~~~
|
||||
|
||||
Wraps MAME’s ``palette_t`` class, which represents a table of colours that can
|
||||
be looked up by zero-based index. Palettes always contain additional special
|
||||
entries for black and white.
|
||||
|
||||
Each colour has an associated contrast adjustment value. Each adjustment group
|
||||
has associated brightness and contrast adjustment values. The palette also has
|
||||
overall brightness, contrast and gamma adjustment values.
|
||||
|
||||
Colours are represented in alpha/red/green/blue (ARGB) format. Channel values
|
||||
range from 0 (transparent or off) to 255 (opaque or full intensity), inclusive.
|
||||
Colour channel values are not pre-multiplied by the alpha value. Channel values
|
||||
are packed into the bytes of 32-bit unsigned integers, in the order alpha, red,
|
||||
green, blue from most-significant to least-significant byte.
|
||||
|
||||
Instantiation
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
emu.palette(colors, [groups])
|
||||
Creates a palette with the specified number of colours and
|
||||
brightness/contrast adjustment groups. The number of colour groups defaults
|
||||
to one if not specified. Colours are initialised to black, brightness
|
||||
adjustment is initialised to 0.0, contrast adjustment initialised to 1.0,
|
||||
and gamma adjustment is initialised to 1.0.
|
||||
|
||||
Methods
|
||||
^^^^^^^
|
||||
|
||||
palette:entry_color(index)
|
||||
Gets the colour at the specified zero-based index.
|
||||
|
||||
Index values range from zero to the number of colours in the palette minus
|
||||
one. Returns black if the index is greater than or equal to the number of
|
||||
colours in the palette.
|
||||
palette:entry_contrast(index)
|
||||
Gets the contrast adjustment for the colour at the specified zero-based
|
||||
index. This is a floating-point number.
|
||||
|
||||
Index values range from zero to the number of colours in the palette minus
|
||||
one. Returns 1.0 if the index is greater than or equal to the number of
|
||||
colours in the palette.
|
||||
palette:entry_adjusted_color(index, [group])
|
||||
Gets a colour with brightness, contrast and gamma adjustments applied.
|
||||
|
||||
If the group is specified, colour index values range from zero to the number
|
||||
of colours in the palette minus one, and group values range from zero to the
|
||||
number of adjustment groups in the palette minus one.
|
||||
|
||||
If the group is not specified, index values range from zero to the number of
|
||||
colours multiplied by the number of adjustment groups plus one. Index
|
||||
values may be calculated by multiplying the zero-based group index by the
|
||||
number of colours in the palette, and adding the zero-based colour index.
|
||||
The last two index values correspond to the special entries for black and
|
||||
white, respectively.
|
||||
|
||||
Returns black if the specified combination of index and adjustment group is
|
||||
invalid.
|
||||
palette:entry_set_color(index, color)
|
||||
Sets the colour at the specified zero-based index. The colour may be
|
||||
specified as a single packed 32-bit value; or as individual red, green and
|
||||
blue channel values, in that order.
|
||||
|
||||
Index values range from zero to the number of colours in the palette minus
|
||||
one. Raises an error if the index value is invalid.
|
||||
palette:entry_set_red_level(index, level)
|
||||
Sets the red channel value of the colour at the specified zero-based index.
|
||||
Other channel values are not affected.
|
||||
|
||||
Index values range from zero to the number of colours in the palette minus
|
||||
one. Raises an error if the index value is invalid.
|
||||
palette:entry_set_green_level(index, level)
|
||||
Sets the green channel value of the colour at the specified zero-based
|
||||
index. Other channel values are not affected.
|
||||
|
||||
Index values range from zero to the number of colours in the palette minus
|
||||
one. Raises an error if the index value is invalid.
|
||||
palette:entry_set_blue_level(index, level)
|
||||
Sets the blue channel value of the colour at the specified zero-based index.
|
||||
Other channel values are not affected.
|
||||
|
||||
Index values range from zero to the number of colours in the palette minus
|
||||
one. Raises an error if the index value is invalid.
|
||||
palette:entry_set_contrast(index, level)
|
||||
Sets the contrast adjustment value for the colour at the specified
|
||||
zero-based index. This must be a floating-point number.
|
||||
|
||||
Index values range from zero to the number of colours in the palette minus
|
||||
one. Raises an error if the index value is invalid.
|
||||
palette:group_set_brightness(group, brightness)
|
||||
Sets the brightness adjustment value for the adjustment group at the
|
||||
specified zero-based index. This must be a floating-point number.
|
||||
|
||||
Group values range from zero to the number of adjustment groups in the
|
||||
palette minus one. Raises an error if the index value is invalid.
|
||||
palette:group_set_contrast(group, contrast)
|
||||
Sets the contrast adjustment value for the adjustment group at the specified
|
||||
zero-based index. This must be a floating-point number.
|
||||
|
||||
Group values range from zero to the number of adjustment groups in the
|
||||
palette minus one. Raises an error if the index value is invalid.
|
||||
|
||||
Properties
|
||||
^^^^^^^^^^
|
||||
|
||||
palette.colors (read-only)
|
||||
The number of colour entries in each group of colours in the palette.
|
||||
palette.groups (read-only)
|
||||
The number of groups of colours in the palette.
|
||||
palette.max_index (read-only)
|
||||
The number of valid colour indices in the palette.
|
||||
palette.black_entry (read-only)
|
||||
The index of the special entry for the colour black.
|
||||
palette.white_entry (read-only)
|
||||
The index of the special entry for the colour white.
|
||||
palette.brightness (write-only)
|
||||
The overall brightness adjustment for the palette. This is a floating-point
|
||||
number.
|
||||
palette.contrast (write-only)
|
||||
The overall contrast adjustment for the palette. This is a floating-point
|
||||
number.
|
||||
palette.gamma (write-only)
|
||||
The overall gamma adjustment for the palette. This is a floating-point
|
||||
number.
|
||||
|
||||
.. _luareference-render-bitmap:
|
||||
|
||||
Bitmap
|
||||
~~~~~~
|
||||
|
||||
Wraps implementation of MAME’s ``bitmap_t`` and ``bitmap_specific`` classes,
|
||||
Wraps implementations of MAME’s ``bitmap_t`` and ``bitmap_specific`` classes,
|
||||
which represent two-dimensional bitmaps stored in row-major order. Pixel
|
||||
coordinates are zero-based, increasing to the right and down. Several pixel
|
||||
formats are supported.
|
||||
@ -2712,6 +2845,70 @@ formats are supported.
|
||||
Instantiation
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
emu.bitmap_ind8(palette, [width, height], [xslop, yslop])
|
||||
Creates an 8-bit indexed bitmap. Each pixel is a zero-based, unsigned 8-bit
|
||||
index into a :ref:`palette <luareference-render-palette>`.
|
||||
|
||||
If no width and height are specified, they are assumed to be zero. If the
|
||||
width is specified, the height must also be specified. The X and Y slop
|
||||
values set the amount of extra storage in pixels to reserve at the
|
||||
left/right of each row and top/bottom of each column, respectively. If an X
|
||||
slop value is specified, a Y slop value must be specified as well. If no X
|
||||
and Y slop values are specified, they are assumed to be zero (the storage
|
||||
will be sized to fit the bitmap content). If the width and/or height is
|
||||
less than or equal to zero, no storage will be allocated, irrespective of
|
||||
the X and Y slop values, and the width and height of the bitmap will both be
|
||||
set to zero.
|
||||
|
||||
The initial clipping rectangle is set to the entirety of the bitmap.
|
||||
emu.bitmap_ind16(palette, [width, height], [xslop, yslop])
|
||||
Creates a 16-bit indexed bitmap. Each pixel is a zero-based, unsigned
|
||||
16-bit index into a :ref:`palette <luareference-render-palette>`.
|
||||
|
||||
If no width and height are specified, they are assumed to be zero. If the
|
||||
width is specified, the height must also be specified. The X and Y slop
|
||||
values set the amount of extra storage in pixels to reserve at the
|
||||
left/right of each row and top/bottom of each column, respectively. If an X
|
||||
slop value is specified, a Y slop value must be specified as well. If no X
|
||||
and Y slop values are specified, they are assumed to be zero (the storage
|
||||
will be sized to fit the bitmap content). If the width and/or height is
|
||||
less than or equal to zero, no storage will be allocated, irrespective of
|
||||
the X and Y slop values, and the width and height of the bitmap will both be
|
||||
set to zero.
|
||||
|
||||
The initial clipping rectangle is set to the entirety of the bitmap.
|
||||
emu.bitmap_ind32(palette, [width, height], [xslop, yslop])
|
||||
Creates a 32-bit indexed bitmap. Each pixel is a zero-based, unsigned
|
||||
32-bit index into a :ref:`palette <luareference-render-palette>`.
|
||||
|
||||
If no width and height are specified, they are assumed to be zero. If the
|
||||
width is specified, the height must also be specified. The X and Y slop
|
||||
values set the amount of extra storage in pixels to reserve at the
|
||||
left/right of each row and top/bottom of each column, respectively. If an X
|
||||
slop value is specified, a Y slop value must be specified as well. If no X
|
||||
and Y slop values are specified, they are assumed to be zero (the storage
|
||||
will be sized to fit the bitmap content). If the width and/or height is
|
||||
less than or equal to zero, no storage will be allocated, irrespective of
|
||||
the X and Y slop values, and the width and height of the bitmap will both be
|
||||
set to zero.
|
||||
|
||||
The initial clipping rectangle is set to the entirety of the bitmap.
|
||||
emu.bitmap_ind64(palette, [width, height], [xslop, yslop])
|
||||
Creates a 64-bit indexed bitmap. Each pixel is a zero-based, unsigned
|
||||
64-bit index into a :ref:`palette <luareference-render-palette>`.
|
||||
|
||||
If no width and height are specified, they are assumed to be zero. If the
|
||||
width is specified, the height must also be specified. The X and Y slop
|
||||
values set the amount of extra storage in pixels to reserve at the
|
||||
left/right of each row and top/bottom of each column, respectively. If an X
|
||||
slop value is specified, a Y slop value must be specified as well. If no X
|
||||
and Y slop values are specified, they are assumed to be zero (the storage
|
||||
will be sized to fit the bitmap content). If the width and/or height is
|
||||
less than or equal to zero, no storage will be allocated, irrespective of
|
||||
the X and Y slop values, and the width and height of the bitmap will both be
|
||||
set to zero.
|
||||
|
||||
The initial clipping rectangle is set to the entirety of the bitmap.
|
||||
emu.bitmap_yuy16([width, height], [xslop], yslop])
|
||||
Creates a Y'CbCr format bitmap with 4:2:2 chroma subsampling (horizontal
|
||||
pairs of pixels have individual luma values but share chroma values). Each
|
||||
@ -2775,6 +2972,70 @@ emu.bitmap_argb32([width, height], [xslop, yslop])
|
||||
set to zero.
|
||||
|
||||
The initial clipping rectangle is set to the entirety of the bitmap.
|
||||
emu.bitmap_ind8(source, [x0, y0, x1, y1])
|
||||
Creates an 8-bit indexed bitmap representing a view of a portion of an
|
||||
existing bitmap. The initial clipping rectangle is set to the bounds of the
|
||||
view. The source bitmap will be locked, preventing resizing and
|
||||
reallocation.
|
||||
|
||||
If no coordinates are specified, the new bitmap will represent a view of the
|
||||
source bitmap’s current clipping rectangle. If coordinates are specified,
|
||||
the new bitmap will represent a view of the rectangle with top left corner
|
||||
at (x0, y0) and bottom right corner at (x1, y1) in the source bitmap.
|
||||
Coordinates are in units of pixels. The bottom right coordinates are
|
||||
inclusive.
|
||||
|
||||
The source bitmap must be owned by the Lua script and must use the 8-bit
|
||||
indexed format. Raises an error if coordinates are specified representing a
|
||||
rectangle not fully contained within the source bitmap’s clipping rectangle.
|
||||
emu.bitmap_ind16(source, [x0, y0, x1, y1])
|
||||
Creates a 16-bit indexed bitmap representing a view of a portion of an
|
||||
existing bitmap. The initial clipping rectangle is set to the bounds of the
|
||||
view. The source bitmap will be locked, preventing resizing and
|
||||
reallocation.
|
||||
|
||||
If no coordinates are specified, the new bitmap will represent a view of the
|
||||
source bitmap’s current clipping rectangle. If coordinates are specified,
|
||||
the new bitmap will represent a view of the rectangle with top left corner
|
||||
at (x0, y0) and bottom right corner at (x1, y1) in the source bitmap.
|
||||
Coordinates are in units of pixels. The bottom right coordinates are
|
||||
inclusive.
|
||||
|
||||
The source bitmap must be owned by the Lua script and must use the 16-bit
|
||||
indexed format. Raises an error if coordinates are specified representing a
|
||||
rectangle not fully contained within the source bitmap’s clipping rectangle.
|
||||
emu.bitmap_ind32(source, [x0, y0, x1, y1])
|
||||
Creates a 32-bit indexed bitmap representing a view of a portion of an
|
||||
existing bitmap. The initial clipping rectangle is set to the bounds of the
|
||||
view. The source bitmap will be locked, preventing resizing and
|
||||
reallocation.
|
||||
|
||||
If no coordinates are specified, the new bitmap will represent a view of the
|
||||
source bitmap’s current clipping rectangle. If coordinates are specified,
|
||||
the new bitmap will represent a view of the rectangle with top left corner
|
||||
at (x0, y0) and bottom right corner at (x1, y1) in the source bitmap.
|
||||
Coordinates are in units of pixels. The bottom right coordinates are
|
||||
inclusive.
|
||||
|
||||
The source bitmap must be owned by the Lua script and must use the 32-bit
|
||||
indexed format. Raises an error if coordinates are specified representing a
|
||||
rectangle not fully contained within the source bitmap’s clipping rectangle.
|
||||
emu.bitmap_ind64(source, [x0, y0, x1, y1])
|
||||
Creates a 64-bit indexed bitmap representing a view of a portion of an
|
||||
existing bitmap. The initial clipping rectangle is set to the bounds of the
|
||||
view. The source bitmap will be locked, preventing resizing and
|
||||
reallocation.
|
||||
|
||||
If no coordinates are specified, the new bitmap will represent a view of the
|
||||
source bitmap’s current clipping rectangle. If coordinates are specified,
|
||||
the new bitmap will represent a view of the rectangle with top left corner
|
||||
at (x0, y0) and bottom right corner at (x1, y1) in the source bitmap.
|
||||
Coordinates are in units of pixels. The bottom right coordinates are
|
||||
inclusive.
|
||||
|
||||
The source bitmap must be owned by the Lua script and must use the 64-bit
|
||||
indexed format. Raises an error if coordinates are specified representing a
|
||||
rectangle not fully contained within the source bitmap’s clipping rectangle.
|
||||
emu.bitmap_yuy16(source, [x0, y0, x1, y1])
|
||||
Creates a Y'CbCr format bitmap with 4:2:2 chroma subsampling representing a
|
||||
view of a portion of an existing bitmap. The initial clipping rectangle is
|
||||
@ -2827,6 +3088,10 @@ emu.bitmap_argb32(source, [x0, y0, x1, y1])
|
||||
Methods
|
||||
^^^^^^^
|
||||
|
||||
bitmap:cliprect()
|
||||
Returns the left, top, right and bottom coordinates of the bitmap’s clipping
|
||||
rectangle. Coordinates are in units of pixels; the bottom and right
|
||||
coordinates are inclusive.
|
||||
bitmap:reset()
|
||||
Sets the width and height to zero, and frees the pixel storage if the bitmap
|
||||
owns its own storage, or releases the source bitmap if the it represents a
|
||||
@ -2898,6 +3163,17 @@ bitmap:wrap(source, [x0, y0, x1, y1])
|
||||
bitmap:pix(x, y)
|
||||
Returns the colour value of the pixel at the specified location.
|
||||
Coordinates are zero-based in units of pixels.
|
||||
bitmap:pixels([x0, y0, x1, y1])
|
||||
Returns the pixels, width and height of the portion of the bitmap with top
|
||||
left corner at (x0, y0) and bottom right corner at (x1, y1). Coordinates
|
||||
are in units of pixels. The bottom right coordinates are inclusive. If
|
||||
coordinates are not specified, the bitmap’s clipping rectangle is used.
|
||||
|
||||
Pixels are returned packed into a binary string in host Endian order.
|
||||
Pixels are organised in row-major order, from left to right then top to
|
||||
bottom. The size and format of the pixel values depends on the format of
|
||||
the bitmap. Raises an error if coordinates are specified representing a
|
||||
rectangle not fully contained within the bitmap’s clipping rectangle.
|
||||
bitmap:fill(color, [x0, y0, x1, y1])
|
||||
Fills a portion of the bitmap with the specified colour value. If
|
||||
coordinates are not specified, the clipping rectangle is filled; if
|
||||
@ -2916,6 +3192,10 @@ bitmap:plot_box(x, y, width, height, color)
|
||||
Properties
|
||||
^^^^^^^^^^
|
||||
|
||||
bitmap.palette (read/write)
|
||||
The :ref:`palette <luareference-render-palette>` used to translate pixel
|
||||
values to colours. Only applicable for bitmaps that use indexed pixel
|
||||
formats.
|
||||
bitmap.width (read-only)
|
||||
Width of the bitmap in pixels.
|
||||
bitmap.height (read-only)
|
||||
@ -2989,7 +3269,7 @@ Methods
|
||||
render:texture_alloc(bitmap)
|
||||
Creates a :ref:`render texture <luareference-render-texture>` based on a
|
||||
:ref:`bitmap <luareference-render-bitmap>`. The bitmap must be owned by the
|
||||
Lua script, and must use the Y'CbCr, RGB or ARGB format. The bitmap’s
|
||||
Lua script, and must use the Y'CbCr, RGB or ARGB pixel format. The bitmap’s
|
||||
storage will be locked, preventing resizing and reallocation. Render
|
||||
textures must be freed before the emulation session ends.
|
||||
|
||||
|
@ -280,4 +280,7 @@ each control is displayed on the left and its current state is shown on the
|
||||
right. When an analog axis control is highlighted, its state is also shown in
|
||||
graphical form below the menu. Digital control states are either zero
|
||||
(inactive) or one (active). Analog axis input states range from -65,536 to
|
||||
65,536 with the neutral position at zero.
|
||||
65,536 with the neutral position at zero. You can also select **Copy Device
|
||||
ID** to copy the device’s ID to the clipboard. This is useful for setting up
|
||||
:ref:`stable controller IDs <devicemap>` in :ref:`controller configuration files
|
||||
<ctrlrcfg>`.
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -493,7 +493,8 @@ project ("ocore_" .. _OPTIONS["osd"])
|
||||
MAME_DIR .. "src/osd/modules/file/winfile.h",
|
||||
MAME_DIR .. "src/osd/modules/file/winptty.cpp",
|
||||
MAME_DIR .. "src/osd/modules/file/winsocket.cpp",
|
||||
MAME_DIR .. "src/osd/windows/winutil.cpp", -- FIXME put the necessary functions somewhere more appropriate
|
||||
MAME_DIR .. "src/osd/windows/winutil.cpp", -- FIXME put the necessary functions somewhere more appropriate?
|
||||
MAME_DIR .. "src/osd/windows/winutil.h",
|
||||
}
|
||||
else
|
||||
files {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) ) \
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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(); });
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -225,6 +134,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)
|
||||
{
|
||||
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
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()))
|
||||
{
|
||||
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()));
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -191,6 +191,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)
|
||||
{
|
||||
|
@ -93,6 +93,7 @@ private:
|
||||
|
||||
// functions
|
||||
void append_software_entry(const software_info &swinfo);
|
||||
void update_search(void *selectedref);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
m_palette->deref();
|
||||
m_palette = nullptr;
|
||||
}
|
||||
|
||||
// then reference any new palette
|
||||
if (palette != nullptr)
|
||||
{
|
||||
// first reference the new palette
|
||||
if (palette)
|
||||
palette->ref();
|
||||
m_palette = palette;
|
||||
}
|
||||
|
||||
// then dereference any existing palette
|
||||
if (m_palette)
|
||||
m_palette->deref();
|
||||
|
||||
m_palette = palette;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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; }
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
//-------------------------------------------------
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
utf8_data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, string_ref, kCFStringEncodingUTF8, '?');
|
||||
CFRelease(string_ref);
|
||||
}
|
||||
|
||||
if (utf8_data)
|
||||
{
|
||||
CFIndex const length = CFDataGetLength(utf8_data);
|
||||
CFRange const range = CFRangeMake(0, length);
|
||||
|
||||
result.resize(length);
|
||||
CFDataGetBytes(data_ref, range, reinterpret_cast<unsigned char *>(&result[0]));
|
||||
has_result = true;
|
||||
|
||||
CFRelease(data_ref);
|
||||
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
|
||||
//============================================================
|
||||
|
@ -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
|
||||
|
||||
//============================================================
|
||||
|
@ -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,20 +168,87 @@ 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
|
||||
//============================================================
|
||||
|
@ -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" },
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user