-bus/a2bus: Added Apple II Parallel Printer Interface Card.
-frontend/mame/audit.cpp: Fixed another annoying edge case. -Cleaned up RawInput code slightly.
This commit is contained in:
parent
da9213faaa
commit
cf7fe1e04d
@ -2330,6 +2330,8 @@ if (BUSES["A2BUS"]~=null) then
|
|||||||
MAME_DIR .. "src/devices/bus/a2bus/a2midi.h",
|
MAME_DIR .. "src/devices/bus/a2bus/a2midi.h",
|
||||||
MAME_DIR .. "src/devices/bus/a2bus/a2mockingboard.cpp",
|
MAME_DIR .. "src/devices/bus/a2bus/a2mockingboard.cpp",
|
||||||
MAME_DIR .. "src/devices/bus/a2bus/a2mockingboard.h",
|
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.cpp",
|
||||||
MAME_DIR .. "src/devices/bus/a2bus/a2pic.h",
|
MAME_DIR .. "src/devices/bus/a2bus/a2pic.h",
|
||||||
MAME_DIR .. "src/devices/bus/a2bus/a2sam.cpp",
|
MAME_DIR .. "src/devices/bus/a2bus/a2sam.cpp",
|
||||||
|
233
src/devices/bus/a2bus/a2parprn.cpp
Normal file
233
src/devices/bus/a2bus/a2parprn.cpp
Normal file
@ -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()));
|
||||||
|
}
|
||||||
|
}
|
96
src/devices/bus/a2bus/a2parprn.h
Normal file
96
src/devices/bus/a2bus/a2parprn.h
Normal file
@ -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
|
@ -1,6 +1,6 @@
|
|||||||
// license:BSD-3-Clause
|
// license:BSD-3-Clause
|
||||||
// copyright-holders:Vas Crabb
|
// copyright-holders:Vas Crabb
|
||||||
/*********************************************************************
|
/***********************************************************************
|
||||||
|
|
||||||
Apple II Parallel Interface Card (670-0021)
|
Apple II Parallel Interface Card (670-0021)
|
||||||
|
|
||||||
@ -34,7 +34,18 @@
|
|||||||
|
|
||||||
*wired to 500ns strobe but connector hole is blocked
|
*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
|
#ifndef MAME_BUS_A2BUS_A2PIC_H
|
||||||
#define MAME_BUS_A2BUS_A2PIC_H
|
#define MAME_BUS_A2BUS_A2PIC_H
|
||||||
|
|
||||||
|
@ -45,6 +45,35 @@ class parent_rom_vector : public std::vector<parent_rom>
|
|||||||
public:
|
public:
|
||||||
using std::vector<parent_rom>::vector;
|
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 ¤t, char const *name, util::hash_collection const &hashes, uint64_t length) const
|
std::add_pointer_t<device_type> 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
|
// 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
|
// count ROMs required/found
|
||||||
std::size_t found(0);
|
std::size_t found(0);
|
||||||
|
@ -69,6 +69,7 @@ II Plus: RAM options reduced to 16/32/48 KB.
|
|||||||
#include "bus/a2bus/a2memexp.h"
|
#include "bus/a2bus/a2memexp.h"
|
||||||
#include "bus/a2bus/a2midi.h"
|
#include "bus/a2bus/a2midi.h"
|
||||||
#include "bus/a2bus/a2mockingboard.h"
|
#include "bus/a2bus/a2mockingboard.h"
|
||||||
|
#include "bus/a2bus/a2parprn.h"
|
||||||
#include "bus/a2bus/a2pic.h"
|
#include "bus/a2bus/a2pic.h"
|
||||||
#include "bus/a2bus/a2sam.h"
|
#include "bus/a2bus/a2sam.h"
|
||||||
#include "bus/a2bus/a2scsi.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("ultraterm", A2BUS_ULTRATERM); /* Videx UltraTerm (original) */
|
||||||
device.option_add("ultratermenh", A2BUS_ULTRATERMENH); /* Videx UltraTerm (enhanced //e) */
|
device.option_add("ultratermenh", A2BUS_ULTRATERMENH); /* Videx UltraTerm (enhanced //e) */
|
||||||
device.option_add("aevm80", A2BUS_AEVIEWMASTER80); /* Applied Engineering ViewMaster 80 */
|
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("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("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! */
|
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("applesurance", A2BUS_APPLESURANCE); /* Applesurance Diagnostic Controller */
|
||||||
// device.option_add("magicmusician", A2BUS_MAGICMUSICIAN); /* Magic Musician Card */
|
// device.option_add("magicmusician", A2BUS_MAGICMUSICIAN); /* Magic Musician Card */
|
||||||
device.option_add("byte8251", A2BUS_BYTE8251); /* BYTE Magazine 8251 serial 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)
|
void apple2_state::apple2_common(machine_config &config)
|
||||||
|
@ -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/a2memexp.h"
|
||||||
#include "bus/a2bus/a2midi.h"
|
#include "bus/a2bus/a2midi.h"
|
||||||
#include "bus/a2bus/a2mockingboard.h"
|
#include "bus/a2bus/a2mockingboard.h"
|
||||||
|
#include "bus/a2bus/a2parprn.h"
|
||||||
#include "bus/a2bus/a2pic.h"
|
#include "bus/a2bus/a2pic.h"
|
||||||
#include "bus/a2bus/a2sam.h"
|
#include "bus/a2bus/a2sam.h"
|
||||||
#include "bus/a2bus/a2scsi.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("ultraterm", A2BUS_ULTRATERM); /* Videx UltraTerm (original) */
|
||||||
device.option_add("ultratermenh", A2BUS_ULTRATERMENH); /* Videx UltraTerm (enhanced //e) */
|
device.option_add("ultratermenh", A2BUS_ULTRATERMENH); /* Videx UltraTerm (enhanced //e) */
|
||||||
device.option_add("aevm80", A2BUS_AEVIEWMASTER80); /* Applied Engineering ViewMaster 80 */
|
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("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("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! */
|
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("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("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("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)
|
static void apple2eaux_cards(device_slot_interface &device)
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
#include "bus/a2bus/a2memexp.h"
|
#include "bus/a2bus/a2memexp.h"
|
||||||
#include "bus/a2bus/a2midi.h"
|
#include "bus/a2bus/a2midi.h"
|
||||||
#include "bus/a2bus/a2mockingboard.h"
|
#include "bus/a2bus/a2mockingboard.h"
|
||||||
|
#include "bus/a2bus/a2parprn.h"
|
||||||
#include "bus/a2bus/a2pic.h"
|
#include "bus/a2bus/a2pic.h"
|
||||||
#include "bus/a2bus/a2sam.h"
|
#include "bus/a2bus/a2sam.h"
|
||||||
#include "bus/a2bus/a2scsi.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("ultraterm", A2BUS_ULTRATERM); /* Videx UltraTerm (original) */
|
||||||
device.option_add("ultratermenh", A2BUS_ULTRATERMENH); /* Videx UltraTerm (enhanced //e) */
|
device.option_add("ultratermenh", A2BUS_ULTRATERMENH); /* Videx UltraTerm (enhanced //e) */
|
||||||
device.option_add("aevm80", A2BUS_AEVIEWMASTER80); /* Applied Engineering ViewMaster 80 */
|
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("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("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! */
|
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("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("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("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)
|
void apple2gs_state::apple2gs(machine_config &config)
|
||||||
|
@ -32,9 +32,8 @@
|
|||||||
#include "input_common.h"
|
#include "input_common.h"
|
||||||
#include "input_windows.h"
|
#include "input_windows.h"
|
||||||
|
|
||||||
//============================================================
|
|
||||||
// MACROS
|
namespace {
|
||||||
//============================================================
|
|
||||||
|
|
||||||
// Typedefs for dynamically loaded functions
|
// Typedefs for dynamically loaded functions
|
||||||
typedef UINT (WINAPI *get_rawinput_device_list_ptr)(PRAWINPUTDEVICELIST, PUINT, UINT);
|
typedef UINT (WINAPI *get_rawinput_device_list_ptr)(PRAWINPUTDEVICELIST, PUINT, UINT);
|
||||||
@ -48,17 +47,24 @@ private:
|
|||||||
HKEY m_key;
|
HKEY m_key;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
safe_regkey()
|
safe_regkey() : m_key(nullptr) { }
|
||||||
: 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)
|
explicit operator bool() const { return m_key != nullptr; }
|
||||||
: m_key(key)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool valid() const { return m_key != nullptr; }
|
|
||||||
|
|
||||||
void close()
|
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<WCHAR []>((datalen + (sizeof(WCHAR) * 2) - 1) / sizeof(WCHAR));
|
||||||
|
|
||||||
|
// now get the actual data
|
||||||
|
if (RegQueryValueExW(m_key, path, nullptr, nullptr, reinterpret_cast<LPBYTE>(buffer.get()), &datalen) != ERROR_SUCCESS)
|
||||||
|
return std::wstring();
|
||||||
|
|
||||||
|
buffer[datalen / sizeof(WCHAR)] = 0;
|
||||||
|
return std::wstring(buffer.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//============================================================
|
std::wstring trim_prefix(const std::wstring &devicename)
|
||||||
// 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<TCHAR[]>(datalen + sizeof(TCHAR));
|
|
||||||
buffer[datalen / sizeof(TCHAR)] = 0;
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
|
|
||||||
// otherwise return an empty string
|
|
||||||
return std::wstring();
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::wstring trim_prefix(const std::wstring &devicename)
|
|
||||||
{
|
{
|
||||||
// remove anything prior to the final semicolon
|
// remove anything prior to the final semicolon
|
||||||
auto semicolon_index = devicename.find_last_of(';');
|
auto semicolon_index = devicename.find_last_of(';');
|
||||||
@ -142,22 +146,22 @@ static std::wstring trim_prefix(const std::wstring &devicename)
|
|||||||
return 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\\");
|
static const std::wstring basepath(L"SYSTEM\\CurrentControlSet\\Enum\\");
|
||||||
|
|
||||||
// allocate a temporary string and concatenate the base path plus the name
|
// 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());
|
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
|
// convert all # to \ in the name
|
||||||
for (int i = 4; i < name.length(); i++)
|
for (int i = 4; i < name.length(); i++)
|
||||||
*chdst++ = (name[i] == '#') ? '\\' : name[i];
|
*chdst++ = (name[i] == '#') ? L'\\' : name[i];
|
||||||
*chdst = 0;
|
*chdst = 0;
|
||||||
|
|
||||||
// remove the final chunk
|
// remove the final chunk
|
||||||
chdst = wcsrchr(regpath_buffer.get(), '\\');
|
chdst = wcsrchr(regpath_buffer.get(), L'\\');
|
||||||
if (chdst == nullptr)
|
if (chdst == nullptr)
|
||||||
return std::wstring();
|
return std::wstring();
|
||||||
|
|
||||||
@ -166,15 +170,15 @@ static std::wstring compute_device_regpath(const std::wstring &name)
|
|||||||
return std::wstring(regpath_buffer.get());
|
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
|
// now try to open the registry key
|
||||||
auto device_key = reg_open_key(HKEY_LOCAL_MACHINE, regpath);
|
auto device_key = safe_regkey::open(HKEY_LOCAL_MACHINE, regpath);
|
||||||
if (!device_key.valid())
|
if (!device_key)
|
||||||
return std::wstring();
|
return std::wstring();
|
||||||
|
|
||||||
// fetch the device description; if it exists, we are finished
|
// 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())
|
if (!regstring.empty())
|
||||||
return trim_prefix(regstring);
|
return trim_prefix(regstring);
|
||||||
|
|
||||||
@ -183,25 +187,7 @@ static std::wstring improve_name_from_base_path(const std::wstring ®path, boo
|
|||||||
return std::wstring();
|
return std::wstring();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void foreach_subkey(HKEY key, std::function<bool(HKEY)> action)
|
std::wstring improve_name_from_usb_path(const std::wstring ®path)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
static const std::wstring usbbasepath(L"SYSTEM\\CurrentControlSet\\Enum\\USB");
|
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);
|
std::wstring parentid = regpath.substr(last_slash_index + 1);
|
||||||
|
|
||||||
// open the USB key
|
// open the USB key
|
||||||
auto usb_key = reg_open_key(HKEY_LOCAL_MACHINE, usbbasepath);
|
auto usb_key = safe_regkey::open(HKEY_LOCAL_MACHINE, usbbasepath);
|
||||||
if (!usb_key.valid())
|
if (!usb_key)
|
||||||
return std::wstring();
|
return std::wstring();
|
||||||
|
|
||||||
std::wstring regstring;
|
std::wstring regstring;
|
||||||
|
|
||||||
foreach_subkey(usb_key, [®string, &parentid](HKEY subkey)
|
usb_key.foreach_subkey(
|
||||||
{
|
[®string, &parentid] (safe_regkey const &subkey)
|
||||||
foreach_subkey(subkey, [®string, &parentid](HKEY endkey)
|
{
|
||||||
{
|
subkey.foreach_subkey(
|
||||||
std::wstring endparentid = reg_query_string(endkey, L"ParentIdPrefix");
|
[®string, &parentid] (safe_regkey const &endkey)
|
||||||
|
{
|
||||||
|
std::wstring endparentid = endkey.query_string(L"ParentIdPrefix");
|
||||||
|
|
||||||
// This key doesn't have a ParentIdPrefix
|
// This key doesn't have a ParentIdPrefix
|
||||||
if (endparentid.empty())
|
if (endparentid.empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// do we have a match?
|
// do we have a match?
|
||||||
if (parentid.find(endparentid) == 0)
|
if (parentid.find(endparentid) == 0)
|
||||||
regstring = reg_query_string(endkey, L"DeviceDesc");
|
regstring = endkey.query_string(L"DeviceDesc");
|
||||||
|
|
||||||
return regstring.empty();
|
return regstring.empty();
|
||||||
});
|
});
|
||||||
|
|
||||||
return regstring.empty();
|
return regstring.empty();
|
||||||
});
|
});
|
||||||
|
|
||||||
return trim_prefix(regstring);
|
return trim_prefix(regstring);
|
||||||
}
|
}
|
||||||
@ -246,7 +234,7 @@ static std::wstring improve_name_from_usb_path(const std::wstring ®path)
|
|||||||
// rawinput_device_improve_name
|
// 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:
|
// The RAW name received is formatted as:
|
||||||
// \??\type-id#hardware-id#instance-id#{DeviceClasses-id}
|
// \??\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>
|
class rawinput_device : public event_based_device<RAWINPUT>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
HANDLE m_handle;
|
HANDLE m_handle = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
rawinput_device(running_machine& machine, const char *name, const char *id, input_device_class deviceclass, input_module& module)
|
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),
|
event_based_device(machine, name, id, deviceclass, module)
|
||||||
m_handle(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,9 +292,9 @@ class rawinput_keyboard_device : public rawinput_device
|
|||||||
public:
|
public:
|
||||||
keyboard_state keyboard;
|
keyboard_state keyboard;
|
||||||
|
|
||||||
rawinput_keyboard_device(running_machine& machine, const char *name, const char *id, input_module& module)
|
rawinput_keyboard_device(running_machine &machine, const char *name, const char *id, input_module &module) :
|
||||||
: rawinput_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
|
rawinput_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
|
||||||
keyboard({{0}})
|
keyboard({{0}})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,9 +328,9 @@ private:
|
|||||||
public:
|
public:
|
||||||
mouse_state mouse;
|
mouse_state mouse;
|
||||||
|
|
||||||
rawinput_mouse_device(running_machine& machine, const char *name, const char *id, input_module& module)
|
rawinput_mouse_device(running_machine &machine, const char *name, const char *id, input_module &module) :
|
||||||
: rawinput_device(machine, name, id, DEVICE_CLASS_MOUSE, module),
|
rawinput_device(machine, name, id, DEVICE_CLASS_MOUSE, module),
|
||||||
mouse({0})
|
mouse({0})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,8 +388,8 @@ private:
|
|||||||
public:
|
public:
|
||||||
mouse_state lightgun;
|
mouse_state lightgun;
|
||||||
|
|
||||||
rawinput_lightgun_device(running_machine& machine, const char *name, const char *id, input_module& 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),
|
rawinput_device(machine, name, id, DEVICE_CLASS_LIGHTGUN, module),
|
||||||
lightgun({0})
|
lightgun({0})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -456,19 +443,14 @@ class rawinput_module : public wininput_module
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
osd::dynamic_module::ptr m_user32_dll;
|
osd::dynamic_module::ptr m_user32_dll;
|
||||||
get_rawinput_device_list_ptr get_rawinput_device_list;
|
get_rawinput_device_list_ptr get_rawinput_device_list = nullptr;
|
||||||
get_rawinput_data_ptr get_rawinput_data;
|
get_rawinput_data_ptr get_rawinput_data = nullptr;
|
||||||
get_rawinput_device_info_ptr get_rawinput_device_info;
|
get_rawinput_device_info_ptr get_rawinput_device_info = nullptr;
|
||||||
register_rawinput_devices_ptr register_rawinput_devices;
|
register_rawinput_devices_ptr register_rawinput_devices = nullptr;
|
||||||
std::mutex m_module_lock;
|
std::mutex m_module_lock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
rawinput_module(const char *type, const char* name)
|
rawinput_module(const char *type, const char *name) : wininput_module(type, name)
|
||||||
: wininput_module(type, name),
|
|
||||||
get_rawinput_device_list(nullptr),
|
|
||||||
get_rawinput_data(nullptr),
|
|
||||||
get_rawinput_device_info(nullptr),
|
|
||||||
register_rawinput_devices(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,13 +463,7 @@ public:
|
|||||||
get_rawinput_device_info = m_user32_dll->bind<get_rawinput_device_info_ptr>("GetRawInputDeviceInfoW");
|
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");
|
register_rawinput_devices = m_user32_dll->bind<register_rawinput_devices_ptr>("RegisterRawInputDevices");
|
||||||
|
|
||||||
if (!get_rawinput_device_list || !get_rawinput_data ||
|
return get_rawinput_device_list && get_rawinput_data && get_rawinput_device_info && register_rawinput_devices;
|
||||||
!get_rawinput_device_info || !register_rawinput_devices )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_init(running_machine &machine) override
|
void input_init(running_machine &machine) override
|
||||||
@ -501,7 +477,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
auto rawinput_devices = std::make_unique<RAWINPUTDEVICELIST[]>(device_count);
|
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;
|
return;
|
||||||
|
|
||||||
// iterate backwards through devices; new devices are added at the head
|
// iterate backwards through devices; new devices are added at the head
|
||||||
@ -533,7 +509,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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 usagepage() = 0;
|
||||||
virtual USHORT usage() = 0;
|
virtual USHORT usage() = 0;
|
||||||
|
|
||||||
@ -550,16 +526,15 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class TDevice>
|
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
|
// 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)
|
if ((*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, nullptr, &name_length) != 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
std::unique_ptr<TCHAR[]> tname = std::make_unique<TCHAR[]>(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) == -1)
|
if (name_length > 1 && (*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == UINT(-1))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// if this is an RDP name, skip it
|
// if this is an RDP name, skip it
|
||||||
@ -575,7 +550,7 @@ protected:
|
|||||||
// set device id to raw input name
|
// set device id to raw input name
|
||||||
std::string utf8_id = osd::text::from_wstring(tname.get());
|
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
|
// Add the handle
|
||||||
devinfo->set_handle(rawinputdevice->hDevice);
|
devinfo->set_handle(rawinputdevice->hDevice);
|
||||||
@ -583,7 +558,7 @@ protected:
|
|||||||
return devinfo;
|
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
|
// Only handle raw input data
|
||||||
if (!input_enabled() || eventid != INPUT_EVENT_RAWINPUT)
|
if (!input_enabled() || eventid != INPUT_EVENT_RAWINPUT)
|
||||||
@ -622,15 +597,18 @@ protected:
|
|||||||
auto *input = reinterpret_cast<RAWINPUT*>(data);
|
auto *input = reinterpret_cast<RAWINPUT*>(data);
|
||||||
|
|
||||||
// find the device in the list and update
|
// find the device in the list and update
|
||||||
auto target_device = std::find_if(devicelist()->begin(), devicelist()->end(), [input](auto &device)
|
auto target_device = std::find_if(
|
||||||
{
|
devicelist()->begin(),
|
||||||
auto devinfo = dynamic_cast<rawinput_device*>(device.get());
|
devicelist()->end(),
|
||||||
return devinfo != nullptr && input->header.hDevice == devinfo->device_handle();
|
[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())
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -654,7 +632,8 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
USHORT usagepage() override { return 1; }
|
USHORT usagepage() override { return 1; }
|
||||||
USHORT usage() override { return 6; }
|
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
|
// make sure this is a keyboard
|
||||||
if (device->dwType != RIM_TYPEKEYBOARD)
|
if (device->dwType != RIM_TYPEKEYBOARD)
|
||||||
@ -671,12 +650,12 @@ protected:
|
|||||||
for (int keynum = 0; keynum < MAX_KEYS; keynum++)
|
for (int keynum = 0; keynum < MAX_KEYS; keynum++)
|
||||||
{
|
{
|
||||||
input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
|
input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
|
||||||
TCHAR keyname[100];
|
WCHAR keyname[100];
|
||||||
|
|
||||||
// generate the name
|
// generate the name
|
||||||
if (GetKeyNameText(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, ARRAY_LENGTH(keyname)) == 0)
|
if (GetKeyNameTextW(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, ARRAY_LENGTH(keyname)) == 0)
|
||||||
_sntprintf(keyname, ARRAY_LENGTH(keyname), TEXT("Scan%03d"), keynum);
|
_snwprintf(keyname, ARRAY_LENGTH(keyname), L"Scan%03d", keynum);
|
||||||
std::string name = osd::text::from_tstring(keyname);
|
std::string name = osd::text::from_wstring(keyname);
|
||||||
|
|
||||||
// add the item to the device
|
// 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]);
|
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:
|
protected:
|
||||||
USHORT usagepage() override { return 1; }
|
USHORT usagepage() override { return 1; }
|
||||||
USHORT usage() override { return 2; }
|
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
|
// make sure this is a mouse
|
||||||
if (device->dwType != RIM_TYPEMOUSE)
|
if (device->dwType != RIM_TYPEMOUSE)
|
||||||
@ -747,7 +727,8 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
USHORT usagepage() override { return 1; }
|
USHORT usagepage() override { return 1; }
|
||||||
USHORT usage() override { return 2; }
|
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
|
// make sure this is a mouse
|
||||||
@ -781,6 +762,8 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
#else
|
#else
|
||||||
MODULE_NOT_SUPPORTED(keyboard_input_rawinput, OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
|
MODULE_NOT_SUPPORTED(keyboard_input_rawinput, OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
|
||||||
MODULE_NOT_SUPPORTED(mouse_input_rawinput, OSD_MOUSEINPUT_PROVIDER, "rawinput")
|
MODULE_NOT_SUPPORTED(mouse_input_rawinput, OSD_MOUSEINPUT_PROVIDER, "rawinput")
|
||||||
|
@ -40,14 +40,10 @@ struct mouse_state
|
|||||||
class wininput_module : public input_module_base
|
class wininput_module : public input_module_base
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
bool m_global_inputs_enabled;
|
bool m_global_inputs_enabled = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wininput_module(const char * type, const char * name)
|
wininput_module(const char *type, const char *name) : input_module_base(type, name) { }
|
||||||
: input_module_base(type, name),
|
|
||||||
m_global_inputs_enabled(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~wininput_module() { }
|
virtual ~wininput_module() { }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user