1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifndef COMMON_HARDWARE_KEY_H
24 #define COMMON_HARDWARE_KEY_H
25 
26 #include "common/scummsys.h"
27 
28 #include "common/array.h"
29 #include "common/events.h"
30 #include "common/keyboard.h"
31 #include "common/str.h"
32 
33 namespace Common {
34 
35 typedef uint32 HardwareInputCode;
36 
37 enum HardwareInputType {
38 	/** Empty / invalid input type */
39 	kHardwareInputTypeInvalid,
40 	/** Keyboard input that sends -up and -down events */
41 	kHardwareInputTypeKeyboard,
42 	/** Mouse input that sends -up and -down events */
43 	kHardwareInputTypeMouse,
44 	/** Joystick input that sends -up and -down events */
45 	kHardwareInputTypeJoystickButton,
46 	/** Joystick input that sends "analog" values */
47 	kHardwareInputTypeJoystickHalfAxis,
48 	/** Input that sends single events */
49 	kHardwareInputTypeCustom
50 };
51 
52 /**
53 * Describes an available hardware input
54 */
55 struct HardwareInput {
56 	/** unique id used for saving/loading to config */
57 	String id;
58 
59 	/** Human readable description */
60 	U32String description;
61 
62 	/** Type tag */
63 	HardwareInputType type;
64 
65 	/**
66 	 * A platform specific unique identifier for an input event
67 	 * generated when this input is triggered.
68 	 * This is only relevant when type == kHardwareInputTypeGeneric
69 	 */
70 	HardwareInputCode inputCode;
71 
72 	/**
73 	 * The KeyState that is generated by the back-end
74 	 * when this hardware key is pressed.
75 	 * This is only relevant when type == kHardwareInputTypeKeyboard
76 	 */
77 	KeyState key;
78 
HardwareInputHardwareInput79 	HardwareInput()
80 		: inputCode(0), type(kHardwareInputTypeInvalid) { }
81 
createCustomHardwareInput82 	static HardwareInput createCustom(const String &i, HardwareInputCode ic, const U32String &desc) {
83 		return createSimple(kHardwareInputTypeCustom, i, ic, desc);
84 	}
85 
createKeyboardHardwareInput86 	static HardwareInput createKeyboard(const String &i, KeyState ky, const U32String &desc) {
87 		HardwareInput hardwareInput;
88 		hardwareInput.id = i;
89 		hardwareInput.description = desc;
90 		hardwareInput.type = kHardwareInputTypeKeyboard;
91 		hardwareInput.inputCode = 0;
92 		hardwareInput.key = ky;
93 		return hardwareInput;
94 	}
95 
createJoystickButtonHardwareInput96 	static HardwareInput createJoystickButton(const String &i, uint8 button, const U32String &desc) {
97 		return createSimple(kHardwareInputTypeJoystickButton, i, button, desc);
98 	}
99 
createJoystickHalfAxisHardwareInput100 	static HardwareInput createJoystickHalfAxis(const String &i, uint8 axis, bool positiveHalf, const U32String &desc) {
101 		return createSimple(kHardwareInputTypeJoystickHalfAxis, i, axis * 2 + (positiveHalf ? 1 : 0), desc);
102 	}
103 
createMouseHardwareInput104 	static HardwareInput createMouse(const String &i, uint8 button, const U32String &desc) {
105 		return createSimple(kHardwareInputTypeMouse, i, button, desc);
106 	}
107 
108 private:
createSimpleHardwareInput109 	static HardwareInput createSimple(HardwareInputType type, const String &i, HardwareInputCode ic, const U32String &desc) {
110 		HardwareInput hardwareInput;
111 		hardwareInput.id = i;
112 		hardwareInput.description = desc;
113 		hardwareInput.type = type;
114 		hardwareInput.inputCode = ic;
115 		return hardwareInput;
116 	}
117 };
118 
119 /**
120  * Entry in a static table of custom backend hardware inputs
121  */
122 struct HardwareInputTableEntry {
123 	const char *hwId;
124 	HardwareInputCode code;
125 	const char *desc;
126 
findWithCodeHardwareInputTableEntry127 	static const HardwareInputTableEntry *findWithCode(const HardwareInputTableEntry *_entries, HardwareInputCode code) {
128 		for (const HardwareInputTableEntry *hw = _entries;  hw->hwId; hw++) {
129 			if (hw->code == code) {
130 				return hw;
131 			}
132 		}
133 		return nullptr;
134 	}
135 
findWithIdHardwareInputTableEntry136 	static const HardwareInputTableEntry *findWithId(const HardwareInputTableEntry *_entries, const String &id) {
137 		for (const HardwareInputTableEntry *hw = _entries;  hw->hwId; hw++) {
138 			if (id.equals(hw->hwId)) {
139 				return hw;
140 			}
141 		}
142 		return nullptr;
143 	}
144 };
145 
146 /**
147  * Entry in a static table of available non-modifier keys
148  */
149 struct KeyTableEntry {
150 	const char *hwId;
151 	KeyCode keycode;
152 	const char *desc;
153 };
154 
155 /**
156  * Entry in a static table of available key modifiers
157  */
158 struct ModifierTableEntry {
159 	byte flag;
160 	const char *id;
161 	const char *desc;
162 };
163 
164 enum AxisType {
165 	/** An axis that sends "analog" values from JOYAXIS_MIN to JOYAXIS_MAX. e.g. a gamepad stick axis */
166 	kAxisTypeFull,
167 	/** An axis that sends "analog" values from 0 to JOYAXIS_MAX. e.g. a gamepad trigger */
168 	kAxisTypeHalf
169 };
170 
171 struct AxisTableEntry {
172 	const char *hwId;
173 	HardwareInputCode code;
174 	AxisType type;
175 	const char *desc;
176 
findWithCodeAxisTableEntry177 	static const AxisTableEntry *findWithCode(const AxisTableEntry *_entries, HardwareInputCode code) {
178 		for (const AxisTableEntry *hw = _entries;  hw->hwId; hw++) {
179 			if (hw->code == code) {
180 				return hw;
181 			}
182 		}
183 		return nullptr;
184 	}
185 
findWithIdAxisTableEntry186 	static const AxisTableEntry *findWithId(const AxisTableEntry *_entries, const String &id) {
187 		for (const AxisTableEntry *hw = _entries;  hw->hwId; hw++) {
188 			if (id.equals(hw->hwId)) {
189 				return hw;
190 			}
191 		}
192 		return nullptr;
193 	}
194 };
195 
196 
197 /**
198  * Interface for querying information about a hardware input device
199  */
200 class HardwareInputSet {
201 public:
202 	virtual ~HardwareInputSet();
203 
204 	/**
205 	 * Retrieve a hardware input description from an unique identifier
206 	 *
207 	 * In case no input was found with the specified id, an empty
208 	 * HardwareInput structure is return with the type set to
209 	 * kHardwareInputTypeInvalid.
210 	 */
211 	virtual HardwareInput findHardwareInput(const String &id) const = 0;
212 
213 	/**
214 	 * Retrieve a hardware input description from one of the events
215 	 * produced when the input is triggered.
216 	 *
217 	 * In case the specified event is not produced by this device,
218 	 * an empty HardwareInput structure is return with the type set to
219 	 * kHardwareInputTypeInvalid.
220 	 */
221 	virtual HardwareInput findHardwareInput(const Event &event) const = 0;
222 };
223 
224 /**
225  * A keyboard input device
226  *
227  * Describes the keys and key + modifiers combinations as HardwareInputs
228  */
229 class KeyboardHardwareInputSet : public HardwareInputSet {
230 public:
231 	KeyboardHardwareInputSet(const KeyTableEntry *keys, const ModifierTableEntry *modifiers);
232 
233 	// HardwareInputSet API
234 	HardwareInput findHardwareInput(const String &id) const override;
235 	HardwareInput findHardwareInput(const Event &event) const override;
236 
237 	/** Transform a keystate into a canonical form that can be used to unambiguously identify the keypress */
238 	static KeyState normalizeKeyState(const KeyState &keystate);
239 
240 private:
241 	const KeyTableEntry *_keys;
242 	const ModifierTableEntry *_modifiers;
243 };
244 
245 /**
246  * A mouse input device
247  *
248  * Describes the mouse buttons
249  */
250 class MouseHardwareInputSet : public HardwareInputSet {
251 public:
252 	MouseHardwareInputSet(const HardwareInputTableEntry *buttonEntries);
253 
254 	// HardwareInputSet API
255 	HardwareInput findHardwareInput(const String &id) const override;
256 	HardwareInput findHardwareInput(const Event &event) const override;
257 
258 private:
259 	const HardwareInputTableEntry *_buttonEntries;
260 };
261 
262 /**
263  * A joystick input device
264  */
265 class JoystickHardwareInputSet : public HardwareInputSet {
266 public:
267 	JoystickHardwareInputSet(const HardwareInputTableEntry *buttonEntries, const AxisTableEntry *axisEntries);
268 
269 	// HardwareInputSet API
270 	HardwareInput findHardwareInput(const String &id) const override;
271 	HardwareInput findHardwareInput(const Event &event) const override;
272 
273 private:
274 	const HardwareInputTableEntry *_buttonEntries;
275 	const AxisTableEntry *_axisEntries;
276 };
277 
278 /**
279  * A custom backend input device
280  *
281  * @todo This is currently unused. Perhaps it should be removed.
282  */
283 class CustomHardwareInputSet : public HardwareInputSet {
284 public:
285 	CustomHardwareInputSet(const HardwareInputTableEntry *hardwareEntries);
286 
287 	// HardwareInputSet API
288 	HardwareInput findHardwareInput(const String &id) const override;
289 	HardwareInput findHardwareInput(const Event &event) const override;
290 
291 private:
292 	const HardwareInputTableEntry *_hardwareEntries;
293 };
294 
295 /**
296  * A composite input device that delegates to a set of actual input devices.
297  */
298 class CompositeHardwareInputSet : public HardwareInputSet {
299 public:
300 	~CompositeHardwareInputSet() override;
301 
302 	// HardwareInputSet API
303 	HardwareInput findHardwareInput(const String &id) const override;
304 	HardwareInput findHardwareInput(const Event &event) const override;
305 
306 	/**
307 	 * Add an input device to this composite device
308 	 *
309 	 * Takes ownership of the hardware input set
310 	 */
311 	void addHardwareInputSet(HardwareInputSet *hardwareInputSet);
312 
313 private:
314 	Array<HardwareInputSet *> _inputSets;
315 };
316 
317 /** A standard set of keyboard keys */
318 extern const KeyTableEntry defaultKeys[];
319 
320 /** A standard set of keyboard modifiers */
321 extern const ModifierTableEntry defaultModifiers[];
322 
323 /** A standard set of mouse buttons */
324 extern const HardwareInputTableEntry defaultMouseButtons[];
325 
326 /** A standard set of joystick buttons based on the ScummVM event model */
327 extern const HardwareInputTableEntry defaultJoystickButtons[];
328 
329 /** A standard set of joystick axes based on the ScummVM event model */
330 extern const AxisTableEntry defaultJoystickAxes[];
331 
332 } // End of namespace Common
333 
334 #endif // #ifndef COMMON_HARDWARE_KEY_H
335