summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/natkeyboard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/natkeyboard.cpp')
-rw-r--r--src/emu/natkeyboard.cpp228
1 files changed, 162 insertions, 66 deletions
diff --git a/src/emu/natkeyboard.cpp b/src/emu/natkeyboard.cpp
index 53a95f46a4b..05ce1f9d685 100644
--- a/src/emu/natkeyboard.cpp
+++ b/src/emu/natkeyboard.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles,Vas Crabb
/***************************************************************************
natkeyboard.cpp
@@ -12,6 +12,9 @@
#include "natkeyboard.h"
#include "emuopts.h"
+#include <algorithm>
+#include <cstring>
+
//**************************************************************************
// DEBUGGING
@@ -330,8 +333,8 @@ natural_keyboard::natural_keyboard(running_machine &machine)
, m_charqueue_empty()
{
// try building a list of keycodes; if none are available, don't bother
- build_codes(machine.ioport());
- if (!m_keycode_map.empty())
+ build_codes();
+ if (m_have_charkeys)
{
m_buffer.resize(KEY_BUFFER_SIZE);
m_timer = machine.scheduler().timer_alloc(timer_expired_delegate(FUNC(natural_keyboard::timer), this));
@@ -370,16 +373,18 @@ void natural_keyboard::set_in_use(bool usage)
machine().options().set_value(OPTION_NATURAL_KEYBOARD, usage, OPTION_PRIORITY_CMDLINE);
// lock out (or unlock) all keyboard inputs
- for (auto &port : machine().ioport().ports())
- for (ioport_field &field : port.second->fields())
- if (field.type() == IPT_KEYBOARD)
- {
- field.live().lockout = usage;
+ for (kbd_dev_info &devinfo : m_keyboards)
+ {
+ for (ioport_field &field : devinfo.keyfields)
+ {
+ bool const is_keyboard(field.type() == IPT_KEYBOARD);
+ field.live().lockout = !devinfo.enabled || (is_keyboard && usage);
- // clear pressed status when going out of use
- if (!usage)
- field.set_value(0);
- }
+ // clear pressed status when going out of use
+ if (is_keyboard && !usage)
+ field.set_value(0);
+ }
+ }
}
}
@@ -413,19 +418,24 @@ void natural_keyboard::post_char(char32_t ch, bool normalize_crlf)
machine().logerror("natural_keyboard::post_char(): code=%i (%s) field.name='%s'\n", int(ch), unicode_to_string(ch).c_str(), (code != nullptr && code->field[0] != nullptr) ? code->field[0]->name() : "<null>");
}
- // can we post this key in the queue directly?
if (can_post_directly(ch))
+ {
+ // can post this key in the queue directly
internal_post(ch);
-
- // can we post this key with an alternate representation?
+ }
else if (can_post_alternate(ch))
{
- const char_info *info = char_info::find(ch);
+ // can post this key with an alternate representation
+ char_info const *const info = char_info::find(ch);
assert(info != nullptr && info->alternate != nullptr);
- const char *altstring = info->alternate;
- while (*altstring != 0)
+ char const *altstring = info->alternate;
+ unsigned remain(std::strlen(altstring));
+ while (remain)
{
- altstring += uchar_from_utf8(&ch, altstring, strlen(altstring));
+ int const used(uchar_from_utf8(&ch, altstring, remain));
+ assert(0 < used);
+ altstring += used;
+ remain -= used;
internal_post(ch);
}
}
@@ -601,16 +611,60 @@ void natural_keyboard::paste()
// chars
//-------------------------------------------------
-void natural_keyboard::build_codes(ioport_manager &manager)
+void natural_keyboard::build_codes()
{
- // find all shift keys
- unsigned mask = 0;
- std::array<ioport_field *, SHIFT_COUNT> shift;
- std::fill(std::begin(shift), std::end(shift), nullptr);
+ ioport_manager &manager(machine().ioport());
+
+ // find all the devices with keyboard or keypad inputs
for (auto const &port : manager.ports())
{
+ auto devinfo(
+ std::find_if(
+ m_keyboards.begin(),
+ m_keyboards.end(),
+ [&port] (kbd_dev_info const &info)
+ {
+ return &port.second->device() == &info.device.get();
+ }));
for (ioport_field &field : port.second->fields())
{
+ bool const is_keyboard(field.type() == IPT_KEYBOARD);
+ if (is_keyboard || (field.type() == IPT_KEYPAD))
+ {
+ if (m_keyboards.end() == devinfo)
+ devinfo = m_keyboards.emplace(devinfo, port.second->device());
+ devinfo->keyfields.emplace_back(field);
+ if (is_keyboard)
+ devinfo->keyboard = true;
+ else
+ devinfo->keypad = true;
+ }
+ }
+ }
+ std::sort(
+ std::begin(m_keyboards),
+ std::end(m_keyboards),
+ [] (kbd_dev_info const &l, kbd_dev_info const &r)
+ {
+ return 0 > std::strcmp(l.device.get().tag(), r.device.get().tag());
+ });
+
+ // set up key mappings for each keyboard
+ std::array<ioport_field *, SHIFT_COUNT> shift;
+ unsigned mask;
+ bool have_keyboard(false);
+ for (kbd_dev_info &devinfo : m_keyboards)
+ {
+ // enable all pure keypads and the first keyboard
+ if (!devinfo.keyboard || !have_keyboard)
+ devinfo.enabled = true;
+ have_keyboard = have_keyboard || devinfo.keyboard;
+
+ // find all shift keys
+ std::fill(std::begin(shift), std::end(shift), nullptr);
+ mask = 0;
+ for (ioport_field &field : devinfo.keyfields)
+ {
if (field.type() == IPT_KEYBOARD)
{
std::vector<char32_t> const codes = field.keyboard_codes(0);
@@ -624,13 +678,11 @@ void natural_keyboard::build_codes(ioport_manager &manager)
}
}
}
- }
- // iterate over ports and fields
- for (auto const &port : manager.ports())
- {
- for (ioport_field &field : port.second->fields())
+ // iterate over keyboard/keypad fields
+ for (ioport_field &field : devinfo.keyfields)
{
+ field.live().lockout = !devinfo.enabled;
if (field.type() == IPT_KEYBOARD)
{
// iterate over all shift states
@@ -644,13 +696,14 @@ void natural_keyboard::build_codes(ioport_manager &manager)
{
if (((code < UCHAR_SHIFT_BEGIN) || (code > UCHAR_SHIFT_END)) && (code != 0))
{
- keycode_map::iterator const found(m_keycode_map.find(code));
+ m_have_charkeys = true;
+ keycode_map::iterator const found(devinfo.codemap.find(code));
keycode_map_entry newcode;
std::fill(std::begin(newcode.field), std::end(newcode.field), nullptr);
newcode.shift = curshift;
newcode.condition = field.condition();
- unsigned fieldnum = 0;
+ unsigned fieldnum(0);
for (unsigned i = 0, bits = curshift; (i < SHIFT_COUNT) && bits; ++i, bits >>= 1)
{
if (BIT(bits, 0))
@@ -658,11 +711,11 @@ void natural_keyboard::build_codes(ioport_manager &manager)
}
newcode.field[fieldnum] = &field;
- if (m_keycode_map.end() == found)
+ if (devinfo.codemap.end() == found)
{
keycode_map_entries entries;
entries.emplace_back(newcode);
- m_keycode_map.emplace(code, std::move(entries));
+ devinfo.codemap.emplace(code, std::move(entries));
}
else
found->second.emplace_back(newcode);
@@ -670,7 +723,7 @@ void natural_keyboard::build_codes(ioport_manager &manager)
if (LOG_NATURAL_KEYBOARD)
{
machine().logerror("natural_keyboard: code=%u (%s) port=%p field.name='%s'\n",
- code, unicode_to_string(code), (void *)&port, field.name());
+ code, unicode_to_string(code), (void *)&field.port(), field.name());
}
}
}
@@ -678,15 +731,31 @@ void natural_keyboard::build_codes(ioport_manager &manager)
}
}
}
+
+ // sort mapping entries by shift state
+ for (auto &mapping : devinfo.codemap)
+ {
+ std::sort(
+ mapping.second.begin(),
+ mapping.second.end(),
+ [] (keycode_map_entry const &x, keycode_map_entry const &y) { return x.shift < y.shift; });
+ }
}
+}
- // sort mapping entries by shift state
- for (auto &mapping : m_keycode_map)
+
+//-------------------------------------------------
+// set_keyboard_enabled - enable or disable a
+// device with key inputs
+//-------------------------------------------------
+
+void natural_keyboard::set_keyboard_enabled(size_t n, bool enable)
+{
+ if (enable != m_keyboards[n].enabled)
{
- std::sort(
- mapping.second.begin(),
- mapping.second.end(),
- [] (keycode_map_entry const &x, keycode_map_entry const &y) { return x.shift < y.shift; });
+ m_keyboards[n].enabled = enable;
+ for (ioport_field &field : m_keyboards[n].keyfields)
+ field.live().lockout = !enable || ((field.type() == IPT_KEYBOARD) && in_use());
}
}
@@ -801,13 +870,15 @@ void natural_keyboard::timer(void *ptr, int param)
// the driver does not have a queue_chars handler
// loop through this character's component codes
- const keycode_map_entry *const code = find_code(m_buffer[m_bufbegin]);
+ if (!m_fieldnum)
+ m_current_code = find_code(m_buffer[m_bufbegin]);
bool advance;
- if (code)
+ if (m_current_code)
{
+ keycode_map_entry const code(*m_current_code);
do
{
- ioport_field *const field = code->field[m_fieldnum];
+ ioport_field *const field = code.field[m_fieldnum];
if (field)
{
// special handling for toggle fields
@@ -817,8 +888,8 @@ void natural_keyboard::timer(void *ptr, int param)
field->set_value(!field->digital_value());
}
}
- while (code->field[m_fieldnum] && (++m_fieldnum < code->field.size()) && m_status_keydown);
- advance = (m_fieldnum >= code->field.size()) || !code->field[m_fieldnum];
+ while (code.field[m_fieldnum] && (++m_fieldnum < code.field.size()) && m_status_keydown);
+ advance = (m_fieldnum >= code.field.size()) || !code.field[m_fieldnum];
}
else
{
@@ -888,13 +959,20 @@ std::string natural_keyboard::unicode_to_string(char32_t ch) const
const natural_keyboard::keycode_map_entry *natural_keyboard::find_code(char32_t ch) const
{
- keycode_map::const_iterator const found(m_keycode_map.find(ch));
- if (m_keycode_map.end() == found)
- return nullptr;
- for (keycode_map_entry const &entry : found->second)
+ for (kbd_dev_info const &devinfo : m_keyboards)
{
- if (entry.condition.eval())
- return &entry;
+ if (devinfo.enabled)
+ {
+ keycode_map::const_iterator const found(devinfo.codemap.find(ch));
+ if (devinfo.codemap.end() != found)
+ {
+ for (keycode_map_entry const &entry : found->second)
+ {
+ if (entry.condition.eval())
+ return &entry;
+ }
+ }
+ }
}
return nullptr;
}
@@ -908,25 +986,43 @@ void natural_keyboard::dump(std::ostream &str) const
{
constexpr size_t left_column_width = 24;
- // loop through all codes
- bool first(true);
- for (auto &code : m_keycode_map)
+ // loop through all devices
+ bool firstdev(true);
+ for (kbd_dev_info const &devinfo : m_keyboards)
{
- // describe the character code
- std::string const description(string_format("%08X (%s) ", code.first, unicode_to_string(code.first)));
+ if (!firstdev)
+ str << '\n';
+ util::stream_format(
+ str,
+ "%s(%s) - %s%s%s %sabled\n",
+ devinfo.device.get().type().shortname(),
+ devinfo.device.get().tag(),
+ devinfo.keyboard ? "keyboard" : "",
+ (devinfo.keyboard && devinfo.keypad) ? "/" : "",
+ devinfo.keypad ? "keypad" : "",
+ devinfo.enabled ? "en" : "dis");
+ firstdev = false;
+
+ // loop through all codes
+ bool firstkey(true);
+ for (auto &code : devinfo.codemap)
+ {
+ // describe the character code
+ std::string const description(string_format("%08X (%s) ", code.first, unicode_to_string(code.first)));
- // pad with spaces
- util::stream_format(str, "%-*s", left_column_width, description);
+ // pad with spaces
+ util::stream_format(str, "%-*s", left_column_width, description);
- for (auto &entry : code.second)
- {
- // identify the keys used
- for (std::size_t field = 0; (entry.field.size() > field) && entry.field[field]; ++field)
- util::stream_format(str, "%s'%s'", first ? "" : ", ", entry.field[field]->name());
+ for (auto &entry : code.second)
+ {
+ // identify the keys used
+ for (std::size_t field = 0; (entry.field.size() > field) && entry.field[field]; ++field)
+ util::stream_format(str, "%s'%s'", firstkey ? "" : ", ", entry.field[field]->name());
- // carriage return
- str << '\n';
- first = false;
+ // carriage return
+ str << '\n';
+ firstkey = false;
+ }
}
}
}