1 #include "../ui-base.hpp"
2
3 #include "controller.cpp"
4 #include "userinterface-general.cpp"
5 #include "userinterface-system.cpp"
6 #include "userinterface-emulationspeed.cpp"
7 #include "userinterface-states.cpp"
8 #include "userinterface-videosettings.cpp"
9
bind()10 void MappedInput::bind() {
11 lstring part;
12 part.split("+", name);
13
14 modifier = InputModifier::None;
15 for(unsigned i = 0; i < part.size(); i++) {
16 if(part[i] == "Shift") modifier |= InputModifier::Shift;
17 if(part[i] == "Control") modifier |= InputModifier::Control;
18 if(part[i] == "Alt") modifier |= InputModifier::Alt;
19 if(part[i] == "Super") modifier |= InputModifier::Super;
20 }
21
22 string temp = part[part.size() - 1];
23 part.split(".", temp);
24 scancode = Scancode::decode(part[0]);
25 specifier = InputSpecifier::None;
26 if(part[1] == "Up") specifier = InputSpecifier::Up;
27 if(part[1] == "Down") specifier = InputSpecifier::Down;
28 if(part[1] == "Left") specifier = InputSpecifier::Left;
29 if(part[1] == "Right") specifier = InputSpecifier::Right;
30 if(part[1] == "Lo") specifier = InputSpecifier::Lo;
31 if(part[1] == "Hi") specifier = InputSpecifier::Hi;
32 if(part[1] == "Trigger") specifier = InputSpecifier::Trigger;
33
34 //bypass modifier matching if scancode is itself a modifier
35 modifierOverride = Keyboard::isAnyModifier(scancode);
36
37 //re-encode name, in case previous name was invalid
38 name = "";
39 if(modifier & InputModifier::Shift) name << "Shift+";
40 if(modifier & InputModifier::Control) name << "Control+";
41 if(modifier & InputModifier::Alt) name << "Alt+";
42 if(modifier & InputModifier::Super) name << "Super+";
43 name << Scancode::encode(scancode);
44 if(specifier == InputSpecifier::Up) name << ".Up";
45 if(specifier == InputSpecifier::Down) name << ".Down";
46 if(specifier == InputSpecifier::Left) name << ".Left";
47 if(specifier == InputSpecifier::Right) name << ".Right";
48 if(specifier == InputSpecifier::Lo) name << ".Lo";
49 if(specifier == InputSpecifier::Hi) name << ".Hi";
50 if(specifier == InputSpecifier::Trigger) name << ".Trigger";
51 }
52
cache()53 void MappedInput::cache() {
54 cachedState = state;
55 }
56
MappedInput(const char * label_,const char * configName)57 MappedInput::MappedInput(const char *label_, const char *configName) : parent(0), label(label_) {
58 specifier = InputSpecifier::None;
59 modifierOverride = false;
60 state = 0;
61 previousState = 0;
62 cachedState = 0;
63 config().attach(name = "None", configName);
64 }
65
66 //
67
poll()68 void DigitalInput::poll() {
69 previousState = state;
70 if(modifier == mapper().modifier || modifierOverride) {
71 if(specifier == InputSpecifier::None) {
72 state = mapper().state(scancode);
73 } else if(specifier == InputSpecifier::Up) {
74 state = (bool)(mapper().state(scancode) & Joypad::HatUp);
75 } else if(specifier == InputSpecifier::Down) {
76 state = (bool)(mapper().state(scancode) & Joypad::HatDown);
77 } else if(specifier == InputSpecifier::Left) {
78 state = (bool)(mapper().state(scancode) & Joypad::HatLeft);
79 } else if(specifier == InputSpecifier::Right) {
80 state = (bool)(mapper().state(scancode) & Joypad::HatRight);
81 } else if(specifier == InputSpecifier::Lo) {
82 state = mapper().state(scancode) < -16384;
83 } else if(specifier == InputSpecifier::Hi) {
84 state = mapper().state(scancode) > +16384;
85 } else if(specifier == InputSpecifier::Trigger) {
86 state = mapper().state(scancode) < 0;
87 }
88 } else {
89 state = 0;
90 }
91 }
92
isPressed() const93 bool DigitalInput::isPressed() const { return state; }
wasPressed() const94 bool DigitalInput::wasPressed() const { return previousState; }
95
DigitalInput(const char * label,const char * configName)96 DigitalInput::DigitalInput(const char *label, const char *configName) : MappedInput(label, configName) {
97 }
98
99 //
100
poll()101 void AnalogInput::poll() {
102 previousState = state;
103 if(Mouse::isAnyAxis(scancode)) {
104 if(input.acquired()) {
105 state = mapper().state(scancode);
106 } else {
107 state = 0;
108 }
109 } else if(Joypad::isAnyAxis(scancode)) {
110 state = mapper().state(scancode) / 8192;
111 }
112 }
113
AnalogInput(const char * label,const char * configName)114 AnalogInput::AnalogInput(const char *label, const char *configName) : MappedInput(label, configName) {
115 }
116
117 //
118
poll()119 void HotkeyInput::poll() {
120 DigitalInput::poll();
121 if(mainWindow->isActive() && state != previousState) {
122 state ? pressed() : released();
123 }
124 }
125
HotkeyInput(const char * label,const char * configName)126 HotkeyInput::HotkeyInput(const char *label, const char *configName) : DigitalInput(label, configName) {
127 }
128
129 //
130
attach(MappedInput * input)131 void InputGroup::attach(MappedInput *input) {
132 input->parent = this;
133 add(input);
134 }
135
bind()136 void InputGroup::bind() {
137 for(unsigned i = 0; i < size(); i++) {
138 (*this)[i]->bind();
139 }
140 }
141
poll()142 void InputGroup::poll() {
143 for(unsigned i = 0; i < size(); i++) {
144 (*this)[i]->poll();
145 }
146 }
147
cache()148 void InputGroup::cache() {
149 for(unsigned i = 0; i < size(); i++) {
150 (*this)[i]->cache();
151 }
152 }
153
flushCache()154 void InputGroup::flushCache() {
155 for(unsigned i = 0; i < size(); i++) {
156 MappedInput &input = *((*this)[i]);
157 input.cachedState = 0;
158 }
159 }
160
InputGroup(unsigned category_,const char * label_)161 InputGroup::InputGroup(unsigned category_, const char *label_) : category(category_), label(label_) {
162 mapper().add(this);
163 }
164
165 //
166
mapper()167 InputMapper& mapper() {
168 static InputMapper mapper;
169 return mapper;
170 }
171
calibrate()172 void InputMapper::calibrate() {
173 calibrated = true;
174 audio.clear();
175 QMessageBox::information(settingsWindow, "Joypad Calibration",
176 "Joypads must be calibrated prior to mapping. Please ensure that "
177 "all axes and analog buttons are not pressed or moved in any specific "
178 "direction, and then press ok."
179 );
180
181 poll();
182 for(unsigned i = 0; i < Joypad::Count; i++) {
183 for(unsigned axis = 0; axis < Joypad::Axes; axis++) {
184 int16_t n = state(joypad(i).axis(axis));
185 isTrigger[i][axis] = n < -16384 || n > +16384;
186 }
187 }
188 }
189
bind()190 void InputMapper::bind() {
191 for(unsigned i = 0; i < size(); i++) {
192 (*this)[i]->bind();
193 }
194 }
195
poll()196 void InputMapper::poll() {
197 activeState = !activeState;
198 input.poll(stateTable[activeState]);
199
200 modifier = 0;
201 for(unsigned i = 0; i < Keyboard::Count; i++) {
202 if(state(keyboard(i)[Keyboard::Shift])) modifier |= InputModifier::Shift;
203 if(state(keyboard(i)[Keyboard::Control])) modifier |= InputModifier::Control;
204 if(state(keyboard(i)[Keyboard::Alt])) modifier |= InputModifier::Alt;
205 if(state(keyboard(i)[Keyboard::Super])) modifier |= InputModifier::Super;
206 }
207
208 for(unsigned i = 0; i < size(); i++) {
209 (*this)[i]->poll();
210 }
211
212 for(unsigned i = 0; i < Scancode::Limit; i++) {
213 if(state(i) != previousState(i)) {
214 utility.inputEvent(i);
215 diskBrowser->inputEvent(i);
216 inputSettingsWindow->inputEvent(i);
217 }
218 }
219 }
220
cache()221 void InputMapper::cache() {
222 if(config().input.focusPolicy == Configuration::Input::FocusPolicyIgnoreInput && !mainWindow->isActive()) {
223 for(unsigned i = 0; i < size(); i++) {
224 InputGroup &group = *((*this)[i]);
225 group.flushCache();
226 }
227 } else {
228 for(unsigned i = 0; i < size(); i++) {
229 InputGroup &group = *((*this)[i]);
230 if(group.category == InputCategory::Port1 || group.category == InputCategory::Port2) {
231 group.cache();
232 }
233 }
234 }
235 }
236
status(bool port,unsigned device,unsigned index,unsigned id)237 int16_t InputMapper::status(bool port, unsigned device, unsigned index, unsigned id) {
238 int16_t result = 0;
239
240 if(port == InputCategory::Port1 && port1) result = port1->status(index, id);
241 if(port == InputCategory::Port2 && port2) result = port2->status(index, id);
242
243 if(movie.state == Movie::Playback) {
244 result = movie.read();
245 } else if(movie.state == Movie::Record) {
246 movie.write(result);
247 }
248
249 return result;
250 }
251
modifierString() const252 string InputMapper::modifierString() const {
253 string name;
254 if(modifier & InputModifier::Shift) name << "Shift+";
255 if(modifier & InputModifier::Control) name << "Control+";
256 if(modifier & InputModifier::Alt) name << "Alt+";
257 if(modifier & InputModifier::Super) name << "Super+";
258 return name;
259 }
260
state(uint16_t scancode) const261 int16_t InputMapper::state(uint16_t scancode) const { return stateTable[activeState][scancode]; }
previousState(uint16_t scancode) const262 int16_t InputMapper::previousState(uint16_t scancode) const { return stateTable[!activeState][scancode]; }
distance(uint16_t scancode) const263 unsigned InputMapper::distance(uint16_t scancode) const { return abs(state(scancode) - previousState(scancode)); }
264
InputMapper()265 InputMapper::InputMapper() : port1(0), port2(0) {
266 calibrated = false;
267 for(unsigned i = 0; i < Joypad::Count; i++) {
268 for(unsigned axis = 0; axis < Joypad::Axes; axis++) {
269 isTrigger[i][axis] = false;
270 }
271 }
272
273 activeState = 0;
274 for(unsigned i = 0; i < Scancode::Limit; i++) {
275 stateTable[0][i] = stateTable[1][i] = 0;
276 }
277 }
278