summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/natkeyboard.cpp
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2020-10-11 02:58:46 +1100
committer Vas Crabb <vas@vastheman.com>2020-10-11 02:58:46 +1100
commitc751a5348a89f2cd9d6b84938551e341ec7f8450 (patch)
tree6de05430e61f273376943b79ee61a5b83de3552d /src/emu/natkeyboard.cpp
parent9e971ab36e2752d554239f9eb92397f87679deb5 (diff)
-emu/natkeyboard.cpp: Allow keyboard devices to be enabled/disabled.
This fixes the "typing on all keyboards at once" issue. You can now enable and disable keyboard/keypad inputs per device in the Keyboard Mode menu. Default is to enable the first device with keyboard inputs, and all device with keypad inputs but no keyboard inputs. The settings are saved in the CFG file for the machine. Typing in natural keyboard mode only ever types on one keyboard at a time, but now you can control which keyboard it types on, as it will be the first enabled keyboard. You can easily try this out with something like: mame64d zorba -rs232 terminal cpm -ui/inputmap.cpp: Show device descriptions as well as tag paths. -mac128.cpp: Fixed mouse axis wrap compensation, cleaned up mouse code, eliminated static variables for mouse input state. You could see the issue with wrap detection easily enough just by running mac128k/mac512k/macplus and tapping the arrow keys to move the mouse one pixel at a time. As you moved past the point where the axis count wrapped, it would move one pixel in the opposite direction. There were two function static variables related to mouse input state, probably still lurking from when the code was initially made to use a driver state class. This obviously messes with save states and prevents multiple instances. - bus/a2bus/mouse.cpp: Fixed mouse axis wrap compensation. This device had the same bug with wrap compensation as mac128k.cpp.
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;
+ }
}
}
}