Added mouse support

If there is a curses library with support to mouse the `curses.KEY_MOUSE` constant
will be defined with other constants and functions.
This commit is contained in:
Lael N. Santos
2020-10-05 13:32:58 -03:00
parent ffd3f6d754
commit c10290695e
4 changed files with 242 additions and 2 deletions

View File

@@ -65,7 +65,6 @@ Notes:
#ifndef LUAJIT
# define LUA_COMPAT_5_1
# define LUA_COMPAT_5_3
# define LUA_COMPAT_ALL
#endif
#include "luaconf.h"
@@ -623,7 +622,12 @@ static void register_curses_constants(lua_State *L)
CC(KEY_CANCEL) CC(KEY_CLOSE) CC(KEY_COMMAND)
CC(KEY_COPY) CC(KEY_CREATE) CC(KEY_END)
CC(KEY_EXIT) CC(KEY_FIND) CC(KEY_HELP)
CC(KEY_MARK) CC(KEY_MESSAGE) CC(KEY_MOUSE)
CC(KEY_MARK) CC(KEY_MESSAGE)
#ifndef XCURSES
#ifndef NOMOUSE
CC(KEY_MOUSE)
#endif
#endif
CC(KEY_MOVE) CC(KEY_NEXT) CC(KEY_OPEN)
CC(KEY_OPTIONS) CC(KEY_PREVIOUS) CC(KEY_REDO)
CC(KEY_REFERENCE) CC(KEY_REFRESH) CC(KEY_REPLACE)
@@ -646,6 +650,29 @@ static void register_curses_constants(lua_State *L)
CC2(KEY_F6, KEY_F(6)) CC2(KEY_F7, KEY_F(7)) CC2(KEY_F8, KEY_F(8))
CC2(KEY_F9, KEY_F(9)) CC2(KEY_F10, KEY_F(10)) CC2(KEY_F11, KEY_F(11))
CC2(KEY_F12, KEY_F(12))
#ifndef XCURSES
#ifndef NOMOUSE
/* Mouse Constants */
CC(BUTTON1_RELEASED); CC(BUTTON1_PRESSED); CC(BUTTON1_CLICKED);
CC(BUTTON1_DOUBLE_CLICKED); CC(BUTTON1_TRIPLE_CLICKED);
CC(BUTTON2_RELEASED); CC(BUTTON2_PRESSED); CC(BUTTON2_CLICKED);
CC(BUTTON2_DOUBLE_CLICKED); CC(BUTTON2_TRIPLE_CLICKED);
CC(BUTTON3_RELEASED); CC(BUTTON3_PRESSED); CC(BUTTON3_CLICKED);
CC(BUTTON3_DOUBLE_CLICKED); CC(BUTTON3_TRIPLE_CLICKED);
CC(BUTTON4_RELEASED); CC(BUTTON4_PRESSED); CC(BUTTON4_CLICKED);
CC(BUTTON4_DOUBLE_CLICKED); CC(BUTTON4_TRIPLE_CLICKED);
CC(BUTTON_CTRL); CC(BUTTON_SHIFT); CC(BUTTON_ALT);
CC(REPORT_MOUSE_POSITION); CC(ALL_MOUSE_EVENTS);
#if NCURSES_MOUSE_VERSION > 1
CC(BUTTON5_RELEASED); CC(BUTTON5_PRESSED); CC(BUTTON5_CLICKED);
CC(BUTTON5_DOUBLE_CLICKED); CC(BUTTON5_TRIPLE_CLICKED);
#else
CC(BUTTON1_RESERVED_EVENT); CC(BUTTON2_RESERVED_EVENT);
CC(BUTTON3_RESERVED_EVENT); CC(BUTTON4_RESERVED_EVENT);
#endif
#endif
#endif
}
/*
@@ -731,6 +758,107 @@ static int lc_stdscr(lua_State *L)
LC_NUMBER2(COLS, COLS)
LC_NUMBER2(LINES, LINES)
/*
** =======================================================
** mouse
** =======================================================
*/
#ifndef XCURSES
#ifndef NOMOUSE
static int
lc_ungetmouse(lua_State *L)
{
MEVENT e;
e.bstate = luaL_checklong(L, 1);
e.x = luaL_checkint(L, 2);
e.y = luaL_checkint(L, 3);
e.z = luaL_checkint(L, 4);
e.id = luaL_checkint(L, 5);
lua_pushboolean(L, !(!ungetmouse(&e)));
return 1;
}
/***
Get a new mouse event
@function getmouse
@treturn unsigned long `bstate`, button state
@treturn int `x`, x coordinate
@treturn int `y`, y coordinate
@treturn int `z`, z coordinate
@treturn short `id`, ID to distinguish multiple devices
@see getmouse(3x)
*/
static int
lc_getmouse(lua_State *L)
{
MEVENT e;
if(getmouse(&e) == OK)
{
lua_pushinteger(L, e.bstate);
lua_pushinteger(L, e.x);
lua_pushinteger(L, e.y);
lua_pushinteger(L, e.z);
lua_pushinteger(L, e.id);
return 5;
}
lua_pushnil(L);
return 1;
}
/***
Set a new mouse mask
@function mousemask
@unsigned long `new_mask`, the new mask of mouse events
@treturn unsigned long `mask`, with the mask of reported events
@treturn unsigned long `oldmask`, with the previous mouse mask
@see mousemask(3x)
*/
static int
lc_mousemask(lua_State *L)
{
mmask_t m = luaL_checkint(L, 1);
mmask_t om;
m = mousemask(m, &om);
lua_pushinteger(L, m);
lua_pushinteger(L, om);
return 2;
}
/***
Sets the maximum time (in thousands of a second) that can elapse
between press and release events for them to be recognized as a click.
@function mouseinterval
@int time, the next time to be set or nothing to get the actual.
@treturn int returns the previous interval time
@see mouseinterval(3x)
*/
static int
lc_mouseinterval(lua_State *L)
{
if (!lua_gettop(L))
lua_pushinteger(L, mouseinterval(-1));
else
lua_pushinteger(L, mouseinterval(luaL_checkint(L, 1)));
return 1;
}
/***
Is the mouse driver initialized
@function has_mouse
@treturn bool `true`
@see has_mouse(3x)
*/
static int
lc_has_mouse(lua_State *L)
{
lua_pushboolean(L, has_mouse());
return 1;
}
#endif
#endif
/*
** =======================================================
** color
@@ -2315,6 +2443,16 @@ static const luaL_Reg curseslib[] =
/* outopts */
{ "nl", lc_nl },
#ifndef XCURSES
#ifndef NOMOUSE
{ "mousemask", lc_mousemask },
{ "mouseinterval", lc_mouseinterval},
{ "has_mouse", lc_has_mouse },
{ "getmouse", lc_getmouse },
{ "ungetmouse", lc_ungetmouse },
#endif
#endif
/* slk */
ECF(slk_init)
ECF(slk_set)

View File

@@ -76,6 +76,8 @@ event:register("cm_max", "cm_quit", "cm_exit", "cm_enter")
--
event.keyboard = object {_init = { "key_code", "key_name", "key_meta" }, type = event.ev_keyboard}
event.mouse = object {_init = { "bstate", "x", "y", "id" }, type = event.ev_mouse}
-- define command event
event.command = object {_init = { "command", "extra" }, type = event.ev_command}

View File

@@ -44,6 +44,11 @@ function program:init(name, argv)
-- disable newline
curses.nl(false)
-- init mouse support
if curses.KEY_MOUSE then
curses.mousemask(curses.BUTTON1_PRESSED)
end
-- to filter characters being output to the screen
-- this will filter all characters where a chtype or chstr is used
curses.map_output(true)
@@ -135,6 +140,10 @@ function program:event()
-- get input key
local key_code, key_name, key_meta = self:_input_key()
if key_code then
if key_code == curses.KEY_MOUSE then
local s, x, y, z, id = curses.getmouse()
return event.mouse{s, x, y, id}
end
return event.keyboard{key_code, key_name, key_meta}
end
end

91
tests/getch_test.lua Normal file
View File

@@ -0,0 +1,91 @@
--!A cross-platform terminal ui library based on Lua
--
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-2020, TBOOX Open Source Group.
--
-- @author ruki
-- @file window.lua
--
require("tests/load")
-- requires
local ltui = require("ltui")
local application = ltui.application
local event = ltui.event
local rect = ltui.rect
local window = ltui.window
local label = ltui.label
-- the demo application
local demo = application()
-- init demo
function demo:init()
-- init name
application.init(self, "demo")
-- init background
self:background_set("black")
-- init body window
self:insert(self:body_window())
-- init teste
self:body_window():panel():insert(self:teste())
end
-- get body window
function demo:body_window()
if not self._BODY_WINDOW then
self._BODY_WINDOW = window:new("window.body", rect {1, 1, self:width() - 1, self:height() - 1}, "main window")
end
return self._BODY_WINDOW
end
-- get teste label
function demo:teste()
if not self._TESTE then
self._TESTE = label:new('demo.label', rect {0, 0, 40, 5}, 'this is a test')
end
return self._TESTE
end
-- on resize
function demo:on_resize()
self:body_window():bounds_set(rect {1, 1, self:width() - 1, self:height() - 1})
application.on_resize(self)
end
-- on event
function demo:on_event(e)
if e.type < event.ev_max then
self:teste():text_set('tp: ' ..
tostring(e.type) ..
'; name: ' ..
tostring(e.key_name or e.bstate) ..
'; code: ' ..
tostring(e.key_code or e.x) ..
'; meta: ' ..
tostring(e.key_code or e.y))
end
application.on_event(self, e)
end
-- run demo
demo:run()