summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2020-11-01 00:37:28 +1100
committer Vas Crabb <vas@vastheman.com>2020-11-01 00:37:28 +1100
commitcf7fe1e04d994850543bd799779360ec78df2c89 (patch)
treeb5fe8ef469d7cf1c437e29200f0f0eef5162ccd4
parentda9213faaaa1bb3d69abe4e13ba190bb701cb425 (diff)
-bus/a2bus: Added Apple II Parallel Printer Interface Card.
-frontend/mame/audit.cpp: Fixed another annoying edge case. -Cleaned up RawInput code slightly.
-rw-r--r--scripts/src/bus.lua2
-rw-r--r--src/devices/bus/a2bus/a2parprn.cpp233
-rw-r--r--src/devices/bus/a2bus/a2parprn.h96
-rw-r--r--src/devices/bus/a2bus/a2pic.h15
-rw-r--r--src/frontend/mame/audit.cpp30
-rw-r--r--src/mame/drivers/apple2.cpp6
-rw-r--r--src/mame/drivers/apple2e.cpp6
-rw-r--r--src/mame/drivers/apple2gs.cpp6
-rw-r--r--src/osd/modules/input/input_rawinput.cpp301
-rw-r--r--src/osd/modules/input/input_windows.h8
10 files changed, 530 insertions, 173 deletions
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index 16d9f5a528b..ab13afec201 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -2330,6 +2330,8 @@ if (BUSES["A2BUS"]~=null) then
MAME_DIR .. "src/devices/bus/a2bus/a2midi.h",
MAME_DIR .. "src/devices/bus/a2bus/a2mockingboard.cpp",
MAME_DIR .. "src/devices/bus/a2bus/a2mockingboard.h",
+ MAME_DIR .. "src/devices/bus/a2bus/a2parprn.cpp",
+ MAME_DIR .. "src/devices/bus/a2bus/a2parprn.h",
MAME_DIR .. "src/devices/bus/a2bus/a2pic.cpp",
MAME_DIR .. "src/devices/bus/a2bus/a2pic.h",
MAME_DIR .. "src/devices/bus/a2bus/a2sam.cpp",
diff --git a/src/devices/bus/a2bus/a2parprn.cpp b/src/devices/bus/a2bus/a2parprn.cpp
new file mode 100644
index 00000000000..c1ec975d1fb
--- /dev/null
+++ b/src/devices/bus/a2bus/a2parprn.cpp
@@ -0,0 +1,233 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+#include "emu.h"
+#include "a2parprn.h"
+
+//#define VERBOSE 1
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
+
+namespace {
+
+// FIXME: get proper PROM dumps.
+/*
+ There are most likely multiple revisions.
+ 6309 and 74471 PROMs were used.
+
+ Example silkscreen:
+
+ SINGAPORE
+ 341-0005-00
+ cAPPLE 78-02
+ SN74S471N
+
+ Example label:
+
+ APPLE
+ ©1978
+
+ PROM image here is from entering a listing and zero-filling unused areas.
+
+ ********************************
+ * *
+ * PRINTER CARD I FIRMWARE *
+ * *
+ * WOZ 11/1/77 *
+ * APPLE COMPUTER INC. *
+ * ALL RIGHTS RESERVED *
+ * *
+ ********************************
+*/
+ROM_START(parprn)
+ ROM_REGION(0x100, "prom", 0)
+ ROM_LOAD( "prom.b4", 0x0000, 0x0100, BAD_DUMP CRC(00b742ca) SHA1(c67888354aa013f9cb882eeeed924e292734e717) )
+ROM_END
+
+
+INPUT_PORTS_START(parprn)
+ PORT_START("CFG")
+ PORT_CONFNAME(0x01, 0x00, "Acknowledge latching edge")
+ PORT_CONFSETTING( 0x00, "Falling (/Y-B)")
+ PORT_CONFSETTING( 0x01, "Rising (Y-B)")
+ PORT_CONFNAME(0x06, 0x02, "Printer ready")
+ PORT_CONFSETTING( 0x00, "Always (S5-C-D)")
+ PORT_CONFSETTING( 0x02, "Acknowledge latch (Z-C-D)")
+ PORT_CONFSETTING( 0x04, "ACK (Y-C-D)")
+ PORT_CONFSETTING( 0x06, "/ACK (/Y-C-D)")
+ PORT_CONFNAME(0x08, 0x00, "Strobe polarity")
+ PORT_CONFSETTING( 0x00, "Negative (S5-A-/X, GND-X)")
+ PORT_CONFSETTING( 0x08, "Positive (S5-X, GND-A-/X)")
+ PORT_CONFNAME(0x10, 0x10, "Character width")
+ PORT_CONFSETTING( 0x00, "7-bit")
+ PORT_CONFSETTING( 0x10, "8-bit")
+INPUT_PORTS_END
+
+} // anonymous namespace
+
+
+
+DEFINE_DEVICE_TYPE(A2BUS_PARPRN, a2bus_parprn_device, "a2parprn", "Apple II Parallel Printer Interface Card")
+
+
+
+a2bus_parprn_device::a2bus_parprn_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, A2BUS_PARPRN, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_printer_conn(*this, "prn"),
+ m_printer_out(*this, "prn_out"),
+ m_input_config(*this, "CFG"),
+ m_prom(*this, "prom"),
+ m_strobe_timer(nullptr),
+ m_next_strobe(0U),
+ m_ack_latch(0U),
+ m_ack_in(1U)
+{
+}
+
+
+
+//----------------------------------------------
+// device_a2bus_card_interface implementation
+//----------------------------------------------
+
+u8 a2bus_parprn_device::read_c0nx(u8 offset)
+{
+ if (!machine().side_effects_disabled())
+ {
+ LOG("Read C0n%01X (effective open-bus write)\n", offset);
+
+ // R/W is ignored, so it has the same effect as a write
+ // the bus is open, but 74LS logic has low-impedance inputs so it's likely to latch 0xff
+ write_c0nx(offset, 0xffU);
+ }
+
+ return 0x00U;
+}
+
+
+void a2bus_parprn_device::write_c0nx(u8 offset, u8 data)
+{
+ LOG("Write C0n%01X=%02X\n", offset, data);
+ if (m_ack_latch)
+ LOG("Clearing acknowledge latch\n");
+ else
+ LOG("Previous data not acknowledged\n");
+
+ ioport_value const cfg(m_input_config->read());
+
+ m_printer_out->write(data & (BIT(cfg, 8) ? 0xffU : 0x7fU));
+ m_printer_conn->write_strobe(BIT(~cfg, 3));
+ m_next_strobe = BIT(cfg, 3);
+ m_ack_latch = 0U;
+ m_strobe_timer->adjust(attotime::from_ticks(1, clock()));
+}
+
+
+u8 a2bus_parprn_device::read_cnxx(u8 offset)
+{
+ ioport_value const cfg(m_input_config->read());
+
+ if (BIT(cfg, 2))
+ {
+ if (!BIT(offset, 6) || (BIT(offset, 7) && (BIT(cfg, 1) != m_ack_in)))
+ offset |= 0x40U;
+ else
+ offset &= 0xbfU;
+ }
+ else if (BIT(cfg, 1))
+ {
+ if (!BIT(offset, 6) || (BIT(offset, 7) && !m_ack_latch))
+ offset |= 0x40U;
+ else
+ offset &= 0xbfU;
+ }
+ else
+ {
+ offset ^= 0x40U;
+ }
+
+ return m_prom[offset];
+}
+
+
+
+//----------------------------------------------
+// device_t implementation
+//----------------------------------------------
+
+tiny_rom_entry const *a2bus_parprn_device::device_rom_region() const
+{
+ return ROM_NAME(parprn);
+}
+
+
+void a2bus_parprn_device::device_add_mconfig(machine_config &config)
+{
+ CENTRONICS(config, m_printer_conn, centronics_devices, "printer");
+ m_printer_conn->ack_handler().set(FUNC(a2bus_parprn_device::ack_w));
+
+ OUTPUT_LATCH(config, m_printer_out);
+ m_printer_conn->set_output_latch(*m_printer_out);
+}
+
+
+ioport_constructor a2bus_parprn_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(parprn);
+}
+
+
+void a2bus_parprn_device::device_start()
+{
+ m_strobe_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(a2bus_parprn_device::update_strobe), this));
+
+ save_item(NAME(m_next_strobe));
+ save_item(NAME(m_ack_latch));
+ save_item(NAME(m_ack_in));
+}
+
+
+void a2bus_parprn_device::device_reset()
+{
+ m_ack_latch = 1U;
+}
+
+
+
+//----------------------------------------------
+// printer status inputs
+//----------------------------------------------
+
+WRITE_LINE_MEMBER(a2bus_parprn_device::ack_w)
+{
+ if (bool(state) != bool(m_ack_in))
+ {
+ m_ack_in = state ? 1U : 0U;
+ LOG("ACK=%u\n", m_ack_in);
+ if (started() && (m_ack_in == BIT(m_input_config->read(), 0)))
+ {
+ LOG("Active ACK edge\n");
+ m_ack_latch = 1U;
+ }
+ }
+}
+
+
+
+//----------------------------------------------
+// timer handlers
+//----------------------------------------------
+
+TIMER_CALLBACK_MEMBER(a2bus_parprn_device::update_strobe)
+{
+ ioport_value const cfg(m_input_config->read());
+
+ LOG("Output /STROBE=%u\n", m_next_strobe);
+ m_printer_conn->write_strobe(m_next_strobe);
+ if (m_next_strobe == BIT(cfg, 3))
+ {
+ LOG("Start strobe timer\n");
+ m_next_strobe = BIT(~cfg, 3);
+ m_strobe_timer->adjust(attotime::from_ticks(1, clock()));
+ }
+}
diff --git a/src/devices/bus/a2bus/a2parprn.h b/src/devices/bus/a2bus/a2parprn.h
new file mode 100644
index 00000000000..00fd09bdc93
--- /dev/null
+++ b/src/devices/bus/a2bus/a2parprn.h
@@ -0,0 +1,96 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***********************************************************************
+
+ Apple II Parallel Printer Interface Card
+
+ 20-pin header:
+
+ GND 1 2 ACK
+ SP1* 3 4 F
+ SP2* 5 6 SP3*
+ SP4* 7 8 STR
+ SP5* 9 10 DP0
+ DP1 11 12 DP2
+ DP3 13 14 DP4
+ DP5 15 16 DP6
+ DP7 17 18 SP6*
+ SP7* 19 20 GND
+
+ *spare, SP1-SP5 brought out to pads for wire mods
+
+ DIP jumper B1:
+ no connection NC 1 16 B acknowledge latch clock
+ no connection NC 2 15 D printer ready 1
+ synchronised ACK Y 3 14 C printer ready 2
+ synchronised /ACK /Y 4 13 A idle strobe
+ acknowledge latch Q /Z 5 12 /X strobe on access
+ acknowlwdge latch /Q Z 6 11 S5 +5V via 12kΩ resistor
+ signal ground GND 7 10 X strobe after one cycle
+ header pin 4 F 8 9 NC no connection
+
+ In real life, the card only samples the ACK input on rising
+ edges of the phase 1 clock. Acknowledge pulses shorter than one
+ microsecond may be ignored. This limitation is not emulated.
+
+ The card completely ignores the R/W line. The PROM driver uses
+ and indexed write to access the C0nX region. This produces a
+ spurious read, causing data to be latched and triggering a
+ delayed strobe pulse. This is why the delay is important – the
+ write needs to happen on the cycle immediately following the
+ spurious read to prevent the open bus data from being printed.
+
+ The card was designed to allow user modifications. There are
+ locations at 5A (16-pin) and 5B (20-pin) for additional DIP
+ packages. Common modifications included stretching strobe
+ and/or acknowledge pulses to improve reliability.
+
+***********************************************************************/
+#ifndef MAME_BUS_A2BUS_A2PARPRN_H
+#define MAME_BUS_A2BUS_A2PARPRN_H
+
+#pragma once
+
+#include "a2bus.h"
+#include "bus/centronics/ctronics.h"
+
+class a2bus_parprn_device : public device_t, public device_a2bus_card_interface
+{
+public:
+ a2bus_parprn_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ // device_a2bus_card_interface implementation
+ virtual u8 read_c0nx(u8 offset) override;
+ virtual void write_c0nx(u8 offset, u8 data) override;
+ virtual u8 read_cnxx(u8 offset) override;
+
+protected:
+ // device_t implementation
+ virtual tiny_rom_entry const *device_rom_region() const override;
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual ioport_constructor device_input_ports() const override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ // printer status inputs
+ DECLARE_WRITE_LINE_MEMBER(ack_w);
+
+ // timer handlers
+ TIMER_CALLBACK_MEMBER(update_strobe);
+
+ required_device<centronics_device> m_printer_conn;
+ required_device<output_latch_device> m_printer_out;
+ required_ioport m_input_config;
+ required_region_ptr<u8> m_prom;
+ emu_timer * m_strobe_timer;
+
+ u8 m_next_strobe; // B3 pin 13
+ u8 m_ack_latch; // B2 pin 6
+ u8 m_ack_in; // pin 2
+};
+
+
+DECLARE_DEVICE_TYPE(A2BUS_PARPRN, a2bus_parprn_device)
+
+#endif // MAME_BUS_A2BUS_A2PARPRN_H
diff --git a/src/devices/bus/a2bus/a2pic.h b/src/devices/bus/a2bus/a2pic.h
index 283dd537e7c..a484ee92c4c 100644
--- a/src/devices/bus/a2bus/a2pic.h
+++ b/src/devices/bus/a2bus/a2pic.h
@@ -1,6 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
-/*********************************************************************
+/***********************************************************************
Apple II Parallel Interface Card (670-0021)
@@ -34,7 +34,18 @@
*wired to 500ns strobe but connector hole is blocked
-*********************************************************************/
+ This card has significant flaws:
+ * The strobe pulse begins on the same rising edge of the phase 1
+ clock as the data is latched. The parallel load input ito the
+ strobe time counter (6A) is delayed slightly, but the load
+ happens on the rising phase 1 clock edge. This could glitch
+ on a real printer. MAME always sets the data outputs before
+ starting the strobe pulse.
+ * Acknowledge is ignored while the strobe output is active. If
+ the printer acknowledges the data before the end of the strobe
+ pulse, the card will miss it and wait forever.
+
+***********************************************************************/
#ifndef MAME_BUS_A2BUS_A2PIC_H
#define MAME_BUS_A2BUS_A2PIC_H
diff --git a/src/frontend/mame/audit.cpp b/src/frontend/mame/audit.cpp
index 6509b264e49..736d6f9bf2f 100644
--- a/src/frontend/mame/audit.cpp
+++ b/src/frontend/mame/audit.cpp
@@ -45,6 +45,35 @@ class parent_rom_vector : public std::vector<parent_rom>
public:
using std::vector<parent_rom>::vector;
+ void remove_redundant_parents()
+ {
+ while (!empty())
+ {
+ // find where the next parent starts
+ auto const last(
+ std::find_if(
+ std::next(cbegin()),
+ cend(),
+ [this] (parent_rom const &r) { return &front().type.get() != &r.type.get(); }));
+
+ // examine dumped ROMs in this generation
+ for (auto i = cbegin(); last != i; ++i)
+ {
+ if (!i->hashes.flag(util::hash_collection::FLAG_NO_DUMP))
+ {
+ auto const match(
+ std::find_if(
+ last,
+ cend(),
+ [&i] (parent_rom const &r) { return (i->length == r.length) && (i->hashes == r.hashes); }));
+ if (cend() == match)
+ return;
+ }
+ }
+ erase(cbegin(), last);
+ }
+ }
+
std::add_pointer_t<device_type> find_shared_device(device_t &current, char const *name, util::hash_collection const &hashes, uint64_t length) const
{
// if we're examining a child device, it will always have a perfect match
@@ -172,6 +201,7 @@ media_auditor::summary media_auditor::audit_media(const char *validation)
}
}
}
+ parentroms.remove_redundant_parents();
// count ROMs required/found
std::size_t found(0);
diff --git a/src/mame/drivers/apple2.cpp b/src/mame/drivers/apple2.cpp
index 763deb941bb..db440fd7a35 100644
--- a/src/mame/drivers/apple2.cpp
+++ b/src/mame/drivers/apple2.cpp
@@ -69,6 +69,7 @@ II Plus: RAM options reduced to 16/32/48 KB.
#include "bus/a2bus/a2memexp.h"
#include "bus/a2bus/a2midi.h"
#include "bus/a2bus/a2mockingboard.h"
+#include "bus/a2bus/a2parprn.h"
#include "bus/a2bus/a2pic.h"
#include "bus/a2bus/a2sam.h"
#include "bus/a2bus/a2scsi.h"
@@ -1308,7 +1309,9 @@ static void apple2_cards(device_slot_interface &device)
device.option_add("ultraterm", A2BUS_ULTRATERM); /* Videx UltraTerm (original) */
device.option_add("ultratermenh", A2BUS_ULTRATERMENH); /* Videx UltraTerm (enhanced //e) */
device.option_add("aevm80", A2BUS_AEVIEWMASTER80); /* Applied Engineering ViewMaster 80 */
- device.option_add("parallel", A2BUS_PIC); /* Apple Parallel Interface Card */
+ device.option_add("parprn", A2BUS_PARPRN); /* Apple II Parallel Printer Interface Card */
+ device.option_add("parallel", A2BUS_PIC); /* Apple II Parallel Interface Card */
+ device.option_add("grapplerplus", A2BUS_GRAPPLERPLUS); /* Orange Micro Grappler+ Printer Interface card */
device.option_add("corvus", A2BUS_CORVUS); /* Corvus flat-cable HDD interface (see notes in a2corvus.c) */
device.option_add("mcms1", A2BUS_MCMS1); /* Mountain Computer Music System, card 1 of 2 */
device.option_add("mcms2", A2BUS_MCMS2); /* Mountain Computer Music System, card 2 of 2. must be in card 1's slot + 1! */
@@ -1326,7 +1329,6 @@ static void apple2_cards(device_slot_interface &device)
device.option_add("applesurance", A2BUS_APPLESURANCE); /* Applesurance Diagnostic Controller */
// device.option_add("magicmusician", A2BUS_MAGICMUSICIAN); /* Magic Musician Card */
device.option_add("byte8251", A2BUS_BYTE8251); /* BYTE Magazine 8251 serial card */
- device.option_add("grapplerplus", A2BUS_GRAPPLERPLUS); /* Orange Micro Grappler+ Printer Interface card */
}
void apple2_state::apple2_common(machine_config &config)
diff --git a/src/mame/drivers/apple2e.cpp b/src/mame/drivers/apple2e.cpp
index 838dd8c5237..94ba9109099 100644
--- a/src/mame/drivers/apple2e.cpp
+++ b/src/mame/drivers/apple2e.cpp
@@ -152,6 +152,7 @@ MIG RAM page 2 $CE02 is the speaker/slot bitfield and $CE03 is the paddle/accele
#include "bus/a2bus/a2memexp.h"
#include "bus/a2bus/a2midi.h"
#include "bus/a2bus/a2mockingboard.h"
+#include "bus/a2bus/a2parprn.h"
#include "bus/a2bus/a2pic.h"
#include "bus/a2bus/a2sam.h"
#include "bus/a2bus/a2scsi.h"
@@ -4505,7 +4506,9 @@ static void apple2_cards(device_slot_interface &device)
device.option_add("ultraterm", A2BUS_ULTRATERM); /* Videx UltraTerm (original) */
device.option_add("ultratermenh", A2BUS_ULTRATERMENH); /* Videx UltraTerm (enhanced //e) */
device.option_add("aevm80", A2BUS_AEVIEWMASTER80); /* Applied Engineering ViewMaster 80 */
- device.option_add("parallel", A2BUS_PIC); /* Apple Parallel Interface Card */
+ device.option_add("parprn", A2BUS_PARPRN); /* Apple II Parallel Printer Interface Card */
+ device.option_add("parallel", A2BUS_PIC); /* Apple II Parallel Interface Card */
+ device.option_add("grapplerplus", A2BUS_GRAPPLERPLUS); /* Orange Micro Grappler+ Printer Interface card */
device.option_add("corvus", A2BUS_CORVUS); /* Corvus flat-cable HDD interface (see notes in a2corvus.c) */
device.option_add("mcms1", A2BUS_MCMS1); /* Mountain Computer Music System, card 1 of 2 */
device.option_add("mcms2", A2BUS_MCMS2); /* Mountain Computer Music System, card 2 of 2. must be in card 1's slot + 1! */
@@ -4529,7 +4532,6 @@ static void apple2_cards(device_slot_interface &device)
device.option_add("uthernet", A2BUS_UTHERNET); /* A2RetroSystems Uthernet card */
device.option_add("sider2", A2BUS_SIDER2); /* Advanced Tech Systems / First Class Peripherals Sider 2 SASI card */
device.option_add("sider1", A2BUS_SIDER1); /* Advanced Tech Systems / First Class Peripherals Sider 1 SASI card */
- device.option_add("grapplerplus", A2BUS_GRAPPLERPLUS); /* Orange Micro Grappler+ Printer Interface card */
}
static void apple2eaux_cards(device_slot_interface &device)
diff --git a/src/mame/drivers/apple2gs.cpp b/src/mame/drivers/apple2gs.cpp
index 72674c2bcab..6b12a1f9962 100644
--- a/src/mame/drivers/apple2gs.cpp
+++ b/src/mame/drivers/apple2gs.cpp
@@ -86,6 +86,7 @@
#include "bus/a2bus/a2memexp.h"
#include "bus/a2bus/a2midi.h"
#include "bus/a2bus/a2mockingboard.h"
+#include "bus/a2bus/a2parprn.h"
#include "bus/a2bus/a2pic.h"
#include "bus/a2bus/a2sam.h"
#include "bus/a2bus/a2scsi.h"
@@ -4572,7 +4573,9 @@ static void apple2_cards(device_slot_interface &device)
device.option_add("ultraterm", A2BUS_ULTRATERM); /* Videx UltraTerm (original) */
device.option_add("ultratermenh", A2BUS_ULTRATERMENH); /* Videx UltraTerm (enhanced //e) */
device.option_add("aevm80", A2BUS_AEVIEWMASTER80); /* Applied Engineering ViewMaster 80 */
- device.option_add("parallel", A2BUS_PIC); /* Apple Parallel Interface Card */
+ device.option_add("parprn", A2BUS_PARPRN); /* Apple II Parallel Printer Interface Card */
+ device.option_add("parallel", A2BUS_PIC); /* Apple II Parallel Interface Card */
+ device.option_add("grapplerplus", A2BUS_GRAPPLERPLUS); /* Orange Micro Grappler+ Printer Interface card */
device.option_add("corvus", A2BUS_CORVUS); /* Corvus flat-cable HDD interface (see notes in a2corvus.c) */
device.option_add("mcms1", A2BUS_MCMS1); /* Mountain Computer Music System, card 1 of 2 */
device.option_add("mcms2", A2BUS_MCMS2); /* Mountain Computer Music System, card 2 of 2. must be in card 1's slot + 1! */
@@ -4594,7 +4597,6 @@ static void apple2_cards(device_slot_interface &device)
device.option_add("uthernet", A2BUS_UTHERNET); /* A2RetroSystems Uthernet card */
device.option_add("sider2", A2BUS_SIDER2); /* Advanced Tech Systems / First Class Peripherals Sider 2 SASI card */
device.option_add("sider1", A2BUS_SIDER1); /* Advanced Tech Systems / First Class Peripherals Sider 1 SASI card */
- device.option_add("grapplerplus", A2BUS_GRAPPLERPLUS); /* Orange Micro Grappler+ Printer Interface card */
}
void apple2gs_state::apple2gs(machine_config &config)
diff --git a/src/osd/modules/input/input_rawinput.cpp b/src/osd/modules/input/input_rawinput.cpp
index 7876b297867..3e57f689506 100644
--- a/src/osd/modules/input/input_rawinput.cpp
+++ b/src/osd/modules/input/input_rawinput.cpp
@@ -32,9 +32,8 @@
#include "input_common.h"
#include "input_windows.h"
-//============================================================
-// MACROS
-//============================================================
+
+namespace {
// Typedefs for dynamically loaded functions
typedef UINT (WINAPI *get_rawinput_device_list_ptr)(PRAWINPUTDEVICELIST, PUINT, UINT);
@@ -48,17 +47,24 @@ private:
HKEY m_key;
public:
- safe_regkey()
- : m_key(nullptr)
- {
- }
+ safe_regkey() : m_key(nullptr) { }
+ safe_regkey(safe_regkey const &) = delete;
+ safe_regkey(safe_regkey &&key) : m_key(key.m_key) { key.m_key = nullptr; }
+ explicit safe_regkey(HKEY key) : m_key(key) { }
- explicit safe_regkey(HKEY key)
- : m_key(key)
+ ~safe_regkey() { close(); }
+
+ safe_regkey &operator=(safe_regkey const &) = delete;
+
+ safe_regkey &operator=(safe_regkey &&key)
{
+ close();
+ m_key = key.m_key;
+ key.m_key = nullptr;
+ return *this;
}
- bool valid() const { return m_key != nullptr; }
+ explicit operator bool() const { return m_key != nullptr; }
void close()
{
@@ -69,70 +75,68 @@ public:
}
}
- ~safe_regkey()
- {
- close();
- }
-
operator HKEY() const { return m_key; }
-};
-
-//============================================================
-// reg_open_key
-//============================================================
-
-static safe_regkey reg_open_key(HKEY basekey, const std::wstring &subkey)
-{
- HKEY key;
- if (RegOpenKeyEx(basekey, subkey.c_str(), 0, KEY_READ, &key) == ERROR_SUCCESS)
- return safe_regkey(key);
- return safe_regkey();
+ safe_regkey open(std::wstring const &subkey) const { return open(m_key, subkey); }
-}
+ std::wstring enum_key(int index) const
+ {
+ WCHAR keyname[MAX_PATH];
+ DWORD namelen = MAX_PATH;
+ if (RegEnumKeyEx(m_key, index, keyname, &namelen, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
+ return std::wstring(keyname, namelen);
+ else
+ return std::wstring();
+ }
-//============================================================
-// reg_enum_key
-//============================================================
+ std::wstring query_string(WCHAR const *path) const
+ {
+ // first query to get the length
+ DWORD datalen;
+ if (RegQueryValueExW(m_key, path, nullptr, nullptr, nullptr, &datalen) != ERROR_SUCCESS)
+ return std::wstring();
-static std::wstring reg_enum_key(HKEY key, int index)
-{
- WCHAR keyname[MAX_PATH];
- DWORD namelen;
- if (RegEnumKeyEx(key, index, keyname, &namelen, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
- return std::wstring(keyname, namelen);
+ // allocate a buffer
+ auto buffer = std::make_unique<WCHAR []>((datalen + (sizeof(WCHAR) * 2) - 1) / sizeof(WCHAR));
- return std::wstring();
-}
+ // now get the actual data
+ if (RegQueryValueExW(m_key, path, nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer.get()), &datalen) != ERROR_SUCCESS)
+ return std::wstring();
-//============================================================
-// reg_query_string
-//============================================================
-
-static std::wstring reg_query_string(HKEY key, const TCHAR *path)
-{
- DWORD datalen;
- LONG result;
+ buffer[datalen / sizeof(WCHAR)] = 0;
+ return std::wstring(buffer.get());
+ }
- // first query to get the length
- result = RegQueryValueEx(key, path, nullptr, nullptr, nullptr, &datalen);
- if (result != ERROR_SUCCESS)
- return std::wstring();
+ template <typename T> void foreach_subkey(T &&action) const
+ {
+ std::wstring name;
+ for (int i = 0; ; i++)
+ {
+ name = enum_key(i);
+ if (name.empty())
+ break;
- // allocate a buffer
- auto buffer = std::make_unique<TCHAR[]>(datalen + sizeof(TCHAR));
- buffer[datalen / sizeof(TCHAR)] = 0;
+ safe_regkey const subkey = open(name);
+ if (!subkey)
+ break;
- // now get the actual data
- result = RegQueryValueEx(key, path, nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer.get()), &datalen);
- if (result == ERROR_SUCCESS)
- return std::wstring(buffer.get());
+ bool const shouldcontinue = action(subkey);
+ if (!shouldcontinue)
+ break;
+ }
+ }
- // otherwise return an empty string
- return std::wstring();
-}
+ static safe_regkey open(HKEY basekey, std::wstring const &subkey)
+ {
+ HKEY key(nullptr);
+ if (RegOpenKeyEx(basekey, subkey.c_str(), 0, KEY_READ, &key) == ERROR_SUCCESS)
+ return safe_regkey(key);
+ else
+ return safe_regkey();
+ }
+};
-static std::wstring trim_prefix(const std::wstring &devicename)
+std::wstring trim_prefix(const std::wstring &devicename)
{
// remove anything prior to the final semicolon
auto semicolon_index = devicename.find_last_of(';');
@@ -142,22 +146,22 @@ static std::wstring trim_prefix(const std::wstring &devicename)
return devicename;
}
-static std::wstring compute_device_regpath(const std::wstring &name)
+std::wstring compute_device_regpath(const std::wstring &name)
{
static const std::wstring basepath(L"SYSTEM\\CurrentControlSet\\Enum\\");
// allocate a temporary string and concatenate the base path plus the name
- auto regpath_buffer = std::make_unique<TCHAR[]>(basepath.length() + 1 + name.length());
+ auto regpath_buffer = std::make_unique<WCHAR []>(basepath.length() + 1 + name.length());
wcscpy(regpath_buffer.get(), basepath.c_str());
- WCHAR * chdst = regpath_buffer.get() + basepath.length();
+ WCHAR *chdst = regpath_buffer.get() + basepath.length();
// convert all # to \ in the name
for (int i = 4; i < name.length(); i++)
- *chdst++ = (name[i] == '#') ? '\\' : name[i];
+ *chdst++ = (name[i] == '#') ? L'\\' : name[i];
*chdst = 0;
// remove the final chunk
- chdst = wcsrchr(regpath_buffer.get(), '\\');
+ chdst = wcsrchr(regpath_buffer.get(), L'\\');
if (chdst == nullptr)
return std::wstring();
@@ -166,15 +170,15 @@ static std::wstring compute_device_regpath(const std::wstring &name)
return std::wstring(regpath_buffer.get());
}
-static std::wstring improve_name_from_base_path(const std::wstring &regpath, bool *hid)
+std::wstring improve_name_from_base_path(const std::wstring &regpath, bool *hid)
{
// now try to open the registry key
- auto device_key = reg_open_key(HKEY_LOCAL_MACHINE, regpath);
- if (!device_key.valid())
+ auto device_key = safe_regkey::open(HKEY_LOCAL_MACHINE, regpath);
+ if (!device_key)
return std::wstring();
// fetch the device description; if it exists, we are finished
- auto regstring = reg_query_string(device_key, L"DeviceDesc");
+ auto regstring = device_key.query_string(L"DeviceDesc");
if (!regstring.empty())
return trim_prefix(regstring);
@@ -183,25 +187,7 @@ static std::wstring improve_name_from_base_path(const std::wstring &regpath, boo
return std::wstring();
}
-static void foreach_subkey(HKEY key, std::function<bool(HKEY)> action)
-{
- for (int i = 0; ; i++)
- {
- std::wstring name = reg_enum_key(key, i);
- if (name.empty())
- break;
-
- safe_regkey subkey = reg_open_key(key, name);
- if (!subkey.valid())
- break;
-
- bool shouldcontinue = action(subkey);
- if (!shouldcontinue)
- break;
- }
-}
-
-static std::wstring improve_name_from_usb_path(const std::wstring &regpath)
+std::wstring improve_name_from_usb_path(const std::wstring &regpath)
{
static const std::wstring usbbasepath(L"SYSTEM\\CurrentControlSet\\Enum\\USB");
@@ -213,31 +199,33 @@ static std::wstring improve_name_from_usb_path(const std::wstring &regpath)
std::wstring parentid = regpath.substr(last_slash_index + 1);
// open the USB key
- auto usb_key = reg_open_key(HKEY_LOCAL_MACHINE, usbbasepath);
- if (!usb_key.valid())
+ auto usb_key = safe_regkey::open(HKEY_LOCAL_MACHINE, usbbasepath);
+ if (!usb_key)
return std::wstring();
std::wstring regstring;
- foreach_subkey(usb_key, [&regstring, &parentid](HKEY subkey)
- {
- foreach_subkey(subkey, [&regstring, &parentid](HKEY endkey)
- {
- std::wstring endparentid = reg_query_string(endkey, L"ParentIdPrefix");
+ usb_key.foreach_subkey(
+ [&regstring, &parentid] (safe_regkey const &subkey)
+ {
+ subkey.foreach_subkey(
+ [&regstring, &parentid] (safe_regkey const &endkey)
+ {
+ std::wstring endparentid = endkey.query_string(L"ParentIdPrefix");
- // This key doesn't have a ParentIdPrefix
- if (endparentid.empty())
- return true;
+ // This key doesn't have a ParentIdPrefix
+ if (endparentid.empty())
+ return true;
- // do we have a match?
- if (parentid.find(endparentid) == 0)
- regstring = reg_query_string(endkey, L"DeviceDesc");
+ // do we have a match?
+ if (parentid.find(endparentid) == 0)
+ regstring = endkey.query_string(L"DeviceDesc");
- return regstring.empty();
- });
+ return regstring.empty();
+ });
- return regstring.empty();
- });
+ return regstring.empty();
+ });
return trim_prefix(regstring);
}
@@ -246,7 +234,7 @@ static std::wstring improve_name_from_usb_path(const std::wstring &regpath)
// rawinput_device_improve_name
//============================================================
-static std::wstring rawinput_device_improve_name(const std::wstring &name)
+std::wstring rawinput_device_improve_name(const std::wstring &name)
{
// The RAW name received is formatted as:
// \??\type-id#hardware-id#instance-id#{DeviceClasses-id}
@@ -283,12 +271,11 @@ static std::wstring rawinput_device_improve_name(const std::wstring &name)
class rawinput_device : public event_based_device<RAWINPUT>
{
private:
- HANDLE m_handle;
+ HANDLE m_handle = nullptr;
public:
- rawinput_device(running_machine& machine, const char *name, const char *id, input_device_class deviceclass, input_module& module)
- : event_based_device(machine, name, id, deviceclass, module),
- m_handle(nullptr)
+ rawinput_device(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module) :
+ event_based_device(machine, name, id, deviceclass, module)
{
}
@@ -305,9 +292,9 @@ class rawinput_keyboard_device : public rawinput_device
public:
keyboard_state keyboard;
- rawinput_keyboard_device(running_machine& machine, const char *name, const char *id, input_module& module)
- : rawinput_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
- keyboard({{0}})
+ rawinput_keyboard_device(running_machine &machine, const char *name, const char *id, input_module &module) :
+ rawinput_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
+ keyboard({{0}})
{
}
@@ -341,9 +328,9 @@ private:
public:
mouse_state mouse;
- rawinput_mouse_device(running_machine& machine, const char *name, const char *id, input_module& module)
- : rawinput_device(machine, name, id, DEVICE_CLASS_MOUSE, module),
- mouse({0})
+ rawinput_mouse_device(running_machine &machine, const char *name, const char *id, input_module &module) :
+ rawinput_device(machine, name, id, DEVICE_CLASS_MOUSE, module),
+ mouse({0})
{
}
@@ -401,8 +388,8 @@ private:
public:
mouse_state lightgun;
- rawinput_lightgun_device(running_machine& machine, const char *name, const char *id, input_module& module)
- : rawinput_device(machine, name, id, DEVICE_CLASS_LIGHTGUN, module),
+ rawinput_lightgun_device(running_machine &machine, const char *name, const char *id, input_module &module) :
+ rawinput_device(machine, name, id, DEVICE_CLASS_LIGHTGUN, module),
lightgun({0})
{
}
@@ -456,19 +443,14 @@ class rawinput_module : public wininput_module
{
private:
osd::dynamic_module::ptr m_user32_dll;
- get_rawinput_device_list_ptr get_rawinput_device_list;
- get_rawinput_data_ptr get_rawinput_data;
- get_rawinput_device_info_ptr get_rawinput_device_info;
- register_rawinput_devices_ptr register_rawinput_devices;
+ get_rawinput_device_list_ptr get_rawinput_device_list = nullptr;
+ get_rawinput_data_ptr get_rawinput_data = nullptr;
+ get_rawinput_device_info_ptr get_rawinput_device_info = nullptr;
+ register_rawinput_devices_ptr register_rawinput_devices = nullptr;
std::mutex m_module_lock;
public:
- rawinput_module(const char *type, const char* name)
- : wininput_module(type, name),
- get_rawinput_device_list(nullptr),
- get_rawinput_data(nullptr),
- get_rawinput_device_info(nullptr),
- register_rawinput_devices(nullptr)
+ rawinput_module(const char *type, const char *name) : wininput_module(type, name)
{
}
@@ -481,13 +463,7 @@ public:
get_rawinput_device_info = m_user32_dll->bind<get_rawinput_device_info_ptr>("GetRawInputDeviceInfoW");
register_rawinput_devices = m_user32_dll->bind<register_rawinput_devices_ptr>("RegisterRawInputDevices");
- if (!get_rawinput_device_list || !get_rawinput_data ||
- !get_rawinput_device_info || !register_rawinput_devices )
- {
- return false;
- }
-
- return true;
+ return get_rawinput_device_list && get_rawinput_data && get_rawinput_device_info && register_rawinput_devices;
}
void input_init(running_machine &machine) override
@@ -501,7 +477,7 @@ public:
return;
auto rawinput_devices = std::make_unique<RAWINPUTDEVICELIST[]>(device_count);
- if ((*get_rawinput_device_list)(rawinput_devices.get(), &device_count, sizeof(RAWINPUTDEVICELIST)) == -1)
+ if ((*get_rawinput_device_list)(rawinput_devices.get(), &device_count, sizeof(RAWINPUTDEVICELIST)) == UINT(-1))
return;
// iterate backwards through devices; new devices are added at the head
@@ -533,7 +509,7 @@ public:
}
protected:
- virtual void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) = 0;
+ virtual void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST *device) = 0;
virtual USHORT usagepage() = 0;
virtual USHORT usage() = 0;
@@ -550,16 +526,15 @@ protected:
}
template<class TDevice>
- TDevice* create_rawinput_device(running_machine &machine, PRAWINPUTDEVICELIST rawinputdevice)
+ TDevice *create_rawinput_device(running_machine &machine, PRAWINPUTDEVICELIST rawinputdevice)
{
- TDevice* devinfo;
- UINT name_length = 0;
// determine the length of the device name, allocate it, and fetch it if not nameless
+ UINT name_length = 0;
if ((*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, nullptr, &name_length) != 0)
return nullptr;
- std::unique_ptr<TCHAR[]> tname = std::make_unique<TCHAR[]>(name_length + 1);
- if (name_length > 1 && (*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == -1)
+ std::unique_ptr<WCHAR []> tname = std::make_unique<WCHAR []>(name_length + 1);
+ if (name_length > 1 && (*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == UINT(-1))
return nullptr;
// if this is an RDP name, skip it
@@ -575,7 +550,7 @@ protected:
// set device id to raw input name
std::string utf8_id = osd::text::from_wstring(tname.get());
- devinfo = devicelist()->create_device<TDevice>(machine, utf8_name.c_str(), utf8_id.c_str(), *this);
+ TDevice *devinfo = devicelist()->create_device<TDevice>(machine, utf8_name.c_str(), utf8_id.c_str(), *this);
// Add the handle
devinfo->set_handle(rawinputdevice->hDevice);
@@ -583,7 +558,7 @@ protected:
return devinfo;
}
- bool handle_input_event(input_event eventid, void* eventdata) override
+ bool handle_input_event(input_event eventid, void *eventdata) override
{
// Only handle raw input data
if (!input_enabled() || eventid != INPUT_EVENT_RAWINPUT)
@@ -622,15 +597,18 @@ protected:
auto *input = reinterpret_cast<RAWINPUT*>(data);
// find the device in the list and update
- auto target_device = std::find_if(devicelist()->begin(), devicelist()->end(), [input](auto &device)
- {
- auto devinfo = dynamic_cast<rawinput_device*>(device.get());
- return devinfo != nullptr && input->header.hDevice == devinfo->device_handle();
- });
+ auto target_device = std::find_if(
+ devicelist()->begin(),
+ devicelist()->end(),
+ [input] (auto const &device)
+ {
+ auto devinfo = dynamic_cast<rawinput_device *>(device.get());
+ return devinfo && (input->header.hDevice == devinfo->device_handle());
+ });
if (target_device != devicelist()->end())
{
- static_cast<rawinput_device*>((*target_device).get())->queue_events(input, 1);
+ static_cast<rawinput_device *>((*target_device).get())->queue_events(input, 1);
return true;
}
}
@@ -654,7 +632,8 @@ public:
protected:
USHORT usagepage() override { return 1; }
USHORT usage() override { return 6; }
- void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override
+
+ void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST *device) override
{
// make sure this is a keyboard
if (device->dwType != RIM_TYPEKEYBOARD)
@@ -671,12 +650,12 @@ protected:
for (int keynum = 0; keynum < MAX_KEYS; keynum++)
{
input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
- TCHAR keyname[100];
+ WCHAR keyname[100];
// generate the name
- if (GetKeyNameText(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, ARRAY_LENGTH(keyname)) == 0)
- _sntprintf(keyname, ARRAY_LENGTH(keyname), TEXT("Scan%03d"), keynum);
- std::string name = osd::text::from_tstring(keyname);
+ if (GetKeyNameTextW(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, ARRAY_LENGTH(keyname)) == 0)
+ _snwprintf(keyname, ARRAY_LENGTH(keyname), L"Scan%03d", keynum);
+ std::string name = osd::text::from_wstring(keyname);
// add the item to the device
devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state<std::uint8_t>, &devinfo->keyboard.state[keynum]);
@@ -699,7 +678,8 @@ public:
protected:
USHORT usagepage() override { return 1; }
USHORT usage() override { return 2; }
- void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override
+
+ void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST *device) override
{
// make sure this is a mouse
if (device->dwType != RIM_TYPEMOUSE)
@@ -747,7 +727,8 @@ public:
protected:
USHORT usagepage() override { return 1; }
USHORT usage() override { return 2; }
- void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override
+
+ void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST *device) override
{
// make sure this is a mouse
@@ -781,6 +762,8 @@ protected:
}
};
+} // anonymous namespace
+
#else
MODULE_NOT_SUPPORTED(keyboard_input_rawinput, OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
MODULE_NOT_SUPPORTED(mouse_input_rawinput, OSD_MOUSEINPUT_PROVIDER, "rawinput")
diff --git a/src/osd/modules/input/input_windows.h b/src/osd/modules/input/input_windows.h
index 7afc487fb62..4a355e2793a 100644
--- a/src/osd/modules/input/input_windows.h
+++ b/src/osd/modules/input/input_windows.h
@@ -40,14 +40,10 @@ struct mouse_state
class wininput_module : public input_module_base
{
protected:
- bool m_global_inputs_enabled;
+ bool m_global_inputs_enabled = false;
public:
- wininput_module(const char * type, const char * name)
- : input_module_base(type, name),
- m_global_inputs_enabled(false)
- {
- }
+ wininput_module(const char *type, const char *name) : input_module_base(type, name) { }
virtual ~wininput_module() { }