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
18#include "JoyMap.hxx"
19
20// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
21JoyMap::JoyMap(void)
22{
23}
24
25// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
26void JoyMap::add(const Event::Type event, const JoyMapping& mapping)
27{
28 myMap[mapping] = event;
29}
30
31// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
32void JoyMap::add(const Event::Type event, const EventMode mode, const int button,
33 const JoyAxis axis, const JoyDir adir,
34 const int hat, const JoyHatDir hdir)
35{
36 add(event, JoyMapping(mode, button, axis, adir, hat, hdir));
37}
38
39// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
40void JoyMap::add(const Event::Type event, const EventMode mode, const int button,
41 const int hat, const JoyHatDir hdir)
42{
43 add(event, JoyMapping(mode, button, hat, hdir));
44}
45
46// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
47void JoyMap::erase(const JoyMapping& mapping)
48{
49 myMap.erase(mapping);
50}
51
52// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
53void JoyMap::erase(const EventMode mode, const int button,
54 const JoyAxis axis, const JoyDir adir)
55{
56 erase(JoyMapping(mode, button, axis, adir));
57}
58
59// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
60void JoyMap::erase(const EventMode mode, const int button,
61 const int hat, const JoyHatDir hdir)
62{
63 erase(JoyMapping(mode, button, hat, hdir));
64}
65
66// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
67Event::Type JoyMap::get(const JoyMapping& mapping) const
68{
69 auto find = myMap.find(mapping);
70 if (find != myMap.end())
71 return find->second;
72
73 // try without button as modifier
74 JoyMapping m = mapping;
75
76 m.button = JOY_CTRL_NONE;
77
78 find = myMap.find(m);
79 if (find != myMap.end())
80 return find->second;
81
82 return Event::Type::NoType;
83}
84
85// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
86Event::Type JoyMap::get(const EventMode mode, const int button,
87 const JoyAxis axis, const JoyDir adir) const
88{
89 return get(JoyMapping(mode, button, axis, adir));
90}
91
92// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
93Event::Type JoyMap::get(const EventMode mode, const int button,
94 const int hat, const JoyHatDir hdir) const
95{
96 return get(JoyMapping(mode, button, hat, hdir));
97}
98
99// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100bool JoyMap::check(const JoyMapping & mapping) const
101{
102 auto find = myMap.find(mapping);
103
104 return (find != myMap.end());
105}
106
107// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
108bool JoyMap::check(const EventMode mode, const int button,
109 const JoyAxis axis, const JoyDir adir,
110 const int hat, const JoyHatDir hdir) const
111{
112 return check(JoyMapping(mode, button, axis, adir, hat, hdir));
113}
114
115// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
116string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const
117{
118 ostringstream buf;
119
120 // button description
121 if (mapping.button != JOY_CTRL_NONE)
122 buf << "/B" << mapping.button;
123
124 // axis description
125 if (mapping.axis != JoyAxis::NONE)
126 {
127 buf << "/A";
128 switch (mapping.axis)
129 {
130 case JoyAxis::X: buf << "X"; break;
131 case JoyAxis::Y: buf << "Y"; break;
132 case JoyAxis::Z: buf << "Z"; break;
133 default: buf << int(mapping.axis); break;
134 }
135
136 if (Event::isAnalog(event))
137 buf << "+|-";
138 else if (mapping.adir == JoyDir::NEG)
139 buf << "-";
140 else
141 buf << "+";
142 }
143
144 // hat description
145 if (mapping.hat != JOY_CTRL_NONE)
146 {
147 buf << "/H" << mapping.hat;
148 switch (mapping.hdir)
149 {
150 case JoyHatDir::UP: buf << "Y+"; break;
151 case JoyHatDir::DOWN: buf << "Y-"; break;
152 case JoyHatDir::LEFT: buf << "X-"; break;
153 case JoyHatDir::RIGHT: buf << "X+"; break;
154 default: break;
155 }
156 }
157
158 return buf.str();
159}
160
161// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
162string JoyMap::getEventMappingDesc(int stick, const Event::Type event, const EventMode mode) const
163{
164 ostringstream buf;
165
166 for (auto item : myMap)
167 {
168 if (item.second == event && item.first.mode == mode)
169 {
170 if (buf.str() != "")
171 buf << ", ";
172 buf << "J" << stick << getDesc(event, item.first);
173 }
174 }
175 return buf.str();
176}
177
178// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
179JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const EventMode mode) const
180{
181 JoyMappingArray map;
182
183 for (auto item : myMap)
184 if (item.second == event && item.first.mode == mode)
185 map.push_back(item.first);
186
187 return map;
188}
189
190// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
191string JoyMap::saveMapping(const EventMode mode) const
192{
193 ostringstream buf;
194
195 for (auto item : myMap)
196 {
197 if (item.first.mode == mode)
198 {
199 if (buf.str() != "")
200 buf << "|";
201 buf << item.second << ":" << item.first.button << ","
202 << int(item.first.axis) << "," << int(item.first.adir) << ","
203 << item.first.hat << "," << int(item.first.hdir);
204 }
205 }
206 return buf.str();
207}
208
209// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
210int JoyMap::loadMapping(string& list, const EventMode mode)
211{
212 // Since istringstream swallows whitespace, we have to make the
213 // delimiters be spaces
214 std::replace(list.begin(), list.end(), '|', ' ');
215 std::replace(list.begin(), list.end(), ':', ' ');
216 std::replace(list.begin(), list.end(), ',', ' ');
217 istringstream buf(list);
218 int event, button, axis, adir, hat, hdir, i = 0;
219
220 while (buf >> event && buf >> button
221 && buf >> axis && buf >> adir
222 && buf >> hat && buf >> hdir && ++i)
223 add(Event::Type(event), EventMode(mode), button, JoyAxis(axis), JoyDir(adir), hat, JoyHatDir(hdir));
224
225 return i;
226}
227
228// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
229void JoyMap::eraseMode(const EventMode mode)
230{
231 for (auto item = myMap.begin(); item != myMap.end();)
232 if (item->first.mode == mode) {
233 auto _item = item++;
234 erase(_item->first);
235 }
236 else item++;
237}
238
239// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
240void JoyMap::eraseEvent(const Event::Type event, const EventMode mode)
241{
242 for (auto item = myMap.begin(); item != myMap.end();)
243 if (item->second == event && item->first.mode == mode) {
244 auto _item = item++;
245 erase(_item->first);
246 }
247 else item++;
248}
249