1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#include "common/config.h"
22
23#include "wrap_Keyboard.h"
24
25#include "sdl/Keyboard.h"
26
27namespace love
28{
29namespace keyboard
30{
31
32#define instance() (Module::getInstance<Keyboard>(Module::M_KEYBOARD))
33
34int w_setKeyRepeat(lua_State *L)
35{
36 instance()->setKeyRepeat(luax_checkboolean(L, 1));
37 return 0;
38}
39
40int w_hasKeyRepeat(lua_State *L)
41{
42 luax_pushboolean(L, instance()->hasKeyRepeat());
43 return 1;
44}
45
46int w_isDown(lua_State *L)
47{
48 Keyboard::Key k;
49
50 bool istable = lua_istable(L, 1);
51 int num = istable ? (int) luax_objlen(L, 1) : lua_gettop(L);
52
53 std::vector<Keyboard::Key> keylist;
54 keylist.reserve(num);
55
56 if (istable)
57 {
58 for (int i = 0; i < num; i++)
59 {
60 lua_rawgeti(L, 1, i + 1);
61
62 const char *name = luaL_checkstring(L, -1);
63 if (!Keyboard::getConstant(name, k))
64 return luax_enumerror(L, "key constant", name);
65
66 keylist.push_back(k);
67 lua_pop(L, 1);
68 }
69 }
70 else
71 {
72 for (int i = 0; i < num; i++)
73 {
74 const char *name = luaL_checkstring(L, i + 1);
75 if (!Keyboard::getConstant(name, k))
76 return luax_enumerror(L, "key constant", name);
77
78 keylist.push_back(k);
79 }
80 }
81
82 luax_pushboolean(L, instance()->isDown(keylist));
83 return 1;
84}
85
86int w_isScancodeDown(lua_State *L)
87{
88 Keyboard::Scancode scancode;
89
90 bool istable = lua_istable(L, 1);
91 int num = istable ? (int) luax_objlen(L, 1) : lua_gettop(L);
92
93 std::vector<Keyboard::Scancode> scancodelist;
94 scancodelist.reserve(num);
95
96 if (istable)
97 {
98 for (int i = 0; i < num; i++)
99 {
100 lua_rawgeti(L, 1, i + 1);
101
102 const char *name = luaL_checkstring(L, -1);
103 if (!Keyboard::getConstant(name, scancode))
104 return luax_enumerror(L, "scancode", name);
105
106 scancodelist.push_back(scancode);
107 lua_pop(L, 1);
108 }
109 }
110 else
111 {
112 for (int i = 0; i < num; i++)
113 {
114 const char *name = luaL_checkstring(L, i + 1);
115 if (!Keyboard::getConstant(name, scancode))
116 return luax_enumerror(L, "scancode", name);
117
118 scancodelist.push_back(scancode);
119 }
120 }
121
122 luax_pushboolean(L, instance()->isScancodeDown(scancodelist));
123 return 1;
124}
125
126int w_getScancodeFromKey(lua_State *L)
127{
128 const char *keystr = luaL_checkstring(L, 1);
129 Keyboard::Key key;
130 if (!Keyboard::getConstant(keystr, key))
131 return luax_enumerror(L, "key constant", keystr);
132
133 Keyboard::Scancode scancode = instance()->getScancodeFromKey(key);
134
135 const char *scancodestr;
136 if (!Keyboard::getConstant(scancode, scancodestr))
137 return luaL_error(L, "Unknown scancode.");
138
139 lua_pushstring(L, scancodestr);
140 return 1;
141}
142
143int w_getKeyFromScancode(lua_State *L)
144{
145 const char *scancodestr = luaL_checkstring(L, 1);
146 Keyboard::Scancode scancode;
147 if (!Keyboard::getConstant(scancodestr, scancode))
148 return luax_enumerror(L, "scancode", scancodestr);
149
150 Keyboard::Key key = instance()->getKeyFromScancode(scancode);
151
152 const char *keystr;
153 if (!Keyboard::getConstant(key, keystr))
154 return luaL_error(L, "Unknown key constant");
155
156 lua_pushstring(L, keystr);
157 return 1;
158}
159
160int w_setTextInput(lua_State *L)
161{
162 bool enable = luax_checkboolean(L, 1);
163
164 if (lua_gettop(L) <= 1)
165 instance()->setTextInput(enable);
166 else
167 {
168 double x = luaL_checknumber(L, 2);
169 double y = luaL_checknumber(L, 3);
170 double w = luaL_checknumber(L, 4);
171 double h = luaL_checknumber(L, 5);
172 instance()->setTextInput(enable, x, y, w, h);
173 }
174
175 return 0;
176}
177
178int w_hasTextInput(lua_State *L)
179{
180 luax_pushboolean(L, instance()->hasTextInput());
181 return 1;
182}
183
184int w_hasScreenKeyboard(lua_State *L)
185{
186 luax_pushboolean(L, instance()->hasScreenKeyboard());
187 return 1;
188}
189
190// List of functions to wrap.
191static const luaL_Reg functions[] =
192{
193 { "setKeyRepeat", w_setKeyRepeat },
194 { "hasKeyRepeat", w_hasKeyRepeat },
195 { "setTextInput", w_setTextInput },
196 { "hasTextInput", w_hasTextInput },
197 { "hasScreenKeyboard", w_hasScreenKeyboard },
198 { "isDown", w_isDown },
199 { "isScancodeDown", w_isScancodeDown },
200 { "getScancodeFromKey", w_getScancodeFromKey },
201 { "getKeyFromScancode", w_getKeyFromScancode },
202 { 0, 0 }
203};
204
205extern "C" int luaopen_love_keyboard(lua_State *L)
206{
207 Keyboard *instance = instance();
208 if (instance == nullptr)
209 {
210 luax_catchexcept(L, [&](){ instance = new love::keyboard::sdl::Keyboard(); });
211 }
212 else
213 instance->retain();
214
215 WrappedModule w;
216 w.module = instance;
217 w.name = "keyboard";
218 w.type = &Module::type;
219 w.functions = functions;
220 w.types = 0;
221
222 return luax_register_module(L, w);
223}
224
225} // keyboard
226} // love
227