Report port internal names not hnames to Lua
[lsnes.git] / src / lua / input.cpp
blob89a3cde2b6901bf2b48cb31a3c91d0b2f953415b
1 #include "core/keymapper.hpp"
2 #include "lua/internal.hpp"
3 #include "core/movie.hpp"
4 #include "core/moviedata.hpp"
5 #include "core/controller.hpp"
6 #include "interface/romtype.hpp"
7 #include <iostream>
9 extern bool* lua_veto_flag;
11 namespace
13 int input_set(lua_state& L, unsigned port, unsigned controller, unsigned index, short value)
15 if(!lua_input_controllerdata)
16 return 0;
17 lua_input_controllerdata->axis3(port, controller, index, value);
18 return 0;
21 int input_get(lua_state& L, unsigned port, unsigned controller, unsigned index)
23 if(!lua_input_controllerdata)
24 return 0;
25 L.pushnumber(lua_input_controllerdata->axis3(port, controller, index));
26 return 1;
29 int input_controllertype(lua_state& L, unsigned port, unsigned controller)
31 auto& m = get_movie();
32 controller_frame f = m.read_subframe(m.get_current_frame(), 0);
33 if(port >= f.get_port_count()) {
34 L.pushnil();
35 return 1;
37 const port_type& p = f.get_port_type(port);
38 if(controller >= p.controller_info->controller_count)
39 L.pushnil();
40 else
41 L.pushstring(p.controller_info->controllers[controller]->type);
42 return 1;
45 int input_seta(lua_state& L, unsigned port, unsigned controller, uint64_t base, const char* fname)
47 if(!lua_input_controllerdata)
48 return 0;
49 short val;
50 if(port >= lua_input_controllerdata->get_port_count())
51 return 0;
52 const port_type& pt = lua_input_controllerdata->get_port_type(port);
53 if(controller >= pt.controller_info->controller_count)
54 return 0;
55 for(unsigned i = 0; i < pt.controller_info->controllers[controller]->button_count; i++) {
56 val = (base >> i) & 1;
57 L.get_numeric_argument<short>(i + base, val, fname);
58 lua_input_controllerdata->axis3(port, controller, i, val);
60 return 0;
63 int input_geta(lua_state& L, unsigned port, unsigned controller)
65 if(!lua_input_controllerdata)
66 return 0;
67 if(port >= lua_input_controllerdata->get_port_count())
68 return 0;
69 const port_type& pt = lua_input_controllerdata->get_port_type(port);
70 if(controller >= pt.controller_info->controller_count)
71 return 0;
72 uint64_t fret = 0;
73 for(unsigned i = 0; i < pt.controller_info->controllers[controller]->button_count; i++)
74 if(lua_input_controllerdata->axis3(port, controller, i))
75 fret |= (1ULL << i);
76 L.pushnumber(fret);
77 for(unsigned i = 0; i < pt.controller_info->controllers[controller]->button_count; i++)
78 L.pushnumber(lua_input_controllerdata->axis3(port, controller, i));
79 return pt.controller_info->controllers[controller]->button_count + 1;
82 function_ptr_luafun iset(LS, "input.set", [](lua_state& L, const std::string& fname) -> int {
83 if(!lua_input_controllerdata)
84 return 0;
85 unsigned controller = L.get_numeric_argument<unsigned>(1, fname.c_str());
86 unsigned index = L.get_numeric_argument<unsigned>(2, fname.c_str());
87 short value = L.get_numeric_argument<short>(3, fname.c_str());
88 auto _controller = lua_input_controllerdata->porttypes().legacy_pcid_to_pair(controller);
89 return input_set(L, _controller.first, _controller.second, index, value);
90 });
92 function_ptr_luafun iset2(LS, "input.set2", [](lua_state& L, const std::string& fname) -> int {
93 unsigned port = L.get_numeric_argument<unsigned>(1, fname.c_str());
94 unsigned controller = L.get_numeric_argument<unsigned>(2, fname.c_str());
95 unsigned index = L.get_numeric_argument<unsigned>(3, fname.c_str());
96 short value = L.get_numeric_argument<short>(4, fname.c_str());
97 return input_set(L, port, controller, index, value);
98 });
100 function_ptr_luafun iget(LS, "input.get", [](lua_state& L, const std::string& fname) -> int {
101 if(!lua_input_controllerdata)
102 return 0;
103 unsigned controller = L.get_numeric_argument<unsigned>(1, fname.c_str());
104 unsigned index = L.get_numeric_argument<unsigned>(2, fname.c_str());
105 auto _controller = lua_input_controllerdata->porttypes().legacy_pcid_to_pair(controller);
106 return input_get(L, _controller.first, _controller.second, index);
109 function_ptr_luafun iget2(LS, "input.get2", [](lua_state& L, const std::string& fname) -> int {
110 unsigned port = L.get_numeric_argument<unsigned>(1, fname.c_str());
111 unsigned controller = L.get_numeric_argument<unsigned>(2, fname.c_str());
112 unsigned index = L.get_numeric_argument<unsigned>(3, fname.c_str());
113 return input_get(L, port, controller, index);
116 function_ptr_luafun iseta(LS, "input.seta", [](lua_state& L, const std::string& fname) -> int {
117 if(!lua_input_controllerdata)
118 return 0;
119 unsigned controller = L.get_numeric_argument<unsigned>(1, fname.c_str());
120 uint64_t base = L.get_numeric_argument<uint64_t>(2, fname.c_str());
121 auto _controller = lua_input_controllerdata->porttypes().legacy_pcid_to_pair(controller);
122 return input_seta(L, _controller.first, _controller.second, base, fname.c_str());
125 function_ptr_luafun iseta2(LS, "input.seta2", [](lua_state& L, const std::string& fname) -> int {
126 unsigned port = L.get_numeric_argument<unsigned>(1, fname.c_str());
127 unsigned controller = L.get_numeric_argument<unsigned>(2, fname.c_str());
128 uint64_t base = L.get_numeric_argument<uint64_t>(3, fname.c_str());
129 return input_seta(L, port, controller, base, fname.c_str());
132 function_ptr_luafun igeta(LS, "input.geta", [](lua_state& L, const std::string& fname) -> int {
133 if(!lua_input_controllerdata)
134 return 0;
135 unsigned controller = L.get_numeric_argument<unsigned>(1, fname.c_str());
136 auto _controller = lua_input_controllerdata->porttypes().legacy_pcid_to_pair(controller);
137 return input_geta(L, _controller.first, _controller.second);
140 function_ptr_luafun igeta2(LS, "input.geta2", [](lua_state& L, const std::string& fname) -> int {
141 unsigned port = L.get_numeric_argument<unsigned>(1, fname.c_str());
142 unsigned controller = L.get_numeric_argument<unsigned>(2, fname.c_str());
143 return input_geta(L, port, controller);
146 function_ptr_luafun igett(LS, "input.controllertype", [](lua_state& L, const std::string& fname) -> int {
147 unsigned controller = L.get_numeric_argument<unsigned>(1, fname.c_str());
148 auto& m = get_movie();
149 const port_type_set& s = m.read_subframe(m.get_current_frame(), 0).porttypes();
150 auto _controller = s.legacy_pcid_to_pair(controller);
151 return input_controllertype(L, _controller.first, _controller.second);
154 function_ptr_luafun igett2(LS, "input.controllertype2", [](lua_state& L, const std::string& fname) -> int {
155 unsigned port = L.get_numeric_argument<unsigned>(1, fname.c_str());
156 unsigned controller = L.get_numeric_argument<unsigned>(2, fname.c_str());
157 return input_controllertype(L, port, controller);
160 function_ptr_luafun ireset(LS, "input.reset", [](lua_state& L, const std::string& fname) -> int {
161 if(!lua_input_controllerdata)
162 return 0;
163 long cycles = 0;
164 L.get_numeric_argument(1, cycles, fname.c_str());
165 if(cycles < 0)
166 return 0;
167 short lo = cycles % 10000;
168 short hi = cycles / 10000;
169 lua_input_controllerdata->axis3(0, 0, 1, 1);
170 lua_input_controllerdata->axis3(0, 0, 2, hi);
171 lua_input_controllerdata->axis3(0, 0, 3, lo);
172 return 0;
175 function_ptr_luafun iraw(LS, "input.raw", [](lua_state& L, const std::string& fname) -> int {
176 L.newtable();
177 for(auto i : lsnes_kbd.all_keys()) {
178 L.pushstring(i->get_name().c_str());
179 push_keygroup_parameters(L, *i);
180 L.settable(-3);
182 return 1;
185 class _keyhook_listener : public keyboard_event_listener
187 void on_key_event(keyboard_modifier_set& modifiers, keyboard_key& key, keyboard_event& event)
189 lua_callback_keyhook(key.get_name(), key);
191 } keyhook_listener;
192 std::set<std::string> hooked;
194 function_ptr_luafun ireq(LS, "input.keyhook", [](lua_state& L, const std::string& fname) -> int {
195 bool state;
196 std::string x = L.get_string(1, fname.c_str());
197 state = L.get_bool(2, fname.c_str());
198 keyboard_key* key = lsnes_kbd.try_lookup_key(x);
199 if(!key) {
200 L.pushstring("Invalid key name");
201 L.error();
202 return 0;
204 bool ostate = hooked.count(x) > 0;
205 if(ostate == state)
206 return 0;
207 if(state) {
208 hooked.insert(x);
209 key->add_listener(keyhook_listener, true);
210 } else {
211 hooked.erase(x);
212 key->remove_listener(keyhook_listener);
214 return 0;
217 function_ptr_luafun ijget(LS, "input.joyget", [](lua_state& L, const std::string& fname) -> int {
218 unsigned lcid = L.get_numeric_argument<unsigned>(1, fname.c_str());
219 if(!lua_input_controllerdata)
220 return 0;
221 auto pcid = controls.lcid_to_pcid(lcid - 1);
222 if(pcid.first < 0) {
223 L.pushstring("Invalid controller for input.joyget");
224 L.error();
225 return 0;
227 L.newtable();
228 const port_type& pt = lua_input_controllerdata->get_port_type(pcid.first);
229 const port_controller& ctrl = *pt.controller_info->controllers[pcid.second];
230 unsigned lcnt = ctrl.button_count;
231 for(unsigned i = 0; i < lcnt; i++) {
232 if(ctrl.buttons[i]->type == port_controller_button::TYPE_NULL)
233 continue;
234 L.pushstring(ctrl.buttons[i]->name);
235 if(ctrl.buttons[i]->is_analog())
236 L.pushnumber(lua_input_controllerdata->axis3(pcid.first, pcid.second, i));
237 else if(ctrl.buttons[i]->type == port_controller_button::TYPE_BUTTON)
238 L.pushboolean(lua_input_controllerdata->axis3(pcid.first, pcid.second, i) != 0);
239 L.settable(-3);
241 return 1;
244 function_ptr_luafun ijset(LS, "input.joyset", [](lua_state& L, const std::string& fname) -> int {
245 unsigned lcid = L.get_numeric_argument<unsigned>(1, fname.c_str());
246 if(L.type(2) != LUA_TTABLE) {
247 L.pushstring("Invalid type for input.joyset");
248 L.error();
249 return 0;
251 if(!lua_input_controllerdata)
252 return 0;
253 auto pcid = controls.lcid_to_pcid(lcid - 1);
254 if(pcid.first < 0) {
255 L.pushstring("Invalid controller for input.joyset");
256 L.error();
257 return 0;
259 const port_type& pt = lua_input_controllerdata->get_port_type(pcid.first);
260 const port_controller& ctrl = *pt.controller_info->controllers[pcid.second];
261 unsigned lcnt = ctrl.button_count;
262 for(unsigned i = 0; i < lcnt; i++) {
263 if(ctrl.buttons[i]->type == port_controller_button::TYPE_NULL)
264 continue;
265 L.pushstring(ctrl.buttons[i]->name);
266 L.gettable(2);
267 int s;
268 if(ctrl.buttons[i]->is_analog()) {
269 if(L.type(-1) == LUA_TNIL)
270 s = lua_input_controllerdata->axis3(pcid.first, pcid.second, i);
271 else
272 s = L.tonumber(-1);
273 } else {
274 if(L.type(-1) == LUA_TNIL)
275 s = lua_input_controllerdata->axis3(pcid.first, pcid.second, i);
276 else if(L.type(-1) == LUA_TSTRING)
277 s = lua_input_controllerdata->axis3(pcid.first, pcid.second, i) ^ 1;
278 else
279 s = L.toboolean(-1) ? 1 : 0;
281 lua_input_controllerdata->axis3(pcid.first, pcid.second, i, s);
282 L.pop(1);
284 return 0;
287 function_ptr_luafun ijlcid_to_pcid(LS, "input.lcid_to_pcid", [](lua_state& L, const std::string& fname) ->
288 int {
289 unsigned lcid = L.get_numeric_argument<unsigned>(1, fname.c_str());
290 auto pcid = controls.lcid_to_pcid(lcid - 1);
291 if(pcid.first < 0)
292 return 0;
293 int legacy_pcid = -1;
294 for(unsigned i = 0;; i++)
295 try {
296 auto p = controls.legacy_pcid_to_pair(i);
297 if(p.first == pcid.first && p.second == pcid.second) {
298 legacy_pcid = i;
299 break;
301 } catch(...) {
302 break;
304 if(legacy_pcid >= 0)
305 L.pushnumber(legacy_pcid);
306 else
307 L.pushboolean(false);
308 L.pushnumber(pcid.first);
309 L.pushnumber(pcid.second);
310 return 3;
313 //THE NEW API.
315 function_ptr_luafun ijlcid_to_pcid2(LS, "input.lcid_to_pcid2", [](lua_state& L, const std::string& fname) ->
316 int {
317 unsigned lcid = L.get_numeric_argument<unsigned>(1, fname.c_str());
318 auto pcid = controls.lcid_to_pcid(lcid - 1);
319 if(pcid.first < 0)
320 return 0;
321 L.pushnumber(pcid.first);
322 L.pushnumber(pcid.second);
323 return 2;
326 function_ptr_luafun iporttype(LS, "input.port_type", [](lua_state& L, const std::string& fname) -> int {
327 unsigned port = L.get_numeric_argument<unsigned>(1, fname.c_str());
328 auto& m = get_movie();
329 const port_type_set& s = m.read_subframe(m.get_current_frame(), 0).porttypes();
330 try {
331 const port_type& p = s.port_type(port);
332 L.pushlstring(p.name);
333 } catch(...) {
334 return 0;
336 return 1;
339 const port_controller_set* lookup_ps(unsigned port)
341 auto& m = get_movie();
342 controller_frame f = m.read_subframe(m.get_current_frame(), 0);
343 const port_type& p = f.get_port_type(port);
344 return p.controller_info;
347 function_ptr_luafun iveto(LS, "input.veto_button", [](lua_state& LS, const std::string& fname) -> int {
348 if(lua_veto_flag) *lua_veto_flag = true;
349 return 0;
352 function_ptr_luafun ictrlinfo(LS, "input.controller_info", [](lua_state& L, const std::string& fname) -> int {
353 unsigned port = L.get_numeric_argument<unsigned>(1, fname.c_str());
354 unsigned controller = L.get_numeric_argument<unsigned>(2, fname.c_str());
355 const port_controller_set* ps;
356 unsigned lcid = 0;
357 unsigned classnum = 1;
358 ps = lookup_ps(port);
359 if(!ps || ps->controller_count <= controller)
360 return 0;
361 for(unsigned i = 0; i < 8; i++) {
362 auto pcid = controls.lcid_to_pcid(i);
363 if(pcid.first < 0)
364 continue;
365 if(pcid.first == port && pcid.second == controller) {
366 lcid = i + 1;
367 break;
369 const port_controller_set* ps2 = lookup_ps(pcid.first);
370 if(!strcmp(ps->controllers[controller]->cclass, ps2->controllers[pcid.second]->cclass))
371 classnum++;
373 port_controller* cs = ps->controllers[controller];
374 L.newtable();
375 L.pushstring("type");
376 L.pushstring(cs->type);
377 L.rawset(-3);
378 L.pushstring("class");
379 L.pushstring(cs->cclass);
380 L.rawset(-3);
381 L.pushstring("classnum");
382 L.pushnumber(classnum);
383 L.rawset(-3);
384 L.pushstring("lcid");
385 L.pushnumber(lcid);
386 L.rawset(-3);
387 L.pushstring("button_count");
388 L.pushnumber(cs->button_count);
389 L.rawset(-3);
390 L.pushstring("buttons");
391 L.newtable();
392 //Push the buttons.
393 for(unsigned i = 0; i < cs->button_count; i++) {
394 L.pushnumber(i + 1);
395 L.newtable();
396 L.pushstring("type");
397 switch(cs->buttons[i]->type) {
398 case port_controller_button::TYPE_NULL: L.pushstring("null"); break;
399 case port_controller_button::TYPE_BUTTON: L.pushstring("button"); break;
400 case port_controller_button::TYPE_AXIS: L.pushstring("axis"); break;
401 case port_controller_button::TYPE_RAXIS: L.pushstring("raxis"); break;
402 case port_controller_button::TYPE_TAXIS: L.pushstring("axis"); break;
404 L.rawset(-3);
405 if(cs->buttons[i]->symbol) {
406 L.pushstring("symbol");
407 L.pushlstring(&cs->buttons[i]->symbol, 1);
408 L.rawset(-3);
410 L.pushstring("name");
411 L.pushstring(cs->buttons[i]->name);
412 L.rawset(-3);
413 L.pushstring("hidden");
414 L.pushboolean(cs->buttons[i]->shadow);
415 L.rawset(-3);
416 L.rawset(-3);
418 L.rawset(-3);
419 return 1;