[GB.NCURSES]
* NEW: Add ReadLine() function to Window that does the same as ncurses getstr(3X) but usable in all input modes * NEW: Encapsulate Input, Cursor and Border modes into static objects * NEW: Tidy up Color class in various places * NEW: Specifiying color values is now done via floats instead of ints * NEW: Remove ContainerW and ContainerH (and corresponding long forms) properties from Window class. It is always .Width/.Height + 2 * NEW: Rename Input.Repeater to Input.RepeatDelay * OPT: Remove unnecessary ncurses input mode changes * OPT: Tidy up Input and Screen code * OPT: Reduce useless calls to input queue read callback in Screen class * BUG: Add constant for already implemented "very visible" cursor mode * BUG: Use opaque input module in Window.Ask() * BUG: Note that NoDelay and Window/Screen events still not work git-svn-id: svn://localhost/gambas/trunk@4827 867c0c6c-44f3-4631-809d-bfa615b0a4ec
This commit is contained in:
parent
35b390e5e1
commit
0a4dd6f9d2
11 changed files with 822 additions and 598 deletions
|
@ -13,5 +13,5 @@ gb_ncurses_la_SOURCES = \
|
||||||
c_key.h c_key.c \
|
c_key.h c_key.c \
|
||||||
c_color.h c_color.c \
|
c_color.h c_color.c \
|
||||||
c_screen.h c_screen.c \
|
c_screen.h c_screen.c \
|
||||||
input.h input.c
|
c_input.h c_input.c
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
#include "c_color.h"
|
#include "c_color.h"
|
||||||
#include "c_screen.h"
|
#include "c_screen.h"
|
||||||
|
|
||||||
static int _index;
|
|
||||||
static int _color;
|
static int _color;
|
||||||
|
static int _pair;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Colour initialisation
|
* Colour initialisation
|
||||||
|
@ -41,6 +41,50 @@ void COLOR_init()
|
||||||
use_default_colors();
|
use_default_colors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise a colour
|
||||||
|
* @index: the color number
|
||||||
|
* @r: red
|
||||||
|
* @g: green
|
||||||
|
* @b: blue
|
||||||
|
* Note that one gives colour amounts in floats 0.0 - 1.0
|
||||||
|
*/
|
||||||
|
int COLOR_setcolor(short index, float r, float g, float b)
|
||||||
|
{
|
||||||
|
return init_color(index, r * 1000, g * 1000, b * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise one field of a colour
|
||||||
|
* @index: color number
|
||||||
|
* @val: value as float 0.0 - 1.0
|
||||||
|
* @what: field number
|
||||||
|
*/
|
||||||
|
int COLOR_setcolor_one(short index, float val, int what)
|
||||||
|
{
|
||||||
|
short r, g, b;
|
||||||
|
float rf, gf, bf;
|
||||||
|
|
||||||
|
color_content(index, &r, &g, &b);
|
||||||
|
rf = ((float) r) / 1000;
|
||||||
|
gf = ((float) g) / 1000;
|
||||||
|
bf = ((float) b) / 1000;
|
||||||
|
switch (what) {
|
||||||
|
case 0:
|
||||||
|
rf = val;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
gf = val;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
bf = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return COLOR_setcolor(index, rf, gf, bf);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise a colour pair
|
* Initialise a colour pair
|
||||||
* @index: colour pair index
|
* @index: colour pair index
|
||||||
|
@ -105,81 +149,120 @@ static int COLOR_content(short color, short *r, short *g, short *b)
|
||||||
* Color static class
|
* Color static class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
BEGIN_PROPERTY(Color_Capabilities)
|
BEGIN_PROPERTY(Color_Available)
|
||||||
|
|
||||||
RETURN_SELF();
|
GB.ReturnBoolean(has_colors());
|
||||||
|
|
||||||
END_PROPERTY
|
END_PROPERTY
|
||||||
|
|
||||||
BEGIN_PROPERTY(Color_Colors)
|
BEGIN_PROPERTY(Color_CanChange)
|
||||||
|
|
||||||
|
GB.ReturnBoolean(can_change_color());
|
||||||
|
|
||||||
|
END_PROPERTY
|
||||||
|
|
||||||
|
BEGIN_PROPERTY(Color_Count)
|
||||||
|
|
||||||
GB.ReturnInteger(COLORS);
|
GB.ReturnInteger(COLORS);
|
||||||
|
|
||||||
END_PROPERTY
|
END_PROPERTY
|
||||||
|
|
||||||
BEGIN_PROPERTY(Color_Pairs)
|
|
||||||
|
|
||||||
GB.ReturnInteger(COLOR_PAIRS);
|
|
||||||
|
|
||||||
END_PROPERTY
|
|
||||||
|
|
||||||
BEGIN_METHOD(Color_get, GB_INTEGER index)
|
BEGIN_METHOD(Color_get, GB_INTEGER index)
|
||||||
|
|
||||||
if (!PAIR_VALID(VARG(index))) {
|
if (!COLOR_VALID(VARG(index))) {
|
||||||
GB.Error(GB_ERR_BOUND);
|
GB.Error(GB_ERR_BOUND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_index = VARG(index);
|
_color = VARG(index);
|
||||||
RETURN_SELF();
|
RETURN_SELF();
|
||||||
|
|
||||||
END_METHOD
|
END_METHOD
|
||||||
|
|
||||||
BEGIN_METHOD(Color_Define, GB_INTEGER color; GB_INTEGER r; GB_INTEGER g; GB_INTEGER b)
|
BEGIN_METHOD(Color_Set, GB_INTEGER color; GB_INTEGER r; GB_INTEGER g; GB_INTEGER b)
|
||||||
|
|
||||||
if (!COLOR_VALID(VARG(color))) {
|
if (!COLOR_VALID(VARG(color))) {
|
||||||
GB.Error(GB_ERR_BOUND);
|
GB.Error(GB_ERR_BOUND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
init_color(VARG(color), VARG(r), VARG(g), VARG(b));
|
init_color(VARG(color), VARG(r), VARG(g), VARG(b));
|
||||||
|
REFRESH();
|
||||||
|
|
||||||
END_METHOD
|
END_METHOD
|
||||||
|
|
||||||
BEGIN_METHOD(Color_Content, GB_INTEGER color)
|
/*
|
||||||
|
* .ColorInfo virtual class
|
||||||
|
*/
|
||||||
|
|
||||||
if (!COLOR_VALID(VARG(color))) {
|
BEGIN_PROPERTY(ColorInfo_Red)
|
||||||
|
|
||||||
|
short red;
|
||||||
|
|
||||||
|
if (READ_PROPERTY) {
|
||||||
|
COLOR_content(_color, &red, NULL, NULL);
|
||||||
|
GB.ReturnInteger(red);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
COLOR_setcolor_one(_color, VPROP(GB_FLOAT), 0);
|
||||||
|
REAL_REFRESH();
|
||||||
|
|
||||||
|
END_PROPERTY
|
||||||
|
|
||||||
|
BEGIN_PROPERTY(ColorInfo_Green)
|
||||||
|
|
||||||
|
short green;
|
||||||
|
|
||||||
|
if (READ_PROPERTY) {
|
||||||
|
COLOR_content(_color, NULL, &green, NULL);
|
||||||
|
GB.ReturnInteger(green);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
COLOR_setcolor_one(_color, VPROP(GB_FLOAT), 1);
|
||||||
|
|
||||||
|
END_PROPERTY
|
||||||
|
|
||||||
|
BEGIN_PROPERTY(ColorInfo_Blue)
|
||||||
|
|
||||||
|
short blue;
|
||||||
|
|
||||||
|
if (READ_PROPERTY) {
|
||||||
|
COLOR_content(_color, NULL, NULL, &blue);
|
||||||
|
GB.ReturnInteger(blue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
COLOR_setcolor_one(_color, VPROP(GB_FLOAT), 2);
|
||||||
|
|
||||||
|
END_PROPERTY
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pair static class
|
||||||
|
*/
|
||||||
|
|
||||||
|
BEGIN_PROPERTY(Pair_Count)
|
||||||
|
|
||||||
|
GB.ReturnInteger(COLOR_PAIRS);
|
||||||
|
|
||||||
|
END_PROPERTY
|
||||||
|
|
||||||
|
BEGIN_METHOD(Pair_get, GB_INTEGER index)
|
||||||
|
|
||||||
|
if (!PAIR_VALID(VARG(index))) {
|
||||||
GB.Error(GB_ERR_BOUND);
|
GB.Error(GB_ERR_BOUND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_color = VARG(color);
|
_pair = VARG(index);
|
||||||
RETURN_SELF();
|
RETURN_SELF();
|
||||||
|
|
||||||
END_METHOD
|
END_METHOD
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* .Color.Capabilities virtual class
|
* .PairInfo virtual class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
BEGIN_PROPERTY(ColorCapabilities_Change)
|
BEGIN_PROPERTY(PairInfo_Background)
|
||||||
|
|
||||||
GB.ReturnBoolean(can_change_color());
|
|
||||||
|
|
||||||
END_PROPERTY
|
|
||||||
|
|
||||||
BEGIN_PROPERTY(ColorCapabilities_Color)
|
|
||||||
|
|
||||||
GB.ReturnBoolean(has_colors());
|
|
||||||
|
|
||||||
END_PROPERTY
|
|
||||||
|
|
||||||
/*
|
|
||||||
* .Color.Pair virtual class
|
|
||||||
*/
|
|
||||||
|
|
||||||
BEGIN_PROPERTY(ColorPair_Background)
|
|
||||||
|
|
||||||
short f, b;
|
short f, b;
|
||||||
|
|
||||||
pair_content(_index, &f, &b);
|
pair_content(_pair, &f, &b);
|
||||||
if (READ_PROPERTY) {
|
if (READ_PROPERTY) {
|
||||||
GB.ReturnInteger(b);
|
GB.ReturnInteger(b);
|
||||||
return;
|
return;
|
||||||
|
@ -189,17 +272,17 @@ BEGIN_PROPERTY(ColorPair_Background)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
b = VPROP(GB_INTEGER);
|
b = VPROP(GB_INTEGER);
|
||||||
COLOR_setpair(_index, f, b);
|
COLOR_setpair(_pair, f, b);
|
||||||
REAL_REFRESH();
|
REAL_REFRESH();
|
||||||
|
|
||||||
|
|
||||||
END_PROPERTY
|
END_PROPERTY
|
||||||
|
|
||||||
BEGIN_PROPERTY(ColorPair_Foreground)
|
BEGIN_PROPERTY(PairInfo_Foreground)
|
||||||
|
|
||||||
short f, b;
|
short f, b;
|
||||||
|
|
||||||
pair_content(_index, &f, &b);
|
pair_content(_pair, &f, &b);
|
||||||
if (READ_PROPERTY) {
|
if (READ_PROPERTY) {
|
||||||
GB.ReturnInteger(f);
|
GB.ReturnInteger(f);
|
||||||
return;
|
return;
|
||||||
|
@ -209,44 +292,12 @@ BEGIN_PROPERTY(ColorPair_Foreground)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
f = VPROP(GB_INTEGER);
|
f = VPROP(GB_INTEGER);
|
||||||
COLOR_setpair(_index, f, b);
|
COLOR_setpair(_pair, f, b);
|
||||||
REAL_REFRESH();
|
REAL_REFRESH();
|
||||||
|
|
||||||
END_PROPERTY
|
END_PROPERTY
|
||||||
|
|
||||||
/*
|
GB_DESC CColorDesc[] = {
|
||||||
* .Color.Content virtual class
|
|
||||||
*/
|
|
||||||
|
|
||||||
BEGIN_PROPERTY(ColorContent_Red)
|
|
||||||
|
|
||||||
short red;
|
|
||||||
|
|
||||||
COLOR_content(_color, &red, NULL, NULL);
|
|
||||||
GB.ReturnInteger(red);
|
|
||||||
|
|
||||||
END_PROPERTY
|
|
||||||
|
|
||||||
BEGIN_PROPERTY(ColorContent_Green)
|
|
||||||
|
|
||||||
short green;
|
|
||||||
|
|
||||||
COLOR_content(_color, NULL, &green, NULL);
|
|
||||||
GB.ReturnInteger(green);
|
|
||||||
|
|
||||||
END_PROPERTY
|
|
||||||
|
|
||||||
BEGIN_PROPERTY(ColorContent_Blue)
|
|
||||||
|
|
||||||
short blue;
|
|
||||||
|
|
||||||
COLOR_content(_color, NULL, NULL, &blue);
|
|
||||||
GB.ReturnInteger(blue);
|
|
||||||
|
|
||||||
END_PROPERTY
|
|
||||||
|
|
||||||
GB_DESC CColorDesc[] =
|
|
||||||
{
|
|
||||||
GB_DECLARE("Color", 0),
|
GB_DECLARE("Color", 0),
|
||||||
GB_NOT_CREATABLE(),
|
GB_NOT_CREATABLE(),
|
||||||
|
|
||||||
|
@ -259,47 +310,44 @@ GB_DESC CColorDesc[] =
|
||||||
GB_CONSTANT("Cyan", "i", COLOR_CYAN),
|
GB_CONSTANT("Cyan", "i", COLOR_CYAN),
|
||||||
GB_CONSTANT("White", "i", COLOR_WHITE),
|
GB_CONSTANT("White", "i", COLOR_WHITE),
|
||||||
|
|
||||||
GB_STATIC_PROPERTY_READ("Capabilities", ".Color.Capabilities", Color_Capabilities),
|
GB_STATIC_PROPERTY_READ("Available", "b", Color_Available),
|
||||||
GB_STATIC_PROPERTY_READ("Colors", "i", Color_Colors),
|
GB_STATIC_PROPERTY_READ("CanChange", "b", Color_CanChange),
|
||||||
GB_STATIC_PROPERTY_READ("Pairs", "i", Color_Pairs),
|
GB_STATIC_PROPERTY_READ("Count", "i", Color_Count),
|
||||||
|
|
||||||
GB_STATIC_METHOD("_get", ".Color.Pair", Color_get, "(Index)i"),
|
GB_STATIC_METHOD("_get", ".ColorInfo", Color_get, "(Index)i"),
|
||||||
GB_STATIC_METHOD("Define", NULL, Color_Define, "(Color)i(R)i(G)i(B)i"),
|
GB_STATIC_METHOD("Set", NULL, Color_Set, "(Color)i(R)i(G)i(B)i"),
|
||||||
GB_STATIC_METHOD("Content", ".Color.Content", Color_Content, "(Color)i"),
|
|
||||||
|
|
||||||
GB_END_DECLARE
|
GB_END_DECLARE
|
||||||
};
|
};
|
||||||
|
|
||||||
GB_DESC CColorCapabilitiesDesc[] =
|
GB_DESC CColorInfoDesc[] = {
|
||||||
{
|
GB_DECLARE(".ColorInfo", 0),
|
||||||
GB_DECLARE(".Color.Capabilities", 0),
|
|
||||||
GB_VIRTUAL_CLASS(),
|
GB_VIRTUAL_CLASS(),
|
||||||
|
|
||||||
GB_STATIC_PROPERTY_READ("Color", "b", ColorCapabilities_Color),
|
GB_STATIC_PROPERTY("Red", "i", ColorInfo_Red),
|
||||||
GB_STATIC_PROPERTY_READ("Change", "b", ColorCapabilities_Change),
|
GB_STATIC_PROPERTY("Green", "i", ColorInfo_Green),
|
||||||
|
GB_STATIC_PROPERTY("Blue", "i", ColorInfo_Blue),
|
||||||
|
|
||||||
GB_END_DECLARE
|
GB_END_DECLARE
|
||||||
};
|
};
|
||||||
|
|
||||||
GB_DESC CColorPairDesc[] =
|
GB_DESC CPairDesc[] = {
|
||||||
{
|
GB_DECLARE("Pair", 0),
|
||||||
GB_DECLARE(".Color.Pair", 0),
|
GB_NOT_CREATABLE(),
|
||||||
|
|
||||||
|
GB_STATIC_PROPERTY_READ("Count", "i", Pair_Count),
|
||||||
|
|
||||||
|
GB_STATIC_METHOD("_get", ".PairInfo", Pair_get, "(Index)i"),
|
||||||
|
|
||||||
|
GB_END_DECLARE
|
||||||
|
};
|
||||||
|
|
||||||
|
GB_DESC CPairInfoDesc[] = {
|
||||||
|
GB_DECLARE(".PairInfo", 0),
|
||||||
GB_VIRTUAL_CLASS(),
|
GB_VIRTUAL_CLASS(),
|
||||||
|
|
||||||
GB_STATIC_PROPERTY("Background", "i", ColorPair_Background),
|
GB_STATIC_PROPERTY("Background", "i", PairInfo_Background),
|
||||||
GB_STATIC_PROPERTY("Foreground", "i", ColorPair_Foreground),
|
GB_STATIC_PROPERTY("Foreground", "i", PairInfo_Foreground),
|
||||||
|
|
||||||
GB_END_DECLARE
|
|
||||||
};
|
|
||||||
|
|
||||||
GB_DESC CColorContentDesc[] =
|
|
||||||
{
|
|
||||||
GB_DECLARE(".Color.Content", 0),
|
|
||||||
GB_VIRTUAL_CLASS(),
|
|
||||||
|
|
||||||
GB_STATIC_PROPERTY_READ("Red", "i", ColorContent_Red),
|
|
||||||
GB_STATIC_PROPERTY_READ("Green", "i", ColorContent_Green),
|
|
||||||
GB_STATIC_PROPERTY_READ("Blue", "i", ColorContent_Blue),
|
|
||||||
|
|
||||||
GB_END_DECLARE
|
GB_END_DECLARE
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
#ifndef __C_COLOR_C
|
#ifndef __C_COLOR_C
|
||||||
extern GB_DESC CColorDesc[];
|
extern GB_DESC CColorDesc[];
|
||||||
extern GB_DESC CColorCapabilitiesDesc[];
|
extern GB_DESC CColorInfoDesc[];
|
||||||
extern GB_DESC CColorPairDesc[];
|
extern GB_DESC CPairDesc[];
|
||||||
extern GB_DESC CColorContentDesc[];
|
extern GB_DESC CPairInfoDesc[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -19,7 +19,9 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
void COLOR_init();
|
void COLOR_init();
|
||||||
int COLOR_setpair(short index, short fg, short bg);
|
int COLOR_setcolor(short, float, float, float);
|
||||||
int COLOR_setpair_one(short index, short val, int what);
|
int COLOR_setcolor_one(short, float, int);
|
||||||
|
int COLOR_setpair(short, short, short);
|
||||||
|
int COLOR_setpair_one(short, short, int);
|
||||||
|
|
||||||
#endif /* __C_COLOR_H */
|
#endif /* __C_COLOR_H */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* input.c - gb.ncurses opaque input routines
|
* c_input.c - gb.ncurses opaque input routines
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Tobias Boege <tobias@gambas-buch.de>
|
* Copyright (C) 2012 Tobias Boege <tobias@gambas-buch.de>
|
||||||
*
|
*
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
* MA 02110-1301, USA.
|
* MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define __INPUT_C
|
#define __C_INPUT_C
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -36,32 +36,17 @@
|
||||||
#include "gb_common.h"
|
#include "gb_common.h"
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "input.h"
|
#include "c_input.h"
|
||||||
#include "c_window.h"
|
#include "c_window.h"
|
||||||
|
|
||||||
#define E_UNSUPP "Unsupported value"
|
#define E_UNSUPP "Unsupported value"
|
||||||
#define E_NO_NODELAY "Could not initialise NoDelay mode"
|
#define E_NO_NODELAY "Could not initialise NoDelay mode"
|
||||||
|
|
||||||
|
/* True input mode is inherited from terminal, we need a surely invalid
|
||||||
|
* value to be reset upon initialisation */
|
||||||
static int _input = -1;
|
static int _input = -1;
|
||||||
static char _watching = 0;
|
|
||||||
|
|
||||||
/* Note that this is not safe for functions that are used to change the mode
|
|
||||||
* settings, in particular INPUT_init_nodelay() and INPUT_exit_nodelay(),
|
|
||||||
* because @_input is updated after this function */
|
|
||||||
#define IN_NODELAY (_input == INPUT_NODELAY)
|
#define IN_NODELAY (_input == INPUT_NODELAY)
|
||||||
|
static char _watch_fd = -1;
|
||||||
static struct {
|
|
||||||
struct {
|
|
||||||
struct termios term;
|
|
||||||
int kbmode;
|
|
||||||
void (*error_hook)();
|
|
||||||
} old;
|
|
||||||
int fd;
|
|
||||||
unsigned short pressed;
|
|
||||||
unsigned int delay;
|
|
||||||
GB_TIMER *timer;
|
|
||||||
} no_delay;
|
|
||||||
static char _exiting_nodelay = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input initialisation
|
* Input initialisation
|
||||||
|
@ -69,7 +54,8 @@ static char _exiting_nodelay = 0;
|
||||||
int INPUT_init()
|
int INPUT_init()
|
||||||
{
|
{
|
||||||
INPUT_mode(INPUT_CBREAK);
|
INPUT_mode(INPUT_CBREAK);
|
||||||
INPUT_repeater_delay(100);
|
INPUT_watch(0);
|
||||||
|
NODELAY_repeater_delay(1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,179 +70,46 @@ void INPUT_exit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Begin or stop watching the input queue in question depending on @_input
|
|
||||||
*/
|
|
||||||
static int INPUT_watch(char start)
|
|
||||||
{
|
|
||||||
int fd = IN_NODELAY ? no_delay.fd : 0;
|
|
||||||
|
|
||||||
if (!start && !_watching)
|
|
||||||
|
#define MY_DEBUG() fprintf(stderr, "in %s\n", __func__)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin watching the given fd (for read)
|
||||||
|
* @fd: fd to watch. -1 means to stop watching at all.
|
||||||
|
* This automatically stops watching the previously watched fd, if any
|
||||||
|
*/
|
||||||
|
static int INPUT_watch(int fd)
|
||||||
|
{
|
||||||
|
MY_DEBUG();
|
||||||
|
|
||||||
|
if (fd == _watch_fd)
|
||||||
return 0;
|
return 0;
|
||||||
if (start && _watching)
|
|
||||||
INPUT_watch(!start);
|
if (_watch_fd != -1)
|
||||||
GB.Watch(fd, start ? GB_WATCH_READ : GB_WATCH_NONE,
|
GB.Watch(_watch_fd, GB_WATCH_NONE, NULL, 0);
|
||||||
INPUT_callback, 0);
|
if (fd == -1)
|
||||||
_watching = start;
|
return 0;
|
||||||
|
|
||||||
|
GB.Watch(fd, GB_WATCH_READ, INPUT_callback, 0);
|
||||||
|
_watch_fd = fd;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to be called by Gambas when data arrives
|
* Function to be called by Gambas when data arrives
|
||||||
|
* Params currently not used
|
||||||
*/
|
*/
|
||||||
static void INPUT_callback(int fd, int flag, intptr_t arg)
|
static void INPUT_callback(int fd, int flag, intptr_t arg)
|
||||||
{
|
{
|
||||||
WINDOW_raise_read(NULL);
|
MY_DEBUG();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/* if (IN_NODELAY)
|
||||||
* Return if the given fd can be used with console_ioctls
|
NODELAY_change_pressed(NODELAY_get(-1));
|
||||||
* @fd: file descriptor to test
|
else
|
||||||
* The idea was derived from "kbd" package, getfd.c, is_a_console()
|
*/ WINDOW_raise_read(NULL);
|
||||||
*/
|
|
||||||
static inline char is_cons(int fd)
|
|
||||||
{
|
|
||||||
char type;
|
|
||||||
|
|
||||||
if (fd != -1 && isatty(fd) && ioctl(fd, KDGKBTYPE, &type) != -1
|
|
||||||
&& (type == KB_101 || type == KB_84))
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an fd that can be used with console_ioctls or -1 if none
|
|
||||||
* available
|
|
||||||
*/
|
|
||||||
int INPUT_consolefd()
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (is_cons(0))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fd = open("/dev/tty", O_RDWR);
|
|
||||||
if (fd == -1)
|
|
||||||
return -1;
|
|
||||||
if (is_cons(fd))
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init NoDelay mode
|
|
||||||
* We save old settings and prepare the TTY driver and Gambas
|
|
||||||
*/
|
|
||||||
static int INPUT_init_nodelay()
|
|
||||||
{
|
|
||||||
int fd = INPUT_consolefd();
|
|
||||||
struct termios term;
|
|
||||||
|
|
||||||
if (fd == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* TODO: implement switching between vts, need available signals to
|
|
||||||
* be sent */
|
|
||||||
|
|
||||||
tcgetattr(fd, &no_delay.old.term);
|
|
||||||
ioctl(fd, KDGKBMODE, &no_delay.old.kbmode);
|
|
||||||
|
|
||||||
memcpy(&term, &no_delay.old.term, sizeof(term));
|
|
||||||
term.c_lflag &= ~(ICANON | ECHO | ISIG);
|
|
||||||
term.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
|
|
||||||
/* Have no timeout per default */
|
|
||||||
term.c_cc[VMIN] = 0;
|
|
||||||
term.c_cc[VTIME] = -1;
|
|
||||||
tcsetattr(fd, TCSAFLUSH, &term);
|
|
||||||
no_delay.old.error_hook = GB.Hook(GB_HOOK_ERROR,
|
|
||||||
INPUT_nodelay_error_hook);
|
|
||||||
|
|
||||||
no_delay.fd = fd;
|
|
||||||
|
|
||||||
no_delay.timer = NULL;
|
|
||||||
|
|
||||||
/* Switch to K_MEDIUMRAW now. Could not have been done on-the-fly
|
|
||||||
* when reading from the console fd, because our key repeat code
|
|
||||||
* relies on data maybe present on that fd (to determine if we can
|
|
||||||
* safely inject new events for the currently pressed key or shall
|
|
||||||
* examine if there is another keypress) and there wouldn't be
|
|
||||||
* anything if we switch on-the-fly */
|
|
||||||
ioctl(no_delay.fd, KDSKBMODE, K_MEDIUMRAW);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleanup NoDelay mode
|
|
||||||
* Restore old settings
|
|
||||||
* This assumes that @_input reflects the current settings
|
|
||||||
*/
|
|
||||||
static int INPUT_exit_nodelay()
|
|
||||||
{
|
|
||||||
/* @_input must be updated after this function, if even, after this
|
|
||||||
* function */
|
|
||||||
if (!IN_NODELAY)
|
|
||||||
return 0;
|
|
||||||
if (_exiting_nodelay)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
_exiting_nodelay = 1;
|
|
||||||
ioctl(no_delay.fd, KDSKBMODE, no_delay.old.kbmode);
|
|
||||||
tcsetattr(no_delay.fd, TCSANOW, &no_delay.old.term);
|
|
||||||
GB.Hook(GB_HOOK_ERROR, no_delay.old.error_hook);
|
|
||||||
if (no_delay.timer)
|
|
||||||
GB.Unref((void **) &no_delay.timer);
|
|
||||||
close(no_delay.fd);
|
|
||||||
_exiting_nodelay = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The NoDelay mode error hook
|
|
||||||
* This calls the former error hook, saved by INPUT_init_nodelay() to not
|
|
||||||
* disturb any piece code
|
|
||||||
*/
|
|
||||||
static void INPUT_nodelay_error_hook()
|
|
||||||
{
|
|
||||||
if (_exiting_nodelay)
|
|
||||||
return;
|
|
||||||
INPUT_exit_nodelay();
|
|
||||||
no_delay.old.error_hook();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return or set the repeater delay
|
|
||||||
* @val: value to set the delay to. This value must be at least 1 or an
|
|
||||||
* error is returned. If it is REPEATER_RETURN, the current value is
|
|
||||||
* returned to the caller.
|
|
||||||
* Note that this setting affects the repeater function itself, that gets
|
|
||||||
* called in this interval to generate events and the INPUT_get_nodelay()
|
|
||||||
* function which will wait to return the amount of milliseconds if it is to
|
|
||||||
* return the pressed key.
|
|
||||||
*/
|
|
||||||
int INPUT_repeater_delay(int val)
|
|
||||||
{
|
|
||||||
if (val == REPEATER_RETURN)
|
|
||||||
return no_delay.delay;
|
|
||||||
if (val < 1)
|
|
||||||
return -1;
|
|
||||||
no_delay.delay = (unsigned int) val;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NoDelay mode event repeater
|
|
||||||
* Used to insert Window_Read events if there is a key pressed
|
|
||||||
*/
|
|
||||||
static int INPUT_nodelay_repeater()
|
|
||||||
{
|
|
||||||
fprintf(stderr, "here\n");
|
|
||||||
if (!no_delay.pressed)
|
|
||||||
return TRUE;
|
|
||||||
WINDOW_raise_read(NULL);
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -271,26 +124,21 @@ int INPUT_mode(int mode)
|
||||||
if (mode == _input)
|
if (mode == _input)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
INPUT_watch(0);
|
if (IN_NODELAY)
|
||||||
|
NODELAY_exit();
|
||||||
if (_input == INPUT_NODELAY)
|
|
||||||
INPUT_exit_nodelay();
|
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case INPUT_COOKED:
|
case INPUT_COOKED:
|
||||||
noraw();
|
|
||||||
nocbreak();
|
nocbreak();
|
||||||
break;
|
break;
|
||||||
case INPUT_CBREAK:
|
case INPUT_CBREAK:
|
||||||
noraw();
|
|
||||||
cbreak();
|
cbreak();
|
||||||
break;
|
break;
|
||||||
case INPUT_RAW:
|
case INPUT_RAW:
|
||||||
nocbreak();
|
|
||||||
raw();
|
raw();
|
||||||
break;
|
break;
|
||||||
case INPUT_NODELAY:
|
case INPUT_NODELAY:
|
||||||
if (INPUT_init_nodelay() == -1) {
|
if (NODELAY_init() == -1) {
|
||||||
GB.Error(E_NO_NODELAY);
|
GB.Error(E_NO_NODELAY);
|
||||||
/* We return 0 to not override the previous
|
/* We return 0 to not override the previous
|
||||||
* error message with the one emitted by the
|
* error message with the one emitted by the
|
||||||
|
@ -304,11 +152,20 @@ int INPUT_mode(int mode)
|
||||||
}
|
}
|
||||||
_input = mode;
|
_input = mode;
|
||||||
|
|
||||||
INPUT_watch(1);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drain the input queue
|
||||||
|
*/
|
||||||
|
void INPUT_drain()
|
||||||
|
{
|
||||||
|
if (IN_NODELAY)
|
||||||
|
NODELAY_drain();
|
||||||
|
else
|
||||||
|
flushinp();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve input from ncurses
|
* Retrieve input from ncurses
|
||||||
*/
|
*/
|
||||||
|
@ -332,8 +189,261 @@ static int INPUT_get_ncurses(int timeout)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a keypress within the given timeout
|
||||||
|
* @timeout: number of milliseconds to wait. If no key is pressed during it,
|
||||||
|
* 0 will be returned.
|
||||||
|
*/
|
||||||
|
int INPUT_get(int timeout)
|
||||||
|
{
|
||||||
|
if (IN_NODELAY)
|
||||||
|
return NODELAY_get(timeout);
|
||||||
|
else
|
||||||
|
return INPUT_get_ncurses(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
BEGIN_PROPERTY(Input_IsConsole)
|
||||||
|
|
||||||
|
int fd = NODELAY_consolefd();
|
||||||
|
|
||||||
|
if (fd == -1) {
|
||||||
|
GB.ReturnBoolean(FALSE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
GB.ReturnBoolean(TRUE);
|
||||||
|
|
||||||
|
END_PROPERTY
|
||||||
|
|
||||||
|
BEGIN_PROPERTY(Input_RepeatDelay)
|
||||||
|
|
||||||
|
if (READ_PROPERTY) {
|
||||||
|
GB.ReturnInteger(NODELAY_repeater_delay(REPEATER_RETURN));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (NODELAY_repeater_delay(VPROP(GB_INTEGER)) == -1) {
|
||||||
|
GB.Error("Invalid value");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
END_PROPERTY
|
||||||
|
|
||||||
|
GB_DESC CInputDesc[] = {
|
||||||
|
GB_DECLARE("Input", 0),
|
||||||
|
GB_NOT_CREATABLE(),
|
||||||
|
|
||||||
|
GB_CONSTANT("NoTimeout", "i", TIMEOUT_NOTIMEOUT),
|
||||||
|
|
||||||
|
GB_CONSTANT("Cooked", "i", INPUT_COOKED),
|
||||||
|
GB_CONSTANT("CBreak", "i", INPUT_CBREAK),
|
||||||
|
GB_CONSTANT("Raw", "i", INPUT_RAW),
|
||||||
|
GB_CONSTANT("NoDelay", "i", INPUT_NODELAY),
|
||||||
|
|
||||||
|
GB_STATIC_PROPERTY_READ("IsConsole", "b", Input_IsConsole),
|
||||||
|
GB_STATIC_PROPERTY("RepeatDelay", "i", Input_RepeatDelay),
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return codes from INPUT_trans_keycode()
|
* NODELAY routines
|
||||||
|
*/
|
||||||
|
static struct {
|
||||||
|
struct {
|
||||||
|
struct termios term;
|
||||||
|
int kbmode;
|
||||||
|
void (*error_hook)();
|
||||||
|
} old;
|
||||||
|
int fd;
|
||||||
|
unsigned short pressed;
|
||||||
|
unsigned int delay;
|
||||||
|
GB_TIMER *timer;
|
||||||
|
} no_delay;
|
||||||
|
static char _exiting_nodelay = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init NoDelay mode
|
||||||
|
* We save old settings and prepare the TTY driver and Gambas
|
||||||
|
* Precisely:
|
||||||
|
* - (TTY driver:)
|
||||||
|
* - Save all related values
|
||||||
|
* - Set terminal to (ncurses) raw()-like input mode as base for NoDelay
|
||||||
|
* - Set keyboard to K_MEDIUMRAW mode to see key make and break codes
|
||||||
|
* - (Gambas:)
|
||||||
|
* - Install specific error hook
|
||||||
|
* - Reset repeater timer
|
||||||
|
* - Begin watching console fd
|
||||||
|
*/
|
||||||
|
static int NODELAY_init()
|
||||||
|
{
|
||||||
|
int fd = NODELAY_consolefd();
|
||||||
|
struct termios term;
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* TODO: implement switching between vts, need available signals to
|
||||||
|
* be sent */
|
||||||
|
|
||||||
|
tcgetattr(fd, &no_delay.old.term);
|
||||||
|
ioctl(fd, KDGKBMODE, &no_delay.old.kbmode);
|
||||||
|
|
||||||
|
memcpy(&term, &no_delay.old.term, sizeof(term));
|
||||||
|
term.c_lflag &= ~(ICANON | ECHO | ISIG);
|
||||||
|
term.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
|
||||||
|
/* Have no timeout per default */
|
||||||
|
term.c_cc[VMIN] = 0;
|
||||||
|
term.c_cc[VTIME] = TIMEOUT_NOTIMEOUT;
|
||||||
|
tcsetattr(fd, TCSAFLUSH, &term);
|
||||||
|
no_delay.old.error_hook = GB.Hook(GB_HOOK_ERROR,
|
||||||
|
NODELAY_error_hook);
|
||||||
|
no_delay.fd = fd;
|
||||||
|
|
||||||
|
no_delay.timer = NULL;
|
||||||
|
|
||||||
|
ioctl(no_delay.fd, KDSKBMODE, K_MEDIUMRAW);
|
||||||
|
|
||||||
|
INPUT_watch(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup NoDelay mode
|
||||||
|
* Restore old settings, see NODELAY_init() for details
|
||||||
|
* This function gets called by our error hook and the error hook is removed
|
||||||
|
* here. When removing a hook, it gets automatically called: Hence
|
||||||
|
* @_exiting_nodelay
|
||||||
|
*/
|
||||||
|
static int NODELAY_exit()
|
||||||
|
{
|
||||||
|
if (_exiting_nodelay)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
_exiting_nodelay = 1;
|
||||||
|
|
||||||
|
INPUT_watch(0);
|
||||||
|
|
||||||
|
ioctl(no_delay.fd, KDSKBMODE, no_delay.old.kbmode);
|
||||||
|
|
||||||
|
if (no_delay.timer)
|
||||||
|
GB.Unref((void **) &no_delay.timer);
|
||||||
|
|
||||||
|
GB.Hook(GB_HOOK_ERROR, no_delay.old.error_hook);
|
||||||
|
tcsetattr(no_delay.fd, TCSANOW, &no_delay.old.term);
|
||||||
|
|
||||||
|
close(no_delay.fd);
|
||||||
|
|
||||||
|
_exiting_nodelay = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The NoDelay mode error hook
|
||||||
|
* This calls the former error hook, saved by NODELAY_init() to not
|
||||||
|
* disturb any piece code
|
||||||
|
*/
|
||||||
|
static void NODELAY_error_hook()
|
||||||
|
{
|
||||||
|
if (_exiting_nodelay)
|
||||||
|
return;
|
||||||
|
NODELAY_exit();
|
||||||
|
no_delay.old.error_hook();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return if the given fd can be used with console_ioctls
|
||||||
|
* @fd: file descriptor to test
|
||||||
|
* The idea was derived from "kbd" package, getfd.c, is_a_console()
|
||||||
|
*/
|
||||||
|
static inline char NODELAY_is_cons(int fd)
|
||||||
|
{
|
||||||
|
char type;
|
||||||
|
|
||||||
|
if (fd != -1 && isatty(fd) && ioctl(fd, KDGKBTYPE, &type) != -1
|
||||||
|
&& (type == KB_101 || type == KB_84))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an fd that can be used with console_ioctls or -1 if none
|
||||||
|
* available
|
||||||
|
*/
|
||||||
|
static int NODELAY_consolefd()
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (NODELAY_is_cons(0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fd = open("/dev/tty", O_RDWR);
|
||||||
|
if (fd == -1)
|
||||||
|
return -1;
|
||||||
|
if (NODELAY_is_cons(fd))
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drain NoDelay input queue
|
||||||
|
*/
|
||||||
|
static inline void NODELAY_drain()
|
||||||
|
{
|
||||||
|
tcflush(no_delay.fd, TCIFLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return or set the repeater delay
|
||||||
|
* @val: value to set the delay to. This value must be at least 1 or an
|
||||||
|
* error is returned. If it is REPEATER_RETURN, the current value is
|
||||||
|
* returned to the caller.
|
||||||
|
* Note that this setting affects the repeater function itself, that gets
|
||||||
|
* called in this interval to generate events and the INPUT_get_nodelay()
|
||||||
|
* function which will wait to return the amount of milliseconds if it is to
|
||||||
|
* return the pressed key.
|
||||||
|
*/
|
||||||
|
static int NODELAY_repeater_delay(int val)
|
||||||
|
{
|
||||||
|
if (val == REPEATER_RETURN)
|
||||||
|
return no_delay.delay;
|
||||||
|
if (val < 1)
|
||||||
|
return -1;
|
||||||
|
no_delay.delay = (unsigned int) val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post callback to insert new read event during next event loop.
|
||||||
|
* This is important because the NODELAY_repeater() gets called by the
|
||||||
|
* timer. If we raise an event from there, the event handler may destroy the
|
||||||
|
* timer we are currently in by issuing a NODELAY_change_pressed(). This has
|
||||||
|
* consequently be done outside the timer tick.
|
||||||
|
* @arg: unused
|
||||||
|
*/
|
||||||
|
static void NODELAY_post_read(intptr_t arg)
|
||||||
|
{
|
||||||
|
WINDOW_raise_read(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NoDelay mode event repeater. This function is the timer callback
|
||||||
|
* Used to insert Window_Read events if there is a key pressed
|
||||||
|
*/
|
||||||
|
static int NODELAY_repeater()
|
||||||
|
{
|
||||||
|
MY_DEBUG();
|
||||||
|
|
||||||
|
|
||||||
|
if (!no_delay.pressed)
|
||||||
|
return TRUE;
|
||||||
|
GB.Post(NODELAY_post_read, 0);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return codes from NODELAY_trans_keycode()
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
TRANS_NEED_MORE = -1,
|
TRANS_NEED_MORE = -1,
|
||||||
|
@ -366,19 +476,23 @@ enum {
|
||||||
* we exploit ncurses key_defined() routine to translate the sequence to an
|
* we exploit ncurses key_defined() routine to translate the sequence to an
|
||||||
* int for us. This gives an int like ncurses getch() would do.
|
* int for us. This gives an int like ncurses getch() would do.
|
||||||
*/
|
*/
|
||||||
static int INPUT_trans_keycode(unsigned char kc)
|
static int NODELAY_trans_keycode(unsigned char kc)
|
||||||
{
|
{
|
||||||
/* Pause/Break has the largest scancode: e1 1d 45 e1 9d c5 */
|
/* Pause/Break has the largest scancode: e1 1d 45 e1 9d c5 */
|
||||||
static unsigned char codes[8];
|
static unsigned char codes[8];
|
||||||
static int num = 0;
|
static int num = 0;
|
||||||
static int modifiers = MOD_NONE;
|
static int modifiers = MOD_NONE;
|
||||||
|
|
||||||
unsigned char seq[8];
|
|
||||||
struct kbentry kbe;
|
struct kbentry kbe;
|
||||||
struct kbsentry kbs;
|
struct kbsentry kbs;
|
||||||
register int mod;
|
register int mod;
|
||||||
|
|
||||||
/* TODO: Hope they're fixed */
|
|
||||||
|
|
||||||
|
MY_DEBUG();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define KEYCODE_LCTRL 0x1d
|
#define KEYCODE_LCTRL 0x1d
|
||||||
#define KEYCODE_RCTRL 0x61
|
#define KEYCODE_RCTRL 0x61
|
||||||
#define KEYCODE_ALT 0x38
|
#define KEYCODE_ALT 0x38
|
||||||
|
@ -417,7 +531,7 @@ account_key:
|
||||||
return TRANS_NEED_MORE;
|
return TRANS_NEED_MORE;
|
||||||
}
|
}
|
||||||
/* Keys with two keycodes, no matter, those correspond to
|
/* Keys with two keycodes, no matter, those correspond to
|
||||||
* single-keycode keys, we can safely use @kc */
|
* single-keycode keys, we can safely use @kc != 0xe0 */
|
||||||
if (codes[0] == '\xe0' && num != 2)
|
if (codes[0] == '\xe0' && num != 2)
|
||||||
return TRANS_NEED_MORE;
|
return TRANS_NEED_MORE;
|
||||||
|
|
||||||
|
@ -437,35 +551,39 @@ account_key:
|
||||||
kbe.kb_index = kc & 0x7f;
|
kbe.kb_index = kc & 0x7f;
|
||||||
kbe.kb_value = 0;
|
kbe.kb_value = 0;
|
||||||
ioctl(no_delay.fd, KDGKBENT, &kbe);
|
ioctl(no_delay.fd, KDGKBENT, &kbe);
|
||||||
seq[0] = (unsigned char) kbe.kb_value;
|
|
||||||
/* Has an escape sequence? */
|
/* Has an escape sequence? */
|
||||||
kbs.kb_func = seq[0];
|
kbs.kb_func = (unsigned char) kbe.kb_value;
|
||||||
ioctl(no_delay.fd, KDGKBSENT, &kbs);
|
ioctl(no_delay.fd, KDGKBSENT, &kbs);
|
||||||
if (kbs.kb_string[0]) {
|
if (kbs.kb_string[0])
|
||||||
strncpy((char *) seq, (char *) kbs.kb_string, 7);
|
return key_defined((char *) kbs.kb_string);
|
||||||
seq[7] = '\0';
|
else
|
||||||
return key_defined((char *) seq);
|
return (int) ((unsigned char) kbe.kb_value);
|
||||||
} else {
|
|
||||||
return (int) seq[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the currently pressed key
|
* Change the currently pressed key
|
||||||
* @key: current key. 0 means that no key is pressed
|
* @key: current key. 0 means that no key is pressed
|
||||||
* This install the repeater
|
* This installs the repeater
|
||||||
*/
|
*/
|
||||||
static void INPUT_change_pressed(int key)
|
static void NODELAY_change_pressed(int key)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%d\n", no_delay.delay);
|
|
||||||
|
|
||||||
|
MY_DEBUG();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* if (key == no_delay.pressed)
|
||||||
|
return;
|
||||||
if (key == 0) {
|
if (key == 0) {
|
||||||
GB.Unref((void **) no_delay.timer);
|
GB.Unref((void **) no_delay.timer);
|
||||||
no_delay.timer = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
no_delay.timer = GB.Every(no_delay.delay,
|
no_delay.timer = GB.Every(no_delay.delay,
|
||||||
(GB_TIMER_CALLBACK) INPUT_nodelay_repeater, 0);
|
(GB_TIMER_CALLBACK) NODELAY_repeater, 0);
|
||||||
}
|
}
|
||||||
no_delay.pressed = key;
|
*/ no_delay.pressed = key;
|
||||||
|
//NODELAY_repeater();
|
||||||
|
WINDOW_raise_read(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -480,7 +598,7 @@ static void INPUT_change_pressed(int key)
|
||||||
* Note carefully, that there is an emergency exit: pressing ESC thrice
|
* Note carefully, that there is an emergency exit: pressing ESC thrice
|
||||||
* during one second will immediately abort NoDelay mode and enter CBreak.
|
* during one second will immediately abort NoDelay mode and enter CBreak.
|
||||||
*/
|
*/
|
||||||
static int INPUT_get_nodelay(int timeout)
|
static int NODELAY_get(int timeout)
|
||||||
{
|
{
|
||||||
static char esc = 0;
|
static char esc = 0;
|
||||||
struct termios old, new;
|
struct termios old, new;
|
||||||
|
@ -490,6 +608,13 @@ static int INPUT_get_nodelay(int timeout)
|
||||||
int key; /* This will already be ncurses compatible */
|
int key; /* This will already be ncurses compatible */
|
||||||
struct timeval tv1, tv2;
|
struct timeval tv1, tv2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MY_DEBUG();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (timeout > -1) {
|
if (timeout > -1) {
|
||||||
gettimeofday(&tv1, NULL);
|
gettimeofday(&tv1, NULL);
|
||||||
tcgetattr(no_delay.fd, &old);
|
tcgetattr(no_delay.fd, &old);
|
||||||
|
@ -543,26 +668,26 @@ recalc_timeout:
|
||||||
if (time(NULL) - stamp > 0)
|
if (time(NULL) - stamp > 0)
|
||||||
esc = 0;
|
esc = 0;
|
||||||
if (++esc == 3) {
|
if (++esc == 3) {
|
||||||
INPUT_exit_nodelay();
|
NODELAY_exit();
|
||||||
INPUT_mode(INPUT_CBREAK);
|
INPUT_mode(INPUT_CBREAK);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
stamp = time(NULL);
|
stamp = time(NULL);
|
||||||
}
|
}
|
||||||
/* We use ncurses keys for operations on our no_delay data */
|
/* We use ncurses keys for operations on our no_delay data */
|
||||||
if ((key = INPUT_trans_keycode(b)) == TRANS_NEED_MORE)
|
if ((key = NODELAY_trans_keycode(b)) == TRANS_NEED_MORE)
|
||||||
goto recalc_timeout;
|
goto recalc_timeout;
|
||||||
/* Ignore break codes, except when it is the currently
|
/* Ignore break codes, except when it is the currently
|
||||||
pressed key */
|
pressed key */
|
||||||
if (IS_BREAK(b)) {
|
if (IS_BREAK(b)) {
|
||||||
if (no_delay.pressed == key)
|
if (no_delay.pressed == key)
|
||||||
INPUT_change_pressed(0);
|
// NODELAY_change_pressed(0);
|
||||||
/* Key release isn't visible to the gambas programmer
|
/* Key release isn't visible to the gambas programmer
|
||||||
* and thus not really an event to gb.ncurses. If
|
* and thus not really an event to gb.ncurses. If
|
||||||
* time is left, we try again reading another key */
|
* time is left, we try again reading another key */
|
||||||
goto recalc_timeout;
|
goto recalc_timeout;
|
||||||
} else {
|
} else {
|
||||||
INPUT_change_pressed(key);
|
// NODELAY_change_pressed(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,16 +698,3 @@ cleanup:
|
||||||
tcsetattr(no_delay.fd, TCSANOW, &old);
|
tcsetattr(no_delay.fd, TCSANOW, &old);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a keypress within the given timeout
|
|
||||||
* @timeout: number of milliseconds to wait. If no key is pressed during it,
|
|
||||||
* 0 will be returned.
|
|
||||||
*/
|
|
||||||
int INPUT_get(int timeout)
|
|
||||||
{
|
|
||||||
if (_input == INPUT_NODELAY)
|
|
||||||
return INPUT_get_nodelay(timeout);
|
|
||||||
else
|
|
||||||
return INPUT_get_ncurses(timeout);
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* input.h - gb.ncurses opaque input routines for use of either ncurses or
|
* c_input.h - gb.ncurses opaque input routines for use of either ncurses or
|
||||||
* the terminal driver directly
|
* the terminal driver directly
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Tobias Boege <tobias@gambas-buch.de>
|
* Copyright (C) 2012 Tobias Boege <tobias@gambas-buch.de>
|
||||||
|
@ -20,12 +20,12 @@
|
||||||
* MA 02110-1301, USA.
|
* MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __INPUT_H
|
#ifndef __C_INPUT_H
|
||||||
#define __INPUT_H
|
#define __C_INPUT_H
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* Return the current mode */
|
/* Return the current mode */
|
||||||
INPUT_RETURN,
|
INPUT_RETURN = -1,
|
||||||
/* Line discipline, signal generation */
|
/* Line discipline, signal generation */
|
||||||
INPUT_COOKED,
|
INPUT_COOKED,
|
||||||
/* No line discipline, signal generation */
|
/* No line discipline, signal generation */
|
||||||
|
@ -39,23 +39,34 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* Let INPUT_repeater_delay() return the current value of the
|
TIMEOUT_NOTIMEOUT = -1
|
||||||
repeater delay */
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
REPEATER_RETURN = -1
|
REPEATER_RETURN = -1
|
||||||
};
|
};
|
||||||
|
|
||||||
int INPUT_init();
|
#ifndef __C_INPUT_C
|
||||||
void INPUT_exit();
|
extern GB_DESC CInputDesc[];
|
||||||
int INPUT_consolefd();
|
|
||||||
int INPUT_mode(int mode);
|
|
||||||
int INPUT_get(int timeout);
|
|
||||||
int INPUT_repeater_delay(int val);
|
|
||||||
#ifdef __INPUT_C
|
|
||||||
static int INPUT_init_nodelay();
|
|
||||||
static int INPUT_exit_nodelay();
|
|
||||||
static void INPUT_nodelay_error_hook();
|
|
||||||
static int INPUT_nodelay_repeater();
|
|
||||||
static void INPUT_callback(int fd, int flag, intptr_t arg);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __INPUT_H */
|
int INPUT_init();
|
||||||
|
void INPUT_exit();
|
||||||
|
int INPUT_mode(int);
|
||||||
|
int INPUT_get(int);
|
||||||
|
void INPUT_drain();
|
||||||
|
#ifdef __C_INPUT_C
|
||||||
|
static int INPUT_watch(int);
|
||||||
|
static void INPUT_callback(int, int, intptr_t);
|
||||||
|
static int NODELAY_init();
|
||||||
|
static int NODELAY_exit();
|
||||||
|
static void NODELAY_error_hook();
|
||||||
|
static int NODELAY_consolefd();
|
||||||
|
static inline void NODELAY_drain();
|
||||||
|
static int NODELAY_repeater();
|
||||||
|
static int NODELAY_repeater_delay(int);
|
||||||
|
static void NODELAY_change_pressed(int);
|
||||||
|
static int NODELAY_get(int);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __C_INPUT_H */
|
|
@ -34,8 +34,7 @@ BEGIN_METHOD(Key_get, GB_STRING key)
|
||||||
|
|
||||||
END_METHOD
|
END_METHOD
|
||||||
|
|
||||||
GB_DESC CKeyDesc[] =
|
GB_DESC CKeyDesc[] = {
|
||||||
{
|
|
||||||
GB_DECLARE("Key", 0),
|
GB_DECLARE("Key", 0),
|
||||||
GB_NOT_CREATABLE(),
|
GB_NOT_CREATABLE(),
|
||||||
|
|
||||||
|
|
|
@ -29,22 +29,18 @@
|
||||||
|
|
||||||
#include "gambas.h"
|
#include "gambas.h"
|
||||||
|
|
||||||
#include "c_screen.h"
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "input.h"
|
#include "c_screen.h"
|
||||||
|
#include "c_input.h"
|
||||||
|
|
||||||
#define THIS ((CSCREEN *) _object)
|
#define THIS ((CSCREEN *) _object)
|
||||||
#define IS_BUFFERED (THIS->buffered)
|
#define IS_BUFFERED (THIS->buffered)
|
||||||
|
|
||||||
#define E_UNSUPP "Unsupported value"
|
#define E_UNSUPP "Unsupported value"
|
||||||
|
|
||||||
static bool _cursor;
|
|
||||||
static int _echo;
|
|
||||||
|
|
||||||
/* Currently active screen */
|
|
||||||
static CSCREEN *active = NULL;
|
static CSCREEN *active = NULL;
|
||||||
|
|
||||||
GB_SIGNAL_CALLBACK *callback;
|
GB_SIGNAL_CALLBACK *_sigwinch_cb;
|
||||||
|
|
||||||
DECLARE_EVENT(EVENT_Read);
|
DECLARE_EVENT(EVENT_Read);
|
||||||
DECLARE_EVENT(EVENT_Resize);
|
DECLARE_EVENT(EVENT_Resize);
|
||||||
|
@ -52,69 +48,28 @@ DECLARE_EVENT(EVENT_Resize);
|
||||||
/*
|
/*
|
||||||
* Signal handler for the SIGWINCH signal.
|
* Signal handler for the SIGWINCH signal.
|
||||||
* @signum: signal number given
|
* @signum: signal number given
|
||||||
|
* @arg: unused
|
||||||
* This routine dispatches the Resize Event
|
* This routine dispatches the Resize Event
|
||||||
*/
|
*/
|
||||||
void SCREEN_sigwinch_handler(int signum, intptr_t data)
|
static void SCREEN_sigwinch_handler(int signum, intptr_t arg)
|
||||||
{
|
{
|
||||||
if (signum == SIGWINCH)
|
if (signum == SIGWINCH)
|
||||||
GB.Raise(active, EVENT_Resize, 0);
|
GB.Raise(active, EVENT_Resize, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set mode of @_cursor
|
|
||||||
*/
|
|
||||||
static int SCREEN_cursor_mode(int mode)
|
|
||||||
{
|
|
||||||
switch (mode) {
|
|
||||||
case CURSOR_HIDDEN:
|
|
||||||
curs_set(0);
|
|
||||||
break;
|
|
||||||
case CURSOR_VISIBLE:
|
|
||||||
curs_set(1);
|
|
||||||
break;
|
|
||||||
case CURSOR_VERY:
|
|
||||||
curs_set(2);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
_cursor = mode;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set mode of @_echo
|
|
||||||
*/
|
|
||||||
static int SCREEN_echo_mode(int mode)
|
|
||||||
{
|
|
||||||
switch (mode) {
|
|
||||||
case ECHO_NOECHO:
|
|
||||||
noecho();
|
|
||||||
break;
|
|
||||||
case ECHO_ECHO:
|
|
||||||
echo();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
_echo = mode;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screen initialisation
|
* Screen initialisation
|
||||||
*/
|
*/
|
||||||
int SCREEN_init()
|
int SCREEN_init()
|
||||||
{
|
{
|
||||||
/* Global variable default setup */
|
/* Global variable default setup */
|
||||||
SCREEN_cursor_mode(CURSOR_VISIBLE);
|
CURSOR_mode(CURSOR_VISIBLE);
|
||||||
SCREEN_echo_mode(ECHO_NOECHO);
|
ECHO_mode(ECHO_NOECHO);
|
||||||
|
|
||||||
INPUT_init();
|
INPUT_init();
|
||||||
|
|
||||||
/* callback = GB.Signal.Register(SIGSEGV,
|
// _sigwinch_cb = GB.Signal.Register(SIGWINCH,
|
||||||
SCREEN_sigwinch_handler, (intptr_t) NULL);
|
// SCREEN_sigwinch_handler, (intptr_t) NULL);
|
||||||
*/
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,8 +80,7 @@ void SCREEN_exit()
|
||||||
{
|
{
|
||||||
INPUT_exit();
|
INPUT_exit();
|
||||||
|
|
||||||
/* GB.Signal.Unregister(SIGWINCH, callback);
|
// GB.Signal.Unregister(SIGWINCH, _sigwinch_cb);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,14 +127,23 @@ void SCREEN_refresh(void *_object)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let the specified screen raise its Read event. If the _object is NULL,
|
* Let the specified screen raise its Read event. If the _object is NULL,
|
||||||
* the currently active screen will raise.
|
* the currently active screen will raise. The latter case is the last
|
||||||
|
* resort for the difficulty of raising Read event in Window-Screen
|
||||||
|
* relation, while there need not be a focused window to raise this event,
|
||||||
|
* there is always an active screen.
|
||||||
*/
|
*/
|
||||||
void SCREEN_raise_read(void *_object)
|
void SCREEN_raise_read(void *_object)
|
||||||
{
|
{
|
||||||
|
bool risen;
|
||||||
|
|
||||||
if (!_object)
|
if (!_object)
|
||||||
GB.Raise(active, EVENT_Read, 0);
|
risen = GB.Raise(active, EVENT_Read, 0);
|
||||||
else
|
else
|
||||||
GB.Raise(_object, EVENT_Read, 0);
|
risen = GB.Raise(_object, EVENT_Read, 0);
|
||||||
|
|
||||||
|
/* Reduce watch callback calling overhead */
|
||||||
|
if (!risen)
|
||||||
|
INPUT_drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
BEGIN_PROPERTY(Screen_Buffered)
|
BEGIN_PROPERTY(Screen_Buffered)
|
||||||
|
@ -196,11 +159,11 @@ END_PROPERTY
|
||||||
BEGIN_PROPERTY(Screen_Cursor)
|
BEGIN_PROPERTY(Screen_Cursor)
|
||||||
|
|
||||||
if (READ_PROPERTY) {
|
if (READ_PROPERTY) {
|
||||||
GB.ReturnInteger(_cursor);
|
GB.ReturnInteger(CURSOR_mode(CURSOR_RETURN));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SCREEN_cursor_mode(VPROP(GB_INTEGER)) == -1)
|
if (CURSOR_mode(VPROP(GB_INTEGER)) == -1)
|
||||||
GB.Error(E_UNSUPP);
|
GB.Error(E_UNSUPP);
|
||||||
|
|
||||||
END_PROPERTY
|
END_PROPERTY
|
||||||
|
@ -208,11 +171,11 @@ END_PROPERTY
|
||||||
BEGIN_PROPERTY(Screen_Echo)
|
BEGIN_PROPERTY(Screen_Echo)
|
||||||
|
|
||||||
if (READ_PROPERTY) {
|
if (READ_PROPERTY) {
|
||||||
GB.ReturnBoolean(_echo);
|
GB.ReturnBoolean(ECHO_mode(ECHO_RETURN));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SCREEN_echo_mode(!!VPROP(GB_BOOLEAN)) == -1)
|
if (ECHO_mode(!!VPROP(GB_BOOLEAN)) == -1)
|
||||||
GB.Error(E_UNSUPP);
|
GB.Error(E_UNSUPP);
|
||||||
|
|
||||||
END_PROPERTY
|
END_PROPERTY
|
||||||
|
@ -229,32 +192,6 @@ BEGIN_PROPERTY(Screen_Input)
|
||||||
|
|
||||||
END_PROPERTY
|
END_PROPERTY
|
||||||
|
|
||||||
BEGIN_PROPERTY(Screen_IsConsole)
|
|
||||||
|
|
||||||
int fd = INPUT_consolefd();
|
|
||||||
|
|
||||||
if (fd == -1) {
|
|
||||||
GB.ReturnBoolean(FALSE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
GB.ReturnBoolean(TRUE);
|
|
||||||
|
|
||||||
END_PROPERTY
|
|
||||||
|
|
||||||
BEGIN_PROPERTY(Screen_Repeater)
|
|
||||||
|
|
||||||
if (READ_PROPERTY) {
|
|
||||||
GB.ReturnInteger(INPUT_repeater_delay(REPEATER_RETURN));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (INPUT_repeater_delay(VPROP(GB_INTEGER)) == -1) {
|
|
||||||
GB.Error("Invalid value");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
END_PROPERTY
|
|
||||||
|
|
||||||
BEGIN_PROPERTY(Screen_Lines)
|
BEGIN_PROPERTY(Screen_Lines)
|
||||||
|
|
||||||
GB.ReturnInteger(LINES);
|
GB.ReturnInteger(LINES);
|
||||||
|
@ -275,6 +212,8 @@ END_METHOD
|
||||||
|
|
||||||
BEGIN_METHOD_VOID(Screen_free)
|
BEGIN_METHOD_VOID(Screen_free)
|
||||||
|
|
||||||
|
/* TODO: for now, while Screen instantiation wouldn't do anything
|
||||||
|
* useful */
|
||||||
SCREEN_exit();
|
SCREEN_exit();
|
||||||
|
|
||||||
END_METHOD
|
END_METHOD
|
||||||
|
@ -285,29 +224,18 @@ BEGIN_METHOD_VOID(Screen_Refresh)
|
||||||
|
|
||||||
END_METHOD
|
END_METHOD
|
||||||
|
|
||||||
GB_DESC CScreenDesc[] =
|
GB_DESC CScreenDesc[] = {
|
||||||
{
|
|
||||||
GB_DECLARE("Screen", sizeof(CSCREEN)),
|
GB_DECLARE("Screen", sizeof(CSCREEN)),
|
||||||
GB_AUTO_CREATABLE(),
|
GB_AUTO_CREATABLE(),
|
||||||
|
|
||||||
GB_EVENT("Read", NULL, NULL, &EVENT_Read),
|
GB_EVENT("Read", NULL, NULL, &EVENT_Read),
|
||||||
GB_EVENT("Resize", NULL, NULL, &EVENT_Resize),
|
GB_EVENT("Resize", NULL, NULL, &EVENT_Resize),
|
||||||
|
|
||||||
GB_CONSTANT("Hidden", "i", CURSOR_HIDDEN),
|
|
||||||
GB_CONSTANT("Visible", "i", CURSOR_VISIBLE),
|
|
||||||
|
|
||||||
GB_CONSTANT("Cooked", "i", INPUT_COOKED),
|
|
||||||
GB_CONSTANT("CBreak", "i", INPUT_CBREAK),
|
|
||||||
GB_CONSTANT("Raw", "i", INPUT_RAW),
|
|
||||||
GB_CONSTANT("NoDelay", "i", INPUT_NODELAY),
|
|
||||||
|
|
||||||
GB_PROPERTY("Buffered", "b", Screen_Buffered),
|
GB_PROPERTY("Buffered", "b", Screen_Buffered),
|
||||||
|
|
||||||
GB_STATIC_PROPERTY("Cursor", "i", Screen_Cursor),
|
GB_STATIC_PROPERTY("Cursor", "i", Screen_Cursor),
|
||||||
GB_STATIC_PROPERTY("Echo", "b", Screen_Echo),
|
GB_STATIC_PROPERTY("Echo", "b", Screen_Echo),
|
||||||
GB_STATIC_PROPERTY("Input", "i", Screen_Input),
|
GB_STATIC_PROPERTY("Input", "i", Screen_Input),
|
||||||
GB_STATIC_PROPERTY_READ("IsConsole", "b", Screen_IsConsole),
|
|
||||||
GB_STATIC_PROPERTY("Repeater", "i", Screen_Repeater),
|
|
||||||
|
|
||||||
GB_STATIC_PROPERTY_READ("Lines", "i", Screen_Lines), //GB_PROPERTY
|
GB_STATIC_PROPERTY_READ("Lines", "i", Screen_Lines), //GB_PROPERTY
|
||||||
GB_STATIC_PROPERTY_READ("Cols", "i", Screen_Cols),
|
GB_STATIC_PROPERTY_READ("Cols", "i", Screen_Cols),
|
||||||
|
@ -319,3 +247,73 @@ GB_DESC CScreenDesc[] =
|
||||||
|
|
||||||
GB_END_DECLARE
|
GB_END_DECLARE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CURSOR routines
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int _cursor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return or set cursor mode
|
||||||
|
* @mode: choose operation
|
||||||
|
*/
|
||||||
|
int CURSOR_mode(int mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case CURSOR_RETURN:
|
||||||
|
return _cursor;
|
||||||
|
case CURSOR_HIDDEN:
|
||||||
|
curs_set(0);
|
||||||
|
break;
|
||||||
|
case CURSOR_VISIBLE:
|
||||||
|
curs_set(1);
|
||||||
|
break;
|
||||||
|
case CURSOR_VERY:
|
||||||
|
curs_set(2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
_cursor = mode;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_DESC CCursorDesc[] = {
|
||||||
|
GB_DECLARE("Cursor", 0),
|
||||||
|
GB_NOT_CREATABLE(),
|
||||||
|
|
||||||
|
GB_CONSTANT("Hidden", "i", CURSOR_HIDDEN),
|
||||||
|
GB_CONSTANT("Visible", "i", CURSOR_VISIBLE),
|
||||||
|
GB_CONSTANT("Very", "i", CURSOR_VERY),
|
||||||
|
|
||||||
|
GB_END_DECLARE
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ECHO routines
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int _echo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return or set echo mode
|
||||||
|
* @mode: choose operation
|
||||||
|
*/
|
||||||
|
int ECHO_mode(int mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case ECHO_RETURN:
|
||||||
|
return _echo;
|
||||||
|
case ECHO_NOECHO:
|
||||||
|
noecho();
|
||||||
|
break;
|
||||||
|
case ECHO_ECHO:
|
||||||
|
echo();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
_echo = mode;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define __C_SCREEN_H
|
#define __C_SCREEN_H
|
||||||
|
|
||||||
#include "gambas.h"
|
#include "gambas.h"
|
||||||
|
#include "c_input.h"
|
||||||
|
|
||||||
/* This will produce final output on terminal screen */
|
/* This will produce final output on terminal screen */
|
||||||
#define REAL_REFRESH() SCREEN_real_refresh()
|
#define REAL_REFRESH() SCREEN_real_refresh()
|
||||||
|
@ -30,11 +31,14 @@
|
||||||
(read: to check if the output is buffered and if not produce output by means of
|
(read: to check if the output is buffered and if not produce output by means of
|
||||||
REAL_REFRESH()) */
|
REAL_REFRESH()) */
|
||||||
#define REFRESH() SCREEN_refresh(NULL)
|
#define REFRESH() SCREEN_refresh(NULL)
|
||||||
|
/* The Screen - like in ncurses - is the sole source of input */
|
||||||
|
#define SCREEN_get(t) INPUT_get(t)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cursor modes
|
* Cursor modes
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
|
CURSOR_RETURN = -1,
|
||||||
CURSOR_HIDDEN,
|
CURSOR_HIDDEN,
|
||||||
CURSOR_VISIBLE,
|
CURSOR_VISIBLE,
|
||||||
CURSOR_VERY
|
CURSOR_VERY
|
||||||
|
@ -44,12 +48,14 @@ enum {
|
||||||
* Echo modes
|
* Echo modes
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
|
ECHO_RETURN = -1,
|
||||||
ECHO_NOECHO,
|
ECHO_NOECHO,
|
||||||
ECHO_ECHO
|
ECHO_ECHO
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef __C_SCREEN_C
|
#ifndef __C_SCREEN_C
|
||||||
extern GB_DESC CScreenDesc[];
|
extern GB_DESC CScreenDesc[];
|
||||||
|
extern GB_DESC CCursorDesc[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -65,4 +71,7 @@ void SCREEN_refresh();
|
||||||
void SCREEN_real_refresh();
|
void SCREEN_real_refresh();
|
||||||
void SCREEN_raise_read(void *);
|
void SCREEN_raise_read(void *);
|
||||||
|
|
||||||
|
int CURSOR_mode(int);
|
||||||
|
int ECHO_mode(int);
|
||||||
|
|
||||||
#endif /* __C_SCREEN_H */
|
#endif /* __C_SCREEN_H */
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "c_screen.h"
|
#include "c_screen.h"
|
||||||
#include "c_color.h"
|
#include "c_color.h"
|
||||||
#include "input.h"
|
|
||||||
|
|
||||||
#define THIS ((CWINDOW *) _object)
|
#define THIS ((CWINDOW *) _object)
|
||||||
#define HAS_BORDER (THIS->border != BORDER_NONE)
|
#define HAS_BORDER (THIS->border != BORDER_NONE)
|
||||||
|
@ -118,7 +117,7 @@ DECLARE_EVENT(EVENT_Read);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* C Window interface
|
* C Window interface
|
||||||
* @_object: Reference to the struct nc_window representing the current object.
|
* @_object: Reference to the CWINDOW representing the current object.
|
||||||
*
|
*
|
||||||
* The theory: Each window has a main and a content window pointer. The main window
|
* The theory: Each window has a main and a content window pointer. The main window
|
||||||
* represents the window object outwards. It is linked to a panel structure which
|
* represents the window object outwards. It is linked to a panel structure which
|
||||||
|
@ -382,7 +381,7 @@ static int WINDOW_cursor_move(void *_object, int x, int y)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move the entire nc_window on screen.
|
* Move the entire window on screen.
|
||||||
* @x: new x coordinate
|
* @x: new x coordinate
|
||||||
* @y: new y coordinate of the upper left corner of the main window relative to the
|
* @y: new y coordinate of the upper left corner of the main window relative to the
|
||||||
* screen. Again, -1 denotes to leave the value as is
|
* screen. Again, -1 denotes to leave the value as is
|
||||||
|
@ -579,7 +578,55 @@ static int WINDOW_get_str(void *_object, int x, int y, unsigned int len, char **
|
||||||
*/
|
*/
|
||||||
static int WINDOW_key_timeout(void *_object, int timeout, int *ret)
|
static int WINDOW_key_timeout(void *_object, int timeout, int *ret)
|
||||||
{
|
{
|
||||||
*ret = INPUT_get(timeout);
|
*ret = SCREEN_get(timeout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read an entire string form the input queue
|
||||||
|
* @ret: the pointer to a newly malloced string will be stored there
|
||||||
|
* This function behaves like getstr(3X). Note that getstr() being a
|
||||||
|
* sequence of getch(), we must stick to its characteristics, too, i.e.
|
||||||
|
* beep() when there is a non-printable character typed in and echo all
|
||||||
|
* characters if we echo.
|
||||||
|
*/
|
||||||
|
static int WINDOW_readline(void *_object, char **ret)
|
||||||
|
{
|
||||||
|
int key;
|
||||||
|
int i, j;
|
||||||
|
char *line = NULL, *p, c;
|
||||||
|
|
||||||
|
i = j = 0;
|
||||||
|
while (1) {
|
||||||
|
if (!(i & 256)) {
|
||||||
|
if (!(p = realloc(line, (++j * 256) + 1))) {
|
||||||
|
free(line);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
line = p;
|
||||||
|
}
|
||||||
|
key = SCREEN_get(TIMEOUT_NOTIMEOUT);
|
||||||
|
c = (char) key;
|
||||||
|
if (c == '\n' || c == '\r')
|
||||||
|
break;
|
||||||
|
if (key == KEY_BACKSPACE || key == KEY_LEFT) {
|
||||||
|
if (i > 0)
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((c < 32 && !isspace(c)) || key > 127) {
|
||||||
|
beep();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
line[i++] = c;
|
||||||
|
if (ECHO_mode(ECHO_RETURN)) {
|
||||||
|
line[i] = 0;
|
||||||
|
WINDOW_print(THIS, line + i - 1, -1, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line[i] = 0;
|
||||||
|
*ret = line;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,7 +635,7 @@ static int WINDOW_key_timeout(void *_object, int timeout, int *ret)
|
||||||
*/
|
*/
|
||||||
static void WINDOW_drain()
|
static void WINDOW_drain()
|
||||||
{
|
{
|
||||||
flushinp();
|
INPUT_drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -633,7 +680,8 @@ static int WINDOW_show(void *_object)
|
||||||
* Raise the Window_Read event of the given window. If _object is NULL,
|
* Raise the Window_Read event of the given window. If _object is NULL,
|
||||||
* the currently focused window is used. The event is, however, only risen,
|
* the currently focused window is used. The event is, however, only risen,
|
||||||
* if the window can raise events. Otherwise let the parent screen raise the
|
* if the window can raise events. Otherwise let the parent screen raise the
|
||||||
* event.
|
* event. If there is not even a parent screen accessible, use the active
|
||||||
|
* screen.
|
||||||
*/
|
*/
|
||||||
void WINDOW_raise_read(void *_object)
|
void WINDOW_raise_read(void *_object)
|
||||||
{
|
{
|
||||||
|
@ -657,7 +705,7 @@ static int WINDOW_setfocus(void *_object)
|
||||||
if (focused)
|
if (focused)
|
||||||
GB.Unref((void **) &focused);
|
GB.Unref((void **) &focused);
|
||||||
focused = THIS;
|
focused = THIS;
|
||||||
GB.Ref((void **) &focused);
|
GB.Ref((void *) focused);
|
||||||
/* We watch since SCREEN_init() */
|
/* We watch since SCREEN_init() */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -838,18 +886,6 @@ BEGIN_PROPERTY(Window_Caption)
|
||||||
|
|
||||||
END_PROPERTY
|
END_PROPERTY
|
||||||
|
|
||||||
BEGIN_PROPERTY(Window_ContainerHeight)
|
|
||||||
|
|
||||||
GB.ReturnInteger(getmaxy(THIS->main));
|
|
||||||
|
|
||||||
END_PROPERTY
|
|
||||||
|
|
||||||
BEGIN_PROPERTY(Window_ContainerWidth)
|
|
||||||
|
|
||||||
GB.ReturnInteger(getmaxx(THIS->main));
|
|
||||||
|
|
||||||
END_PROPERTY
|
|
||||||
|
|
||||||
BEGIN_PROPERTY(Window_CursorX)
|
BEGIN_PROPERTY(Window_CursorX)
|
||||||
|
|
||||||
if (READ_PROPERTY) {
|
if (READ_PROPERTY) {
|
||||||
|
@ -1000,7 +1036,7 @@ BEGIN_METHOD(Window_Ask, GB_STRING opts; GB_INTEGER tries)
|
||||||
o = GB.ToZeroString(ARG(opts));
|
o = GB.ToZeroString(ARG(opts));
|
||||||
|
|
||||||
while (miss || t--) {
|
while (miss || t--) {
|
||||||
ch = getch();
|
WINDOW_key_timeout(THIS, -1, &ch);
|
||||||
/* Per convention, only dealing with byte chars */
|
/* Per convention, only dealing with byte chars */
|
||||||
if (ch > 255)
|
if (ch > 255)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1204,9 +1240,14 @@ END_METHOD
|
||||||
|
|
||||||
BEGIN_METHOD_VOID(Window_ReadLine)
|
BEGIN_METHOD_VOID(Window_ReadLine)
|
||||||
|
|
||||||
/*abbruch-kondition? ein backspace mehr, als zeichen vorhanden? eine
|
char *line;
|
||||||
bestimmte taste? NULL wird zurueckgegeben. \n und \x4 werden nicht
|
|
||||||
geliefert.*/
|
if (WINDOW_readline(THIS, &line) == -1) {
|
||||||
|
GB.ReturnNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GB.ReturnNewZeroString(line);
|
||||||
|
free(line);
|
||||||
|
|
||||||
END_METHOD
|
END_METHOD
|
||||||
|
|
||||||
|
@ -1223,6 +1264,79 @@ BEGIN_METHOD_VOID(Window_SetFocus)
|
||||||
|
|
||||||
END_METHOD
|
END_METHOD
|
||||||
|
|
||||||
|
GB_DESC CWindowDesc[] = {
|
||||||
|
GB_DECLARE("Window", sizeof(CWINDOW)),
|
||||||
|
GB_AUTO_CREATABLE(),
|
||||||
|
|
||||||
|
GB_EVENT("Read", NULL, NULL, &EVENT_Read),
|
||||||
|
|
||||||
|
/* Properties */
|
||||||
|
GB_PROPERTY_SELF("Attributes", ".Window.Attrs"),
|
||||||
|
|
||||||
|
GB_PROPERTY("Background", "i", Window_Background),
|
||||||
|
GB_PROPERTY("Paper", "i", Window_Background),
|
||||||
|
|
||||||
|
GB_PROPERTY("Border", "i", Window_Border),
|
||||||
|
|
||||||
|
GB_PROPERTY("Caption", "s", Window_Caption),
|
||||||
|
|
||||||
|
GB_PROPERTY("CursorX", "i", Window_CursorX),
|
||||||
|
GB_PROPERTY("CursorY", "i", Window_CursorY),
|
||||||
|
|
||||||
|
GB_PROPERTY("Foreground", "i", Window_Foreground),
|
||||||
|
GB_PROPERTY("Pen", "i", Window_Foreground),
|
||||||
|
|
||||||
|
GB_PROPERTY("Height", "i", Window_Height),
|
||||||
|
GB_PROPERTY("H", "i", Window_Height),
|
||||||
|
|
||||||
|
GB_PROPERTY("Wrap", "b", Window_Wrap),
|
||||||
|
|
||||||
|
GB_PROPERTY("Width", "i", Window_Width),
|
||||||
|
GB_PROPERTY("W", "i", Window_Width),
|
||||||
|
|
||||||
|
GB_PROPERTY("X", "i", Window_X),
|
||||||
|
GB_PROPERTY("Y", "i", Window_Y),
|
||||||
|
|
||||||
|
/* Methods */
|
||||||
|
GB_METHOD("_new", NULL, Window_new, "[(Parent)Screen;(X)i(Y)i(W)i(H)i]"),
|
||||||
|
GB_METHOD("_free", NULL, Window_free, NULL),
|
||||||
|
GB_METHOD("_get", ".Char.Attrs", Window_get, "(Y)i(X)i"),
|
||||||
|
|
||||||
|
GB_METHOD("Ask", "s", Window_Ask, "(Opts)s[(Tries)i]"),
|
||||||
|
|
||||||
|
GB_METHOD("Lower", NULL, Window_Lower, NULL),
|
||||||
|
GB_METHOD("Raise", NULL, Window_Raise, NULL),
|
||||||
|
|
||||||
|
GB_METHOD("Cls", NULL, Window_Cls, NULL),
|
||||||
|
|
||||||
|
GB_METHOD("Drain", NULL, Window_Drain, NULL),
|
||||||
|
|
||||||
|
GB_METHOD("Full", NULL, Window_Full, NULL),
|
||||||
|
|
||||||
|
GB_METHOD("Get", "s", Window_Get, "(X)i(Y)i[(Len)i]"),
|
||||||
|
|
||||||
|
GB_METHOD("Hide", NULL, Window_Hide, NULL),
|
||||||
|
GB_METHOD("Show", NULL, Window_Show, NULL),
|
||||||
|
|
||||||
|
GB_METHOD("DrawHLine", NULL, Window_DrawHLine, "(X)i(Y)i(Len)i(Ch)s[(Thickness)i]"),
|
||||||
|
GB_METHOD("DrawVLine", NULL, Window_DrawVLine, "(X)i(Y)i(Len)i(Ch)s[(Thickness)i]"),
|
||||||
|
|
||||||
|
GB_METHOD("Insert", NULL, Window_Insert, "(Text)s[(X)i(Y)i]"),
|
||||||
|
GB_METHOD("Print", NULL, Window_Print, "(Text)s[(X)i(Y)i]"),
|
||||||
|
GB_METHOD("PrintCenter", NULL, Window_PrintCenter, "(Text)s"),
|
||||||
|
|
||||||
|
GB_METHOD("Locate", NULL, Window_Locate, "(X)i(Y)i"),
|
||||||
|
GB_METHOD("Move", NULL, Window_Move, "[(X)i(Y)i]"),
|
||||||
|
GB_METHOD("Resize", NULL, Window_Resize, "[(W)i(H)i]"),
|
||||||
|
|
||||||
|
GB_METHOD("Read", "i", Window_Read, "[(Timeout)i]"),
|
||||||
|
GB_METHOD("ReadLine", "s", Window_ReadLine, NULL),
|
||||||
|
|
||||||
|
GB_METHOD("SetFocus", NULL, Window_SetFocus, NULL),
|
||||||
|
|
||||||
|
GB_END_DECLARE
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* .Window.Attrs virtual class
|
* .Window.Attrs virtual class
|
||||||
*/
|
*/
|
||||||
|
@ -1284,6 +1398,21 @@ BEGIN_PROPERTY(WindowAttrs_Color)
|
||||||
|
|
||||||
END_PROPERTY
|
END_PROPERTY
|
||||||
|
|
||||||
|
GB_DESC CWindowAttrsDesc[] = {
|
||||||
|
GB_DECLARE(".Window.Attrs", 0),
|
||||||
|
GB_VIRTUAL_CLASS(),
|
||||||
|
|
||||||
|
GB_PROPERTY("Normal", "b", WindowAttrs_Normal),
|
||||||
|
GB_PROPERTY("Underline", "b", WindowAttrs_Underline),
|
||||||
|
GB_PROPERTY("Reverse", "b", WindowAttrs_Reverse),
|
||||||
|
GB_PROPERTY("Blink", "b", WindowAttrs_Blink),
|
||||||
|
GB_PROPERTY("Bold", "b", WindowAttrs_Bold),
|
||||||
|
|
||||||
|
GB_PROPERTY("Color", "i", WindowAttrs_Color),
|
||||||
|
|
||||||
|
GB_END_DECLARE
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* .Char.Attrs virtual class
|
* .Char.Attrs virtual class
|
||||||
*/
|
*/
|
||||||
|
@ -1349,109 +1478,7 @@ BEGIN_PROPERTY(CharAttrs_Color)
|
||||||
|
|
||||||
END_PROPERTY
|
END_PROPERTY
|
||||||
|
|
||||||
GB_DESC CWindowDesc[] =
|
GB_DESC CCharAttrsDesc[] = {
|
||||||
{
|
|
||||||
GB_DECLARE("Window", sizeof(CWINDOW)),
|
|
||||||
GB_AUTO_CREATABLE(),
|
|
||||||
|
|
||||||
GB_EVENT("Read", NULL, NULL, &EVENT_Read),
|
|
||||||
|
|
||||||
/* Constants */
|
|
||||||
GB_CONSTANT("NoTimeout", "i", TIMEOUT_NOTIMEOUT),
|
|
||||||
GB_CONSTANT("None", "i", BORDER_NONE),
|
|
||||||
GB_CONSTANT("Ascii", "i", BORDER_ASCII),
|
|
||||||
GB_CONSTANT("ACS", "i", BORDER_ACS),
|
|
||||||
|
|
||||||
/* Properties */
|
|
||||||
GB_PROPERTY_SELF("Attributes", ".Window.Attrs"),
|
|
||||||
|
|
||||||
GB_PROPERTY("Background", "i", Window_Background),
|
|
||||||
GB_PROPERTY("Paper", "i", Window_Background),
|
|
||||||
|
|
||||||
GB_PROPERTY("Border", "i", Window_Border),
|
|
||||||
|
|
||||||
GB_PROPERTY("Caption", "s", Window_Caption),
|
|
||||||
|
|
||||||
GB_PROPERTY_READ("ContainerHeight", "i", Window_ContainerHeight),
|
|
||||||
GB_PROPERTY_READ("ContainerH", "i", Window_ContainerHeight),
|
|
||||||
GB_PROPERTY_READ("ContainerWidth", "i", Window_ContainerWidth),
|
|
||||||
GB_PROPERTY_READ("ContainerW", "i", Window_ContainerWidth),
|
|
||||||
|
|
||||||
GB_PROPERTY("CursorX", "i", Window_CursorX),
|
|
||||||
GB_PROPERTY("CursorY", "i", Window_CursorY),
|
|
||||||
|
|
||||||
GB_PROPERTY("Foreground", "i", Window_Foreground),
|
|
||||||
GB_PROPERTY("Pen", "i", Window_Foreground),
|
|
||||||
|
|
||||||
GB_PROPERTY("Height", "i", Window_Height),
|
|
||||||
GB_PROPERTY("H", "i", Window_Height),
|
|
||||||
|
|
||||||
GB_PROPERTY("Wrap", "b", Window_Wrap),
|
|
||||||
|
|
||||||
GB_PROPERTY("Width", "i", Window_Width),
|
|
||||||
GB_PROPERTY("W", "i", Window_Width),
|
|
||||||
|
|
||||||
GB_PROPERTY("X", "i", Window_X),
|
|
||||||
GB_PROPERTY("Y", "i", Window_Y),
|
|
||||||
|
|
||||||
/* Methods */
|
|
||||||
GB_METHOD("_new", NULL, Window_new, "[(Parent)Screen;(X)i(Y)i(W)i(H)i]"),
|
|
||||||
GB_METHOD("_free", NULL, Window_free, NULL),
|
|
||||||
GB_METHOD("_get", ".Char.Attrs", Window_get, "(Y)i(X)i"),
|
|
||||||
|
|
||||||
GB_METHOD("Ask", "s", Window_Ask, "(Opts)s[(Tries)i]"),
|
|
||||||
|
|
||||||
GB_METHOD("Lower", NULL, Window_Lower, NULL),
|
|
||||||
GB_METHOD("Raise", NULL, Window_Raise, NULL),
|
|
||||||
|
|
||||||
GB_METHOD("Cls", NULL, Window_Cls, NULL),
|
|
||||||
|
|
||||||
GB_METHOD("Drain", NULL, Window_Drain, NULL),
|
|
||||||
|
|
||||||
GB_METHOD("Full", NULL, Window_Full, NULL),
|
|
||||||
|
|
||||||
GB_METHOD("Get", "s", Window_Get, "(X)i(Y)i[(Len)i]"),
|
|
||||||
|
|
||||||
GB_METHOD("Hide", NULL, Window_Hide, NULL),
|
|
||||||
GB_METHOD("Show", NULL, Window_Show, NULL),
|
|
||||||
|
|
||||||
GB_METHOD("DrawHLine", NULL, Window_DrawHLine, "(X)i(Y)i(Len)i(Ch)s[(Thickness)i]"),
|
|
||||||
GB_METHOD("DrawVLine", NULL, Window_DrawVLine, "(X)i(Y)i(Len)i(Ch)s[(Thickness)i]"),
|
|
||||||
|
|
||||||
GB_METHOD("Insert", NULL, Window_Insert, "(Text)s[(X)i(Y)i]"),
|
|
||||||
GB_METHOD("Print", NULL, Window_Print, "(Text)s[(X)i(Y)i]"),
|
|
||||||
GB_METHOD("PrintCenter", NULL, Window_PrintCenter, "(Text)s"),
|
|
||||||
|
|
||||||
GB_METHOD("Locate", NULL, Window_Locate, "(X)i(Y)i"),
|
|
||||||
GB_METHOD("Move", NULL, Window_Move, "[(X)i(Y)i]"),
|
|
||||||
GB_METHOD("Resize", NULL, Window_Resize, "[(W)i(H)i]"),
|
|
||||||
|
|
||||||
GB_METHOD("Read", "i", Window_Read, "[(Timeout)i]"),
|
|
||||||
GB_METHOD("ReadLine", "s", Window_ReadLine, NULL),
|
|
||||||
|
|
||||||
GB_METHOD("SetFocus", NULL, Window_SetFocus, NULL),
|
|
||||||
|
|
||||||
GB_END_DECLARE
|
|
||||||
};
|
|
||||||
|
|
||||||
GB_DESC CWindowAttrsDesc[] =
|
|
||||||
{
|
|
||||||
GB_DECLARE(".Window.Attrs", 0),
|
|
||||||
GB_VIRTUAL_CLASS(),
|
|
||||||
|
|
||||||
GB_PROPERTY("Normal", "b", WindowAttrs_Normal),
|
|
||||||
GB_PROPERTY("Underline", "b", WindowAttrs_Underline),
|
|
||||||
GB_PROPERTY("Reverse", "b", WindowAttrs_Reverse),
|
|
||||||
GB_PROPERTY("Blink", "b", WindowAttrs_Blink),
|
|
||||||
GB_PROPERTY("Bold", "b", WindowAttrs_Bold),
|
|
||||||
|
|
||||||
GB_PROPERTY("Color", "i", WindowAttrs_Color),
|
|
||||||
|
|
||||||
GB_END_DECLARE
|
|
||||||
};
|
|
||||||
|
|
||||||
GB_DESC CCharAttrsDesc[] =
|
|
||||||
{
|
|
||||||
GB_DECLARE(".Char.Attrs", 0),
|
GB_DECLARE(".Char.Attrs", 0),
|
||||||
GB_VIRTUAL_CLASS(),
|
GB_VIRTUAL_CLASS(),
|
||||||
|
|
||||||
|
@ -1465,3 +1492,18 @@ GB_DESC CCharAttrsDesc[] =
|
||||||
|
|
||||||
GB_END_DECLARE
|
GB_END_DECLARE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Border static class
|
||||||
|
*/
|
||||||
|
|
||||||
|
GB_DESC CBorderDesc[] = {
|
||||||
|
GB_DECLARE("Border", 0),
|
||||||
|
GB_NOT_CREATABLE(),
|
||||||
|
|
||||||
|
GB_CONSTANT("None", "i", BORDER_NONE),
|
||||||
|
GB_CONSTANT("Ascii", "i", BORDER_ASCII),
|
||||||
|
GB_CONSTANT("ACS", "i", BORDER_ACS),
|
||||||
|
|
||||||
|
GB_END_DECLARE
|
||||||
|
};
|
||||||
|
|
|
@ -37,11 +37,6 @@ enum {
|
||||||
BORDER_ACS
|
BORDER_ACS
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Timeout constants */
|
|
||||||
enum {
|
|
||||||
TIMEOUT_NOTIMEOUT = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
/* @reqs for *_attrs_driver() */
|
/* @reqs for *_attrs_driver() */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -77,6 +72,7 @@ typedef struct {
|
||||||
extern GB_DESC CWindowDesc[];
|
extern GB_DESC CWindowDesc[];
|
||||||
extern GB_DESC CWindowAttrsDesc[];
|
extern GB_DESC CWindowAttrsDesc[];
|
||||||
extern GB_DESC CCharAttrsDesc[];
|
extern GB_DESC CCharAttrsDesc[];
|
||||||
|
extern GB_DESC CBorderDesc[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void WINDOW_raise_read(void *);
|
void WINDOW_raise_read(void *);
|
||||||
|
|
|
@ -25,28 +25,35 @@
|
||||||
#include "c_key.h"
|
#include "c_key.h"
|
||||||
#include "c_color.h"
|
#include "c_color.h"
|
||||||
#include "c_screen.h"
|
#include "c_screen.h"
|
||||||
|
#include "c_input.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
GB_INTERFACE GB EXPORT;
|
GB_INTERFACE GB EXPORT;
|
||||||
|
|
||||||
GB_DESC *GB_CLASSES[] EXPORT =
|
GB_DESC *GB_CLASSES[] EXPORT = {
|
||||||
{
|
|
||||||
CScreenDesc,
|
CScreenDesc,
|
||||||
|
CInputDesc,
|
||||||
|
CCursorDesc,
|
||||||
|
|
||||||
CWindowDesc,
|
CWindowDesc,
|
||||||
CWindowAttrsDesc,
|
CWindowAttrsDesc,
|
||||||
CCharAttrsDesc,
|
CCharAttrsDesc,
|
||||||
|
CBorderDesc,
|
||||||
|
|
||||||
CKeyDesc,
|
CKeyDesc,
|
||||||
|
|
||||||
CColorDesc,
|
CColorDesc,
|
||||||
CColorCapabilitiesDesc,
|
CColorInfoDesc,
|
||||||
CColorPairDesc,
|
CPairDesc,
|
||||||
CColorContentDesc,
|
CPairInfoDesc,
|
||||||
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool _init = FALSE;
|
static bool _init = FALSE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if we are in ncurses mode
|
* Return if we are in ncurses mode
|
||||||
*/
|
*/
|
||||||
bool MAIN_running()
|
bool MAIN_running()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue