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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
20 | KeyMap::KeyMap(void) |
21 | : myModEnabled(true) |
22 | { |
23 | } |
24 | |
25 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
26 | void KeyMap::add(const Event::Type event, const Mapping& mapping) |
27 | { |
28 | myMap[convertMod(mapping)] = event; |
29 | } |
30 | |
31 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
32 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
38 | void KeyMap::erase(const Mapping& mapping) |
39 | { |
40 | myMap.erase(convertMod(mapping)); |
41 | } |
42 | |
43 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
44 | void KeyMap::erase(const EventMode mode, const int key, const int mod) |
45 | { |
46 | erase(Mapping(mode, key, mod)); |
47 | } |
48 | |
49 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
50 | Event::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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
72 | Event::Type KeyMap::get(const EventMode mode, const int key, const int mod) const |
73 | { |
74 | return get(Mapping(mode, key, mod)); |
75 | } |
76 | |
77 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
78 | bool KeyMap::check(const Mapping& mapping) const |
79 | { |
80 | auto find = myMap.find(convertMod(mapping)); |
81 | |
82 | return (find != myMap.end()); |
83 | } |
84 | |
85 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
86 | bool KeyMap::check(const EventMode mode, const int key, const int mod) const |
87 | { |
88 | return check(Mapping(mode, key, mod)); |
89 | } |
90 | |
91 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
92 | string 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
141 | string KeyMap::getDesc(const EventMode mode, const int key, const int mod) const |
142 | { |
143 | return getDesc(Mapping(mode, key, mod)); |
144 | } |
145 | |
146 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
147 | string 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
164 | KeyMap::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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
176 | string 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
193 | int 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
210 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
221 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
232 | KeyMap::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 | |