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