summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_common.h
blob: 830b5154745bb6fc4ac87f0178f751ecfa174352 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
//============================================================
//
//  input_common.h - Common code for all MAME input modules
//
//  SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================

#ifndef INPUT_COMMON_H_
#define INPUT_COMMON_H_

#include "input_module.h"

#include "inputdev.h"

#include <chrono>
#include <memory>
#include <mutex>
#include <queue>
#include <algorithm>
#include <functional>


//============================================================
//  PARAMETERS
//============================================================

enum
{
	POVDIR_LEFT = 0,
	POVDIR_RIGHT,
	POVDIR_UP,
	POVDIR_DOWN
};

#define MAX_KEYS            256
#define MAX_AXES            32
#define MAX_BUTTONS         32
#define MAX_HATS            8
#define MAX_POV             4

/****************************************************************************
*      DirectInput compatible keyboard scan codes
****************************************************************************/
#define KEY_UNKNOWN         0x00
#define KEY_ESCAPE          0x01
#define KEY_1               0x02
#define KEY_2               0x03
#define KEY_3               0x04
#define KEY_4               0x05
#define KEY_5               0x06
#define KEY_6               0x07
#define KEY_7               0x08
#define KEY_8               0x09
#define KEY_9               0x0A
#define KEY_0               0x0B
#define KEY_MINUS           0x0C    /* - on main keyboard */
#define KEY_EQUALS          0x0D
#define KEY_BACK            0x0E    /* backspace */
#define KEY_TAB             0x0F
#define KEY_Q               0x10
#define KEY_W               0x11
#define KEY_E               0x12
#define KEY_R               0x13
#define KEY_T               0x14
#define KEY_Y               0x15
#define KEY_U               0x16
#define KEY_I               0x17
#define KEY_O               0x18
#define KEY_P               0x19
#define KEY_LBRACKET        0x1A
#define KEY_RBRACKET        0x1B
#define KEY_RETURN          0x1C    /* Enter on main keyboard */
#define KEY_LCONTROL        0x1D
#define KEY_A               0x1E
#define KEY_S               0x1F
#define KEY_D               0x20
#define KEY_F               0x21
#define KEY_G               0x22
#define KEY_H               0x23
#define KEY_J               0x24
#define KEY_K               0x25
#define KEY_L               0x26
#define KEY_SEMICOLON       0x27
#define KEY_APOSTROPHE      0x28
#define KEY_GRAVE           0x29    /* accent grave */
#define KEY_LSHIFT          0x2A
#define KEY_BACKSLASH       0x2B
#define KEY_Z               0x2C
#define KEY_X               0x2D
#define KEY_C               0x2E
#define KEY_V               0x2F
#define KEY_B               0x30
#define KEY_N               0x31
#define KEY_M               0x32
#define KEY_COMMA           0x33
#define KEY_PERIOD          0x34    /* . on main keyboard */
#define KEY_SLASH           0x35    /* / on main keyboard */
#define KEY_RSHIFT          0x36
#define KEY_MULTIPLY        0x37    /* * on numeric keypad */
#define KEY_LMENU           0x38    /* left Alt */
#define KEY_SPACE           0x39
#define KEY_CAPITAL         0x3A
#define KEY_F1              0x3B
#define KEY_F2              0x3C
#define KEY_F3              0x3D
#define KEY_F4              0x3E
#define KEY_F5              0x3F
#define KEY_F6              0x40
#define KEY_F7              0x41
#define KEY_F8              0x42
#define KEY_F9              0x43
#define KEY_F10             0x44
#define KEY_NUMLOCK         0x45
#define KEY_SCROLL          0x46    /* Scroll Lock */
#define KEY_NUMPAD7         0x47
#define KEY_NUMPAD8         0x48
#define KEY_NUMPAD9         0x49
#define KEY_SUBTRACT        0x4A    /* - on numeric keypad */
#define KEY_NUMPAD4         0x4B
#define KEY_NUMPAD5         0x4C
#define KEY_NUMPAD6         0x4D
#define KEY_ADD             0x4E    /* + on numeric keypad */
#define KEY_NUMPAD1         0x4F
#define KEY_NUMPAD2         0x50
#define KEY_NUMPAD3         0x51
#define KEY_NUMPAD0         0x52
#define KEY_DECIMAL         0x53    /* . on numeric keypad */
#define KEY_OEM_102         0x56    /* <> or \| on RT 102-key keyboard (Non-U.S.) */
#define KEY_F11             0x57
#define KEY_F12             0x58
#define KEY_F13             0x64    /*                     (NEC PC98) */
#define KEY_F14             0x65    /*                     (NEC PC98) */
#define KEY_F15             0x66    /*                     (NEC PC98) */
#define KEY_KANA            0x70    /* (Japanese keyboard)            */
#define KEY_ABNT_C1         0x73    /* /? on Brazilian keyboard */
#define KEY_CONVERT         0x79    /* (Japanese keyboard)            */
#define KEY_NOCONVERT       0x7B    /* (Japanese keyboard)            */
#define KEY_YEN             0x7D    /* (Japanese keyboard)            */
#define KEY_ABNT_C2         0x7E    /* Numpad . on Brazilian keyboard */
#define KEY_NUMPADEQUALS    0x8D    /* = on numeric keypad (NEC PC98) */
#define KEY_PREVTRACK       0x90    /* Previous Track (DIK_CIRCUMFLEX on Japanese keyboard) */
#define KEY_AT              0x91    /*                     (NEC PC98) */
#define KEY_COLON           0x92    /*                     (NEC PC98) */
#define KEY_UNDERLINE       0x93    /*                     (NEC PC98) */
#define KEY_KANJI           0x94    /* (Japanese keyboard)            */
#define KEY_STOP            0x95    /*                     (NEC PC98) */
#define KEY_AX              0x96    /*                     (Japan AX) */
#define KEY_UNLABELED       0x97    /*                        (J3100) */
#define KEY_NEXTTRACK       0x99    /* Next Track */
#define KEY_NUMPADENTER     0x9C    /* Enter on numeric keypad */
#define KEY_RCONTROL        0x9D
#define KEY_MUTE            0xA0    /* Mute */
#define KEY_CALCULATOR      0xA1    /* Calculator */
#define KEY_PLAYPAUSE       0xA2    /* Play / Pause */
#define KEY_MEDIASTOP       0xA4    /* Media Stop */
#define KEY_VOLUMEDOWN      0xAE    /* Volume - */
#define KEY_VOLUMEUP        0xB0    /* Volume + */
#define KEY_WEBHOME         0xB2    /* Web home */
#define KEY_NUMPADCOMMA     0xB3    /* , on numeric keypad (NEC PC98) */
#define KEY_DIVIDE          0xB5    /* / on numeric keypad */
#define KEY_SYSRQ           0xB7
#define KEY_RMENU           0xB8    /* right Alt */
#define KEY_PAUSE           0xC5    /* Pause */
#define KEY_HOME            0xC7    /* Home on arrow keypad */
#define KEY_UP              0xC8    /* UpArrow on arrow keypad */
#define KEY_PRIOR           0xC9    /* PgUp on arrow keypad */
#define KEY_LEFT            0xCB    /* LeftArrow on arrow keypad */
#define KEY_RIGHT           0xCD    /* RightArrow on arrow keypad */
#define KEY_END             0xCF    /* End on arrow keypad */
#define KEY_DOWN            0xD0    /* DownArrow on arrow keypad */
#define KEY_NEXT            0xD1    /* PgDn on arrow keypad */
#define KEY_INSERT          0xD2    /* Insert on arrow keypad */
#define KEY_DELETE          0xD3    /* Delete on arrow keypad */
#define KEY_LWIN            0xDB    /* Left Windows key */
#define KEY_RWIN            0xDC    /* Right Windows key */
#define KEY_APPS            0xDD    /* AppMenu key */
#define KEY_POWER           0xDE    /* System Power */
#define KEY_SLEEP           0xDF    /* System Sleep */
#define KEY_WAKE            0xE3    /* System Wake */
#define KEY_WEBSEARCH       0xE5    /* Web Search */
#define KEY_WEBFAVORITES    0xE6    /* Web Favorites */
#define KEY_WEBREFRESH      0xE7    /* Web Refresh */
#define KEY_WEBSTOP         0xE8    /* Web Stop */
#define KEY_WEBFORWARD      0xE9    /* Web Forward */
#define KEY_WEBBACK         0xEA    /* Web Back */
#define KEY_MYCOMPUTER      0xEB    /* My Computer */
#define KEY_MAIL            0xEC    /* Mail */
#define KEY_MEDIASELECT     0xED    /* Media Select */

//============================================================
//  device_info
//============================================================

class input_device_list;

class device_info
{
	friend input_device_list;

private:
	std::string             m_name;
	std::string             m_id;
	input_device *          m_device;
	running_machine &       m_machine;
	input_module &          m_module;
	input_device_class      m_deviceclass;

public:
	// Constructor
	device_info(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module)
		: m_name(name),
		m_id(id),
		m_device(nullptr),
		m_machine(machine),
		m_module(module),
		m_deviceclass(deviceclass)
	{
	}

	// Destructor
	virtual ~device_info() {}

	// Getters
	running_machine &         machine() const { return m_machine; }
	const char *              name() const { return m_name.c_str(); }
	const char *              id() const { return m_id.c_str(); }
	input_device *            device() const { return m_device; }
	input_module &            module() const { return m_module; }
	input_device_class        deviceclass() const { return m_deviceclass; }

	// Poll and reset methods
	virtual void poll() {};
	virtual void reset() = 0;
};

//============================================================
//  event_based_device
//============================================================

#define DEFAULT_EVENT_QUEUE_SIZE 20

template <class TEvent>
class event_based_device : public device_info
{
private:
	std::queue<TEvent>   m_event_queue;

protected:
	std::mutex           m_device_lock;

	virtual void process_event(TEvent &ev) = 0;

public:
	event_based_device(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module)
		: device_info(machine, name, id, deviceclass, module)
	{
	}

	void queue_events(const TEvent *events, int count)
	{
		std::lock_guard<std::mutex> scope_lock(m_device_lock);
		for (int i = 0; i < count; i++)
			m_event_queue.push(events[i]);

		// If we've gone over the size, remove old events from the queue
		while (m_event_queue.size() > DEFAULT_EVENT_QUEUE_SIZE)
			m_event_queue.pop();
	}

	void virtual poll() override
	{
		std::lock_guard<std::mutex> scope_lock(m_device_lock);

		// Process each event until the queue is empty
		while (!m_event_queue.empty())
		{
			TEvent &next_event = m_event_queue.front();
			process_event(next_event);
			m_event_queue.pop();
		}
	}
};

//============================================================
//  input_device_list class
//============================================================

class input_device_list
{
private:
	std::vector<std::unique_ptr<device_info>> m_list;

public:
	size_t size() const { return m_list.size(); }
	auto begin() { return m_list.begin(); }
	auto end() { return m_list.end(); }

	void poll_devices()
	{
		for (auto &device: m_list)
			device->poll();
	}

	void reset_devices()
	{
		for (auto &device: m_list)
			device->reset();
	}

	void free_device(device_info* devinfo)
	{
		// find the device to remove
		auto device_matches = [devinfo](std::unique_ptr<device_info> &device) { return devinfo == device.get(); };
		m_list.erase(std::remove_if(std::begin(m_list), std::end(m_list), device_matches), m_list.end());
	}

	void for_each_device(std::function<void (device_info*)> action)
	{
		for (auto &device: m_list)
			action(device.get());
	}

	void free_all_devices()
	{
		while (!m_list.empty())
			m_list.pop_back();
	}

	template <typename TActual, typename... TArgs>
	TActual* create_device(running_machine &machine, const char *name, const char *id, input_module &module, TArgs&&... args)
	{
		// allocate the device object
		auto devinfo = std::make_unique<TActual>(machine, name, id, module, std::forward<TArgs>(args)...);

		return add_device(machine, std::move(devinfo));
	}

	template <typename TActual>
	TActual* add_device(running_machine &machine, std::unique_ptr<TActual> devinfo)
	{
		// Add the device to the machine
		devinfo->m_device = machine.input().device_class(devinfo->deviceclass()).add_device(devinfo->name(), devinfo->id(), devinfo.get());

		// append us to the list
		m_list.push_back(std::move(devinfo));

		return static_cast<TActual*>(m_list.back().get());
	}
};

// keyboard translation table

struct key_trans_entry {
	input_item_id   mame_key;

#if defined(OSD_SDL)
	int             sdl_scancode;
#elif defined(OSD_WINDOWS)
	int             scan_code;
	unsigned char   virtual_key;
#elif defined(OSD_UWP)
	int             scan_code;
	Windows::System::VirtualKey virtual_key;
#endif

	char            ascii_key;
	char const  *   mame_key_name;
	char *          ui_name;
};

class keyboard_trans_table
{
private:
	// default constructor is private
	keyboard_trans_table();

	static key_trans_entry              s_default_table[];
	std::unique_ptr<key_trans_entry[]>  m_custom_table;

	key_trans_entry *                   m_table;
	uint32_t                              m_table_size;

public:
	// constructor
	keyboard_trans_table(std::unique_ptr<key_trans_entry[]> table, unsigned int size);

	// getters/setters
	uint32_t size() const { return m_table_size; }

	// public methods
	input_item_id lookup_mame_code(const char * scode) const;
	int lookup_mame_index(const char * scode) const;

#if defined(OSD_WINDOWS)
	input_item_id map_di_scancode_to_itemid(int di_scancode) const;
	int vkey_for_mame_code(input_code code) const;
#elif defined(OSD_UWP)
	input_item_id map_di_scancode_to_itemid(int di_scancode) const;
	const char* ui_label_for_mame_key(input_item_id code) const;
#endif

	static keyboard_trans_table& instance()
	{
		static keyboard_trans_table s_instance;
		return s_instance;
	}

	key_trans_entry & operator [](int i) const { return m_table[i]; }
};

//============================================================
//  input_module_base - base class for input modules
//============================================================

class osd_options;

typedef std::chrono::high_resolution_clock clock_type;
typedef std::chrono::time_point<std::chrono::high_resolution_clock> timepoint_type;

// 10 milliseconds polling interval
#define MIN_POLLING_INTERVAL 10

class input_module_base : public input_module
{
public:
	input_module_base(const char *type, const char* name)
		: input_module(type, name),
		m_input_enabled(false),
		m_mouse_enabled(false),
		m_lightgun_enabled(false),
		m_input_paused(false),
		m_options(nullptr)
	{
	}

private:
	bool                  m_input_enabled;
	bool                  m_mouse_enabled;
	bool                  m_lightgun_enabled;
	bool                  m_input_paused;
	const osd_options *   m_options;
	input_device_list     m_devicelist;
	clock_type            m_clock;
	timepoint_type        m_last_poll;

protected:
	void set_mouse_enabled(bool value) { m_mouse_enabled = value; }

public:

	const osd_options *   options() const { return m_options; }
	input_device_list *   devicelist() { return &m_devicelist; }
	bool                  input_enabled() const { return m_input_enabled; }
	bool                  input_paused() const { return m_input_paused; }
	bool                  mouse_enabled() const { return m_mouse_enabled; }
	bool                  lightgun_enabled() const { return m_lightgun_enabled; }

	int init(const osd_options &options) override;

	void poll_if_necessary(running_machine &machine) override
	{
		auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(m_clock.now() - m_last_poll);
		if (elapsed.count() >= MIN_POLLING_INTERVAL)
		{
			poll(machine);
		}
	}

	virtual void poll(running_machine &machine)
	{
		// ignore if not enabled
		if (m_input_enabled)
		{
			// grab the current time
			m_last_poll = m_clock.now();

			before_poll(machine);

			// track if mouse/lightgun is enabled, for mouse hiding purposes
			m_mouse_enabled = machine.input().device_class(DEVICE_CLASS_MOUSE).enabled();
			m_lightgun_enabled = machine.input().device_class(DEVICE_CLASS_LIGHTGUN).enabled();
		}

		// poll all of the devices
		if (should_poll_devices(machine))
		{
			m_devicelist.poll_devices();
		}
		else
		{
			m_devicelist.reset_devices();
		}
	}

	virtual void pause() override
	{
		// keep track of the paused state
		m_input_paused = true;
	}

	virtual void resume() override
	{
		// keep track of the paused state
		m_input_paused = false;
	}

	virtual void exit() override
	{
		devicelist()->free_all_devices();
	}

protected:
	virtual int init_internal() { return 0; }
	virtual bool should_poll_devices(running_machine &machine) = 0;
	virtual void before_poll(running_machine &machine) {}
};

template <class TItem>
int generic_button_get_state(void *device_internal, void *item_internal)
{
	device_info *devinfo = static_cast<device_info *>(device_internal);
	TItem *itemdata = static_cast<TItem*>(item_internal);

	// return the current state
	devinfo->module().poll_if_necessary(devinfo->machine());
	return *itemdata >> 7;
}

template <class TItem>
int generic_axis_get_state(void *device_internal, void *item_internal)
{
	device_info *devinfo = static_cast<device_info *>(device_internal);
	TItem *axisdata = static_cast<TItem*>(item_internal);

	// return the current state
	devinfo->module().poll_if_necessary(devinfo->machine());
	return *axisdata;
}

//============================================================
//  default_button_name
//============================================================

inline static const char *default_button_name(int which)
{
	static char buffer[20];
	snprintf(buffer, std::size(buffer), "B%d", which);
	return buffer;
}

//============================================================
//  default_pov_name
//============================================================

inline static const char *default_pov_name(int which)
{
	static char buffer[20];
	snprintf(buffer, std::size(buffer), "POV%d", which);
	return buffer;
}

// default axis names
const char *const default_axis_name[] =
{
	"X", "Y", "Z", "RX",
	"RY", "RZ", "SL1", "SL2"
};

inline static int32_t normalize_absolute_axis(double raw, double rawmin, double rawmax)
{
	double center = (rawmax + rawmin) / 2.0;

	// make sure we have valid data
	if (rawmin >= rawmax)
		return int32_t(raw);

	// above center
	if (raw >= center)
	{
		double result = (raw - center) * INPUT_ABSOLUTE_MAX / (rawmax - center);
		return std::min(result, (double)INPUT_ABSOLUTE_MAX);
	}

	// below center
	else
	{
		double result = -((center - raw) * (double)-INPUT_ABSOLUTE_MIN / (center - rawmin));
		return std::max(result, (double)INPUT_ABSOLUTE_MIN);
	}
}

#endif // INPUT_COMMON_H_