Merge pull request #2672 from npwoods/multiple_natural_keyboard_bindings

Added support for multiple PORT_CHAR() bindings, and adopted in the CoCo driver  (addresses MT#2618)
This commit is contained in:
R. Belmont 2017-10-10 21:07:00 -04:00 committed by GitHub
commit dc2b6e95eb
6 changed files with 85 additions and 58 deletions

View File

@ -616,7 +616,9 @@ ioport_field::ioport_field(ioport_port &port, ioport_type type, ioport_value def
// reset sequences and chars
for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype)
m_seq[seqtype].set_default();
std::fill(std::begin(m_chars), std::end(m_chars), char32_t(0));
for (int i = 0; i < ARRAY_LENGTH(m_chars); i++)
std::fill(std::begin(m_chars[i]), std::end(m_chars[i]), char32_t(0));
// for DIP switches and configs, look for a default value from the owner
if (type == IPT_DIPSWITCH || type == IPT_CONFIG)
@ -755,16 +757,20 @@ ioport_type_class ioport_field::type_class() const
//-------------------------------------------------
// keyboard_code - accesses a particular keyboard
// code
// keyboard_codes - accesses a particular keyboard
// code list
//-------------------------------------------------
char32_t ioport_field::keyboard_code(int which) const
std::vector<char32_t> ioport_field::keyboard_codes(int which) const
{
if (which >= ARRAY_LENGTH(m_chars))
throw emu_fatalerror("Tried to access keyboard_code with out-of-range index %d\n", which);
return m_chars[which];
std::vector<char32_t> result;
for (int i = 0; i < ARRAY_LENGTH(m_chars[which]) && m_chars[which] != 0; i++)
result.push_back(m_chars[which][i]);
return result;
}
@ -774,7 +780,8 @@ char32_t ioport_field::keyboard_code(int which) const
std::string ioport_field::key_name(int which) const
{
char32_t ch = keyboard_code(which);
std::vector<char32_t> codes = keyboard_codes(which);
char32_t ch = codes.empty() ? 0 : codes[0];
// attempt to get the string from the character info table
switch (ch)
@ -1373,8 +1380,8 @@ ioport_field_live::ioport_field_live(ioport_field &field, analog_field *analog)
// loop through each character on the field
for (int which = 0; which < 4; which++)
{
char32_t const ch = field.keyboard_code(which);
if (ch == 0)
std::vector<char32_t> const codes = field.keyboard_codes(which);
if (codes.empty())
break;
name.append(string_format("%-*s ", std::max(SPACE_COUNT - 1, 0), field.key_name(which)));
}
@ -3059,16 +3066,27 @@ ioport_configurer& ioport_configurer::field_alloc(ioport_type type, ioport_value
// field_add_char - add a character to a field
//-------------------------------------------------
ioport_configurer& ioport_configurer::field_add_char(char32_t ch)
ioport_configurer& ioport_configurer::field_add_char(std::initializer_list<char32_t> charlist)
{
for (int index = 0; index < ARRAY_LENGTH(m_curfield->m_chars); index++)
if (m_curfield->m_chars[index] == 0)
if (m_curfield->m_chars[index][0] == 0)
{
m_curfield->m_chars[index] = ch;
const size_t char_count = ARRAY_LENGTH(m_curfield->m_chars[index]);
assert(charlist.size() > 0 && charlist.size() <= char_count);
for (size_t i = 0; i < char_count; i++)
m_curfield->m_chars[index][i] = i < charlist.size() ? *(charlist.begin() + i) : 0;
return *this;
}
throw emu_fatalerror("PORT_CHAR(%d) could not be added - maximum amount exceeded\n", ch);
std::ostringstream s;
bool is_first = true;
for (char32_t ch : charlist)
{
util::stream_format(s, "%s%d", is_first ? "" : ",", (int)ch);
is_first = false;
}
throw emu_fatalerror("PORT_CHAR(%s) could not be added - maximum amount exceeded\n", s.str().c_str());
}

View File

@ -1063,7 +1063,7 @@ public:
const ioport_value *remap_table() const { return m_remap_table; }
u8 way() const { return m_way; }
char32_t keyboard_code(int which) const;
std::vector<char32_t> keyboard_codes(int which) const;
std::string key_name(int which) const;
ioport_field_live &live() const { assert(m_live != nullptr); return *m_live; }
@ -1149,7 +1149,7 @@ private:
// data relevant to other specific types
u8 m_way; // digital joystick 2/4/8-way descriptions
char32_t m_chars[1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1)]; // unicode key data
char32_t m_chars[1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1)][2]; // unicode key data
};
@ -1501,7 +1501,7 @@ public:
// field helpers
ioport_configurer& field_alloc(ioport_type type, ioport_value defval, ioport_value mask, const char *name = nullptr);
ioport_configurer& field_add_char(char32_t ch);
ioport_configurer& field_add_char(std::initializer_list<char32_t> charlist);
ioport_configurer& field_add_code(input_seq_type which, input_code code);
ioport_configurer& field_set_way(int way) { m_curfield->m_way = way; return *this; }
ioport_configurer& field_set_rotated() { m_curfield->m_flags |= ioport_field::FIELD_FLAG_ROTATED; return *this; }
@ -1746,8 +1746,8 @@ ATTR_COLD void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, s
configurer.setting_alloc((_default), (_name));
// keyboard chars
#define PORT_CHAR(_ch) \
configurer.field_add_char(_ch);
#define PORT_CHAR(...) \
configurer.field_add_char({ __VA_ARGS__ });
// name of table

View File

@ -580,11 +580,14 @@ void natural_keyboard::build_codes(ioport_manager &manager)
{
if (field.type() == IPT_KEYBOARD)
{
char32_t const code = field.keyboard_code(0);
if ((code >= UCHAR_SHIFT_BEGIN) && (code <= UCHAR_SHIFT_END))
std::vector<char32_t> const codes = field.keyboard_codes(0);
for (char32_t code : codes)
{
mask |= 1U << (code - UCHAR_SHIFT_BEGIN);
shift[code - UCHAR_SHIFT_BEGIN] = &field;
if ((code >= UCHAR_SHIFT_BEGIN) && (code <= UCHAR_SHIFT_END))
{
mask |= 1U << (code - UCHAR_SHIFT_BEGIN);
shift[code - UCHAR_SHIFT_BEGIN] = &field;
}
}
}
}
@ -603,35 +606,38 @@ void natural_keyboard::build_codes(ioport_manager &manager)
if (!(curshift & ~mask))
{
// fetch the code, ignoring 0 and shiters
char32_t const code = field.keyboard_code(curshift);
if (((code < UCHAR_SHIFT_BEGIN) || (code > UCHAR_SHIFT_END)) && (code != 0))
std::vector<char32_t> const codes = field.keyboard_codes(curshift);
for (char32_t code : codes)
{
// prefer lowest shift state
keycode_map::iterator const found(m_keycode_map.find(code));
if ((m_keycode_map.end() == found) || (found->second.shift > curshift))
if (((code < UCHAR_SHIFT_BEGIN) || (code > UCHAR_SHIFT_END)) && (code != 0))
{
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)
// prefer lowest shift state
keycode_map::iterator const found(m_keycode_map.find(code));
if ((m_keycode_map.end() == found) || (found->second.shift > curshift))
{
if (BIT(bits, 0))
newcode.field[fieldnum++] = shift[i];
}
keycode_map_entry newcode;
std::fill(std::begin(newcode.field), std::end(newcode.field), nullptr);
newcode.shift = curshift;
assert(fieldnum < ARRAY_LENGTH(newcode.field));
newcode.field[fieldnum] = &field;
if (m_keycode_map.end() == found)
m_keycode_map.emplace(code, newcode);
else
found->second = newcode;
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];
}
if (LOG_NATURAL_KEYBOARD)
{
machine().logerror("natural_keyboard: code=%u (%s) port=%p field.name='%s'\n",
assert(fieldnum < ARRAY_LENGTH(newcode.field));
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());
}
}
}
}

View File

@ -1876,13 +1876,16 @@ void validity_checker::validate_inputs()
// verify natural keyboard codes
for (int which = 0; which < 1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1); which++)
{
char32_t code = field.keyboard_code(which);
if (code && !uchar_isvalid(code))
std::vector<char32_t> codes = field.keyboard_codes(which);
for (char32_t code : codes)
{
osd_printf_error("Field '%s' has non-character U+%04X in PORT_CHAR(%d)\n",
name,
(unsigned)code,
(int)code);
if (!uchar_isvalid(code))
{
osd_printf_error("Field '%s' has non-character U+%04X in PORT_CHAR(%d)\n",
name,
(unsigned)code,
(int)code);
}
}
}
}

View File

@ -181,10 +181,10 @@ static INPUT_PORTS_START( coco_keyboard )
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_NAME("UP") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_NAME("DOWN") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_NAME("LEFT") PORT_CODE(KEYCODE_LEFT) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_NAME("UP") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP), '^')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_NAME("DOWN") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN), 10)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_NAME("LEFT") PORT_CODE(KEYCODE_LEFT) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(LEFT), 8)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT), 9)
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco12_state, coco_state::keyboard_changed, nullptr) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_START("row4")

View File

@ -111,10 +111,10 @@ static INPUT_PORTS_START( coco3_keyboard )
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_NAME("UP") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_NAME("DOWN") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_NAME("LEFT") PORT_CODE(KEYCODE_LEFT) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_NAME("UP") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP), '^')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_NAME("DOWN") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN), 10)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_NAME("LEFT") PORT_CODE(KEYCODE_LEFT) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(LEFT), 8)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT), 9)
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, coco3_state, coco_state::keyboard_changed, nullptr) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_START("row4")