36 using std::shared_ptr;
37 using std::make_shared;
50 static constexpr
bool SANE_CAPSLOCK_BEHAVIOR =
false;
55 static constexpr
bool SANE_CAPSLOCK_BEHAVIOR =
true;
59 static const int TRY_AGAIN = 0x80;
69 , row(row_), press(press_), release(release_)
72 assert((press != 0) || (release != 0));
76 assert((press & release) == 0);
78 [[nodiscard]]
byte getRow()
const {
return row; }
79 [[nodiscard]]
byte getPress()
const {
return press; }
80 [[nodiscard]]
byte getRelease()
const {
return release; }
82 template<
typename Archive>
void serialize(Archive& ar,
unsigned )
84 ar.template serializeBase<StateChange>(*
this);
85 ar.serialize(
"row", row,
90 byte row, press, release;
101 constexpr std::array<KeyMatrixPosition, UnicodeKeymap::KeyInfo::NUM_MODIFIERS>
130 , commandController(commandController_)
131 , msxEventDistributor(msxEventDistributor_)
132 , stateChangeDistributor(stateChangeDistributor_)
133 , keyTab(keyTabs[matrix])
135 , keyMatrixUpCmd (commandController, stateChangeDistributor, scheduler_)
136 , keyMatrixDownCmd(commandController, stateChangeDistributor, scheduler_)
137 , keyTypeCmd (commandController, stateChangeDistributor, scheduler_)
138 , capsLockAligner(eventDistributor, scheduler_)
139 , keyboardSettings(commandController)
140 , msxKeyEventQueue(scheduler_, commandController.getInterpreter())
141 , keybDebuggable(motherBoard)
142 , unicodeKeymap(config.getChildData(
144 , hasKeypad(config.getChildDataAsBool(
"has_keypad", true))
145 , blockRow11(matrix == MATRIX_MSX
146 && !config.getChildDataAsBool(
"has_yesno_keys", false))
147 , keyGhosting(config.getChildDataAsBool(
"key_ghosting", true))
148 , keyGhostingSGCprotected(config.getChildDataAsBool(
149 "key_ghosting_sgc_protected", true))
150 , modifierIsLock(
KeyInfo::CAPS_MASK
151 | (config.getChildDataAsBool(
"code_kana_locks", false) ?
KeyInfo::CODE_MASK : 0)
152 | (config.getChildDataAsBool(
"graph_locks", false) ?
KeyInfo::GRAPH_MASK : 0))
178 template<
unsigned NUM_ROWS>
179 static void doKeyGhosting(
byte (&matrix)[NUM_ROWS],
bool protectRow6)
197 bool changedSomething;
199 changedSomething =
false;
200 for (
auto i :
xrange(NUM_ROWS - 1)) {
201 auto row1 = matrix[i];
202 for (
auto j :
xrange(i + 1, NUM_ROWS)) {
203 auto row2 = matrix[j];
204 if ((row1 != row2) && ((row1 | row2) != 0xff)) {
205 auto rowIold = matrix[i];
206 auto rowJold = matrix[j];
209 if (protectRow6 && i == 6) {
210 matrix[i] = row1 & row2;
211 matrix[j] = (row1 | 0x15) & row2;
213 }
else if (protectRow6 && j == 6) {
214 matrix[i] = row1 & (row2 | 0x15);
215 matrix[j] = row1 & row2;
216 row1 &= (row2 | 0x15);
220 auto newRow = row1 & row2;
225 if (rowIold != matrix[i] ||
226 rowJold != matrix[j]) {
227 changedSomething =
true;
232 }
while (changedSomething);
239 const auto* matrix = keyTypeCmd.isActive() ? typeKeyMatrix : userKeyMatrix;
241 keyMatrix[row] = cmdKeyMatrix[row] & matrix[row];
244 doKeyGhosting(keyMatrix, keyGhostingSGCprotected);
268 hostKeyMatrix[row] = source.hostKeyMatrix[row];
277 void Keyboard::signalMSXEvent(
const shared_ptr<const Event>& event,
285 msxKeyEventQueue.process_asap(time, event);
289 void Keyboard::signalStateChange(
const shared_ptr<StateChange>& event)
291 const auto* kms =
dynamic_cast<const KeyMatrixState*
>(
event.get());
294 userKeyMatrix[kms->getRow()] &= ~kms->getPress();
295 userKeyMatrix[kms->getRow()] |= kms->getRelease();
299 void Keyboard::stopReplay(EmuTime::param time)
301 for (
auto [row, hkm] :
enumerate(hostKeyMatrix)) {
302 changeKeyMatrixEvent(time,
byte(row), hkm);
305 msxKeyEventQueue.clear();
306 memset(dynKeymap, 0,
sizeof(dynKeymap));
311 return modifierIsLock
312 & (locksOn ^ keyInfo.modmask)
316 void Keyboard::pressKeyMatrixEvent(EmuTime::param time, KeyMatrixPosition pos)
318 if (!pos.isValid()) {
322 auto row = pos.getRow();
323 auto press = pos.getMask();
324 if (((hostKeyMatrix[row] & press) == 0) &&
325 ((userKeyMatrix[row] & press) == 0)) {
329 changeKeyMatrixEvent(time, row, hostKeyMatrix[row] & ~press);
332 void Keyboard::releaseKeyMatrixEvent(EmuTime::param time, KeyMatrixPosition pos)
334 if (!pos.isValid()) {
338 auto row = pos.getRow();
339 auto release = pos.getMask();
340 if (((hostKeyMatrix[row] & release) == release) &&
341 ((userKeyMatrix[row] & release) == release)) {
348 changeKeyMatrixEvent(time, row, hostKeyMatrix[row] | release);
351 void Keyboard::changeKeyMatrixEvent(EmuTime::param time,
byte row,
byte newValue)
355 hostKeyMatrix[row] = newValue;
357 byte diff = userKeyMatrix[row] ^ newValue;
358 if (diff == 0)
return;
359 byte press = userKeyMatrix[row] & diff;
360 byte release = newValue & diff;
361 stateChangeDistributor.
distributeNew(make_shared<KeyMatrixState>(
362 time, row, press, release));
368 bool Keyboard::processQueuedEvent(
const Event& event, EmuTime::param time)
372 const auto& keyEvent = checked_cast<const KeyEvent&>(event);
375 ? keyEvent.getScanCode() : keyEvent.getKeyCode();
385 ad_printf(
"Key pressed, unicode: 0x%04x, keyCode: 0x%05x, keyName: %s\n",
386 keyEvent.getUnicode(),
387 keyEvent.getKeyCode(),
389 debug(
"Key pressed, unicode: 0x%04x, keyCode: 0x%05x, keyName: %s\n",
390 keyEvent.getUnicode(),
391 keyEvent.getKeyCode(),
394 ad_printf(
"Key released, keyCode: 0x%05x, keyName: %s\n",
395 keyEvent.getKeyCode(),
397 debug(
"Key released, keyCode: 0x%05x, keyName: %s\n",
398 keyEvent.getKeyCode(),
404 for (
auto n :
xrange(3)) {
407 if (deadkey.isValid()) {
408 updateKeyMatrix(time, down, deadkey.pos);
416 processCapslockEvent(time, down);
419 processCodeKanaChange(time, down);
422 processGraphChange(time, down);
425 processKeypadEnterKey(time, down);
428 return processKeyEvent(time, down, keyEvent);
437 void Keyboard::processCodeKanaChange(EmuTime::param time,
bool down)
450 void Keyboard::processGraphChange(EmuTime::param time,
bool down)
463 void Keyboard::processCapslockEvent(EmuTime::param time,
bool down)
465 if (SANE_CAPSLOCK_BEHAVIOR) {
466 debug(
"Changing CAPS lock state according to SDL request\n");
472 debug(
"Pressing CAPS lock and scheduling a release\n");
479 void Keyboard::executeUntil(EmuTime::param time)
481 debug(
"Releasing CAPS lock\n");
485 void Keyboard::processKeypadEnterKey(EmuTime::param time,
bool down)
492 processSdlKey(time, down,
503 void Keyboard::processSdlKey(EmuTime::param time,
bool down,
Keys::KeyCode key)
505 if (key < MAX_KEYSYM) {
506 auto pos = keyTab[key];
508 if (pos.getRow() == 11 && blockRow11) {
512 updateKeyMatrix(time, down, pos);
520 void Keyboard::updateKeyMatrix(EmuTime::param time,
bool down, KeyMatrixPosition pos)
522 if (!pos.isValid()) {
527 pressKeyMatrixEvent(time, pos);
532 for (
auto [i, mp] :
enumerate(modifierPos)) {
534 msxModifiers &= ~(1 << i);
538 releaseKeyMatrixEvent(time, pos);
539 for (
auto [i, mp] :
enumerate(modifierPos)) {
541 msxModifiers |= 1 << i;
556 bool Keyboard::processKeyEvent(EmuTime::param time,
bool down,
const KeyEvent& keyEvent)
560 auto keyCode = keyEvent.getKeyCode();
561 auto scanCode = keyEvent.getScanCode();
570 if (isOnKeypad && !hasKeypad &&
590 #if defined(__APPLE__)
598 unicode = keyEvent.getUnicode();
599 if ((unicode < 0x20) || ((0x7F <= unicode) && (unicode < 0xA0))) {
609 keyInfo = unicodeKeymap.
get(unicode);
610 if (!keyInfo.isValid()) {
617 if (key < MAX_KEYSYM) {
624 dynKeymap[key] = unicode;
641 processSdlKey(time, down, key);
646 return pressUnicodeByUser(time, keyInfo, unicode,
true);
650 #if defined(__APPLE__)
656 unsigned unicode = (key < MAX_KEYSYM)
664 processSdlKey(time, down, key);
668 pressUnicodeByUser(time, unicodeKeymap.
get(unicode), unicode,
false);
676 unsigned row = tokens[1].getInt(interp);
677 unsigned mask = tokens[2].getInt(interp);
679 throw CommandException(
"Invalid row");
682 throw CommandException(
"Invalid mask");
685 cmdKeyMatrix[row] |=
mask;
687 cmdKeyMatrix[row] &= ~
mask;
730 bool Keyboard::pressUnicodeByUser(
734 bool insertCodeKanaRelease =
false;
743 insertCodeKanaRelease =
true;
752 pressKeyMatrixEvent(time, keyInfo.pos);
754 byte modmask = keyInfo.modmask & ~modifierIsLock;
755 if ((
'A' <= unicode && unicode <=
'Z') || (
'a' <= unicode && unicode <=
'z')) {
760 modmask &= ~
KeyInfo::SHIFT_MASK;
769 for (
auto [i, mp] :
enumerate(modifierPos)) {
770 if ((modmask >> i) & 1) {
771 pressKeyMatrixEvent(time, mp);
776 releaseKeyMatrixEvent(time, keyInfo.pos);
779 for (
auto [i, mp] :
enumerate(modifierPos)) {
780 if (!((modifierIsLock >> i) & 1)) {
783 if ((msxModifiers >> i) & 1) {
784 releaseKeyMatrixEvent(time, mp);
786 pressKeyMatrixEvent(time, mp);
792 return insertCodeKanaRelease;
807 int Keyboard::pressAscii(
unsigned unicode,
bool down)
811 if (!keyInfo.isValid()) {
814 byte modmask = keyInfo.
modmask & ~modifierIsLock;
817 byte toggleLocks = needsLockToggle(keyInfo);
818 for (
auto [i, mp] :
enumerate(modifierPos)) {
819 if ((toggleLocks >> i) & 1) {
820 debug(
"Toggling lock %d\n", i);
822 releaseMask |= 1 << i;
823 typeKeyMatrix[mp.getRow()] &= ~mp.getMask();
826 if (releaseMask == 0) {
827 debug(
"Key pasted, unicode: 0x%04x, row: %02d, col: %d, modmask: %02x\n",
828 unicode, keyInfo.pos.getRow(), keyInfo.pos.getColumn(), modmask);
857 auto isPressed = [&](
auto& key) {
858 return (typeKeyMatrix[key.getRow()] & key.getMask()) == 0;
863 releaseMask = TRY_AGAIN;
867 for (
auto [i, mp] :
enumerate(modifierPos)) {
868 if ((modmask >> i) & 1) {
869 typeKeyMatrix[mp.getRow()] &= ~mp.getMask();
872 if (releaseMask == 0) {
874 typeKeyMatrix[keyInfo.pos.getRow()] &= ~keyInfo.pos.getMask();
878 typeKeyMatrix[keyInfo.pos.getRow()] |= keyInfo.pos.getMask();
879 for (
auto [i, mp] :
enumerate(modifierPos)) {
880 if ((modmask >> i) & 1) {
881 typeKeyMatrix[mp.getRow()] |= mp.getMask();
895 void Keyboard::pressLockKeys(
byte lockKeysMask,
bool down)
897 for (
auto [i, mp] :
enumerate(modifierPos)) {
898 if ((lockKeysMask >> i) & 1) {
901 typeKeyMatrix[mp.getRow()] &= ~mp.getMask();
904 typeKeyMatrix[mp.getRow()] |= mp.getMask();
918 bool Keyboard::commonKeys(
unsigned unicode1,
unsigned unicode2)
921 auto keyPos1 = unicodeKeymap.
get(unicode1).
pos;
922 auto keyPos2 = unicodeKeymap.
get(unicode2).
pos;
924 return keyPos1 == keyPos2 && keyPos1.
isValid();
927 void Keyboard::debug(
const char* format, ...)
931 va_start(args, format);
932 vfprintf(stderr, format, args);
940 Keyboard::KeyMatrixUpCmd::KeyMatrixUpCmd(
941 CommandController& commandController_,
942 StateChangeDistributor& stateChangeDistributor_,
944 : RecordedCommand(commandController_, stateChangeDistributor_,
945 scheduler_,
"keymatrixup")
949 void Keyboard::KeyMatrixUpCmd::execute(
952 checkNumArgs(tokens, 3, Prefix{1},
"row mask");
954 return keyboard.processCmd(getInterpreter(), tokens,
true);
957 string Keyboard::KeyMatrixUpCmd::help(
const vector<string>& )
const
959 static const string helpText =
960 "keymatrixup <row> <bitmask> release a key in the keyboardmatrix\n";
967 Keyboard::KeyMatrixDownCmd::KeyMatrixDownCmd(CommandController& commandController_,
968 StateChangeDistributor& stateChangeDistributor_,
970 : RecordedCommand(commandController_, stateChangeDistributor_,
971 scheduler_,
"keymatrixdown")
976 TclObject& , EmuTime::param )
978 checkNumArgs(tokens, 3, Prefix{1},
"row mask");
980 return keyboard.processCmd(getInterpreter(), tokens,
false);
983 string Keyboard::KeyMatrixDownCmd::help(
const vector<string>& )
const
985 static const string helpText =
986 "keymatrixdown <row> <bitmask> press a key in the keyboardmatrix\n";
993 Keyboard::MsxKeyEventQueue::MsxKeyEventQueue(
994 Scheduler& scheduler_, Interpreter& interp_)
1000 void Keyboard::MsxKeyEventQueue::process_asap(
1001 EmuTime::param time,
const shared_ptr<const Event>& event)
1003 bool processImmediately = eventQueue.empty();
1004 eventQueue.push_back(event);
1005 if (processImmediately) {
1010 void Keyboard::MsxKeyEventQueue::clear()
1016 void Keyboard::MsxKeyEventQueue::executeUntil(EmuTime::param time)
1019 shared_ptr<const Event>
event = eventQueue.front();
1021 bool insertCodeKanaRelease = keyboard.processQueuedEvent(*event, time);
1023 if (insertCodeKanaRelease) {
1027 eventQueue.push_front(make_shared<KeyUpEvent>(
1028 keyboard.keyboardSettings.getCodeKanaHostKey()));
1031 if (!eventQueue.empty()) {
1032 eventQueue.pop_front();
1039 if (!eventQueue.empty()) {
1048 Keyboard::KeyInserter::KeyInserter(
1049 CommandController& commandController_,
1050 StateChangeDistributor& stateChangeDistributor_,
1052 : RecordedCommand(commandController_, stateChangeDistributor_,
1053 scheduler_,
"type_via_keyboard")
1056 , releaseLast(false)
1061 releaseBeforePress =
false;
1062 typingFrequency = 15;
1065 void Keyboard::KeyInserter::execute(
1068 checkNumArgs(tokens, AtLeast{2},
"?-release? ?-freq hz? text");
1070 releaseBeforePress =
false;
1071 typingFrequency = 15;
1074 if (tokens.
size() == 2) {
1075 type(tokens[1].getString());
1080 flagArg(
"-release", releaseBeforePress),
1081 valueArg(
"-freq", typingFrequency),
1085 if (typingFrequency <= 0) {
1086 throw CommandException(
"Wrong argument for -freq (should be a positive number)");
1088 if (arguments.size() != 1)
throw SyntaxError();
1090 type(arguments[0].getString());
1093 string Keyboard::KeyInserter::help(
const vector<string>& )
const
1095 static const string helpText =
"Type a string in the emulated MSX.\n" \
1096 "Use -release to make sure the keys are always released before typing new ones (necessary for some game input routines, but in general, this means typing is twice as slow).\n" \
1097 "Use -freq to tweak how fast typing goes and how long the keys will be pressed (and released in case -release was used). Keys will be typed at the given frequency and will remain pressed/released for 1/freq seconds";
1101 void Keyboard::KeyInserter::tabCompletion(vector<string>& tokens)
const
1103 vector<const char*> options;
1104 if (!
contains(tokens,
"-release")) {
1105 options.push_back(
"-release");
1108 options.push_back(
"-freq");
1110 completeString(tokens, options);
1113 void Keyboard::KeyInserter::type(std::string_view str)
1119 oldLocksOn = keyboard.locksOn;
1120 if (text_utf8.empty()) {
1121 reschedule(getCurrentTime());
1123 text_utf8.append(str.data(), str.size());
1126 void Keyboard::KeyInserter::executeUntil(EmuTime::param time)
1129 if (lockKeysMask != 0) {
1131 keyboard.pressLockKeys(lockKeysMask,
false);
1134 keyboard.pressAscii(last,
false);
1136 if (text_utf8.empty()) {
1137 releaseLast =
false;
1138 keyboard.debug(
"Restoring locks: %02X -> %02X\n", keyboard.locksOn, oldLocksOn);
1139 auto diff = oldLocksOn ^ keyboard.locksOn;
1140 lockKeysMask = diff;
1143 keyboard.locksOn ^= diff;
1144 keyboard.pressLockKeys(diff,
true);
1151 auto it =
begin(text_utf8);
1153 if (releaseLast && (releaseBeforePress || keyboard.commonKeys(last, current))) {
1157 releaseLast =
false;
1161 lockKeysMask = keyboard.pressAscii(current,
true);
1162 if (lockKeysMask == 0) {
1165 text_utf8.erase(
begin(text_utf8), it);
1166 }
else if (lockKeysMask & TRY_AGAIN) {
1167 lockKeysMask &= ~TRY_AGAIN;
1168 releaseLast =
false;
1169 }
else if (releaseBeforePress) {
1174 }
catch (std::exception&) {
1180 void Keyboard::KeyInserter::reschedule(EmuTime::param time)
1197 Keyboard::CapsLockAligner::CapsLockAligner(
1198 EventDistributor& eventDistributor_,
1201 , eventDistributor(eventDistributor_)
1208 Keyboard::CapsLockAligner::~CapsLockAligner()
1214 int Keyboard::CapsLockAligner::signalEvent(
const shared_ptr<const Event>& event)
1216 if (!SANE_CAPSLOCK_BEHAVIOR) {
1221 if (state ==
IDLE) {
1222 EmuTime::param time = getCurrentTime();
1225 alignCapsLock(time);
1227 state = MUST_ALIGN_CAPSLOCK;
1236 void Keyboard::CapsLockAligner::executeUntil(EmuTime::param time)
1239 case MUST_ALIGN_CAPSLOCK:
1240 alignCapsLock(time);
1242 case MUST_DISTRIBUTE_KEY_RELEASE: {
1245 keyboard.msxEventDistributor.distributeEvent(event, time);
1264 void Keyboard::CapsLockAligner::alignCapsLock(EmuTime::param time)
1266 bool hostCapsLockOn = ((SDL_GetModState() & KMOD_CAPS) != 0);
1269 keyboard.debug(
"Resyncing host and MSX CAPS lock\n");
1273 keyboard.msxEventDistributor.distributeEvent(event, time);
1274 keyboard.debug(
"Sending fake CAPS release\n");
1275 state = MUST_DISTRIBUTE_KEY_RELEASE;
1285 Keyboard::KeybDebuggable::KeybDebuggable(MSXMotherBoard& motherBoard_)
1286 : SimpleDebuggable(motherBoard_,
"keymatrix",
"MSX Keyboard Matrix",
1287 KeyMatrixPosition::NUM_ROWS)
1291 byte Keyboard::KeybDebuggable::read(
unsigned address)
1294 return keyboard.getKeys()[address];
1297 void Keyboard::KeybDebuggable::write(
unsigned ,
byte )
1303 template<
typename Archive>
1306 ar.template serializeBase<Schedulable>(*
this);
1307 ar.serialize(
"text", text_utf8,
1309 "lockKeysMask", lockKeysMask,
1310 "releaseLast", releaseLast);
1312 bool oldCodeKanaLockOn, oldGraphLockOn, oldCapsLockOn;
1313 if (!ar.isLoader()) {
1318 ar.serialize(
"oldCodeKanaLockOn", oldCodeKanaLockOn,
1319 "oldGraphLockOn", oldGraphLockOn,
1320 "oldCapsLockOn", oldCapsLockOn);
1321 if (ar.isLoader()) {
1341 template<
typename Archive>
1344 ar.serialize(
"keyTypeCmd", keyTypeCmd,
1345 "cmdKeyMatrix", cmdKeyMatrix);
1346 if (ar.versionAtLeast(version, 3)) {
1347 ar.serialize(
"typeKeyMatrix", typeKeyMatrix);
1352 bool msxCapsLockOn, msxCodeKanaLockOn, msxGraphLockOn;
1353 if (!ar.isLoader()) {
1358 ar.serialize(
"msxCapsLockOn", msxCapsLockOn,
1359 "msxCodeKanaLockOn", msxCodeKanaLockOn,
1360 "msxGraphLockOn", msxGraphLockOn);
1361 if (ar.isLoader()) {
1367 if (ar.versionAtLeast(version, 2)) {
1368 ar.serialize(
"userKeyMatrix", userKeyMatrix,
1369 "dynKeymap", dynKeymap,
1370 "msxmodifiers", msxModifiers,
1371 "msxKeyEventQueue", msxKeyEventQueue);
1375 if (ar.isLoader()) {
1382 template<
typename Archive>
1385 ar.template serializeBase<Schedulable>(*
this);
1394 vector<string> eventStrs;
1395 if (!ar.isLoader()) {
1397 eventQueue, [](
auto& e) {
return e->toString(); }));
1399 ar.serialize(
"eventQueue", eventStrs);
1400 if (ar.isLoader()) {
1401 assert(eventQueue.empty());
1402 for (
auto& s : eventStrs) {
1403 eventQueue.push_back(
1435 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,0x75,0x73,
x ,
x ,
x ,0x77,
x ,
x ,
1436 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,0x72,
x ,
x ,
x ,
x ,
1437 0x80,
x ,
x ,
x ,
x ,
x ,
x ,0x20,
x ,
x ,
x ,
x ,0x22,0x12,0x23,0x24,
1438 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x10,0x11,
x ,0x17,
x ,0x13,
x ,
x ,
1439 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1440 x ,0x84,0x85,0x87,0x86,
x ,
x ,
x ,
x ,
x ,
x ,0x15,0x14,0x16,
x ,
x ,
1441 0x21,0x26,0x27,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x40,0x41,0x42,0x43,0x44,
1442 0x45,0x46,0x47,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
x ,
x ,
x ,
x ,0x83,
1443 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1444 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1445 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1446 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1447 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1448 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,0x81,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1449 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1450 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1451 0x93,0x94,0x95,0x96,0x97,0xA0,0xA1,0xA2,0xA3,0xA4,0xA7,0x92,0x90,0xA5,0x91,0xA6,
1452 x ,0x85,0x86,0x87,0x84,0x82,0x81,
x ,
x ,
x ,0x65,0x66,0x67,0x70,0x71,
x ,
1453 0x76,0x74,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,0x60,
1454 0x60,0x25,0x61,
x ,
x ,0xB3,0xB1,0xB3,0xB1,0xB1,0xB3,
x ,
x ,
x ,
x ,
x ,
1455 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1475 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,0x56,0x81,
x ,
x ,
x ,0x66,
x ,
x ,
1476 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,0x64,
x ,
x ,
x ,
x ,
1477 0x80,
x ,
x ,
x ,
x ,
x ,
x ,0x20,
x ,
x ,
x ,
x ,0x14,0x20,0x16,0x17,
1478 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x10,0x11,0x12,
x ,
x ,0x15,
x ,
x ,
1479 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1480 x ,0x67,0x57,0x87,0x77,
x ,
x ,
x ,
x ,
x ,
x ,0x53,0x54,0x55,
x ,
x ,
1481 x ,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
1482 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x50,0x51,0x52,
x ,
x ,
x ,
x ,0x82,
1483 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1484 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1485 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1486 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1487 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1488 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1489 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1490 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1491 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0xA0,0xA1,0xA6,0xA5,0xA4,0xA3,0xA2,0xA7,
1492 x ,0x57,0x77,0x87,0x67,0x76,
x ,
x ,
x ,
x ,0x70,0x71,0x72,0x73,0x74,
x ,
1493 0x75,0x65,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,0x60,
1494 0x60,
x ,0x61,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1495 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1514 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1515 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1516 0x06,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,0x32,
x ,
x ,
1517 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x30,0x31,
x ,
x ,
x ,0x33,
x ,
x ,
1518 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1519 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1520 x ,0x13,0x42,
x ,0x11,
x ,0x44,0x45,0x46,
x ,0x52,
x ,
x ,0x53,0x43,
x ,
1521 x ,
x ,0x47,0x12,0x50,0x40,0x41,0x10,
x ,0x51,
x ,
x ,
x ,
x ,
x ,
x ,
1522 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1523 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1524 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1525 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1526 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1527 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1528 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1529 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1530 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x30,0x31,
x ,0x33,0x32,0x32,0x33,
x ,
1531 x ,0x00,0x02,0x01,0x03,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1532 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,0x07,
1533 0x17,0x06,0x16,0x07,0x07,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
1534 x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
x ,
static constexpr EmuDuration sec(unsigned x)
static constexpr EmuDuration hz(unsigned x)
A position (row, column) in a keyboard matrix.
constexpr bool isValid() const
Returns true iff this position is valid.
static constexpr unsigned NUM_ROWS
Rows are in the range [0..NUM_ROWS).
KeyMatrixState(EmuTime::param time_, byte row_, byte press_, byte release_)
void serialize(Archive &ar, unsigned)
bool getAlwaysEnableKeypad() const
bool getTraceKeyPresses() const
MappingMode getMappingMode() const
KpEnterMode getKpEnterMode() const
Keys::KeyCode getDeadkeyHostKey(unsigned n) const
bool getAutoToggleCodeKanaLock() const
Keys::KeyCode getCodeKanaHostKey() const
void transferHostKeyMatrix(const Keyboard &source)
void serialize(Archive &ar, unsigned version)
const byte * getKeys() const
Returns a pointer to the current KeyBoard matrix.
Keyboard(MSXMotherBoard &motherBoard, Scheduler &scheduler, CommandController &commandController, EventDistributor &eventDistributor, MSXEventDistributor &msxEventDistributor, StateChangeDistributor &stateChangeDistributor, MatrixType matrix, const DeviceConfig &config)
Constructs a new Keyboard object.
void registerEventListener(MSXEventListener &listener)
Registers a given object to receive certain events.
void unregisterEventListener(MSXEventListener &listener)
Unregisters a previously registered event listener.
ReverseManager & getReverseManager()
void registerKeyboard(Keyboard &keyboard_)
Every class that wants to get scheduled at some point must inherit from this class.
void setSyncPoint(EmuTime::param timestamp)
void registerListener(StateChangeListener &listener)
(Un)registers the given object to receive state change events.
void distributeNew(const EventPtr &event)
Deliver the event to all registered listeners MSX input devices should call the distributeNew() versi...
void unregisterListener(StateChangeListener &listener)
Base class for all external MSX state changing events.
byte getRelevantMods(const KeyInfo &keyInfo) const
Returns a mask in which a bit is set iff the corresponding modifier is relevant for the given key.
KeyInfo get(unsigned unicode) const
KeyInfo getDeadkey(unsigned n) const
constexpr subspan_return_t< Offset, Count > subspan() const
constexpr index_type size() const noexcept
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
KeyCode
Constants that identify keys and key modifiers.
string getName(KeyCode keyCode)
Translate key code to key name.
This file implemented 3 utility functions:
constexpr std::array< KeyMatrixPosition, UnicodeKeymap::KeyInfo::NUM_MODIFIERS > modifierPosForMatrix[]
std::vector< TclObject > parseTclArgs(Interpreter &interp, span< const TclObject > inArgs, span< const ArgsInfo > table)
ArgsInfo valueArg(std::string_view name, T &value)
constexpr KeyMatrixPosition x
Keyboard bindings.
void serialize(Archive &ar, T &t, unsigned version)
constexpr const char *const defaultKeymapForMatrix[]
constexpr nibble mask[4][13]
REGISTER_POLYMORPHIC_CLASS(DiskContainer, NowindRomDisk, "NowindRomDisk")
UnicodeKeymap::KeyInfo KeyInfo
ArgsInfo flagArg(std::string_view name, bool &flag)
void fill(ForwardRange &&range, const T &value)
auto copy(InputRange &&range, OutputIter out)
uint32_t next(octet_iterator &it, octet_iterator end)
auto transform(Range &&range, UnaryOp op)
#define OUTER(type, member)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))>>
static constexpr byte CAPS_MASK
static constexpr byte GRAPH_MASK
static constexpr byte CODE_MASK
static constexpr byte SHIFT_MASK
constexpr auto xrange(T e)
auto end(const zstring_view &x)
auto begin(const zstring_view &x)