openMSX
Keyboard.hh
Go to the documentation of this file.
1 #ifndef KEYBOARD_HH
2 #define KEYBOARD_HH
3 
5 #include "UnicodeKeymap.hh"
8 #include "Schedulable.hh"
10 #include "SimpleDebuggable.hh"
11 #include "EventListener.hh"
12 #include "serialize_meta.hh"
13 #include "span.hh"
14 #include "openmsx.hh"
15 #include <array>
16 #include <deque>
17 #include <string_view>
18 #include <vector>
19 #include <memory>
20 
21 namespace openmsx {
22 
23 class MSXMotherBoard;
24 class Scheduler;
25 class CommandController;
26 class DeviceConfig;
27 class EventDistributor;
28 class MSXEventDistributor;
30 class KeyEvent;
31 class StateChange;
32 class TclObject;
33 class Interpreter;
34 
35 class Keyboard final : private MSXEventListener, private StateChangeListener
36 {
37 public:
39 
40  /** Constructs a new Keyboard object.
41  * @param motherBoard ref to the motherBoard
42  * @param scheduler ref to the scheduler
43  * @param commandController ref to the command controller
44  * @param eventDistributor ref to the emu event distributor
45  * @param msxEventDistributor ref to the user input event distributor
46  * @param stateChangeDistributor ref to the state change distributor
47  * @param matrix which system's keyboard matrix to use
48  * @param config ref to the device configuration
49  */
50  Keyboard(MSXMotherBoard& motherBoard, Scheduler& scheduler,
51  CommandController& commandController,
52  EventDistributor& eventDistributor,
53  MSXEventDistributor& msxEventDistributor,
54  StateChangeDistributor& stateChangeDistributor,
55  MatrixType matrix, const DeviceConfig& config);
56 
57  ~Keyboard();
58 
59  /** Returns a pointer to the current KeyBoard matrix
60  */
61  const byte* getKeys() const;
62 
63  void transferHostKeyMatrix(const Keyboard& source);
64 
65  template<typename Archive>
66  void serialize(Archive& ar, unsigned version);
67 
68 private:
69  // MSXEventListener
70  void signalMSXEvent(const std::shared_ptr<const Event>& event,
71  EmuTime::param time) override;
72  // StateChangeListener
73  void signalStateChange(const std::shared_ptr<StateChange>& event) override;
74  void stopReplay(EmuTime::param time) override;
75 
76  void pressKeyMatrixEvent(EmuTime::param time, KeyMatrixPosition pos);
77  void releaseKeyMatrixEvent(EmuTime::param time, KeyMatrixPosition pos);
78  void changeKeyMatrixEvent (EmuTime::param time, byte row, byte newValue);
79 
80  void processCapslockEvent(EmuTime::param time, bool down);
81  void processCodeKanaChange(EmuTime::param time, bool down);
82  void processGraphChange(EmuTime::param time, bool down);
83  void processKeypadEnterKey(EmuTime::param time, bool down);
84  void processSdlKey(EmuTime::param time, bool down, Keys::KeyCode key);
85  bool processQueuedEvent(const Event& event, EmuTime::param time);
86  bool processKeyEvent(EmuTime::param time, bool down, const KeyEvent& keyEvent);
87  void updateKeyMatrix(EmuTime::param time, bool down, KeyMatrixPosition pos);
88  void processCmd(Interpreter& interp, span<const TclObject> tokens, bool up);
89  bool pressUnicodeByUser(
90  EmuTime::param time, UnicodeKeymap::KeyInfo keyInfo, unsigned unicode,
91  bool down);
92  int pressAscii(unsigned unicode, bool down);
93  void pressLockKeys(byte lockKeysMask, bool down);
94  bool commonKeys(unsigned unicode1, unsigned unicode2);
95  void debug(const char* format, ...);
96 
97  /** Returns a bit vector in which the bit for a modifier is set iff that
98  * modifier is a lock key and must be toggled before the given key input
99  * can be produced.
100  */
101  byte needsLockToggle(const UnicodeKeymap::KeyInfo& keyInfo) const;
102 
103  CommandController& commandController;
104  MSXEventDistributor& msxEventDistributor;
105  StateChangeDistributor& stateChangeDistributor;
106 
107  static const int MAX_KEYSYM = 0x150;
108  static const KeyMatrixPosition keyTabs[][MAX_KEYSYM];
109  const KeyMatrixPosition* keyTab;
110 
111  const std::array<KeyMatrixPosition, UnicodeKeymap::KeyInfo::NUM_MODIFIERS>& modifierPos;
112 
113  struct KeyMatrixUpCmd final : RecordedCommand {
114  KeyMatrixUpCmd(CommandController& commandController,
115  StateChangeDistributor& stateChangeDistributor,
116  Scheduler& scheduler);
117  void execute(span<const TclObject> tokens, TclObject& result,
118  EmuTime::param time) override;
119  std::string help(const std::vector<std::string>& tokens) const override;
120  } keyMatrixUpCmd;
121 
122  struct KeyMatrixDownCmd final : RecordedCommand {
123  KeyMatrixDownCmd(CommandController& commandController,
124  StateChangeDistributor& stateChangeDistributor,
125  Scheduler& scheduler);
126  void execute(span<const TclObject> tokens, TclObject& result,
127  EmuTime::param time) override;
128  std::string help(const std::vector<std::string>& tokens) const override;
129  } keyMatrixDownCmd;
130 
131  class KeyInserter final : public RecordedCommand, public Schedulable {
132  public:
133  KeyInserter(CommandController& commandController,
134  StateChangeDistributor& stateChangeDistributor,
135  Scheduler& scheduler);
136  bool isActive() const { return pendingSyncPoint(); }
137  template<typename Archive>
138  void serialize(Archive& ar, unsigned version);
139 
140  private:
141  void type(std::string_view str);
142  void reschedule(EmuTime::param time);
143 
144  // Command
145  void execute(span<const TclObject> tokens, TclObject& result,
146  EmuTime::param time) override;
147  std::string help(const std::vector<std::string>& tokens) const override;
148  void tabCompletion(std::vector<std::string>& tokens) const override;
149 
150  // Schedulable
151  void executeUntil(EmuTime::param time) override;
152 
153  std::string text_utf8;
154  unsigned last;
155  byte lockKeysMask;
156  bool releaseLast;
157  byte oldLocksOn;
158 
159  bool releaseBeforePress;
160  int typingFrequency;
161  } keyTypeCmd;
162 
163  class CapsLockAligner final : private EventListener, private Schedulable {
164  public:
165  CapsLockAligner(EventDistributor& eventDistributor,
166  Scheduler& scheduler);
167  ~CapsLockAligner();
168 
169  private:
170  // EventListener
171  int signalEvent(const std::shared_ptr<const Event>& event) override;
172 
173  // Schedulable
174  void executeUntil(EmuTime::param time) override;
175 
176  void alignCapsLock(EmuTime::param time);
177 
178  EventDistributor& eventDistributor;
179 
180  enum CapsLockAlignerStateType {
181  MUST_ALIGN_CAPSLOCK, MUST_DISTRIBUTE_KEY_RELEASE, IDLE
182  } state;
183  } capsLockAligner;
184 
185  KeyboardSettings keyboardSettings;
186 
187  class MsxKeyEventQueue final : public Schedulable {
188  public:
189  MsxKeyEventQueue(Scheduler& scheduler, Interpreter& interp);
190  void process_asap(EmuTime::param time,
191  const std::shared_ptr<const Event>& event);
192  void clear();
193  template<typename Archive>
194  void serialize(Archive& ar, unsigned version);
195  private:
196  // Schedulable
197  void executeUntil(EmuTime::param time) override;
198  std::deque<std::shared_ptr<const Event>> eventQueue;
199  Interpreter& interp;
200  } msxKeyEventQueue;
201 
202  struct KeybDebuggable final : SimpleDebuggable {
203  explicit KeybDebuggable(MSXMotherBoard& motherBoard);
204  byte read(unsigned address) override;
205  void write(unsigned address, byte value) override;
206  } keybDebuggable;
207 
208  UnicodeKeymap unicodeKeymap;
209  unsigned dynKeymap[MAX_KEYSYM];
210 
211  /** Keyboard matrix state for 'keymatrix' command. */
212  byte cmdKeyMatrix [KeyMatrixPosition::NUM_ROWS];
213  /** Keyboard matrix state for 'type' command. */
214  byte typeKeyMatrix [KeyMatrixPosition::NUM_ROWS];
215  /** Keyboard matrix state for pressed user keys (live or replay). */
216  byte userKeyMatrix[KeyMatrixPosition::NUM_ROWS];
217  /** Keyboard matrix state that is always in sync with host keyb, also during replay. */
218  byte hostKeyMatrix[KeyMatrixPosition::NUM_ROWS];
219  /** Combination of 'cmdKeyMatrix', 'typeKeyMatrix' and 'userKeyMatrix'. */
220  mutable byte keyMatrix[KeyMatrixPosition::NUM_ROWS];
221 
222  byte msxmodifiers;
223 
224  /** True iff keyboard includes a numeric keypad. */
225  const bool hasKeypad;
226  /** True iff changes to keyboard row 11 must be rejected.
227  * On MSX, row 11 contains the (Japanese) Yes/No keys.
228  */
229  const bool blockRow11;
230  /** True iff pressing multiple keys at once can add ghost key presses. */
231  const bool keyGhosting;
232  /** True iff Shift, Graph and Code are protected against key ghosting. */
233  const bool keyGhostingSGCprotected;
234  /** Bit vector where each modifier's bit (using KeyInfo::Modifier's
235  * numbering) is set iff it is a lock key.
236  */
237  const byte modifierIsLock;
238  mutable bool keysChanged;
239  /** Bit vector where each modifier's bit (using KeyInfo::Modifier's
240  * numbering) is set iff it is a lock key that is currently on in
241  * the emulated machine.
242  */
243  byte locksOn;
244 };
245 SERIALIZE_CLASS_VERSION(Keyboard, 3);
246 
247 } // namespace openmsx
248 
249 #endif
bool getEnum() const noexcept
Definition: EnumSetting.hh:96
const byte * getKeys() const
Returns a pointer to the current KeyBoard matrix.
Definition: Keyboard.cc:213
KeyCode
Constants that identify keys and key modifiers.
Definition: Keys.hh:25
Every class that wants to get scheduled at some point must inherit from this class.
Definition: Schedulable.hh:33
void serialize(Archive &ar, unsigned version)
Definition: Keyboard.cc:1305
Keyboard(MSXMotherBoard &motherBoard, Scheduler &scheduler, CommandController &commandController, EventDistributor &eventDistributor, MSXEventDistributor &msxEventDistributor, StateChangeDistributor &stateChangeDistributor, MatrixType matrix, const DeviceConfig &config)
Constructs a new Keyboard object.
Definition: Keyboard.cc:100
static constexpr unsigned NUM_ROWS
Rows are in the range [0..NUM_ROWS).
void transferHostKeyMatrix(const Keyboard &source)
Definition: Keyboard.cc:228
#define SERIALIZE_CLASS_VERSION(CLASS, VERSION)