initial
[lua-termkey.git] / wrap-termkey.c
blob8aa5b411705546d4ce7a38e0671fd4777b0ae54a
1 /*
2 * This wrapper is Copyright (c) 2020 S. Gilles <sgilles@umd.edu>
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
23 * libtermkey is Copyright (c) 2007-2011 Paul Evans <leonerd@leonerd.org.uk>
25 * Permission is hereby granted, free of charge, to any person obtaining a copy
26 * of this software and associated documentation files (the "Software"), to deal
27 * in the Software without restriction, including without limitation the rights
28 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 * copies of the Software, and to permit persons to whom the Software is
30 * furnished to do so, subject to the following conditions:
32 * The above copyright notice and this permission notice shall be included in
33 * all copies or substantial portions of the Software.
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41 * THE SOFTWARE.
43 #include <stdio.h>
44 #include <string.h>
46 #include <lua.h>
47 #include <lauxlib.h>
48 #include <lualib.h>
50 #include <termkey.h>
52 #define STR(s) STR2(s)
53 #define STR2(s) #s
55 #define WRAP_TERMKEY_NAME "termkey.TermKey*"
57 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 501
58 static void lua_setuservalue(lua_State *L, lua_Integer x) {
59 luaL_checktype(L, -1, LUA_TTABLE);
60 lua_setfenv(L, x);
62 #endif
64 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502
65 static void lua_seti(lua_State *L, lua_Integer i, lua_Integer d) {
66 lua_Integer j = i;
67 if (j < 0 && j > LUA_REGISTRYINDEX) {
68 j += lua_gettop(L) + 1;
70 lua_pushinteger(L, d);
71 lua_insert(L, -2);
72 lua_settable(L, j);
74 #endif
76 static void table_to_fd_tk_flags(lua_State *L, int idx, int *out_fd, int *out_flags) {
77 int flags = 0;
78 size_t sk_len = 0;
80 lua_pushnil(L);
81 while (lua_next(L, idx)) {
82 const char *sk = 0;
83 lua_pushvalue(L, -2);
84 sk = lua_tolstring(L, -1, &sk_len);
86 if (!strncmp(sk, "fd", sk_len) && out_fd) {
87 *out_fd = lua_tointegerx(L, -2, 0);
88 } else if (lua_toboolean(L, -2) && out_flags) {
90 All flags default to false, so we
91 need only set if value is non-false.
93 if (!strncmp(sk, "nointerpret", sk_len)) {
94 flags |= TERMKEY_FLAG_NOINTERPRET;
95 } else if (!strncmp(sk, "convertkp", sk_len)) {
96 flags |= TERMKEY_FLAG_CONVERTKP;
97 } else if (!strncmp(sk, "raw", sk_len)) {
98 flags |= TERMKEY_FLAG_RAW;
99 } else if (!strncmp(sk, "utf8", sk_len)) {
100 flags |= TERMKEY_FLAG_UTF8;
101 } else if (!strncmp(sk, "notermios", sk_len)) {
102 flags |= TERMKEY_FLAG_NOTERMIOS;
103 } else if (!strncmp(sk, "spacesymbol", sk_len)) {
104 flags |= TERMKEY_FLAG_SPACESYMBOL;
105 } else if (!strncmp(sk, "ctrlc", sk_len)) {
106 flags |= TERMKEY_FLAG_CTRLC;
107 } else if (!strncmp(sk, "eintr", sk_len)) {
108 flags |= TERMKEY_FLAG_EINTR;
109 } else if (!strncmp(sk, "nostart", sk_len)) {
110 flags |= TERMKEY_FLAG_NOSTART;
113 lua_pop(L, 2);
116 if (out_flags) {
117 *out_flags = flags;
121 static void table_to_canon_flags(lua_State *L, int idx, int *out_flags) {
122 int flags = 0;
123 size_t sk_len = 0;
125 lua_pushnil(L);
126 while (lua_next(L, idx)) {
127 const char *sk = 0;
128 lua_pushvalue(L, -2);
129 sk = lua_tolstring(L, -1, &sk_len);
131 if (lua_toboolean(L, -2) && out_flags) {
132 if (!strncmp(sk, "spacesymbol", sk_len)) {
133 flags |= TERMKEY_CANON_SPACESYMBOL;
134 } else if (!strncmp(sk, "delbs", sk_len)) {
135 flags |= TERMKEY_CANON_DELBS;
138 lua_pop(L, 2);
141 if (out_flags) {
142 *out_flags = flags;
147 int wrap_termkey_start(lua_State *L) {
148 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
149 termkey_start(*tk);
151 return 0;
154 int wrap_termkey_stop(lua_State *L) {
155 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
156 termkey_stop(*tk);
158 return 0;
161 int wrap_termkey_is_started(lua_State *L) {
162 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
163 lua_pushboolean(L, termkey_is_started(*tk));
165 return 1;
168 int wrap_termkey_get_fd(lua_State *L) {
169 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
170 lua_pushinteger(L, termkey_get_fd(*tk));
172 return 1;
175 int wrap_termkey_get_flags(lua_State *L) {
176 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
177 int flags = termkey_get_flags(*tk);
179 lua_createtable(L, 0, 9);
181 lua_pushboolean(L, !!(flags & TERMKEY_FLAG_NOINTERPRET));
182 lua_setfield(L, -2, "nointerpret");
184 lua_pushboolean(L, !!(flags & TERMKEY_FLAG_CONVERTKP));
185 lua_setfield(L, -2, "convertkp");
187 lua_pushboolean(L, !!(flags &TERMKEY_FLAG_RAW));
188 lua_setfield(L, -2, "raw");
190 lua_pushboolean(L, !!(flags &TERMKEY_FLAG_UTF8));
191 lua_setfield(L, -2, "utf8");
193 lua_pushboolean(L, !!(flags &TERMKEY_FLAG_NOTERMIOS));
194 lua_setfield(L, -2, "notermios");
196 lua_pushboolean(L, !!(flags &TERMKEY_FLAG_SPACESYMBOL));
197 lua_setfield(L, -2, "spacesymbol");
199 lua_pushboolean(L, !!(flags &TERMKEY_FLAG_CTRLC));
200 lua_setfield(L, -2, "ctrlc");
202 lua_pushboolean(L, !!(flags &TERMKEY_FLAG_EINTR));
203 lua_setfield(L, -2, "eintr");
205 lua_pushboolean(L, !!(flags &TERMKEY_FLAG_NOSTART));
206 lua_setfield(L, -2, "nostart");
208 return 1;
211 int wrap_termkey_set_flags(lua_State *L) {
212 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
213 int flags = 0;
215 if (lua_istable(L, 2)) {
216 table_to_fd_tk_flags(L, 2, 0, &flags);
219 termkey_set_flags(*tk, flags);
221 return 0;
224 int wrap_termkey_get_waittime(lua_State *L) {
225 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
226 lua_pushinteger(L, termkey_get_waittime(*tk));
228 return 1;
231 int wrap_termkey_set_waittime(lua_State *L) {
232 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
233 int valid = 0;
234 int waittime = lua_tointegerx(L, 2, &valid);
236 if (valid) {
237 termkey_set_waittime(*tk, waittime);
240 return 0;
243 int wrap_termkey_get_canonflags(lua_State *L) {
244 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
245 int flags = termkey_get_canonflags(*tk);
247 lua_createtable(L, 0, 2);
249 lua_pushboolean(L, !!(flags & TERMKEY_CANON_SPACESYMBOL));
250 lua_setfield(L, -2, "spacesymbol");
252 lua_pushboolean(L, !!(flags & TERMKEY_CANON_DELBS));
253 lua_setfield(L, -2, "delbs");
255 return 1;
258 int wrap_termkey_set_canonflags(lua_State *L) {
259 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
260 int flags = 0;
262 if (lua_istable(L, 2)) {
263 table_to_canon_flags(L, 2, &flags);
266 termkey_set_canonflags(*tk, flags);
268 return 0;
271 int wrap_termkey_get_buffer_size(lua_State *L) {
272 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
273 lua_pushinteger(L, termkey_get_buffer_size(*tk));
275 return 1;
278 int wrap_termkey_set_buffer_size(lua_State *L) {
279 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
280 int valid = 0;
281 size_t buffer_size = lua_tointegerx(L, 2, &valid);
283 if (valid) {
284 termkey_set_buffer_size(*tk, buffer_size);
287 return 0;
290 int wrap_termkey_get_buffer_remaining(lua_State *L) {
291 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
292 lua_pushinteger(L, termkey_get_buffer_remaining(*tk));
294 return 1;
297 static const char *string_from_sym(TermKeySym sym) {
298 switch(sym) {
299 case TERMKEY_SYM_UNKNOWN: return "unknown";
300 case TERMKEY_SYM_NONE: return "none";
301 case TERMKEY_SYM_BACKSPACE: return "backspace";
302 case TERMKEY_SYM_TAB: return "tab";
303 case TERMKEY_SYM_ENTER: return "enter";
304 case TERMKEY_SYM_ESCAPE: return "escape";
305 case TERMKEY_SYM_SPACE: return "space";
306 case TERMKEY_SYM_DEL: return "del";
307 case TERMKEY_SYM_UP: return "up";
308 case TERMKEY_SYM_DOWN: return "down";
309 case TERMKEY_SYM_LEFT: return "left";
310 case TERMKEY_SYM_RIGHT: return "right";
311 case TERMKEY_SYM_BEGIN: return "begin";
312 case TERMKEY_SYM_FIND: return "find";
313 case TERMKEY_SYM_INSERT: return "insert";
314 case TERMKEY_SYM_DELETE: return "delete";
315 case TERMKEY_SYM_SELECT: return "select";
316 case TERMKEY_SYM_PAGEUP: return "pageup";
317 case TERMKEY_SYM_PAGEDOWN: return "pagedown";
318 case TERMKEY_SYM_HOME: return "home";
319 case TERMKEY_SYM_END: return "end";
320 case TERMKEY_SYM_CANCEL: return "cancel";
321 case TERMKEY_SYM_CLEAR: return "clear";
322 case TERMKEY_SYM_CLOSE: return "close";
323 case TERMKEY_SYM_COMMAND: return "command";
324 case TERMKEY_SYM_COPY: return "copy";
325 case TERMKEY_SYM_EXIT: return "exit";
326 case TERMKEY_SYM_HELP: return "help";
327 case TERMKEY_SYM_MARK: return "mark";
328 case TERMKEY_SYM_MESSAGE: return "message";
329 case TERMKEY_SYM_MOVE: return "move";
330 case TERMKEY_SYM_OPEN: return "open";
331 case TERMKEY_SYM_OPTIONS: return "options";
332 case TERMKEY_SYM_PRINT: return "print";
333 case TERMKEY_SYM_REDO: return "redo";
334 case TERMKEY_SYM_REFERENCE: return "reference";
335 case TERMKEY_SYM_REFRESH: return "refresh";
336 case TERMKEY_SYM_REPLACE: return "replace";
337 case TERMKEY_SYM_RESTART: return "restart";
338 case TERMKEY_SYM_RESUME: return "resume";
339 case TERMKEY_SYM_SAVE: return "save";
340 case TERMKEY_SYM_SUSPEND: return "suspend";
341 case TERMKEY_SYM_UNDO: return "undo";
342 case TERMKEY_SYM_KP0: return "kp0";
343 case TERMKEY_SYM_KP1: return "kp1";
344 case TERMKEY_SYM_KP2: return "kp2";
345 case TERMKEY_SYM_KP3: return "kp3";
346 case TERMKEY_SYM_KP4: return "kp4";
347 case TERMKEY_SYM_KP5: return "kp5";
348 case TERMKEY_SYM_KP6: return "kp6";
349 case TERMKEY_SYM_KP7: return "kp7";
350 case TERMKEY_SYM_KP8: return "kp8";
351 case TERMKEY_SYM_KP9: return "kp9";
352 case TERMKEY_SYM_KPENTER: return "kpenter";
353 case TERMKEY_SYM_KPPLUS: return "kpplus";
354 case TERMKEY_SYM_KPMINUS: return "kpminus";
355 case TERMKEY_SYM_KPMULT: return "kpmult";
356 case TERMKEY_SYM_KPDIV: return "kpdiv";
357 case TERMKEY_SYM_KPCOMMA: return "kpcomma";
358 case TERMKEY_SYM_KPPERIOD: return "kpperiod";
359 case TERMKEY_SYM_KPEQUALS: return "kpequals";
360 default: return "unknown";
364 static int luaify_getkey_result(lua_State *L, TermKey *tk, TermKeyKey *k, TermKeyResult r) {
365 TermKeyMouseEvent me;
366 int button = 0, line = 0, col = 0, initial = 0, mode = 0, value = 0;
367 unsigned long cmd = 0;
368 long args[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
369 size_t nargs = 16;
370 const char *str = 0;
372 switch(r) {
373 case TERMKEY_RES_NONE:
374 lua_pushnil(L);
376 return 1;
377 case TERMKEY_RES_EOF:
378 lua_pushliteral(L, "eof");
380 return 1;
381 case TERMKEY_RES_AGAIN:
382 lua_pushliteral(L, "again");
384 return 1;
385 case TERMKEY_RES_ERROR:
386 lua_pushliteral(L, "error");
388 return 1;
389 case TERMKEY_RES_KEY:
390 break;
393 lua_createtable(L, 0, 5);
395 lua_pushboolean(L, !!(k->modifiers & TERMKEY_KEYMOD_SHIFT));
396 lua_setfield(L, -2, "shift");
397 lua_pushboolean(L, !!(k->modifiers & TERMKEY_KEYMOD_ALT));
398 lua_setfield(L, -2, "alt");
399 lua_pushboolean(L, !!(k->modifiers & TERMKEY_KEYMOD_CTRL));
400 lua_setfield(L, -2, "ctrl");
402 if (k->utf8[0]) {
403 lua_pushstring(L, k->utf8);
404 lua_setfield(L, -2, "utf8");
407 switch(k->type) {
408 case TERMKEY_TYPE_UNICODE:
409 lua_pushinteger(L, k->code.codepoint);
410 lua_setfield(L, -2, "codepoint");
411 break;
412 case TERMKEY_TYPE_FUNCTION:
413 lua_pushinteger(L, k->code.number);
414 lua_setfield(L, -2, "function_number");
415 break;
416 case TERMKEY_TYPE_KEYSYM:
417 lua_pushstring(L, string_from_sym(k->code.sym));
418 lua_setfield(L, -2, "sym");
419 break;
420 case TERMKEY_TYPE_MOUSE:
421 termkey_interpret_mouse(tk, k, &me, &button, &line, &col);
422 lua_createtable(L, 0, 4);
424 lua_pushinteger(L, button);
425 lua_setfield(L, -2, "button");
426 lua_pushinteger(L, line);
427 lua_setfield(L, -2, "line");
428 lua_pushinteger(L, col);
429 lua_setfield(L, -2, "col");
431 switch(me) {
432 case TERMKEY_MOUSE_PRESS:
433 lua_pushliteral(L, "press");
434 break;
435 case TERMKEY_MOUSE_DRAG:
436 lua_pushliteral(L, "drag");
437 break;
438 case TERMKEY_MOUSE_RELEASE:
439 lua_pushliteral(L, "release");
440 break;
441 default:
442 lua_pushliteral(L, "unknown");
443 break;
445 lua_setfield(L, -2, "event");
447 lua_setfield(L, -2, "mouse");
448 break;
449 case TERMKEY_TYPE_POSITION:
450 termkey_interpret_position(tk, k, &line, &col);
451 lua_createtable(L, 0, 2);
453 lua_pushinteger(L, line);
454 lua_setfield(L, -2, "line");
455 lua_pushinteger(L, col);
456 lua_setfield(L, -2, "col");
458 lua_setfield(L, -2, "position");
459 break;
460 case TERMKEY_TYPE_MODEREPORT:
461 termkey_interpret_modereport(tk, k, &initial, &mode, &value);
462 lua_createtable(L, 0, 3);
464 lua_pushinteger(L, initial);
465 lua_setfield(L, -2, "initial");
466 lua_pushinteger(L, mode);
467 lua_setfield(L, -2, "mode");
468 lua_pushinteger(L, value);
469 lua_setfield(L, -2, "value");
471 lua_setfield(L, -2, "modereport");
472 break;
473 case TERMKEY_TYPE_DCS: /* fall through */
474 case TERMKEY_TYPE_OSC:
475 termkey_interpret_string(tk, k, &str);
476 lua_pushstring(L, str);
477 lua_setfield(L, -2, "command_string");
478 break;
479 case TERMKEY_TYPE_UNKNOWN_CSI:
480 termkey_interpret_csi(tk, k, args, &nargs, &cmd);
481 lua_createtable(L, 0, 2);
482 lua_createtable(L, 16, 0);
484 for (size_t j = 0; j < nargs; ++j) {
485 lua_pushinteger(L, args[j]);
486 lua_seti(L, -2, j + 1);
489 lua_setfield(L, -2, "args");
491 lua_pushinteger(L, cmd);
492 lua_setfield(L, -2, "cmd");
493 lua_setfield(L, -2, "csi");
495 break;
498 return 1;
501 int wrap_termkey_getkey(lua_State *L) {
502 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
503 TermKeyKey k = { 0 };
504 TermKeyResult r = termkey_getkey(*tk, &k);
506 return luaify_getkey_result(L, *tk, &k, r);
509 int wrap_termkey_getkey_force(lua_State *L) {
510 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
511 TermKeyKey k = { 0 };
512 TermKeyResult r = termkey_getkey_force(*tk, &k);
514 return luaify_getkey_result(L, *tk, &k, r);
517 int wrap_termkey_waitkey(lua_State *L) {
518 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
519 TermKeyKey k = { 0 };
520 TermKeyResult r = termkey_waitkey(*tk, &k);
522 return luaify_getkey_result(L, *tk, &k, r);
525 int wrap_termkey_gc(lua_State *L) {
526 TermKey **tk = (TermKey **) luaL_checkudata(L, 1, WRAP_TERMKEY_NAME);
528 if (*tk) {
529 termkey_destroy(*tk);
532 return 0;
535 static const struct luaL_Reg tk_mapping[] = {
536 { "start", wrap_termkey_start },
537 { "stop", wrap_termkey_stop },
538 { "is_started", wrap_termkey_is_started },
539 { "get_fd", wrap_termkey_get_fd },
540 { "get_flags", wrap_termkey_get_flags },
541 { "set_flags", wrap_termkey_set_flags },
542 { "get_waittime", wrap_termkey_get_waittime },
543 { "set_waittime", wrap_termkey_set_waittime },
544 { "get_canonflags", wrap_termkey_get_canonflags },
545 { "set_canonflags", wrap_termkey_set_canonflags },
546 { "get_buffer_size", wrap_termkey_get_buffer_size },
547 { "set_buffer_size", wrap_termkey_set_buffer_size },
548 { "get_buffer_remaining", wrap_termkey_get_buffer_remaining },
549 { "getkey", wrap_termkey_getkey },
550 { "getkey_force", wrap_termkey_getkey_force },
551 { "waitkey", wrap_termkey_waitkey },
552 { "__gc", wrap_termkey_gc },
553 { 0 },
557 static int wrap_new(lua_State *L) {
558 int flags = 0;
559 int fd = 0;
561 TermKey **tk = (TermKey **) lua_newuserdata(L, sizeof *tk);
562 luaL_getmetatable(L, WRAP_TERMKEY_NAME);
563 lua_pushvalue(L, -1);
564 lua_setuservalue(L, -3);
565 lua_setmetatable(L, -2);
567 if (0 == 1) {
568 luaL_setfuncs(L, tk_mapping, 0);
571 if (lua_istable(L, 1)) {
572 table_to_fd_tk_flags(L, 1, &fd, &flags);
575 *tk = termkey_new(fd, flags);
577 if (!*tk) {
578 lua_pop(L, 1);
579 lua_pushnil(L);
582 return 1;
585 static const struct luaL_Reg mapping[] = {
586 { "new", wrap_new },
587 { 0 },
590 /* Lua metatable initialization */
591 int luaopen_termkey (lua_State *L) {
592 lua_newtable(L);
593 luaL_setfuncs(L, mapping, 0);
594 lua_pushvalue(L, -1);
595 lua_pushliteral(L, "Copyright (C) 2007-2011 Paul Evans <leonerd@leonerd.org.uk>");
596 lua_setfield(L, -2, "_COPYRIGHT");
597 lua_pushliteral(L, "This library allows easy processing of keyboard entry from terminal-based programs.");
598 lua_setfield(L, -2, "_DESCRIPTION");
599 lua_pushliteral(L, "lua-termkey " STR(TERMKEY_VERSION_MAJOR) "." STR(TERMKEY_VERSION_MINOR));
600 lua_setfield(L, -2, "_VERSION");
603 Setting the metatable to be its own index allows mixing
604 metatable methods (__gc) and member functions (start) in the
605 same mapping.
607 luaL_newmetatable(L, WRAP_TERMKEY_NAME);
608 lua_pushvalue(L, -1);
609 lua_setfield(L, -2, "__index");
610 luaL_setfuncs(L, tk_mapping, 0);
611 lua_pop(L, 1);
613 return 1;