1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17#include "KeyMap.hxx"
18
19// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
20KeyMap::KeyMap(void)
21 : myModEnabled(true)
22{
23}
24
25// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
26void KeyMap::add(const Event::Type event, const Mapping& mapping)
27{
28 myMap[convertMod(mapping)] = event;
29}
30
31// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
32void KeyMap::add(const Event::Type event, const EventMode mode, const int key, const int mod)
33{
34 add(event, Mapping(mode, key, mod));
35}
36
37// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
38void KeyMap::erase(const Mapping& mapping)
39{
40 myMap.erase(convertMod(mapping));
41}
42
43// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
44void KeyMap::erase(const EventMode mode, const int key, const int mod)
45{
46 erase(Mapping(mode, key, mod));
47}
48
49// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
50Event::Type KeyMap::get(const Mapping& mapping) const
51{
52 Mapping m = convertMod(mapping);
53
54 if (myModEnabled)
55 {
56 auto find = myMap.find(m);
57 if (find != myMap.end())
58 return find->second;
59 }
60
61 // mapping not found, try without modifiers
62 m.mod = StellaMod(0);
63
64 auto find = myMap.find(m);
65 if (find != myMap.end())
66 return find->second;
67
68 return Event::Type::NoType;
69}
70
71// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
72Event::Type KeyMap::get(const EventMode mode, const int key, const int mod) const
73{
74 return get(Mapping(mode, key, mod));
75}
76
77// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
78bool KeyMap::check(const Mapping& mapping) const
79{
80 auto find = myMap.find(convertMod(mapping));
81
82 return (find != myMap.end());
83}
84
85// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
86bool KeyMap::check(const EventMode mode, const int key, const int mod) const
87{
88 return check(Mapping(mode, key, mod));
89}
90
91// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
92string KeyMap::getDesc(const Mapping& mapping) const
93{
94 ostringstream buf;
95#if defined(BSPF_MACOS) || defined(MACOS_KEYS)
96 string mod2 = "Option";
97 int MOD2 = KBDM_ALT;
98 int LMOD2 = KBDM_LALT;
99 int RMOD2 = KBDM_RALT;
100 string mod3 = "Cmd";
101 int MOD3 = KBDM_GUI;
102 int LMOD3 = KBDM_LGUI;
103 int RMOD3 = KBDM_RGUI;
104#else
105 string mod2 = "Windows";
106 int MOD2 = KBDM_GUI;
107 int LMOD2 = KBDM_LGUI;
108 int RMOD2 = KBDM_RGUI;
109 string mod3 = "Alt";
110 int MOD3 = KBDM_ALT;
111 int LMOD3 = KBDM_LALT;
112 int RMOD3 = KBDM_RALT;
113#endif
114
115 if ((mapping.mod & KBDM_CTRL) == KBDM_CTRL) buf << "Ctrl";
116 else if (mapping.mod & KBDM_LCTRL) buf << "Left Ctrl";
117 else if (mapping.mod & KBDM_RCTRL) buf << "Right Ctrl";
118
119 if ((mapping.mod & (MOD2)) && buf.tellp()) buf << "+";
120 if ((mapping.mod & MOD2) == MOD2) buf << mod2;
121 else if (mapping.mod & LMOD2) buf << "Left " << mod2;
122 else if (mapping.mod & RMOD2) buf << "Right " << mod2;
123
124 if ((mapping.mod & (MOD3)) && buf.tellp()) buf << "+";
125 if ((mapping.mod & MOD3) == MOD3) buf << mod3;
126 else if (mapping.mod & LMOD3) buf << "Left " << mod3;
127 else if (mapping.mod & RMOD3) buf << "Right " << mod3;
128
129 if ((mapping.mod & (KBDM_SHIFT)) && buf.tellp()) buf << "+";
130 if ((mapping.mod & KBDM_SHIFT) == KBDM_SHIFT) buf << "Shift";
131 else if (mapping.mod & KBDM_LSHIFT) buf << "Left Shift";
132 else if (mapping.mod & KBDM_RSHIFT) buf << "Right Shift";
133
134 if (buf.tellp()) buf << "+";
135 buf << StellaKeyName::forKey(mapping.key);
136
137 return buf.str();
138}
139
140// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
141string KeyMap::getDesc(const EventMode mode, const int key, const int mod) const
142{
143 return getDesc(Mapping(mode, key, mod));
144}
145
146// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
147string KeyMap::getEventMappingDesc(const Event::Type event, const EventMode mode) const
148{
149 ostringstream buf;
150
151 for (auto item : myMap)
152 {
153 if (item.second == event && item.first.mode == mode)
154 {
155 if (buf.str() != "")
156 buf << ", ";
157 buf << getDesc(item.first);
158 }
159 }
160 return buf.str();
161}
162
163// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
164KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const EventMode mode) const
165{
166 MappingArray map;
167
168 for (auto item : myMap)
169 if (item.second == event && item.first.mode == mode)
170 map.push_back(item.first);
171
172 return map;
173}
174
175// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
176string KeyMap::saveMapping(const EventMode mode) const
177{
178 ostringstream buf;
179
180 for (auto item : myMap)
181 {
182 if (item.first.mode == mode)
183 {
184 if (buf.str() != "")
185 buf << "|";
186 buf << item.second << ":" << item.first.key << "," << item.first.mod;
187 }
188 }
189 return buf.str();
190}
191
192// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
193int KeyMap::loadMapping(string& list, const EventMode mode)
194{
195 // Since istringstream swallows whitespace, we have to make the
196 // delimiters be spaces
197 std::replace(list.begin(), list.end(), '|', ' ');
198 std::replace(list.begin(), list.end(), ':', ' ');
199 std::replace(list.begin(), list.end(), ',', ' ');
200 istringstream buf(list);
201 int event, key, mod, i = 0;
202
203 while (buf >> event && buf >> key && buf >> mod && ++i)
204 add(Event::Type(event), mode, key, mod);
205
206 return i;
207}
208
209// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
210void KeyMap::eraseMode(const EventMode mode)
211{
212 for (auto item = myMap.begin(); item != myMap.end();)
213 if (item->first.mode == mode) {
214 auto _item = item++;
215 erase(_item->first);
216 }
217 else item++;
218}
219
220// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
221void KeyMap::eraseEvent(const Event::Type event, const EventMode mode)
222{
223 for (auto item = myMap.begin(); item != myMap.end();)
224 if (item->second == event && item->first.mode == mode) {
225 auto _item = item++;
226 erase(_item->first);
227 }
228 else item++;
229}
230
231// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
232KeyMap::Mapping KeyMap::convertMod(const Mapping& mapping) const
233{
234 Mapping m = mapping;
235
236 if (m.key >= KBDK_LCTRL && m.key <= KBDK_RGUI)
237 // handle solo modifier keys differently
238 m.mod = KBDM_NONE;
239 else
240 {
241 // limit to modifiers we want to support
242 m.mod = StellaMod(m.mod & (KBDM_SHIFT | KBDM_CTRL | KBDM_ALT | KBDM_GUI));
243 }
244
245 return m;
246}
247