Lua: Don't lua_error() out of context with pending dtors
[lsnes.git] / src / lua / input.cpp
blobd7ccd77533ffda6772857bbfa909dc856582b63f
1 #include "core/keymapper.hpp"
2 #include "lua/internal.hpp"
3 #include "core/instance.hpp"
4 #include "core/moviedata.hpp"
5 #include "core/controller.hpp"
6 #include "interface/romtype.hpp"
7 #include <iostream>
9 namespace
11 int input_set(lua::state& L, unsigned port, unsigned controller, unsigned index, short value)
13 auto& core = CORE();
14 if(!core.lua2->input_controllerdata)
15 return 0;
16 core.lua2->input_controllerdata->axis3(port, controller, index, value);
17 return 0;
20 int input_get(lua::state& L, unsigned port, unsigned controller, unsigned index)
22 auto& core = CORE();
23 if(!core.lua2->input_controllerdata)
24 return 0;
25 L.pushnumber(core.lua2->input_controllerdata->axis3(port, controller, index));
26 return 1;
29 int input_controllertype(lua::state& L, unsigned port, unsigned controller)
31 auto& core = CORE();
32 auto& m = core.mlogic->get_movie();
33 portctrl::frame f = m.read_subframe(m.get_current_frame(), 0);
34 if(port >= f.get_port_count()) {
35 L.pushnil();
36 return 1;
38 const portctrl::type& p = f.get_port_type(port);
39 if(controller >= p.controller_info->controllers.size())
40 L.pushnil();
41 else
42 L.pushlstring(p.controller_info->controllers[controller].type);
43 return 1;
46 int input_seta(lua::state& L, unsigned port, unsigned controller, uint64_t base, lua::parameters& P)
48 auto& core = CORE();
49 if(!core.lua2->input_controllerdata)
50 return 0;
51 short val;
52 if(port >= core.lua2->input_controllerdata->get_port_count())
53 return 0;
54 const portctrl::type& pt = core.lua2->input_controllerdata->get_port_type(port);
55 if(controller >= pt.controller_info->controllers.size())
56 return 0;
57 for(unsigned i = 0; i < pt.controller_info->controllers[controller].buttons.size(); i++) {
58 val = (base >> i) & 1;
59 P(P.optional(val, val));
60 core.lua2->input_controllerdata->axis3(port, controller, i, val);
62 return 0;
65 int input_geta(lua::state& L, unsigned port, unsigned controller)
67 auto& core = CORE();
68 if(!core.lua2->input_controllerdata)
69 return 0;
70 if(port >= core.lua2->input_controllerdata->get_port_count())
71 return 0;
72 const portctrl::type& pt = core.lua2->input_controllerdata->get_port_type(port);
73 if(controller >= pt.controller_info->controllers.size())
74 return 0;
75 uint64_t fret = 0;
76 for(unsigned i = 0; i < pt.controller_info->controllers[controller].buttons.size(); i++)
77 if(core.lua2->input_controllerdata->axis3(port, controller, i))
78 fret |= (1ULL << i);
79 L.pushnumber(fret);
80 for(unsigned i = 0; i < pt.controller_info->controllers[controller].buttons.size(); i++)
81 L.pushnumber(core.lua2->input_controllerdata->axis3(port, controller, i));
82 return pt.controller_info->controllers[controller].buttons.size() + 1;
85 class _keyhook_listener : public keyboard::event_listener
87 void on_key_event(keyboard::modifier_set& modifiers, keyboard::key& key, keyboard::event& event)
89 auto& core = CORE();
90 core.lua2->callback_keyhook(key.get_name(), key);
92 } S_keyhook_listener;
94 const portctrl::controller_set* lookup_ps(unsigned port)
96 auto& core = CORE();
97 auto& m = core.mlogic->get_movie();
98 portctrl::frame f = m.read_subframe(m.get_current_frame(), 0);
99 const portctrl::type& p = f.get_port_type(port);
100 return p.controller_info;
103 int set(lua::state& L, lua::parameters& P)
105 auto& core = CORE();
106 unsigned controller, index, value;
108 if(!core.lua2->input_controllerdata) return 0;
110 P(controller, index, value);
112 auto _controller = core.lua2->input_controllerdata->porttypes().legacy_pcid_to_pair(controller);
113 return input_set(L, _controller.first, _controller.second, index, value);
116 int set2(lua::state& L, lua::parameters& P)
118 unsigned port, controller, index;
119 short value;
121 P(port, controller, index, value);
123 return input_set(L, port, controller, index, value);
126 int get(lua::state& L, lua::parameters& P)
128 auto& core = CORE();
129 unsigned controller, index;
131 if(!core.lua2->input_controllerdata) return 0;
133 P(controller, index);
135 auto _controller = core.lua2->input_controllerdata->porttypes().legacy_pcid_to_pair(controller);
136 return input_get(L, _controller.first, _controller.second, index);
139 int get2(lua::state& L, lua::parameters& P)
141 unsigned port, controller, index;
143 P(port, controller, index);
145 return input_get(L, port, controller, index);
148 int seta(lua::state& L, lua::parameters& P)
150 auto& core = CORE();
151 unsigned controller;
152 uint64_t base;
154 if(!core.lua2->input_controllerdata) return 0;
156 P(controller, base);
158 auto _controller = core.lua2->input_controllerdata->porttypes().legacy_pcid_to_pair(controller);
159 return input_seta(L, _controller.first, _controller.second, base, P);
162 int seta2(lua::state& L, lua::parameters& P)
164 unsigned port, controller;
165 uint64_t base;
167 P(port, controller, base);
169 return input_seta(L, port, controller, base, P);
172 int geta(lua::state& L, lua::parameters& P)
174 auto& core = CORE();
175 unsigned controller;
177 if(!core.lua2->input_controllerdata) return 0;
179 P(controller);
181 auto _controller = core.lua2->input_controllerdata->porttypes().legacy_pcid_to_pair(controller);
182 return input_geta(L, _controller.first, _controller.second);
185 int geta2(lua::state& L, lua::parameters& P)
187 unsigned port, controller;
189 P(port, controller);
191 return input_geta(L, port, controller);
194 int controllertype(lua::state& L, lua::parameters& P)
196 auto& core = CORE();
197 unsigned controller;
199 P(controller);
201 auto& m = core.mlogic->get_movie();
202 const portctrl::type_set& s = m.read_subframe(m.get_current_frame(), 0).porttypes();
203 auto _controller = s.legacy_pcid_to_pair(controller);
204 return input_controllertype(L, _controller.first, _controller.second);
207 int controllertype2(lua::state& L, lua::parameters& P)
209 unsigned port, controller;
211 P(port, controller);
213 return input_controllertype(L, port, controller);
216 int reset(lua::state& L, lua::parameters& P)
218 auto& core = CORE();
219 long cycles;
221 if(!core.lua2->input_controllerdata) return 0;
223 P(P.optional(cycles, 0));
225 if(cycles < 0)
226 return 0;
227 short lo = cycles % 10000;
228 short hi = cycles / 10000;
229 core.lua2->input_controllerdata->axis3(0, 0, 1, 1);
230 core.lua2->input_controllerdata->axis3(0, 0, 2, hi);
231 core.lua2->input_controllerdata->axis3(0, 0, 3, lo);
232 return 0;
235 int raw(lua::state& L, lua::parameters& P)
237 auto& core = CORE();
238 L.newtable();
239 for(auto i : core.keyboard->all_keys()) {
240 L.pushlstring(i->get_name());
241 push_keygroup_parameters(L, *i);
242 L.settable(-3);
244 return 1;
247 int keyhook(lua::state& L, lua::parameters& P)
249 auto& core = CORE();
250 std::string x;
251 bool state;
253 P(x, state);
255 keyboard::key* key = core.keyboard->try_lookup_key(x);
256 if(!key)
257 throw std::runtime_error("Invalid key name");
258 bool ostate = core.lua2->hooked_keys.count(x) > 0;
259 if(ostate == state)
260 return 0;
261 if(state) {
262 core.lua2->hooked_keys.insert(x);
263 key->add_listener(S_keyhook_listener, true);
264 } else {
265 core.lua2->hooked_keys.erase(x);
266 key->remove_listener(S_keyhook_listener);
268 return 0;
271 int joyget(lua::state& L, lua::parameters& P)
273 auto& core = CORE();
274 unsigned lcid;
276 P(lcid);
278 if(!core.lua2->input_controllerdata)
279 return 0;
280 auto pcid = core.controls->lcid_to_pcid(lcid - 1);
281 if(pcid.first < 0)
282 throw std::runtime_error("Invalid controller for input.joyget");
283 L.newtable();
284 const portctrl::type& pt = core.lua2->input_controllerdata->get_port_type(pcid.first);
285 const portctrl::controller& ctrl = pt.controller_info->controllers[pcid.second];
286 unsigned lcnt = ctrl.buttons.size();
287 for(unsigned i = 0; i < lcnt; i++) {
288 if(ctrl.buttons[i].type == portctrl::button::TYPE_NULL)
289 continue;
290 L.pushlstring(ctrl.buttons[i].name);
291 if(ctrl.buttons[i].is_analog())
292 L.pushnumber(core.lua2->input_controllerdata->axis3(pcid.first, pcid.second, i));
293 else if(ctrl.buttons[i].type == portctrl::button::TYPE_BUTTON)
294 L.pushboolean(core.lua2->input_controllerdata->axis3(pcid.first, pcid.second, i) !=
296 L.settable(-3);
298 return 1;
301 int joyset(lua::state& L, lua::parameters& P)
303 auto& core = CORE();
304 unsigned lcid;
305 int ltbl;
307 P(lcid, P.table(ltbl));
309 if(!core.lua2->input_controllerdata)
310 return 0;
311 auto pcid = core.controls->lcid_to_pcid(lcid - 1);
312 if(pcid.first < 0)
313 throw std::runtime_error("Invalid controller for input.joyset");
314 const portctrl::type& pt = core.lua2->input_controllerdata->get_port_type(pcid.first);
315 const portctrl::controller& ctrl = pt.controller_info->controllers[pcid.second];
316 unsigned lcnt = ctrl.buttons.size();
317 for(unsigned i = 0; i < lcnt; i++) {
318 if(ctrl.buttons[i].type == portctrl::button::TYPE_NULL)
319 continue;
320 L.pushlstring(ctrl.buttons[i].name);
321 L.gettable(ltbl);
322 int s;
323 if(ctrl.buttons[i].is_analog()) {
324 if(L.type(-1) == LUA_TNIL)
325 s = core.lua2->input_controllerdata->axis3(pcid.first, pcid.second, i);
326 else
327 s = L.tonumber(-1);
328 } else {
329 if(L.type(-1) == LUA_TNIL)
330 s = core.lua2->input_controllerdata->axis3(pcid.first, pcid.second, i);
331 else if(L.type(-1) == LUA_TSTRING)
332 s = core.lua2->input_controllerdata->axis3(pcid.first, pcid.second, i) ^ 1;
333 else
334 s = L.toboolean(-1) ? 1 : 0;
336 core.lua2->input_controllerdata->axis3(pcid.first, pcid.second, i, s);
337 L.pop(1);
339 return 0;
342 int lcid_to_pcid(lua::state& L, lua::parameters& P)
344 auto& core = CORE();
345 unsigned lcid;
347 P(lcid);
349 auto pcid = core.controls->lcid_to_pcid(lcid - 1);
350 if(pcid.first < 0)
351 return 0;
352 int legacy_pcid = -1;
353 for(unsigned i = 0;; i++)
354 try {
355 auto p = core.controls->legacy_pcid_to_pair(i);
356 if(p.first == pcid.first && p.second == pcid.second) {
357 legacy_pcid = i;
358 break;
360 } catch(...) {
361 break;
363 if(legacy_pcid >= 0)
364 L.pushnumber(legacy_pcid);
365 else
366 L.pushboolean(false);
367 L.pushnumber(pcid.first);
368 L.pushnumber(pcid.second);
369 return 3;
372 int lcid_to_pcid2(lua::state& L, lua::parameters& P)
374 auto& core = CORE();
375 unsigned lcid;
377 P(lcid);
379 auto pcid = core.controls->lcid_to_pcid(lcid - 1);
380 if(pcid.first < 0)
381 return 0;
382 L.pushnumber(pcid.first);
383 L.pushnumber(pcid.second);
384 return 2;
387 int _port_type(lua::state& L, lua::parameters& P)
389 auto& core = CORE();
390 unsigned port;
392 P(port);
394 auto& m = core.mlogic->get_movie();
395 const portctrl::type_set& s = m.read_subframe(m.get_current_frame(), 0).porttypes();
396 try {
397 const portctrl::type& p = s.port_type(port);
398 L.pushlstring(p.name);
399 } catch(...) {
400 return 0;
402 return 1;
405 int veto_button(lua::state& L, lua::parameters& P)
407 auto& core = CORE();
408 if(core.lua2->veto_flag) *core.lua2->veto_flag = true;
409 return 0;
412 int controller_info(lua::state& L, lua::parameters& P)
414 auto& core = CORE();
415 unsigned port, controller;
417 P(port, controller);
419 const portctrl::controller_set* ps;
420 unsigned lcid = 0;
421 unsigned classnum = 1;
422 ps = lookup_ps(port);
423 if(!ps || ps->controllers.size() <= controller)
424 return 0;
425 for(unsigned i = 0; i < 8; i++) {
426 auto pcid = core.controls->lcid_to_pcid(i);
427 if(pcid.first < 0)
428 continue;
429 if(pcid.first == (int)port && pcid.second == (int)controller) {
430 lcid = i + 1;
431 break;
433 const portctrl::controller_set* ps2 = lookup_ps(pcid.first);
434 if(ps->controllers[controller].cclass == ps2->controllers[pcid.second].cclass)
435 classnum++;
437 const portctrl::controller& cs = ps->controllers[controller];
438 L.newtable();
439 L.pushstring("type");
440 L.pushlstring(cs.type);
441 L.rawset(-3);
442 L.pushstring("class");
443 L.pushlstring(cs.cclass);
444 L.rawset(-3);
445 L.pushstring("classnum");
446 L.pushnumber(classnum);
447 L.rawset(-3);
448 L.pushstring("lcid");
449 L.pushnumber(lcid);
450 L.rawset(-3);
451 L.pushstring("button_count");
452 L.pushnumber(cs.buttons.size());
453 L.rawset(-3);
454 L.pushstring("buttons");
455 L.newtable();
456 //Push the buttons.
457 for(unsigned i = 0; i < cs.buttons.size(); i++) {
458 L.pushnumber(i + 1);
459 L.newtable();
460 L.pushstring("type");
461 switch(cs.buttons[i].type) {
462 case portctrl::button::TYPE_NULL: L.pushstring("null"); break;
463 case portctrl::button::TYPE_BUTTON: L.pushstring("button"); break;
464 case portctrl::button::TYPE_AXIS: L.pushstring("axis"); break;
465 case portctrl::button::TYPE_RAXIS: L.pushstring("raxis"); break;
466 case portctrl::button::TYPE_TAXIS: L.pushstring("axis"); break;
467 case portctrl::button::TYPE_LIGHTGUN: L.pushstring("lightgun"); break;
469 L.rawset(-3);
470 if(cs.buttons[i].symbol) {
471 L.pushstring("symbol");
472 L.pushlstring(&cs.buttons[i].symbol, 1);
473 L.rawset(-3);
475 if(cs.buttons[i].macro != "") {
476 L.pushstring("macro");
477 L.pushlstring(cs.buttons[i].macro);
478 L.rawset(-3);
480 if(cs.buttons[i].is_analog()) {
481 L.pushstring("rmin");
482 L.pushnumber(cs.buttons[i].rmin);
483 L.rawset(-3);
484 L.pushstring("rmax");
485 L.pushnumber(cs.buttons[i].rmax);
486 L.rawset(-3);
488 L.pushstring("name");
489 L.pushlstring(cs.buttons[i].name);
490 L.rawset(-3);
491 L.pushstring("hidden");
492 L.pushboolean(cs.buttons[i].shadow);
493 L.rawset(-3);
494 L.rawset(-3);
496 L.rawset(-3);
497 return 1;
500 lua::functions LUA_input_fns(lua_func_misc, "input", {
501 {"set", set},
502 {"set2", set2},
503 {"get", get},
504 {"get2", get2},
505 {"seta", seta},
506 {"seta2", seta2},
507 {"geta", geta},
508 {"geta2", geta2},
509 {"controllertype", controllertype},
510 {"controllertype2", controllertype2},
511 {"reset", reset},
512 {"raw", raw},
513 {"keyhook", keyhook},
514 {"joyget", joyget},
515 {"joyset", joyset},
516 {"lcid_to_pcid", lcid_to_pcid},
517 {"lcid_to_pcid2", lcid_to_pcid2},
518 {"port_type", _port_type},
519 {"veto_button", veto_button},
520 {"controller_info", controller_info},