summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/natkeyboard.h
blob: c3454ee8dd415a297bc63228f0027462cfd79666 (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
// license:BSD-3-Clause
// copyright-holders:Aaron Giles,Vas Crabb
/***************************************************************************

    natkeyboard.h

    Natural keyboard input support.

***************************************************************************/
#ifndef MAME_EMU_NATKEYBOARD_H
#define MAME_EMU_NATKEYBOARD_H

#pragma once

#include <array>
#include <functional>
#include <iosfwd>
#include <string>
#include <unordered_map>
#include <vector>


//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

// keyboard helper function delegates
using ioport_queue_chars_delegate = delegate<int (const char32_t *, size_t)>;
using ioport_accept_char_delegate = delegate<bool (char32_t)>;
using ioport_charqueue_empty_delegate = delegate<bool ()>;


// ======================> natural_keyboard

// buffer to handle copy/paste/insert of keys
class natural_keyboard
{
	DISABLE_COPYING(natural_keyboard);

public:
	// construction/destruction
	natural_keyboard(running_machine &machine);

	// getters and queries
	running_machine &machine() const { return m_machine; }
	bool empty() const { return (m_bufbegin == m_bufend); }
	bool full() const { return ((m_bufend + 1) % m_buffer.size()) == m_bufbegin; }
	bool can_post() const { return m_have_charkeys || !m_queue_chars.isnull(); }
	bool is_posting() const { return (!empty() || (!m_charqueue_empty.isnull() && !m_charqueue_empty())); }
	bool in_use() const { return m_in_use; }

	// configuration
	void configure(ioport_queue_chars_delegate queue_chars, ioport_accept_char_delegate accept_char, ioport_charqueue_empty_delegate charqueue_empty);
	void set_in_use(bool usage);
	size_t keyboard_count() const { return m_keyboards.size(); }
	device_t &keyboard_device(size_t n) const { return m_keyboards[n].device; }
	bool keyboard_is_keypad(size_t n) const { return !m_keyboards[n].keyboard; }
	bool keyboard_enabled(size_t n) const { return m_keyboards[n].enabled; }
	void enable_keyboard(size_t n) { set_keyboard_enabled(n, true); }
	void disable_keyboard(size_t n) { set_keyboard_enabled(n, false); }

	// posting
	void post_char(char32_t ch, bool normalize_crlf = false);
	void post(const char32_t *text, size_t length = 0, const attotime &rate = attotime::zero);
	void post_utf8(const char *text, size_t length = 0, const attotime &rate = attotime::zero);
	void post_utf8(const std::string &text, const attotime &rate = attotime::zero);
	void post_coded(const char *text, size_t length = 0, const attotime &rate = attotime::zero);
	void post_coded(const std::string &text, const attotime &rate = attotime::zero);
	void paste();

	// debugging
	void dump(std::ostream &str) const;
	std::string dump() const;

private:
	enum
	{
		SHIFT_COUNT = UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1,
		SHIFT_STATES = 1 << SHIFT_COUNT
	};

	// internal keyboard code information
	struct keycode_map_entry
	{
		std::array<ioport_field *, SHIFT_COUNT + 1> field;
		unsigned                                    shift;
		ioport_condition                            condition;
	};
	typedef std::vector<keycode_map_entry> keycode_map_entries;
	typedef std::unordered_map<char32_t, keycode_map_entries> keycode_map;

	// per-device character-to-key mapping
	struct kbd_dev_info
	{
		kbd_dev_info(device_t &dev) : device(dev) { }

		std::reference_wrapper<device_t>                    device;
		std::vector<std::reference_wrapper<ioport_field> >  keyfields;
		keycode_map                                         codemap;
		bool                                                keyboard = false;
		bool                                                keypad = false;
		bool                                                enabled = false;
	};

	// internal helpers
	void build_codes();
	void set_keyboard_enabled(size_t n, bool enable);
	bool can_post_directly(char32_t ch);
	bool can_post_alternate(char32_t ch);
	attotime choose_delay(char32_t ch);
	void internal_post(char32_t ch);
	void timer(void *ptr, int param);
	std::string unicode_to_string(char32_t ch) const;
	const keycode_map_entry *find_code(char32_t ch) const;

	// internal state
	std::vector<kbd_dev_info>       m_keyboards;        // info on keyboard devices in system
	running_machine &               m_machine;          // reference to our machine
	bool                            m_have_charkeys;    // are there keys with character?
	bool                            m_in_use;           // is natural keyboard in use?
	u32                             m_bufbegin;         // index of starting character
	u32                             m_bufend;           // index of ending character
	std::vector<char32_t>           m_buffer;           // actual buffer
	keycode_map_entry const *       m_current_code;     // current code being typed
	unsigned                        m_fieldnum;         // current step in multi-key sequence
	bool                            m_status_keydown;   // current keydown status
	bool                            m_last_cr;          // was the last char a CR?
	emu_timer *                     m_timer;            // timer for posting characters
	attotime                        m_current_rate;     // current rate for posting
	ioport_queue_chars_delegate     m_queue_chars;      // queue characters callback
	ioport_accept_char_delegate     m_accept_char;      // accept character callback
	ioport_charqueue_empty_delegate m_charqueue_empty;  // character queue empty callback
};


inline std::ostream &operator<<(std::ostream &str, natural_keyboard const &kbd) { kbd.dump(str); return str; }

#endif // MAME_EMU_NATKEYBOARD_H