2 #include <snes/snes.hpp>
3 #include <ui-libsnes/libsnes.hpp>
5 #include "core/controllerdata.hpp"
14 inline unsigned ccindex(unsigned port
, unsigned controller
, unsigned control
) throw(std::logic_error
)
16 if(port
>= MAX_PORTS
|| controller
>= MAX_CONTROLLERS_PER_PORT
|| control
>= CONTROLLER_CONTROLS
) {
18 x
<< "ccindex: Invalid (port, controller, control) tuple (" << port
<< "," << controller
19 << "," << control
<< ")";
20 throw std::logic_error(x
.str());
22 return MAX_SYSTEM_CONTROLS
+ port
* CONTROLLER_CONTROLS
* MAX_CONTROLLERS_PER_PORT
+
23 CONTROLLER_CONTROLS
* controller
+ control
;
26 bool parse_button_ctrl(const std::string
& str
, size_t& pos
) throw()
28 if(pos
>= str
.length())
43 short parse_number_ctrl(const std::string
& str
, size_t& pos
) throw()
47 while(pos
< str
.length()) {
49 if(ch
!= ' ' && ch
!= '\t')
53 //Read the sign if any.
54 if(pos
>= str
.length() || (ch
= str
[pos
]) == '|')
56 bool negative
= false;
66 while(pos
< str
.length() && isdigit(static_cast<unsigned char>(ch
= str
[pos
]))) {
67 numval
= numval
* 10 + (ch
- '0');
73 return static_cast<short>(numval
);
76 void parse_end_of_field(const std::string
& str
, size_t& pos
) throw()
78 while(pos
< str
.length() && str
[pos
] != '|')
83 size_t cdecode::system(const std::string
& line
, size_t pos
, short* controls
, unsigned version
) throw(std::bad_alloc
,
86 controls
[0] = parse_button_ctrl(line
, pos
); //Frame sync.
87 controls
[1] = parse_button_ctrl(line
, pos
); //Reset.
88 controls
[2] = parse_number_ctrl(line
, pos
); //Reset cycles hi.
89 controls
[3] = parse_number_ctrl(line
, pos
); //Reset cycles lo.
90 parse_end_of_field(line
, pos
);
94 size_t cdecode::none(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
100 size_t cdecode::gamepad(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
103 for(unsigned i
= 0; i
< 12; i
++)
104 controls
[ccindex(port
, 0, i
)] = parse_button_ctrl(line
, pos
);
105 parse_end_of_field(line
, pos
);
109 size_t cdecode::multitap(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
112 for(unsigned j
= 0; j
< 4; j
++) {
113 for(unsigned i
= 0; i
< 12; i
++)
114 controls
[ccindex(port
, j
, i
)] = parse_button_ctrl(line
, pos
);
115 parse_end_of_field(line
, pos
);
121 size_t cdecode::mouse(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
124 controls
[ccindex(port
, 0, 2)] = parse_button_ctrl(line
, pos
);
125 controls
[ccindex(port
, 0, 3)] = parse_button_ctrl(line
, pos
);
126 controls
[ccindex(port
, 0, 0)] = parse_number_ctrl(line
, pos
);
127 controls
[ccindex(port
, 0, 1)] = parse_number_ctrl(line
, pos
);
128 parse_end_of_field(line
, pos
);
132 size_t cdecode::superscope(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
135 controls
[ccindex(port
, 0, 2)] = parse_button_ctrl(line
, pos
);
136 controls
[ccindex(port
, 0, 3)] = parse_button_ctrl(line
, pos
);
137 controls
[ccindex(port
, 0, 4)] = parse_button_ctrl(line
, pos
);
138 controls
[ccindex(port
, 0, 5)] = parse_button_ctrl(line
, pos
);
139 controls
[ccindex(port
, 0, 0)] = parse_number_ctrl(line
, pos
);
140 controls
[ccindex(port
, 0, 1)] = parse_number_ctrl(line
, pos
);
141 parse_end_of_field(line
, pos
);
145 size_t cdecode::justifier(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
148 controls
[ccindex(port
, 0, 2)] = parse_button_ctrl(line
, pos
);
149 controls
[ccindex(port
, 0, 3)] = parse_button_ctrl(line
, pos
);
150 controls
[ccindex(port
, 0, 0)] = parse_number_ctrl(line
, pos
);
151 controls
[ccindex(port
, 0, 1)] = parse_number_ctrl(line
, pos
);
152 parse_end_of_field(line
, pos
);
156 size_t cdecode::justifiers(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
159 for(unsigned i
= 0; i
< 2; i
++) {
160 controls
[ccindex(port
, i
, 2)] = parse_button_ctrl(line
, pos
);
161 controls
[ccindex(port
, i
, 3)] = parse_button_ctrl(line
, pos
);
162 controls
[ccindex(port
, i
, 0)] = parse_number_ctrl(line
, pos
);
163 controls
[ccindex(port
, i
, 1)] = parse_number_ctrl(line
, pos
);
164 parse_end_of_field(line
, pos
);
170 size_t cencode::system(char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
172 buffer
[bufferpos
++] = controls
[0] ? 'F' : '.';
173 buffer
[bufferpos
++] = controls
[1] ? 'R' : '.';
174 if(controls
[2] || controls
[3]) {
175 bufferpos
+= sprintf(buffer
+ bufferpos
, " %i %i", static_cast<int>(controls
[2]),
176 static_cast<int>(controls
[3]));
181 size_t cencode::none(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
183 return ENCODE_SPECIAL_NO_OUTPUT
;
186 size_t cencode::gamepad(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
188 static const char* characters
= "BYsSudlrAXLR";
189 for(unsigned i
= 0; i
< 12; i
++)
190 buffer
[bufferpos
++] = controls
[ccindex(port
, 0, i
)] ? characters
[i
] : '.';
194 size_t cencode::multitap(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
196 static const char* characters
= "BYsSudlrAXLR";
197 for(unsigned j
= 0; j
< 4; j
++) {
198 for(unsigned i
= 0; i
< 12; i
++)
199 buffer
[bufferpos
++] = controls
[ccindex(port
, j
, i
)] ? characters
[i
] : '.';
200 buffer
[bufferpos
++] = '|';
202 bufferpos
--; //Eat the last '|', it shouldn't be there.
206 size_t cencode::mouse(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
208 bufferpos
+= sprintf(buffer
+ bufferpos
, "%c%c %i %i", controls
[ccindex(port
, 0, 2)] ? 'L' : '.',
209 controls
[ccindex(port
, 0, 3)] ? 'R' : '.', static_cast<int>(controls
[ccindex(port
, 0, 0)]),
210 static_cast<int>(controls
[ccindex(port
, 0, 1)]));
214 size_t cencode::superscope(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
216 bufferpos
+= sprintf(buffer
+ bufferpos
, "%c%c%c%c %i %i", controls
[ccindex(port
, 0, 2)] ? 'T' : '.',
217 controls
[ccindex(port
, 0, 3)] ? 'C' : '.', controls
[ccindex(port
, 0, 4)] ? 'U' : '.',
218 controls
[ccindex(port
, 0, 5)] ? 'P' : '.', static_cast<int>(controls
[ccindex(port
, 0, 0)]),
219 static_cast<int>(controls
[ccindex(port
, 0, 1)]));
223 size_t cencode::justifier(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
225 bufferpos
+= sprintf(buffer
+ bufferpos
, "%c%c %i %i", controls
[ccindex(port
, 0, 2)] ? 'T' : '.',
226 controls
[ccindex(port
, 0, 3)] ? 'S' : '.', static_cast<int>(controls
[ccindex(port
, 0, 0)]),
227 static_cast<int>(controls
[ccindex(port
, 0, 1)]));
231 size_t cencode::justifiers(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
233 bufferpos
+= sprintf(buffer
+ bufferpos
, "%c%c %i %i", controls
[ccindex(port
, 0, 2)] ? 'T' : '.',
234 controls
[ccindex(port
, 0, 3)] ? 'S' : '.', static_cast<int>(controls
[ccindex(port
, 0, 0)]),
235 static_cast<int>(controls
[ccindex(port
, 0, 1)]));
236 buffer
[bufferpos
++] = '|';
237 bufferpos
+= sprintf(buffer
+ bufferpos
, "%c%c %i %i", controls
[ccindex(port
, 0, 2)] ? 'T' : '.',
238 controls
[ccindex(port
, 0, 3)] ? 'S' : '.', static_cast<int>(controls
[ccindex(port
, 0, 0)]),
239 static_cast<int>(controls
[ccindex(port
, 0, 1)]));
244 unsigned ccindex2(unsigned port
, unsigned controller
, unsigned control
) throw(std::logic_error
)
246 return ccindex(port
, controller
, control
);
250 controls_t
controls_t::operator^(controls_t other
) throw()
253 for(size_t i
= 0; i
< TOTAL_CONTROLS
; i
++)
254 x
.controls
[i
] = controls
[i
] ^ ((i
< MAX_SYSTEM_CONTROLS
) ? 0 : other
.controls
[i
]);
258 controls_t::controls_t(bool sync
) throw()
260 memset(controls
, 0, sizeof(controls
));
262 controls
[CONTROL_FRAME_SYNC
] = 1;
265 const short& controls_t::operator()(unsigned port
, unsigned controller
, unsigned control
) const throw(std::logic_error
)
267 return controls
[ccindex(port
, controller
, control
)];
270 const short& controls_t::operator()(unsigned control
) const throw(std::logic_error
)
272 if(control
>= TOTAL_CONTROLS
)
273 throw std::logic_error("controls_t::operator(): Invalid control index");
274 return controls
[control
];
277 short& controls_t::operator()(unsigned port
, unsigned controller
, unsigned control
) throw(std::logic_error
)
279 return controls
[ccindex(port
, controller
, control
)];
282 short& controls_t::operator()(unsigned control
) throw(std::logic_error
)
284 if(control
>= TOTAL_CONTROLS
)
285 throw std::logic_error("controls_t::operator(): Invalid control index");
286 return controls
[control
];
289 controls_t::controls_t(const std::string
& line
, const std::vector
<cdecode::fn_t
>& decoders
, unsigned version
)
290 throw(std::bad_alloc
, std::runtime_error
)
292 memset(controls
, 0, sizeof(controls
));
294 position
= cdecode::system(line
, position
, controls
, version
);
295 for(unsigned i
= 0; i
< decoders
.size(); i
++) {
296 if(position
< line
.length() && line
[position
] == '|')
298 position
= decoders
[i
](i
, line
, position
, controls
);
302 std::string
controls_t::tostring(const std::vector
<cencode::fn_t
>& encoders
) const throw(std::bad_alloc
)
305 size_t linelen
= 0, tmp
;
306 tmp
= cencode::system(buffer
, linelen
, controls
);
307 for(unsigned i
= 0; i
< encoders
.size(); i
++) {
308 if(tmp
!= ENCODE_SPECIAL_NO_OUTPUT
)
309 buffer
[(linelen
= tmp
)++] = '|';
310 tmp
= encoders
[i
](i
, buffer
, linelen
, controls
);
312 if(tmp
!= ENCODE_SPECIAL_NO_OUTPUT
)
314 return std::string(buffer
, buffer
+ linelen
);
317 bool controls_t::operator==(const controls_t
& c
) const throw()
319 for(size_t i
= 0; i
< TOTAL_CONTROLS
; i
++)
320 if(controls
[i
] != c
.controls
[i
])
326 const port_type
& port_type::lookup(const std::string
& name
, bool port2
) throw(std::bad_alloc
,
329 for(unsigned i
= 0; i
<= PT_LAST_CTYPE
; i
++) {
330 if(name
!= port_types
[i
].name
)
332 if(!port2
&& !port_types
[i
].valid_port1
)
333 throw std::runtime_error("Can't connect " + name
+ " to port #1");
334 return port_types
[i
];
336 throw std::runtime_error("Unknown port type '" + name
+ "'");
339 port_type port_types
[] = {
340 { "none", cdecode::none
, cencode::none
, PT_NONE
, 0, DT_NONE
, true, SNES_DEVICE_NONE
},
341 { "gamepad", cdecode::gamepad
, cencode::gamepad
, PT_GAMEPAD
, 1, DT_GAMEPAD
, true, SNES_DEVICE_JOYPAD
},
342 { "multitap", cdecode::multitap
, cencode::multitap
, PT_MULTITAP
, 4, DT_GAMEPAD
, true, SNES_DEVICE_MULTITAP
},
343 { "mouse", cdecode::mouse
, cencode::mouse
, PT_MOUSE
, 1, DT_MOUSE
, true, SNES_DEVICE_MOUSE
},
344 { "superscope", cdecode::superscope
, cencode::superscope
, PT_SUPERSCOPE
, 1, DT_SUPERSCOPE
, false,
345 SNES_DEVICE_SUPER_SCOPE
},
346 { "justifier", cdecode::justifier
, cencode::justifier
, PT_JUSTIFIER
, 1, DT_JUSTIFIER
, false,
347 SNES_DEVICE_JUSTIFIER
},
348 { "justifiers", cdecode::justifiers
, cencode::justifiers
, PT_JUSTIFIERS
, 2, DT_JUSTIFIER
, false,
349 SNES_DEVICE_JUSTIFIERS
}