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 m_printer_conn; + required_device m_printer_out; + required_ioport m_input_config; + required_region_ptr 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 public: using std::vector::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 find_shared_device(device_t ¤t, 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) { } + + ~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; } - explicit safe_regkey(HKEY key) - : m_key(key) - { - } - - bool valid() const { return m_key != nullptr; } + explicit operator bool() const { return m_key != nullptr; } void close() { @@ -69,70 +75,68 @@ public: } } - ~safe_regkey() + operator HKEY() const { return m_key; } + + safe_regkey open(std::wstring const &subkey) const { return open(m_key, subkey); } + + std::wstring enum_key(int index) const { - close(); + 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(); } - operator HKEY() const { return m_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(); + + // allocate a buffer + auto buffer = std::make_unique((datalen + (sizeof(WCHAR) * 2) - 1) / sizeof(WCHAR)); + + // now get the actual data + if (RegQueryValueExW(m_key, path, nullptr, nullptr, reinterpret_cast(buffer.get()), &datalen) != ERROR_SUCCESS) + return std::wstring(); + + buffer[datalen / sizeof(WCHAR)] = 0; + return std::wstring(buffer.get()); + } + + template void foreach_subkey(T &&action) const + { + std::wstring name; + for (int i = 0; ; i++) + { + name = enum_key(i); + if (name.empty()) + break; + + safe_regkey const subkey = open(name); + if (!subkey) + break; + + bool const shouldcontinue = action(subkey); + if (!shouldcontinue) + break; + } + } + + 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(); + } }; -//============================================================ -// 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(); - -} - -//============================================================ -// reg_enum_key -//============================================================ - -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); - - return std::wstring(); -} - -//============================================================ -// reg_query_string -//============================================================ - -static std::wstring reg_query_string(HKEY key, const TCHAR *path) -{ - DWORD datalen; - LONG result; - - // first query to get the length - result = RegQueryValueEx(key, path, nullptr, nullptr, nullptr, &datalen); - if (result != ERROR_SUCCESS) - return std::wstring(); - - // allocate a buffer - auto buffer = std::make_unique(datalen + sizeof(TCHAR)); - buffer[datalen / sizeof(TCHAR)] = 0; - - // now get the actual data - result = RegQueryValueEx(key, path, nullptr, nullptr, reinterpret_cast(buffer.get()), &datalen); - if (result == ERROR_SUCCESS) - return std::wstring(buffer.get()); - - // otherwise return an empty string - return std::wstring(); -} - -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(basepath.length() + 1 + name.length()); + auto regpath_buffer = std::make_unique(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 ®path, bool *hid) +std::wstring improve_name_from_base_path(const std::wstring ®path, 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 ®path, boo return std::wstring(); } -static void foreach_subkey(HKEY key, std::function 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 ®path) +std::wstring improve_name_from_usb_path(const std::wstring ®path) { 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 ®path) 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, [®string, &parentid](HKEY subkey) - { - foreach_subkey(subkey, [®string, &parentid](HKEY endkey) - { - std::wstring endparentid = reg_query_string(endkey, L"ParentIdPrefix"); + usb_key.foreach_subkey( + [®string, &parentid] (safe_regkey const &subkey) + { + subkey.foreach_subkey( + [®string, &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 ®path) // 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 { 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("GetRawInputDeviceInfoW"); register_rawinput_devices = m_user32_dll->bind("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(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 - 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 tname = std::make_unique(name_length + 1); - if (name_length > 1 && (*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == -1) + std::unique_ptr tname = std::make_unique(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(machine, utf8_name.c_str(), utf8_id.c_str(), *this); + TDevice *devinfo = devicelist()->create_device(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(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(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(device.get()); + return devinfo && (input->header.hDevice == devinfo->device_handle()); + }); if (target_device != devicelist()->end()) { - static_cast((*target_device).get())->queue_events(input, 1); + static_cast((*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, &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() { }