2 #include "controllerdata.hpp"
7 #include <snes/snes.hpp>
8 #include <ui-libsnes/libsnes.hpp>
12 inline unsigned ccindex(unsigned port
, unsigned controller
, unsigned control
) throw(std::logic_error
)
14 if(port
>= MAX_PORTS
|| controller
>= MAX_CONTROLLERS_PER_PORT
|| control
>= CONTROLLER_CONTROLS
) {
16 x
<< "ccindex: Invalid (port, controller, control) tuple (" << port
<< "," << controller
17 << "," << control
<< ")";
18 throw std::logic_error(x
.str());
20 return MAX_SYSTEM_CONTROLS
+ port
* CONTROLLER_CONTROLS
* MAX_CONTROLLERS_PER_PORT
+
21 CONTROLLER_CONTROLS
* controller
+ control
;
24 bool parse_button_ctrl(const std::string
& str
, size_t& pos
) throw()
26 if(pos
>= str
.length())
41 short parse_number_ctrl(const std::string
& str
, size_t& pos
) throw()
45 while(pos
< str
.length()) {
47 if(ch
!= ' ' && ch
!= '\t')
51 //Read the sign if any.
52 if(pos
>= str
.length() || (ch
= str
[pos
]) == '|')
54 bool negative
= false;
64 while(pos
< str
.length() && isdigit(static_cast<unsigned char>(ch
= str
[pos
]))) {
65 numval
= numval
* 10 + (ch
- '0');
71 return static_cast<short>(numval
);
74 void parse_end_of_field(const std::string
& str
, size_t& pos
) throw()
76 while(pos
< str
.length() && str
[pos
] != '|')
81 size_t cdecode::system(const std::string
& line
, size_t pos
, short* controls
, unsigned version
) throw(std::bad_alloc
,
84 controls
[0] = parse_button_ctrl(line
, pos
); //Frame sync.
85 controls
[1] = parse_button_ctrl(line
, pos
); //Reset.
86 controls
[2] = parse_number_ctrl(line
, pos
); //Reset cycles hi.
87 controls
[3] = parse_number_ctrl(line
, pos
); //Reset cycles lo.
88 parse_end_of_field(line
, pos
);
92 size_t cdecode::none(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
98 size_t cdecode::gamepad(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
101 for(unsigned i
= 0; i
< 12; i
++)
102 controls
[ccindex(port
, 0, i
)] = parse_button_ctrl(line
, pos
);
103 parse_end_of_field(line
, pos
);
107 size_t cdecode::multitap(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
110 for(unsigned j
= 0; j
< 4; j
++) {
111 for(unsigned i
= 0; i
< 12; i
++)
112 controls
[ccindex(port
, j
, i
)] = parse_button_ctrl(line
, pos
);
113 parse_end_of_field(line
, pos
);
119 size_t cdecode::mouse(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
122 controls
[ccindex(port
, 0, 2)] = parse_button_ctrl(line
, pos
);
123 controls
[ccindex(port
, 0, 3)] = parse_button_ctrl(line
, pos
);
124 controls
[ccindex(port
, 0, 0)] = parse_number_ctrl(line
, pos
);
125 controls
[ccindex(port
, 0, 1)] = parse_number_ctrl(line
, pos
);
126 parse_end_of_field(line
, pos
);
130 size_t cdecode::superscope(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
133 controls
[ccindex(port
, 0, 2)] = parse_button_ctrl(line
, pos
);
134 controls
[ccindex(port
, 0, 3)] = parse_button_ctrl(line
, pos
);
135 controls
[ccindex(port
, 0, 4)] = parse_button_ctrl(line
, pos
);
136 controls
[ccindex(port
, 0, 5)] = parse_button_ctrl(line
, pos
);
137 controls
[ccindex(port
, 0, 0)] = parse_number_ctrl(line
, pos
);
138 controls
[ccindex(port
, 0, 1)] = parse_number_ctrl(line
, pos
);
139 parse_end_of_field(line
, pos
);
143 size_t cdecode::justifier(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
146 controls
[ccindex(port
, 0, 2)] = parse_button_ctrl(line
, pos
);
147 controls
[ccindex(port
, 0, 3)] = parse_button_ctrl(line
, pos
);
148 controls
[ccindex(port
, 0, 0)] = parse_number_ctrl(line
, pos
);
149 controls
[ccindex(port
, 0, 1)] = parse_number_ctrl(line
, pos
);
150 parse_end_of_field(line
, pos
);
154 size_t cdecode::justifiers(unsigned port
, const std::string
& line
, size_t pos
, short* controls
) throw(std::bad_alloc
,
157 for(unsigned i
= 0; i
< 2; i
++) {
158 controls
[ccindex(port
, i
, 2)] = parse_button_ctrl(line
, pos
);
159 controls
[ccindex(port
, i
, 3)] = parse_button_ctrl(line
, pos
);
160 controls
[ccindex(port
, i
, 0)] = parse_number_ctrl(line
, pos
);
161 controls
[ccindex(port
, i
, 1)] = parse_number_ctrl(line
, pos
);
162 parse_end_of_field(line
, pos
);
168 size_t cencode::system(char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
170 buffer
[bufferpos
++] = controls
[0] ? 'F' : '.';
171 buffer
[bufferpos
++] = controls
[1] ? 'R' : '.';
172 if(controls
[2] || controls
[3]) {
173 bufferpos
+= sprintf(buffer
+ bufferpos
, " %i %i", static_cast<int>(controls
[2]),
174 static_cast<int>(controls
[3]));
179 size_t cencode::none(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
181 return ENCODE_SPECIAL_NO_OUTPUT
;
184 size_t cencode::gamepad(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
186 static const char* characters
= "BYsSudlrAXLR";
187 for(unsigned i
= 0; i
< 12; i
++)
188 buffer
[bufferpos
++] = controls
[ccindex(port
, 0, i
)] ? characters
[i
] : '.';
192 size_t cencode::multitap(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
194 static const char* characters
= "BYsSudlrAXLR";
195 for(unsigned j
= 0; j
< 4; j
++) {
196 for(unsigned i
= 0; i
< 12; i
++)
197 buffer
[bufferpos
++] = controls
[ccindex(port
, j
, i
)] ? characters
[i
] : '.';
198 buffer
[bufferpos
++] = '|';
200 bufferpos
--; //Eat the last '|', it shouldn't be there.
204 size_t cencode::mouse(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
206 bufferpos
+= sprintf(buffer
+ bufferpos
, "%c%c %i %i", controls
[ccindex(port
, 0, 2)] ? 'L' : '.',
207 controls
[ccindex(port
, 0, 3)] ? 'R' : '.', static_cast<int>(controls
[ccindex(port
, 0, 0)]),
208 static_cast<int>(controls
[ccindex(port
, 0, 1)]));
212 size_t cencode::superscope(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
214 bufferpos
+= sprintf(buffer
+ bufferpos
, "%c%c%c%c %i %i", controls
[ccindex(port
, 0, 2)] ? 'T' : '.',
215 controls
[ccindex(port
, 0, 3)] ? 'C' : '.', controls
[ccindex(port
, 0, 4)] ? 'U' : '.',
216 controls
[ccindex(port
, 0, 5)] ? 'P' : '.', static_cast<int>(controls
[ccindex(port
, 0, 0)]),
217 static_cast<int>(controls
[ccindex(port
, 0, 1)]));
221 size_t cencode::justifier(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
223 bufferpos
+= sprintf(buffer
+ bufferpos
, "%c%c %i %i", controls
[ccindex(port
, 0, 2)] ? 'T' : '.',
224 controls
[ccindex(port
, 0, 3)] ? 'S' : '.', static_cast<int>(controls
[ccindex(port
, 0, 0)]),
225 static_cast<int>(controls
[ccindex(port
, 0, 1)]));
229 size_t cencode::justifiers(unsigned port
, char* buffer
, size_t bufferpos
, const short* controls
) throw(std::bad_alloc
)
231 bufferpos
+= sprintf(buffer
+ bufferpos
, "%c%c %i %i", controls
[ccindex(port
, 0, 2)] ? 'T' : '.',
232 controls
[ccindex(port
, 0, 3)] ? 'S' : '.', static_cast<int>(controls
[ccindex(port
, 0, 0)]),
233 static_cast<int>(controls
[ccindex(port
, 0, 1)]));
234 buffer
[bufferpos
++] = '|';
235 bufferpos
+= sprintf(buffer
+ bufferpos
, "%c%c %i %i", controls
[ccindex(port
, 0, 2)] ? 'T' : '.',
236 controls
[ccindex(port
, 0, 3)] ? 'S' : '.', static_cast<int>(controls
[ccindex(port
, 0, 0)]),
237 static_cast<int>(controls
[ccindex(port
, 0, 1)]));
242 unsigned ccindex2(unsigned port
, unsigned controller
, unsigned control
) throw(std::logic_error
)
244 return ccindex(port
, controller
, control
);
248 controls_t
controls_t::operator^(controls_t other
) throw()
251 for(size_t i
= 0; i
< TOTAL_CONTROLS
; i
++)
252 x
.controls
[i
] = controls
[i
] ^ ((i
< MAX_SYSTEM_CONTROLS
) ? 0 : other
.controls
[i
]);
256 controls_t::controls_t(bool sync
) throw()
258 memset(controls
, 0, sizeof(controls
));
260 controls
[CONTROL_FRAME_SYNC
] = 1;
263 const short& controls_t::operator()(unsigned port
, unsigned controller
, unsigned control
) const throw(std::logic_error
)
265 return controls
[ccindex(port
, controller
, control
)];
268 const short& controls_t::operator()(unsigned control
) const throw(std::logic_error
)
270 if(control
>= TOTAL_CONTROLS
)
271 throw std::logic_error("controls_t::operator(): Invalid control index");
272 return controls
[control
];
275 short& controls_t::operator()(unsigned port
, unsigned controller
, unsigned control
) throw(std::logic_error
)
277 return controls
[ccindex(port
, controller
, control
)];
280 short& controls_t::operator()(unsigned control
) throw(std::logic_error
)
282 if(control
>= TOTAL_CONTROLS
)
283 throw std::logic_error("controls_t::operator(): Invalid control index");
284 return controls
[control
];
287 controls_t::controls_t(const std::string
& line
, const std::vector
<cdecode::fn_t
>& decoders
, unsigned version
)
288 throw(std::bad_alloc
, std::runtime_error
)
290 memset(controls
, 0, sizeof(controls
));
292 position
= cdecode::system(line
, position
, controls
, version
);
293 for(unsigned i
= 0; i
< decoders
.size(); i
++) {
294 if(position
< line
.length() && line
[position
] == '|')
296 position
= decoders
[i
](i
, line
, position
, controls
);
300 std::string
controls_t::tostring(const std::vector
<cencode::fn_t
>& encoders
) const throw(std::bad_alloc
)
303 size_t linelen
= 0, tmp
;
304 tmp
= cencode::system(buffer
, linelen
, controls
);
305 for(unsigned i
= 0; i
< encoders
.size(); i
++) {
306 if(tmp
!= ENCODE_SPECIAL_NO_OUTPUT
)
307 buffer
[(linelen
= tmp
)++] = '|';
308 tmp
= encoders
[i
](i
, buffer
, linelen
, controls
);
310 if(tmp
!= ENCODE_SPECIAL_NO_OUTPUT
)
312 return std::string(buffer
, buffer
+ linelen
);
315 bool controls_t::operator==(const controls_t
& c
) const throw()
317 for(size_t i
= 0; i
< TOTAL_CONTROLS
; i
++)
318 if(controls
[i
] != c
.controls
[i
])
324 const port_type
& port_type::lookup(const std::string
& name
, bool port2
) throw(std::bad_alloc
,
327 for(unsigned i
= 0; i
<= PT_LAST_CTYPE
; i
++) {
328 if(name
!= port_types
[i
].name
)
330 if(!port2
&& !port_types
[i
].valid_port1
)
331 throw std::runtime_error("Can't connect " + name
+ " to port #1");
332 return port_types
[i
];
334 throw std::runtime_error("Unknown port type '" + name
+ "'");
337 port_type port_types
[] = {
338 { "none", cdecode::none
, cencode::none
, PT_NONE
, 0, DT_NONE
, true, SNES_DEVICE_NONE
},
339 { "gamepad", cdecode::gamepad
, cencode::gamepad
, PT_GAMEPAD
, 1, DT_GAMEPAD
, true, SNES_DEVICE_JOYPAD
},
340 { "multitap", cdecode::multitap
, cencode::multitap
, PT_MULTITAP
, 4, DT_GAMEPAD
, true, SNES_DEVICE_MULTITAP
},
341 { "mouse", cdecode::mouse
, cencode::mouse
, PT_MOUSE
, 1, DT_MOUSE
, true, SNES_DEVICE_MOUSE
},
342 { "superscope", cdecode::superscope
, cencode::superscope
, PT_SUPERSCOPE
, 1, DT_SUPERSCOPE
, false,
343 SNES_DEVICE_SUPER_SCOPE
},
344 { "justifier", cdecode::justifier
, cencode::justifier
, PT_JUSTIFIER
, 1, DT_JUSTIFIER
, false,
345 SNES_DEVICE_JUSTIFIER
},
346 { "justifiers", cdecode::justifiers
, cencode::justifiers
, PT_JUSTIFIERS
, 2, DT_JUSTIFIER
, false,
347 SNES_DEVICE_JUSTIFIERS
}