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.cpp482
1 files changed, 299 insertions, 183 deletions
diff --git a/src/emu/natkeyboard.cpp b/src/emu/natkeyboard.cpp
index 7d154787c0c..1abe9a140ff 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
@@ -10,7 +10,16 @@
#include "emu.h"
#include "natkeyboard.h"
+
+#include "corestr.h"
#include "emuopts.h"
+#include "unicode.h"
+
+// FIXME: allow OSD module headers to be included in a less ugly way
+#include "../osd/modules/lib/osdlib.h"
+
+#include <algorithm>
+#include <cstring>
//**************************************************************************
@@ -25,7 +34,8 @@
// CONSTANTS
//**************************************************************************
-const int KEY_BUFFER_SIZE = 4096;
+const u32 KEY_BUFFER_CHUNK_SIZE = 0x1000;
+const u32 KEY_BUFFER_MAX_SIZE = 0x800000;
const char32_t INVALID_CHAR = '?';
@@ -38,7 +48,7 @@ const char32_t INVALID_CHAR = '?';
struct char_info
{
char32_t ch;
- const char *alternate; // alternative string, in UTF-8
+ const char *alternate; // alternative string, in UTF-8
static const char_info *find(char32_t target);
};
@@ -317,9 +327,11 @@ const char_info charinfo[] =
natural_keyboard::natural_keyboard(running_machine &machine)
: m_machine(machine)
+ , m_have_charkeys(false)
, m_in_use(false)
, m_bufbegin(0)
, m_bufend(0)
+ , m_current_code(nullptr)
, m_fieldnum(0)
, m_status_keydown(false)
, m_last_cr(false)
@@ -330,10 +342,10 @@ 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_keyboards.empty())
{
- m_buffer.resize(KEY_BUFFER_SIZE);
+ m_buffer.resize(KEY_BUFFER_CHUNK_SIZE);
m_timer = machine.scheduler().timer_alloc(timer_expired_delegate(FUNC(natural_keyboard::timer), this));
}
@@ -350,9 +362,10 @@ natural_keyboard::natural_keyboard(running_machine &machine)
void natural_keyboard::configure(ioport_queue_chars_delegate queue_chars, ioport_accept_char_delegate accept_char, ioport_charqueue_empty_delegate charqueue_empty)
{
// set the callbacks
- m_queue_chars = queue_chars;
- m_accept_char = accept_char;
- m_charqueue_empty = charqueue_empty;
+ assert(m_timer != nullptr);
+ m_queue_chars = std::move(queue_chars);
+ m_accept_char = std::move(accept_char);
+ m_charqueue_empty = std::move(charqueue_empty);
}
@@ -370,59 +383,69 @@ 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);
+ }
+ }
}
}
//-------------------------------------------------
-// post - post a single character
+// post_char - post a single character
//-------------------------------------------------
-void natural_keyboard::post(char32_t ch)
+void natural_keyboard::post_char(char32_t ch, bool normalize_crlf)
{
- // ignore any \n that are preceded by \r
- if (m_last_cr && ch == '\n')
+ if (normalize_crlf)
{
- m_last_cr = false;
- return;
- }
+ // ignore any \n that are preceded by \r
+ if (m_last_cr && ch == '\n')
+ {
+ m_last_cr = false;
+ return;
+ }
- // change all eolns to '\r'
- if (ch == '\n')
- ch = '\r';
- else
- m_last_cr = (ch == '\r');
+ // change all eolns to '\r'
+ if (ch == '\n')
+ ch = '\r';
+ else
+ m_last_cr = (ch == '\r');
+ }
// logging
if (LOG_NATURAL_KEYBOARD)
{
const keycode_map_entry *code = find_code(ch);
- machine().logerror("natural_keyboard::post(): 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>");
+ 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);
}
}
@@ -433,23 +456,14 @@ void natural_keyboard::post(char32_t ch)
// post - post a unicode encoded string
//-------------------------------------------------
-void natural_keyboard::post(const char32_t *text, size_t length, const attotime &rate)
+void natural_keyboard::post(std::u32string_view text, const attotime &rate)
{
// set the fixed rate
m_current_rate = rate;
- // 0 length means strlen
- if (length == 0)
- for (const char32_t *scan = text; *scan != 0; scan++)
- length++;
-
- // iterate over characters or until the buffer is full up
- while (length > 0 && !full())
- {
- // fetch next character
- post(*text++);
- length--;
- }
+ // iterate over characters
+ for (char32_t ch : text)
+ post_char(ch, true);
}
@@ -457,21 +471,17 @@ void natural_keyboard::post(const char32_t *text, size_t length, const attotime
// post_utf8 - post a UTF-8 encoded string
//-------------------------------------------------
-void natural_keyboard::post_utf8(const char *text, size_t length, const attotime &rate)
+void natural_keyboard::post_utf8(std::string_view text, const attotime &rate)
{
// set the fixed rate
m_current_rate = rate;
- // 0-length means strlen
- if (length == 0)
- length = strlen(text);
-
// iterate until out of characters
- while (length > 0)
+ while (!text.empty())
{
// decode the next character
char32_t uc;
- int count = uchar_from_utf8(&uc, text, length);
+ int count = uchar_from_utf8(&uc, text);
if (count < 0)
{
count = 1;
@@ -479,84 +489,75 @@ void natural_keyboard::post_utf8(const char *text, size_t length, const attotime
}
// append to the buffer
- post(uc);
- text += count;
- length -= count;
+ post_char(uc, true);
+ text.remove_prefix(count);
}
}
-void natural_keyboard::post_utf8(const std::string &text, const attotime &rate)
-{
- if (!text.empty())
- post_utf8(text.c_str(), text.size(), rate);
-}
-
-
//-------------------------------------------------
// post_coded - post a coded string
//-------------------------------------------------
-void natural_keyboard::post_coded(const char *text, size_t length, const attotime &rate)
+void natural_keyboard::post_coded(std::string_view text, const attotime &rate)
{
+ using namespace std::literals;
static const struct
{
- const char *key;
+ std::string_view key;
char32_t code;
} codes[] =
{
- { "BACKSPACE", 8 },
- { "BS", 8 },
- { "BKSP", 8 },
- { "DEL", UCHAR_MAMEKEY(DEL) },
- { "DELETE", UCHAR_MAMEKEY(DEL) },
- { "END", UCHAR_MAMEKEY(END) },
- { "ENTER", 13 },
- { "ESC", '\033' },
- { "HOME", UCHAR_MAMEKEY(HOME) },
- { "INS", UCHAR_MAMEKEY(INSERT) },
- { "INSERT", UCHAR_MAMEKEY(INSERT) },
- { "PGDN", UCHAR_MAMEKEY(PGDN) },
- { "PGUP", UCHAR_MAMEKEY(PGUP) },
- { "SPACE", 32 },
- { "TAB", 9 },
- { "F1", UCHAR_MAMEKEY(F1) },
- { "F2", UCHAR_MAMEKEY(F2) },
- { "F3", UCHAR_MAMEKEY(F3) },
- { "F4", UCHAR_MAMEKEY(F4) },
- { "F5", UCHAR_MAMEKEY(F5) },
- { "F6", UCHAR_MAMEKEY(F6) },
- { "F7", UCHAR_MAMEKEY(F7) },
- { "F8", UCHAR_MAMEKEY(F8) },
- { "F9", UCHAR_MAMEKEY(F9) },
- { "F10", UCHAR_MAMEKEY(F10) },
- { "F11", UCHAR_MAMEKEY(F11) },
- { "F12", UCHAR_MAMEKEY(F12) },
- { "QUOTE", '\"' }
+ { "BACKSPACE"sv, 8 },
+ { "BS"sv, 8 },
+ { "BKSP"sv, 8 },
+ { "CAPSLOCK"sv, UCHAR_MAMEKEY(CAPSLOCK) },
+ { "CR"sv, 13 },
+ { "DEL"sv, UCHAR_MAMEKEY(DEL) },
+ { "DELETE"sv, UCHAR_MAMEKEY(DEL) },
+ { "END"sv, UCHAR_MAMEKEY(END) },
+ { "ENTER"sv, 13 },
+ { "ESC"sv, '\033' },
+ { "HOME"sv, UCHAR_MAMEKEY(HOME) },
+ { "INS"sv, UCHAR_MAMEKEY(INSERT) },
+ { "INSERT"sv, UCHAR_MAMEKEY(INSERT) },
+ { "LF"sv, 10 },
+ { "PGDN"sv, UCHAR_MAMEKEY(PGDN) },
+ { "PGUP"sv, UCHAR_MAMEKEY(PGUP) },
+ { "SPACE"sv, 32 },
+ { "TAB"sv, 9 },
+ { "F1"sv, UCHAR_MAMEKEY(F1) },
+ { "F2"sv, UCHAR_MAMEKEY(F2) },
+ { "F3"sv, UCHAR_MAMEKEY(F3) },
+ { "F4"sv, UCHAR_MAMEKEY(F4) },
+ { "F5"sv, UCHAR_MAMEKEY(F5) },
+ { "F6"sv, UCHAR_MAMEKEY(F6) },
+ { "F7"sv, UCHAR_MAMEKEY(F7) },
+ { "F8"sv, UCHAR_MAMEKEY(F8) },
+ { "F9"sv, UCHAR_MAMEKEY(F9) },
+ { "F10"sv, UCHAR_MAMEKEY(F10) },
+ { "F11"sv, UCHAR_MAMEKEY(F11) },
+ { "F12"sv, UCHAR_MAMEKEY(F12) },
+ { "QUOTE"sv, '\"' }
};
// set the fixed rate
m_current_rate = rate;
- // 0-length means strlen
- if (length == 0)
- length = strlen(text);
-
// iterate through the source string
- size_t curpos = 0;
- while (curpos < length)
+ while (!text.empty())
{
// extract next character
- char32_t ch = text[curpos];
- size_t increment = 1;
+ char32_t ch = text.front();
+ std::string_view::size_type increment = 1;
// look for escape characters
if (ch == '{')
for (auto & code : codes)
{
- size_t keylen = strlen(code.key);
- if (curpos + keylen + 2 <= length)
- if (core_strnicmp(code.key, &text[curpos + 1], keylen) == 0 && text[curpos + keylen + 1] == '}')
+ std::string_view::size_type keylen = code.key.length();
+ if (keylen + 2 <= text.length())
+ if (util::strequpper(text.substr(1, keylen), code.key) && text[keylen + 1] == '}')
{
ch = code.code;
increment = keylen + 2;
@@ -565,19 +566,12 @@ void natural_keyboard::post_coded(const char *text, size_t length, const attotim
// if we got a code, post it
if (ch != 0)
- post(ch);
- curpos += increment;
+ post_char(ch);
+ text.remove_prefix(increment);
}
}
-void natural_keyboard::post_coded(const std::string &text, const attotime &rate)
-{
- if (!text.empty())
- post_coded(text.c_str(), text.size(), rate);
-}
-
-
//-------------------------------------------------
// paste - does a paste from the keyboard
//-------------------------------------------------
@@ -598,16 +592,63 @@ 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)
+ {
+ if (LOG_NATURAL_KEYBOARD)
+ machine().logerror("natural_keyboard: building codes for %s... (%u fields)\n", devinfo.device.get().tag(), devinfo.keyfields.size());
+
+ // 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);
@@ -617,17 +658,17 @@ void natural_keyboard::build_codes(ioport_manager &manager)
{
mask |= 1U << (code - UCHAR_SHIFT_BEGIN);
shift[code - UCHAR_SHIFT_BEGIN] = &field;
+ if (LOG_NATURAL_KEYBOARD)
+ machine().logerror("natural_keyboard: UCHAR_SHIFT_%d found\n", code - UCHAR_SHIFT_BEGIN + 1);
}
}
}
}
- }
- // 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
@@ -635,38 +676,40 @@ void natural_keyboard::build_codes(ioport_manager &manager)
{
if (!(curshift & ~mask))
{
- // fetch the code, ignoring 0 and shiters
+ // fetch the code, ignoring shifters
std::vector<char32_t> const codes = field.keyboard_codes(curshift);
for (char32_t code : codes)
{
- if (((code < UCHAR_SHIFT_BEGIN) || (code > UCHAR_SHIFT_END)) && (code != 0))
+ if ((code < UCHAR_SHIFT_BEGIN) || (code > UCHAR_SHIFT_END))
{
- // prefer lowest shift state
- keycode_map::iterator const found(m_keycode_map.find(code));
- if ((m_keycode_map.end() == found) || (found->second.shift > curshift))
+ 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);
+ for (unsigned i = 0, bits = curshift; (i < SHIFT_COUNT) && bits; ++i, bits >>= 1)
{
- keycode_map_entry newcode;
- std::fill(std::begin(newcode.field), std::end(newcode.field), nullptr);
- newcode.shift = curshift;
-
- unsigned fieldnum = 0;
- for (unsigned i = 0, bits = curshift; (i < SHIFT_COUNT) && bits; ++i, bits >>= 1)
- {
- if (BIT(bits, 0))
- newcode.field[fieldnum++] = shift[i];
- }
-
- newcode.field[fieldnum] = &field;
- if (m_keycode_map.end() == found)
- m_keycode_map.emplace(code, newcode);
- else
- found->second = newcode;
-
- 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());
- }
+ if (BIT(bits, 0))
+ newcode.field[fieldnum++] = shift[i];
+ }
+
+ newcode.field[fieldnum] = &field;
+ if (devinfo.codemap.end() == found)
+ {
+ keycode_map_entries entries;
+ entries.emplace_back(newcode);
+ devinfo.codemap.emplace(code, std::move(entries));
+ }
+ else
+ found->second.emplace_back(newcode);
+
+ if (LOG_NATURAL_KEYBOARD)
+ {
+ machine().logerror("natural_keyboard: code=%u (%s) port=%p field.name='%s'\n",
+ code, unicode_to_string(code), (void *)&field.port(), field.name());
}
}
}
@@ -674,6 +717,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; });
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// 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)
+ {
+ m_keyboards[n].enabled = enable;
+ for (ioport_field &field : m_keyboards[n].keyfields)
+ field.live().lockout = !enable || ((field.type() == IPT_KEYBOARD) && in_use());
}
}
@@ -759,10 +827,19 @@ void natural_keyboard::internal_post(char32_t ch)
}
// add to the buffer, resizing if necessary
- m_buffer[m_bufend++] = ch;
- if ((m_bufend + 1) % m_buffer.size() == m_bufbegin)
- m_buffer.resize(m_buffer.size() + KEY_BUFFER_SIZE);
- m_bufend %= m_buffer.size();
+ m_buffer[m_bufend] = ch;
+ size_t size = m_buffer.size();
+
+ if ((m_bufend + 1) % size == m_bufbegin)
+ {
+ if (size >= KEY_BUFFER_MAX_SIZE)
+ return;
+
+ m_buffer.insert(m_buffer.begin() + m_bufbegin, KEY_BUFFER_CHUNK_SIZE, INVALID_CHAR);
+ m_bufbegin += KEY_BUFFER_CHUNK_SIZE;
+ }
+
+ m_bufend = (m_bufend + 1) % size;
}
@@ -771,7 +848,7 @@ void natural_keyboard::internal_post(char32_t ch)
// when posting a string of characters
//-------------------------------------------------
-void natural_keyboard::timer(void *ptr, int param)
+void natural_keyboard::timer(s32 param)
{
if (!m_queue_chars.isnull())
{
@@ -788,13 +865,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
@@ -804,8 +883,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
{
@@ -875,8 +954,22 @@ 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));
- return (m_keycode_map.end() != found) ? &found->second : nullptr;
+ for (kbd_dev_info const &devinfo : m_keyboards)
+ {
+ 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;
}
@@ -888,23 +981,46 @@ 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
+ 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);
- // identify the keys used
- for (std::size_t field = 0; (code.second.field.size() > field) && code.second.field[field]; ++field)
- util::stream_format(str, "%s'%s'", first ? "" : ", ", code.second.field[field]->name());
+ for (auto &entry : code.second)
+ {
+ // identify the keys used
+ bool firstkey(true);
+ 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());
+ firstkey = false;
+ }
- // carriage return
- str << '\n';
- first = false;
+ // carriage return
+ str << '\n';
+ }
+ }
}
}
@@ -934,7 +1050,7 @@ const char_info *char_info::find(char32_t target)
{
// perform a simple binary search to find the proper alternate
int low = 0;
- int high = ARRAY_LENGTH(charinfo);
+ int high = std::size(charinfo);
while (high > low)
{
int middle = (high + low) / 2;
@@ -964,7 +1080,7 @@ bool validate_natural_keyboard_statics(void)
const char_info *ci;
// check to make sure that charinfo is in order
- for (i = 0; i < ARRAY_LENGTH(charinfo); i++)
+ for (i = 0; i < std::size(charinfo); i++)
{
if (last_char >= charinfo[i].ch)
{
@@ -975,7 +1091,7 @@ bool validate_natural_keyboard_statics(void)
}
// check to make sure that I can look up everything on alternate_charmap
- for (i = 0; i < ARRAY_LENGTH(charinfo); i++)
+ for (i = 0; i < std::size(charinfo); i++)
{
ci = char_info::find(charinfo[i].ch);
if (ci != &charinfo[i])