openMSX
ImGuiKeyboard.cc
Go to the documentation of this file.
1// Implementation inspired by:
2// https://github.com/CedricGuillemet/ImHotKey
3
4#include "ImGuiKeyboard.hh"
5
6#include "ImGuiCpp.hh"
7#include "ImGuiManager.hh"
8#include "ImGuiUtils.hh"
9
10#include "Keyboard.hh"
11#include "MSXMotherBoard.hh"
12#include "MSXPPI.hh"
13#include "UnicodeKeymap.hh" // KeyMatrixPosition
14
15#include <imgui.h>
16
17#include <array>
18
19namespace openmsx {
20
21void ImGuiKeyboard::save(ImGuiTextBuffer& buf)
22{
23 savePersistent(buf, *this, persistentElements);
24}
25
26void ImGuiKeyboard::loadLine(std::string_view name, zstring_view value)
27{
28 loadOnePersistent(name, value, *this, persistentElements);
29}
30
32{
33 if (!show) return;
34
35 if (!motherBoard) return;
36 const auto* ppi = dynamic_cast<MSXPPI*>(motherBoard->findDevice("ppi"));
37 if (!ppi) return;
38 const auto& keyboard = ppi->getKeyboard();
39 auto matrix = keyboard.getKeys();
40
41 ImGui::SetNextWindowSize({640, 200}, ImGuiCond_FirstUseEver);
42 im::Window("Virtual keyboard", &show, [&]{
43 struct Key {
44 const char* label;
45 gl::vec2 pos;
46 gl::vec2 size;
47 KeyMatrixPosition matrixPos;
48 };
49 // TODO read this from some (MSX machine specific) config file
50 static constexpr std::array keys = {
51 Key{"F1", { 0, 0}, {52,32}, KeyMatrixPosition{0x65}},
52 Key{"F2", { 56, 0}, {52,32}, KeyMatrixPosition{0x66}},
53 Key{"F3", {112, 0}, {52,32}, KeyMatrixPosition{0x67}},
54 Key{"F4", {168, 0}, {52,32}, KeyMatrixPosition{0x70}},
55 Key{"F5", {224, 0}, {52,32}, KeyMatrixPosition{0x71}},
56 Key{"Select", {300, 0}, {52,32}, KeyMatrixPosition{0x76}},
57 Key{"Stop", {356, 0}, {52,32}, KeyMatrixPosition{0x74}},
58 Key{"Home", {432, 0}, {52,32}, KeyMatrixPosition{0x81}},
59 Key{"Ins", {488, 0}, {52,32}, KeyMatrixPosition{0x82}},
60 Key{"Del", {544, 0}, {52,32}, KeyMatrixPosition{0x83}},
61
62 Key{"Esc", { 0, 36}, {36,32}, KeyMatrixPosition{0x72}},
63 Key{"1", { 40, 36}, {36,32}, KeyMatrixPosition{0x01}},
64 Key{"2", { 80, 36}, {36,32}, KeyMatrixPosition{0x02}},
65 Key{"3", {120, 36}, {36,32}, KeyMatrixPosition{0x03}},
66 Key{"4", {160, 36}, {36,32}, KeyMatrixPosition{0x04}},
67 Key{"5", {200, 36}, {36,32}, KeyMatrixPosition{0x05}},
68 Key{"6", {240, 36}, {36,32}, KeyMatrixPosition{0x06}},
69 Key{"7", {280, 36}, {36,32}, KeyMatrixPosition{0x07}},
70 Key{"8", {320, 36}, {36,32}, KeyMatrixPosition{0x10}},
71 Key{"9", {360, 36}, {36,32}, KeyMatrixPosition{0x11}},
72 Key{"0", {400, 36}, {36,32}, KeyMatrixPosition{0x00}},
73 Key{"-", {440, 36}, {36,32}, KeyMatrixPosition{0x12}},
74 Key{"=", {480, 36}, {36,32}, KeyMatrixPosition{0x13}},
75 Key{"\\", {520, 36}, {36,32}, KeyMatrixPosition{0x14}},
76 Key{"BS", {560, 36}, {36,32}, KeyMatrixPosition{0x75}},
77
78 Key{"Tab", { 0, 72}, {56,32}, KeyMatrixPosition{0x73}},
79 Key{"Q", { 60, 72}, {36,32}, KeyMatrixPosition{0x46}},
80 Key{"W", {100, 72}, {36,32}, KeyMatrixPosition{0x54}},
81 Key{"E", {140, 72}, {36,32}, KeyMatrixPosition{0x32}},
82 Key{"R", {180, 72}, {36,32}, KeyMatrixPosition{0x47}},
83 Key{"T", {220, 72}, {36,32}, KeyMatrixPosition{0x51}},
84 Key{"Y", {260, 72}, {36,32}, KeyMatrixPosition{0x56}},
85 Key{"U", {300, 72}, {36,32}, KeyMatrixPosition{0x52}},
86 Key{"I", {340, 72}, {36,32}, KeyMatrixPosition{0x36}},
87 Key{"O", {380, 72}, {36,32}, KeyMatrixPosition{0x44}},
88 Key{"P", {420, 72}, {36,32}, KeyMatrixPosition{0x45}},
89 Key{"[", {460, 72}, {36,32}, KeyMatrixPosition{0x15}},
90 Key{"]", {500, 72}, {36,32}, KeyMatrixPosition{0x16}},
91 Key{"Return", {548, 72}, {48,68}, KeyMatrixPosition{0x77}},
92
93 Key{"Ctrl", { 0,108}, {64,32}, KeyMatrixPosition{0x61}},
94 Key{"A", { 68,108}, {36,32}, KeyMatrixPosition{0x26}},
95 Key{"S", {108,108}, {36,32}, KeyMatrixPosition{0x50}},
96 Key{"D", {148,108}, {36,32}, KeyMatrixPosition{0x31}},
97 Key{"F", {188,108}, {36,32}, KeyMatrixPosition{0x33}},
98 Key{"G", {228,108}, {36,32}, KeyMatrixPosition{0x34}},
99 Key{"H", {268,108}, {36,32}, KeyMatrixPosition{0x35}},
100 Key{"J", {308,108}, {36,32}, KeyMatrixPosition{0x37}},
101 Key{"K", {348,108}, {36,32}, KeyMatrixPosition{0x40}},
102 Key{"L", {388,108}, {36,32}, KeyMatrixPosition{0x41}},
103 Key{";", {428,108}, {36,32}, KeyMatrixPosition{0x17}},
104 Key{"'", {468,108}, {36,32}, KeyMatrixPosition{0x20}},
105 Key{"`", {508,108}, {36,32}, KeyMatrixPosition{0x21}},
106
107 Key{"Shift", { 0,144}, {80,32}, KeyMatrixPosition{0x60}},
108 Key{"Z", { 84,144}, {36,32}, KeyMatrixPosition{0x57}},
109 Key{"X", {124,144}, {36,32}, KeyMatrixPosition{0x55}},
110 Key{"C", {164,144}, {36,32}, KeyMatrixPosition{0x30}},
111 Key{"V", {204,144}, {36,32}, KeyMatrixPosition{0x53}},
112 Key{"B", {244,144}, {36,32}, KeyMatrixPosition{0x27}},
113 Key{"N", {284,144}, {36,32}, KeyMatrixPosition{0x43}},
114 Key{"M", {324,144}, {36,32}, KeyMatrixPosition{0x42}},
115 Key{",", {364,144}, {36,32}, KeyMatrixPosition{0x22}},
116 Key{".", {404,144}, {36,32}, KeyMatrixPosition{0x23}},
117 Key{"/", {444,144}, {36,32}, KeyMatrixPosition{0x24}},
118 Key{"Acc", {484,144}, {36,32}, KeyMatrixPosition{0x25}},
119 Key{"Shift", {524,144}, {72,32}, KeyMatrixPosition{0x60}},
120
121 Key{"Cap", { 84,180}, {36,32}, KeyMatrixPosition{0x63}},
122 Key{"Grp", {124,180}, {36,32}, KeyMatrixPosition{0x62}},
123 Key{"Space", {164,180},{316,32}, KeyMatrixPosition{0x80}},
124 Key{"Cod", {484,180}, {36,32}, KeyMatrixPosition{0x64}},
125
126 Key{"7", {632, 0}, {36,32}, KeyMatrixPosition{0xA2}},
127 Key{"8", {672, 0}, {36,32}, KeyMatrixPosition{0xA3}},
128 Key{"9", {712, 0}, {36,32}, KeyMatrixPosition{0xA4}},
129 Key{"-", {752, 0}, {36,32}, KeyMatrixPosition{0xA5}},
130 Key{"4", {632, 36}, {36,32}, KeyMatrixPosition{0x97}},
131 Key{"5", {672, 36}, {36,32}, KeyMatrixPosition{0xA0}},
132 Key{"6", {712, 36}, {36,32}, KeyMatrixPosition{0xA1}},
133 Key{"/", {752, 36}, {36,32}, KeyMatrixPosition{0x92}},
134 Key{"1", {632, 72}, {36,32}, KeyMatrixPosition{0x94}},
135 Key{"2", {672, 72}, {36,32}, KeyMatrixPosition{0x95}},
136 Key{"3", {712, 72}, {36,32}, KeyMatrixPosition{0x96}},
137 Key{"*", {752, 72}, {36,32}, KeyMatrixPosition{0x90}},
138 Key{"0", {632,108}, {36,32}, KeyMatrixPosition{0x93}},
139 Key{",", {672,108}, {36,32}, KeyMatrixPosition{0xA6}},
140 Key{".", {712,108}, {36,32}, KeyMatrixPosition{0xA7}},
141 Key{"+", {752,108}, {36,32}, KeyMatrixPosition{0x91}},
142
143 Key{"Left", {652,144}, {36,68}, KeyMatrixPosition{0x84}},
144 Key{"Up", {692,144}, {36,32}, KeyMatrixPosition{0x85}},
145 Key{"Down", {692,180}, {36,32}, KeyMatrixPosition{0x86}},
146 Key{"Right", {732,144}, {36,68}, KeyMatrixPosition{0x87}},
147 };
148
149 gl::vec2 maxXY;
150 for (const auto& key : keys) {
151 maxXY = max(maxXY, key.pos + key.size);
152 }
153 gl::vec2 available = ImGui::GetContentRegionAvail();
154 float scale = min_component(available / maxXY);
155
156 gl::vec2 origin = ImGui::GetCursorPos();
157 im::ID_for_range(keys.size(), [&](int i) {
158 const auto& key = keys[i];
159 auto row = key.matrixPos.getRow();
160 auto column = key.matrixPos.getColumn();
161 auto mask = 1 << column;
162 bool active = !(matrix[row] & mask);
163
164 ImGui::SetCursorPos(origin + scale * key.pos);
165 im::StyleColor(ImGuiCol_Button, getColor(active ? imColor::KEY_ACTIVE : imColor::KEY_NOT_ACTIVE), [&]{
166 ImGui::Button(key.label, scale * key.size);
167 });
168
169 if (ImGui::IsItemActivated()) {
170 manager.execute(makeTclList("keymatrixdown", row, mask));
171 }
172 if (ImGui::IsItemDeactivated()) {
173 manager.execute(makeTclList("keymatrixup", row, mask));
174 }
175 if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
176 manager.execute(makeTclList((active ? "keymatrixup" : "keymatrixdown"),
177 row, mask));
178 }
179 });
180 });
181}
182
183} // namespace openmsx
void paint(MSXMotherBoard *motherBoard) override
void loadLine(std::string_view name, zstring_view value) override
void save(ImGuiTextBuffer &buf) override
std::optional< TclObject > execute(TclObject command)
ImGuiManager & manager
Definition ImGuiPart.hh:30
A position (row, column) in a keyboard matrix.
std::span< const uint8_t, KeyMatrixPosition::NUM_ROWS > getKeys() const
Returns a pointer to the current KeyBoard matrix.
Definition Keyboard.cc:809
MSXDevice * findDevice(std::string_view name)
Find a MSXDevice by name.
const Keyboard & getKeyboard() const
Definition MSXPPI.cc:36
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
void Window(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:63
void ID_for_range(int count, std::invocable< int > auto next)
Definition ImGuiCpp.hh:281
This file implemented 3 utility functions:
Definition Autofire.cc:11
bool loadOnePersistent(std::string_view name, zstring_view value, C &c, const std::tuple< Elements... > &tup)
void savePersistent(ImGuiTextBuffer &buf, C &c, const std::tuple< Elements... > &tup)
TclObject makeTclList(Args &&... args)
Definition TclObject.hh:293