mirror of https://github.com/fairyglade/ly
Shift+Tab for previous input
parent
1d3148201c
commit
4122dfac16
@ -1,7 +0,0 @@
|
||||
bin
|
||||
obj
|
||||
src/demo/*.o
|
||||
src/demo/keyboard
|
||||
src/demo/output
|
||||
src/demo/paint
|
||||
src/demo/truecolor
|
@ -1,19 +0,0 @@
|
||||
Copyright (C) 2010-2013 nsf <no.smile.face@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
@ -1,57 +0,0 @@
|
||||
# Termbox
|
||||
[Termbox](https://github.com/nsf/termbox)
|
||||
was a promising Text User Interface (TUI) library.
|
||||
Unfortunately, its original author
|
||||
[changed his mind](https://github.com/nsf/termbox/issues/37#issuecomment-261075481)
|
||||
about consoles and despite the
|
||||
[community's efforts](https://github.com/nsf/termbox/pull/104#issuecomment-300308156)
|
||||
to keep the library's development going, preferred to let it die. Before it happened,
|
||||
[some people](https://wiki.musl-libc.org/alternatives.html)
|
||||
already noticed the robustness of the initial architecture
|
||||
[became compromised](https://github.com/nsf/termbox/commit/66c3f91b14e24510319bce6b5cc2fecf8cf5abff#commitcomment-3790714)
|
||||
in a nonsensical refactoring frenzy. Now, the author refuses to merge features
|
||||
like true-color support, invoking some
|
||||
[spurious correlations](https://github.com/nsf/termbox/pull/104#issuecomment-300292223)
|
||||
we will discuss no further.
|
||||
|
||||
## The new Termbox-next
|
||||
This fork was made to restore the codebase to its original quality (before
|
||||
[66c3f91](https://github.com/nsf/termbox/commit/66c3f91b14e24510319bce6b5cc2fecf8cf5abff))
|
||||
while providing all the functionnalities of the current implementation.
|
||||
This was achieved by branching at
|
||||
[a2e217f](https://github.com/nsf/termbox/commit/a2e217f0fb97e6bbd589136ea3945f9d5a123d81)
|
||||
and cherry-picking all the commits up to
|
||||
[d63b83a](https://github.com/nsf/termbox/commit/d63b83af04e0fd6da836bb8f37e5cec72a1dc95a)
|
||||
if they weren't harmful.
|
||||
|
||||
## Changes
|
||||
A lot of things changed during the process:
|
||||
- *waf*, the original build system, was completely removed from the
|
||||
project and replaced by make.
|
||||
- anything related to python was removed as well
|
||||
|
||||
## Getting started
|
||||
Termbox's interface only consists of 12 functions:
|
||||
```
|
||||
tb_init() // initialization
|
||||
tb_shutdown() // shutdown
|
||||
|
||||
tb_width() // width of the terminal screen
|
||||
tb_height() // height of the terminal screen
|
||||
|
||||
tb_clear() // clear buffer
|
||||
tb_present() // sync internal buffer with terminal
|
||||
|
||||
tb_put_cell()
|
||||
tb_change_cell()
|
||||
tb_blit() // drawing functions
|
||||
|
||||
tb_select_input_mode() // change input mode
|
||||
tb_peek_event() // peek a keyboard event
|
||||
tb_poll_event() // wait for a keyboard event
|
||||
```
|
||||
See src/termbox.h header file for full detail.
|
||||
|
||||
## TL;DR
|
||||
`make` to build a static version of the lib under bin/termbox.a
|
||||
`cd src/demo && make` to build the example programs in src/demo/
|
@ -1,827 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "termbox.h"
|
||||
|
||||
struct key
|
||||
{
|
||||
unsigned char x;
|
||||
unsigned char y;
|
||||
uint32_t ch;
|
||||
};
|
||||
|
||||
#define STOP {0,0,0}
|
||||
struct key K_ESC[] = {{1, 1, 'E'}, {2, 1, 'S'}, {3, 1, 'C'}, STOP};
|
||||
struct key K_F1[] = {{6, 1, 'F'}, {7, 1, '1'}, STOP};
|
||||
struct key K_F2[] = {{9, 1, 'F'}, {10, 1, '2'}, STOP};
|
||||
struct key K_F3[] = {{12, 1, 'F'}, {13, 1, '3'}, STOP};
|
||||
struct key K_F4[] = {{15, 1, 'F'}, {16, 1, '4'}, STOP};
|
||||
struct key K_F5[] = {{19, 1, 'F'}, {20, 1, '5'}, STOP};
|
||||
struct key K_F6[] = {{22, 1, 'F'}, {23, 1, '6'}, STOP};
|
||||
struct key K_F7[] = {{25, 1, 'F'}, {26, 1, '7'}, STOP};
|
||||
struct key K_F8[] = {{28, 1, 'F'}, {29, 1, '8'}, STOP};
|
||||
struct key K_F9[] = {{33, 1, 'F'}, {34, 1, '9'}, STOP};
|
||||
struct key K_F10[] = {{36, 1, 'F'}, {37, 1, '1'}, {38, 1, '0'}, STOP};
|
||||
struct key K_F11[] = {{40, 1, 'F'}, {41, 1, '1'}, {42, 1, '1'}, STOP};
|
||||
struct key K_F12[] = {{44, 1, 'F'}, {45, 1, '1'}, {46, 1, '2'}, STOP};
|
||||
struct key K_PRN[] = {{50, 1, 'P'}, {51, 1, 'R'}, {52, 1, 'N'}, STOP};
|
||||
struct key K_SCR[] = {{54, 1, 'S'}, {55, 1, 'C'}, {56, 1, 'R'}, STOP};
|
||||
struct key K_BRK[] = {{58, 1, 'B'}, {59, 1, 'R'}, {60, 1, 'K'}, STOP};
|
||||
struct key K_LED1[] = {{66, 1, '-'}, STOP};
|
||||
struct key K_LED2[] = {{70, 1, '-'}, STOP};
|
||||
struct key K_LED3[] = {{74, 1, '-'}, STOP};
|
||||
|
||||
struct key K_TILDE[] = {{1, 4, '`'}, STOP};
|
||||
struct key K_TILDE_SHIFT[] = {{1, 4, '~'}, STOP};
|
||||
struct key K_1[] = {{4, 4, '1'}, STOP};
|
||||
struct key K_1_SHIFT[] = {{4, 4, '!'}, STOP};
|
||||
struct key K_2[] = {{7, 4, '2'}, STOP};
|
||||
struct key K_2_SHIFT[] = {{7, 4, '@'}, STOP};
|
||||
struct key K_3[] = {{10, 4, '3'}, STOP};
|
||||
struct key K_3_SHIFT[] = {{10, 4, '#'}, STOP};
|
||||
struct key K_4[] = {{13, 4, '4'}, STOP};
|
||||
struct key K_4_SHIFT[] = {{13, 4, '$'}, STOP};
|
||||
struct key K_5[] = {{16, 4, '5'}, STOP};
|
||||
struct key K_5_SHIFT[] = {{16, 4, '%'}, STOP};
|
||||
struct key K_6[] = {{19, 4, '6'}, STOP};
|
||||
struct key K_6_SHIFT[] = {{19, 4, '^'}, STOP};
|
||||
struct key K_7[] = {{22, 4, '7'}, STOP};
|
||||
struct key K_7_SHIFT[] = {{22, 4, '&'}, STOP};
|
||||
struct key K_8[] = {{25, 4, '8'}, STOP};
|
||||
struct key K_8_SHIFT[] = {{25, 4, '*'}, STOP};
|
||||
struct key K_9[] = {{28, 4, '9'}, STOP};
|
||||
struct key K_9_SHIFT[] = {{28, 4, '('}, STOP};
|
||||
struct key K_0[] = {{31, 4, '0'}, STOP};
|
||||
struct key K_0_SHIFT[] = {{31, 4, ')'}, STOP};
|
||||
struct key K_MINUS[] = {{34, 4, '-'}, STOP};
|
||||
struct key K_MINUS_SHIFT[] = {{34, 4, '_'}, STOP};
|
||||
struct key K_EQUALS[] = {{37, 4, '='}, STOP};
|
||||
struct key K_EQUALS_SHIFT[] = {{37, 4, '+'}, STOP};
|
||||
struct key K_BACKSLASH[] = {{40, 4, '\\'}, STOP};
|
||||
struct key K_BACKSLASH_SHIFT[] = {{40, 4, '|'}, STOP};
|
||||
struct key K_BACKSPACE[] = {{44, 4, 0x2190}, {45, 4, 0x2500}, {46, 4, 0x2500}, STOP};
|
||||
struct key K_INS[] = {{50, 4, 'I'}, {51, 4, 'N'}, {52, 4, 'S'}, STOP};
|
||||
struct key K_HOM[] = {{54, 4, 'H'}, {55, 4, 'O'}, {56, 4, 'M'}, STOP};
|
||||
struct key K_PGU[] = {{58, 4, 'P'}, {59, 4, 'G'}, {60, 4, 'U'}, STOP};
|
||||
struct key K_K_NUMLOCK[] = {{65, 4, 'N'}, STOP};
|
||||
struct key K_K_SLASH[] = {{68, 4, '/'}, STOP};
|
||||
struct key K_K_STAR[] = {{71, 4, '*'}, STOP};
|
||||
struct key K_K_MINUS[] = {{74, 4, '-'}, STOP};
|
||||
|
||||
struct key K_TAB[] = {{1, 6, 'T'}, {2, 6, 'A'}, {3, 6, 'B'}, STOP};
|
||||
struct key K_q[] = {{6, 6, 'q'}, STOP};
|
||||
struct key K_Q[] = {{6, 6, 'Q'}, STOP};
|
||||
struct key K_w[] = {{9, 6, 'w'}, STOP};
|
||||
struct key K_W[] = {{9, 6, 'W'}, STOP};
|
||||
struct key K_e[] = {{12, 6, 'e'}, STOP};
|
||||
struct key K_E[] = {{12, 6, 'E'}, STOP};
|
||||
struct key K_r[] = {{15, 6, 'r'}, STOP};
|
||||
struct key K_R[] = {{15, 6, 'R'}, STOP};
|
||||
struct key K_t[] = {{18, 6, 't'}, STOP};
|
||||
struct key K_T[] = {{18, 6, 'T'}, STOP};
|
||||
struct key K_y[] = {{21, 6, 'y'}, STOP};
|
||||
struct key K_Y[] = {{21, 6, 'Y'}, STOP};
|
||||
struct key K_u[] = {{24, 6, 'u'}, STOP};
|
||||
struct key K_U[] = {{24, 6, 'U'}, STOP};
|
||||
struct key K_i[] = {{27, 6, 'i'}, STOP};
|
||||
struct key K_I[] = {{27, 6, 'I'}, STOP};
|
||||
struct key K_o[] = {{30, 6, 'o'}, STOP};
|
||||
struct key K_O[] = {{30, 6, 'O'}, STOP};
|
||||
struct key K_p[] = {{33, 6, 'p'}, STOP};
|
||||
struct key K_P[] = {{33, 6, 'P'}, STOP};
|
||||
struct key K_LSQB[] = {{36, 6, '['}, STOP};
|
||||
struct key K_LCUB[] = {{36, 6, '{'}, STOP};
|
||||
struct key K_RSQB[] = {{39, 6, ']'}, STOP};
|
||||
struct key K_RCUB[] = {{39, 6, '}'}, STOP};
|
||||
struct key K_ENTER[] =
|
||||
{
|
||||
{43, 6, 0x2591}, {44, 6, 0x2591}, {45, 6, 0x2591}, {46, 6, 0x2591},
|
||||
{43, 7, 0x2591}, {44, 7, 0x2591}, {45, 7, 0x21B5}, {46, 7, 0x2591},
|
||||
{41, 8, 0x2591}, {42, 8, 0x2591}, {43, 8, 0x2591}, {44, 8, 0x2591},
|
||||
{45, 8, 0x2591}, {46, 8, 0x2591}, STOP
|
||||
};
|
||||
struct key K_DEL[] = {{50, 6, 'D'}, {51, 6, 'E'}, {52, 6, 'L'}, STOP};
|
||||
struct key K_END[] = {{54, 6, 'E'}, {55, 6, 'N'}, {56, 6, 'D'}, STOP};
|
||||
struct key K_PGD[] = {{58, 6, 'P'}, {59, 6, 'G'}, {60, 6, 'D'}, STOP};
|
||||
struct key K_K_7[] = {{65, 6, '7'}, STOP};
|
||||
struct key K_K_8[] = {{68, 6, '8'}, STOP};
|
||||
struct key K_K_9[] = {{71, 6, '9'}, STOP};
|
||||
struct key K_K_PLUS[] = {{74, 6, ' '}, {74, 7, '+'}, {74, 8, ' '}, STOP};
|
||||
|
||||
struct key K_CAPS[] = {{1, 8, 'C'}, {2, 8, 'A'}, {3, 8, 'P'}, {4, 8, 'S'}, STOP};
|
||||
struct key K_a[] = {{7, 8, 'a'}, STOP};
|
||||
struct key K_A[] = {{7, 8, 'A'}, STOP};
|
||||
struct key K_s[] = {{10, 8, 's'}, STOP};
|
||||
struct key K_S[] = {{10, 8, 'S'}, STOP};
|
||||
struct key K_d[] = {{13, 8, 'd'}, STOP};
|
||||
struct key K_D[] = {{13, 8, 'D'}, STOP};
|
||||
struct key K_f[] = {{16, 8, 'f'}, STOP};
|
||||
struct key K_F[] = {{16, 8, 'F'}, STOP};
|
||||
struct key K_g[] = {{19, 8, 'g'}, STOP};
|
||||
struct key K_G[] = {{19, 8, 'G'}, STOP};
|
||||
struct key K_h[] = {{22, 8, 'h'}, STOP};
|
||||
struct key K_H[] = {{22, 8, 'H'}, STOP};
|
||||
struct key K_j[] = {{25, 8, 'j'}, STOP};
|
||||
struct key K_J[] = {{25, 8, 'J'}, STOP};
|
||||
struct key K_k[] = {{28, 8, 'k'}, STOP};
|
||||
struct key K_K[] = {{28, 8, 'K'}, STOP};
|
||||
struct key K_l[] = {{31, 8, 'l'}, STOP};
|
||||
struct key K_L[] = {{31, 8, 'L'}, STOP};
|
||||
struct key K_SEMICOLON[] = {{34, 8, ';'}, STOP};
|
||||
struct key K_PARENTHESIS[] = {{34, 8, ':'}, STOP};
|
||||
struct key K_QUOTE[] = {{37, 8, '\''}, STOP};
|
||||
struct key K_DOUBLEQUOTE[] = {{37, 8, '"'}, STOP};
|
||||
struct key K_K_4[] = {{65, 8, '4'}, STOP};
|
||||
struct key K_K_5[] = {{68, 8, '5'}, STOP};
|
||||
struct key K_K_6[] = {{71, 8, '6'}, STOP};
|
||||
|
||||
struct key K_LSHIFT[] = {{1, 10, 'S'}, {2, 10, 'H'}, {3, 10, 'I'}, {4, 10, 'F'}, {5, 10, 'T'}, STOP};
|
||||
struct key K_z[] = {{9, 10, 'z'}, STOP};
|
||||
struct key K_Z[] = {{9, 10, 'Z'}, STOP};
|
||||
struct key K_x[] = {{12, 10, 'x'}, STOP};
|
||||
struct key K_X[] = {{12, 10, 'X'}, STOP};
|
||||
struct key K_c[] = {{15, 10, 'c'}, STOP};
|
||||
struct key K_C[] = {{15, 10, 'C'}, STOP};
|
||||
struct key K_v[] = {{18, 10, 'v'}, STOP};
|
||||
struct key K_V[] = {{18, 10, 'V'}, STOP};
|
||||
struct key K_b[] = {{21, 10, 'b'}, STOP};
|
||||
struct key K_B[] = {{21, 10, 'B'}, STOP};
|
||||
struct key K_n[] = {{24, 10, 'n'}, STOP};
|
||||
struct key K_N[] = {{24, 10, 'N'}, STOP};
|
||||
struct key K_m[] = {{27, 10, 'm'}, STOP};
|
||||
struct key K_M[] = {{27, 10, 'M'}, STOP};
|
||||
struct key K_COMMA[] = {{30, 10, ','}, STOP};
|
||||
struct key K_LANB[] = {{30, 10, '<'}, STOP};
|
||||
struct key K_PERIOD[] = {{33, 10, '.'}, STOP};
|
||||
struct key K_RANB[] = {{33, 10, '>'}, STOP};
|
||||
struct key K_SLASH[] = {{36, 10, '/'}, STOP};
|
||||
struct key K_QUESTION[] = {{36, 10, '?'}, STOP};
|
||||
struct key K_RSHIFT[] = {{42, 10, 'S'}, {43, 10, 'H'}, {44, 10, 'I'}, {45, 10, 'F'}, {46, 10, 'T'}, STOP};
|
||||
struct key K_ARROW_UP[] = {{54, 10, '('}, {55, 10, 0x2191}, {56, 10, ')'}, STOP};
|
||||
struct key K_K_1[] = {{65, 10, '1'}, STOP};
|
||||
struct key K_K_2[] = {{68, 10, '2'}, STOP};
|
||||
struct key K_K_3[] = {{71, 10, '3'}, STOP};
|
||||
struct key K_K_ENTER[] = {{74, 10, 0x2591}, {74, 11, 0x2591}, {74, 12, 0x2591}, STOP};
|
||||
|
||||
struct key K_LCTRL[] = {{1, 12, 'C'}, {2, 12, 'T'}, {3, 12, 'R'}, {4, 12, 'L'}, STOP};
|
||||
struct key K_LWIN[] = {{6, 12, 'W'}, {7, 12, 'I'}, {8, 12, 'N'}, STOP};
|
||||
struct key K_LALT[] = {{10, 12, 'A'}, {11, 12, 'L'}, {12, 12, 'T'}, STOP};
|
||||
struct key K_SPACE[] =
|
||||
{
|
||||
{14, 12, ' '}, {15, 12, ' '}, {16, 12, ' '}, {17, 12, ' '}, {18, 12, ' '},
|
||||
{19, 12, 'S'}, {20, 12, 'P'}, {21, 12, 'A'}, {22, 12, 'C'}, {23, 12, 'E'},
|
||||
{24, 12, ' '}, {25, 12, ' '}, {26, 12, ' '}, {27, 12, ' '}, {28, 12, ' '},
|
||||
STOP
|
||||
};
|
||||
struct key K_RALT[] = {{30, 12, 'A'}, {31, 12, 'L'}, {32, 12, 'T'}, STOP};
|
||||
struct key K_RWIN[] = {{34, 12, 'W'}, {35, 12, 'I'}, {36, 12, 'N'}, STOP};
|
||||
struct key K_RPROP[] = {{38, 12, 'P'}, {39, 12, 'R'}, {40, 12, 'O'}, {41, 12, 'P'}, STOP};
|
||||
struct key K_RCTRL[] = {{43, 12, 'C'}, {44, 12, 'T'}, {45, 12, 'R'}, {46, 12, 'L'}, STOP};
|
||||
struct key K_ARROW_LEFT[] = {{50, 12, '('}, {51, 12, 0x2190}, {52, 12, ')'}, STOP};
|
||||
struct key K_ARROW_DOWN[] = {{54, 12, '('}, {55, 12, 0x2193}, {56, 12, ')'}, STOP};
|
||||
struct key K_ARROW_RIGHT[] = {{58, 12, '('}, {59, 12, 0x2192}, {60, 12, ')'}, STOP};
|
||||
struct key K_K_0[] = {{65, 12, ' '}, {66, 12, '0'}, {67, 12, ' '}, {68, 12, ' '}, STOP};
|
||||
struct key K_K_PERIOD[] = {{71, 12, '.'}, STOP};
|
||||
|
||||
struct combo
|
||||
{
|
||||
struct key* keys[6];
|
||||
};
|
||||
|
||||
struct combo combos[] =
|
||||
{
|
||||
{{K_TILDE, K_2, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_A, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_B, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_C, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_D, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_E, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_F, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_G, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_H, K_BACKSPACE, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_I, K_TAB, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_J, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_K, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_L, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_M, K_ENTER, K_K_ENTER, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_N, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_O, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_P, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_Q, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_R, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_S, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_T, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_U, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_V, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_W, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_X, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_Y, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_Z, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_LSQB, K_ESC, K_3, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_4, K_BACKSLASH, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_RSQB, K_5, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_6, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_7, K_SLASH, K_MINUS_SHIFT, K_LCTRL, K_RCTRL, 0}},
|
||||
{{K_SPACE, 0}},
|
||||
{{K_1_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_DOUBLEQUOTE, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_3_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_4_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_5_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_7_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_QUOTE, 0}},
|
||||
{{K_9_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_0_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_8_SHIFT, K_K_STAR, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_EQUALS_SHIFT, K_K_PLUS, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_COMMA, 0}},
|
||||
{{K_MINUS, K_K_MINUS, 0}},
|
||||
{{K_PERIOD, K_K_PERIOD, 0}},
|
||||
{{K_SLASH, K_K_SLASH, 0}},
|
||||
{{K_0, K_K_0, 0}},
|
||||
{{K_1, K_K_1, 0}},
|
||||
{{K_2, K_K_2, 0}},
|
||||
{{K_3, K_K_3, 0}},
|
||||
{{K_4, K_K_4, 0}},
|
||||
{{K_5, K_K_5, 0}},
|
||||
{{K_6, K_K_6, 0}},
|
||||
{{K_7, K_K_7, 0}},
|
||||
{{K_8, K_K_8, 0}},
|
||||
{{K_9, K_K_9, 0}},
|
||||
{{K_PARENTHESIS, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_SEMICOLON, 0}},
|
||||
{{K_LANB, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_EQUALS, 0}},
|
||||
{{K_RANB, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_QUESTION, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_2_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_A, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_B, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_C, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_D, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_E, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_F, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_G, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_H, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_I, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_J, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_K, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_L, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_M, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_N, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_O, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_P, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_Q, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_R, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_S, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_T, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_U, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_V, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_W, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_X, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_Y, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_Z, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_LSQB, 0}},
|
||||
{{K_BACKSLASH, 0}},
|
||||
{{K_RSQB, 0}},
|
||||
{{K_6_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_MINUS_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_TILDE, 0}},
|
||||
{{K_a, 0}},
|
||||
{{K_b, 0}},
|
||||
{{K_c, 0}},
|
||||
{{K_d, 0}},
|
||||
{{K_e, 0}},
|
||||
{{K_f, 0}},
|
||||
{{K_g, 0}},
|
||||
{{K_h, 0}},
|
||||
{{K_i, 0}},
|
||||
{{K_j, 0}},
|
||||
{{K_k, 0}},
|
||||
{{K_l, 0}},
|
||||
{{K_m, 0}},
|
||||
{{K_n, 0}},
|
||||
{{K_o, 0}},
|
||||
{{K_p, 0}},
|
||||
{{K_q, 0}},
|
||||
{{K_r, 0}},
|
||||
{{K_s, 0}},
|
||||
{{K_t, 0}},
|
||||
{{K_u, 0}},
|
||||
{{K_v, 0}},
|
||||
{{K_w, 0}},
|
||||
{{K_x, 0}},
|
||||
{{K_y, 0}},
|
||||
{{K_z, 0}},
|
||||
{{K_LCUB, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_BACKSLASH_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_RCUB, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_TILDE_SHIFT, K_LSHIFT, K_RSHIFT, 0}},
|
||||
{{K_8, K_BACKSPACE, K_LCTRL, K_RCTRL, 0}}
|
||||
};
|
||||
|
||||
struct combo func_combos[] =
|
||||
{
|
||||
{{K_F1, 0}},
|
||||
{{K_F2, 0}},
|
||||
{{K_F3, 0}},
|
||||
{{K_F4, 0}},
|
||||
{{K_F5, 0}},
|
||||
{{K_F6, 0}},
|
||||
{{K_F7, 0}},
|
||||
{{K_F8, 0}},
|
||||
{{K_F9, 0}},
|
||||
{{K_F10, 0}},
|
||||
{{K_F11, 0}},
|
||||
{{K_F12, 0}},
|
||||
{{K_INS, 0}},
|
||||
{{K_DEL, 0}},
|
||||
{{K_HOM, 0}},
|
||||
{{K_END, 0}},
|
||||
{{K_PGU, 0}},
|
||||
{{K_PGD, 0}},
|
||||
{{K_ARROW_UP, 0}},
|
||||
{{K_ARROW_DOWN, 0}},
|
||||
{{K_ARROW_LEFT, 0}},
|
||||
{{K_ARROW_RIGHT, 0}}
|
||||
};
|
||||
|
||||
void print_tb(const char* str, int x, int y, uint32_t fg, uint32_t bg)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
uint32_t uni;
|
||||
str += utf8_char_to_unicode(&uni, str);
|
||||
tb_change_cell(x, y, uni, fg, bg);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
void printf_tb(int x, int y, uint32_t fg, uint32_t bg, const char* fmt, ...)
|
||||
{
|
||||
char buf[4096];
|
||||
va_list vl;
|
||||
va_start(vl, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, vl);
|
||||
va_end(vl);
|
||||
print_tb(buf, x, y, fg, bg);
|
||||
}
|
||||
|
||||
void draw_key(struct key* k, uint32_t fg, uint32_t bg)
|
||||
{
|
||||
while (k->x)
|
||||
{
|
||||
tb_change_cell(k->x + 2, k->y + 4, k->ch, fg, bg);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_keyboard()
|
||||
{
|
||||
int i;
|
||||
tb_change_cell(0, 0, 0x250C, TB_WHITE, TB_DEFAULT);
|
||||
tb_change_cell(79, 0, 0x2510, TB_WHITE, TB_DEFAULT);
|
||||
tb_change_cell(0, 23, 0x2514, TB_WHITE, TB_DEFAULT);
|
||||
tb_change_cell(79, 23, 0x2518, TB_WHITE, TB_DEFAULT);
|
||||
|
||||
for (i = 1; i < 79; ++i)
|
||||
{
|
||||
tb_change_cell(i, 0, 0x2500, TB_WHITE, TB_DEFAULT);
|
||||
tb_change_cell(i, 23, 0x2500, TB_WHITE, TB_DEFAULT);
|
||||
tb_change_cell(i, 17, 0x2500, TB_WHITE, TB_DEFAULT);
|
||||
tb_change_cell(i, 4, 0x2500, TB_WHITE, TB_DEFAULT);
|
||||
}
|
||||
|
||||
for (i = 1; i < 23; ++i)
|
||||
{
|
||||
tb_change_cell(0, i, 0x2502, TB_WHITE, TB_DEFAULT);
|
||||
tb_change_cell(79, i, 0x2502, TB_WHITE, TB_DEFAULT);
|
||||
}
|
||||
|
||||
tb_change_cell(0, 17, 0x251C, TB_WHITE, TB_DEFAULT);
|
||||
tb_change_cell(79, 17, 0x2524, TB_WHITE, TB_DEFAULT);
|
||||
tb_change_cell(0, 4, 0x251C, TB_WHITE, TB_DEFAULT);
|
||||
tb_change_cell(79, 4, 0x2524, TB_WHITE, TB_DEFAULT);
|
||||
|
||||
for (i = 5; i < 17; ++i)
|
||||
{
|
||||
tb_change_cell(1, i, 0x2588, TB_YELLOW, TB_YELLOW);
|
||||
tb_change_cell(78, i, 0x2588, TB_YELLOW, TB_YELLOW);
|
||||
}
|
||||
|
||||
draw_key(K_ESC, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F1, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F2, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F3, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F4, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F5, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F6, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F7, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F8, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F9, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F10, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F11, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_F12, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_PRN, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_SCR, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_BRK, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_LED1, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_LED2, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_LED3, TB_WHITE, TB_BLUE);
|
||||
|
||||
draw_key(K_TILDE, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_1, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_2, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_3, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_4, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_5, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_6, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_7, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_8, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_9, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_0, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_MINUS, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_EQUALS, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_BACKSLASH, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_BACKSPACE, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_INS, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_HOM, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_PGU, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_NUMLOCK, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_SLASH, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_STAR, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_MINUS, TB_WHITE, TB_BLUE);
|
||||
|
||||
draw_key(K_TAB, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_q, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_w, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_e, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_r, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_t, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_y, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_u, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_i, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_o, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_p, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_LSQB, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_RSQB, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_ENTER, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_DEL, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_END, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_PGD, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_7, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_8, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_9, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_PLUS, TB_WHITE, TB_BLUE);
|
||||
|
||||
draw_key(K_CAPS, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_a, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_s, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_d, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_f, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_g, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_h, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_j, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_k, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_l, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_SEMICOLON, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_QUOTE, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_4, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_5, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_6, TB_WHITE, TB_BLUE);
|
||||
|
||||
draw_key(K_LSHIFT, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_z, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_x, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_c, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_v, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_b, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_n, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_m, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_COMMA, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_PERIOD, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_SLASH, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_RSHIFT, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_ARROW_UP, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_1, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_2, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_3, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_ENTER, TB_WHITE, TB_BLUE);
|
||||
|
||||
draw_key(K_LCTRL, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_LWIN, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_LALT, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_SPACE, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_RCTRL, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_RPROP, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_RWIN, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_RALT, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_ARROW_LEFT, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_ARROW_DOWN, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_ARROW_RIGHT, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_0, TB_WHITE, TB_BLUE);
|
||||
draw_key(K_K_PERIOD, TB_WHITE, TB_BLUE);
|
||||
|
||||
printf_tb(33, 1, TB_MAGENTA | TB_BOLD, TB_DEFAULT, "Keyboard demo!");
|
||||
printf_tb(21, 2, TB_MAGENTA, TB_DEFAULT,
|
||||
"(press CTRL+X and then CTRL+Q to exit)");
|
||||
printf_tb(15, 3, TB_MAGENTA, TB_DEFAULT,
|
||||
"(press CTRL+X and then CTRL+C to change input mode)");
|
||||
|
||||
int inputmode = tb_select_input_mode(0);
|
||||
char inputmode_str[64];
|
||||
|
||||
if (inputmode & TB_INPUT_ESC)
|
||||
{
|
||||
sprintf(inputmode_str, "TB_INPUT_ESC");
|
||||
}
|
||||
|
||||
if (inputmode & TB_INPUT_ALT)
|
||||
{
|
||||
sprintf(inputmode_str, "TB_INPUT_ALT");
|
||||
}
|
||||
|
||||
if (inputmode & TB_INPUT_MOUSE)
|
||||
{
|
||||
sprintf(inputmode_str + 12, " | TB_INPUT_MOUSE");
|
||||
}
|
||||
|
||||
printf_tb(3, 18, TB_WHITE, TB_DEFAULT, "Input mode: %s", inputmode_str);
|
||||
}
|
||||
|
||||
const char* funckeymap(int k)
|
||||
{
|
||||
static const char* fcmap[] =
|
||||
{
|
||||
"CTRL+2, CTRL+~",
|
||||
"CTRL+A",
|
||||
"CTRL+B",
|
||||
"CTRL+C",
|
||||
"CTRL+D",
|
||||
"CTRL+E",
|
||||
"CTRL+F",
|
||||
"CTRL+G",
|
||||
"CTRL+H, BACKSPACE",
|
||||
"CTRL+I, TAB",
|
||||
"CTRL+J",
|
||||
"CTRL+K",
|
||||
"CTRL+L",
|
||||
"CTRL+M, ENTER",
|
||||
"CTRL+N",
|
||||
"CTRL+O",
|
||||
"CTRL+P",
|
||||
"CTRL+Q",
|
||||
"CTRL+R",
|
||||
"CTRL+S",
|
||||
"CTRL+T",
|
||||
"CTRL+U",
|
||||
"CTRL+V",
|
||||
"CTRL+W",
|
||||
"CTRL+X",
|
||||
"CTRL+Y",
|
||||
"CTRL+Z",
|
||||
"CTRL+3, ESC, CTRL+[",
|
||||
"CTRL+4, CTRL+\\",
|
||||
"CTRL+5, CTRL+]",
|
||||
"CTRL+6",
|
||||
"CTRL+7, CTRL+/, CTRL+_",
|
||||
"SPACE"
|
||||
};
|
||||
static const char* fkmap[] =
|
||||
{
|
||||
"F1",
|
||||
"F2",
|
||||
"F3",
|
||||
"F4",
|
||||
"F5",
|
||||
"F6",
|
||||
"F7",
|
||||
"F8",
|
||||
"F9",
|
||||
"F10",
|
||||
"F11",
|
||||
"F12",
|
||||
"INSERT",
|
||||
"DELETE",
|
||||
"HOME",
|
||||
"END",
|
||||
"PGUP",
|
||||
"PGDN",
|
||||
"ARROW UP",
|
||||
"ARROW DOWN",
|
||||
"ARROW LEFT",
|
||||
"ARROW RIGHT"
|
||||
};
|
||||
|
||||
if (k == TB_KEY_CTRL_8)
|
||||
{
|
||||
return "CTRL+8, BACKSPACE 2"; // 0x7F
|
||||
}
|
||||
else if (k >= TB_KEY_ARROW_RIGHT && k <= 0xFFFF)
|
||||
{
|
||||
return fkmap[0xFFFF - k];
|
||||
}
|
||||
else if (k <= TB_KEY_SPACE)
|
||||
{
|
||||
return fcmap[k];
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
void pretty_print_press(struct tb_event* ev)
|
||||
{
|
||||
char buf[7];
|
||||
buf[utf8_unicode_to_char(buf, ev->ch)] = '\0';
|
||||
printf_tb(3, 19, TB_WHITE, TB_DEFAULT, "Key: ");
|
||||
printf_tb(8, 19, TB_YELLOW, TB_DEFAULT, "decimal: %d", ev->key);
|
||||
printf_tb(8, 20, TB_GREEN, TB_DEFAULT, "hex: 0x%X", ev->key);
|
||||
printf_tb(8, 21, TB_CYAN, TB_DEFAULT, "octal: 0%o", ev->key);
|
||||
printf_tb(8, 22, TB_RED, TB_DEFAULT, "string: %s", funckeymap(ev->key));
|
||||
|
||||
printf_tb(54, 19, TB_WHITE, TB_DEFAULT, "Char: ");
|
||||
printf_tb(60, 19, TB_YELLOW, TB_DEFAULT, "decimal: %d", ev->ch);
|
||||
printf_tb(60, 20, TB_GREEN, TB_DEFAULT, "hex: 0x%X", ev->ch);
|
||||
printf_tb(60, 21, TB_CYAN, TB_DEFAULT, "octal: 0%o", ev->ch);
|
||||
printf_tb(60, 22, TB_RED, TB_DEFAULT, "string: %s", buf);
|
||||
|
||||
printf_tb(54, 18, TB_WHITE, TB_DEFAULT, "Modifier: %s",
|
||||
(ev->mod) ? "TB_MOD_ALT" : "none");
|
||||
|
||||
}
|
||||
|
||||
void pretty_print_resize(struct tb_event* ev)
|
||||
{
|
||||
printf_tb(3, 19, TB_WHITE, TB_DEFAULT, "Resize event: %d x %d", ev->w, ev->h);
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
|
||||
void pretty_print_mouse(struct tb_event* ev)
|
||||
{
|
||||
printf_tb(3, 19, TB_WHITE, TB_DEFAULT, "Mouse event: %d x %d", ev->x, ev->y);
|
||||
char* btn = "";
|
||||
|
||||
switch (ev->key)
|
||||
{
|
||||
case TB_KEY_MOUSE_LEFT:
|
||||
btn = "MouseLeft: %d";
|
||||
break;
|
||||
|
||||
case TB_KEY_MOUSE_MIDDLE:
|
||||
btn = "MouseMiddle: %d";
|
||||
break;
|
||||
|
||||
case TB_KEY_MOUSE_RIGHT:
|
||||
btn = "MouseRight: %d";
|
||||
break;
|
||||
|
||||
case TB_KEY_MOUSE_WHEEL_UP:
|
||||
btn = "MouseWheelUp: %d";
|
||||
break;
|
||||
|
||||
case TB_KEY_MOUSE_WHEEL_DOWN:
|
||||
btn = "MouseWheelDown: %d";
|
||||
break;
|
||||
|
||||
case TB_KEY_MOUSE_RELEASE:
|
||||
btn = "MouseRelease: %d";
|
||||
}
|
||||
|
||||
counter++;
|
||||
printf_tb(43, 19, TB_WHITE, TB_DEFAULT, "Key: ");
|
||||
printf_tb(48, 19, TB_YELLOW, TB_DEFAULT, btn, counter);
|
||||
}
|
||||
|
||||
void dispatch_press(struct tb_event* ev)
|
||||
{
|
||||
if (ev->mod & TB_MOD_ALT)
|
||||
{
|
||||
draw_key(K_LALT, TB_WHITE, TB_RED);
|
||||
draw_key(K_RALT, TB_WHITE, TB_RED);
|
||||
}
|
||||
|
||||
struct combo* k = 0;
|
||||
|
||||
if (ev->key >= TB_KEY_ARROW_RIGHT)
|
||||
{
|
||||
k = &func_combos[0xFFFF - ev->key];
|
||||
}
|
||||
else if (ev->ch < 128)
|
||||
{
|
||||
if (ev->ch == 0 && ev->key < 128)
|
||||
{
|
||||
k = &combos[ev->key];
|
||||
}
|
||||
else
|
||||
{
|
||||
k = &combos[ev->ch];
|
||||
}
|
||||
}
|
||||
|
||||
if (!k)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
struct key** keys = k->keys;
|
||||
|
||||
while (*keys)
|
||||
{
|
||||
draw_key(*keys, TB_WHITE, TB_RED);
|
||||
keys++;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
int ret;
|
||||
|
||||
ret = tb_init();
|
||||
|
||||
if (ret)
|
||||
{
|
||||
fprintf(stderr, "tb_init() failed with error code %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
tb_select_input_mode(TB_INPUT_ESC | TB_INPUT_MOUSE);
|
||||
struct tb_event ev;
|
||||
|
||||
tb_clear();
|
||||
draw_keyboard();
|
||||
tb_present();
|
||||
int inputmode = 0;
|
||||
int ctrlxpressed = 0;
|
||||
|
||||
while (tb_poll_event(&ev))
|
||||
{
|
||||
switch (ev.type)
|
||||
{
|
||||
case TB_EVENT_KEY:
|
||||
if (ev.key == TB_KEY_CTRL_Q && ctrlxpressed)
|
||||
{
|
||||
tb_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ev.key == TB_KEY_CTRL_C && ctrlxpressed)
|
||||
{
|
||||
static int chmap[] =
|
||||
{
|
||||
TB_INPUT_ESC | TB_INPUT_MOUSE, // 101
|
||||
TB_INPUT_ALT | TB_INPUT_MOUSE, // 110
|
||||
TB_INPUT_ESC, // 001
|
||||
TB_INPUT_ALT, // 010
|
||||
};
|
||||
inputmode++;
|
||||
|
||||
if (inputmode >= 4)
|
||||
{
|
||||
inputmode = 0;
|
||||
}
|
||||
|
||||
tb_select_input_mode(chmap[inputmode]);
|
||||
}
|
||||
|
||||
if (ev.key == TB_KEY_CTRL_X)
|
||||
{
|
||||
ctrlxpressed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctrlxpressed = 0;
|
||||
}
|
||||
|
||||
tb_clear();
|
||||
draw_keyboard();
|
||||
dispatch_press(&ev);
|
||||
pretty_print_press(&ev);
|
||||
tb_present();
|
||||
break;
|
||||
|
||||
case TB_EVENT_RESIZE:
|
||||
tb_clear();
|
||||
draw_keyboard();
|
||||
pretty_print_resize(&ev);
|
||||
tb_present();
|
||||
break;
|
||||
|
||||
case TB_EVENT_MOUSE:
|
||||
tb_clear();
|
||||
draw_keyboard();
|
||||
pretty_print_mouse(&ev);
|
||||
tb_present();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tb_shutdown();
|
||||
return 0;
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
CC=gcc
|
||||
FLAGS=-std=c99 -pedantic -Wall -Werror -g -static
|
||||
INCL=-I../
|
||||
BIND=../../bin
|
||||
|
||||
%.o:%.c
|
||||
@echo "building source object $@"
|
||||
@$(CC) $(INCL) $(FLAGS) -c -o $@ $<
|
||||
|
||||
all:keyboard output paint truecolor
|
||||
|
||||
keyboard:keyboard.o
|
||||
@echo "compiling $@"
|
||||
@$(CC) $(INCL) $(FLAGS) -o $@ $@.o $(BIND)/termbox.a
|
||||
|
||||
output:output.o
|
||||
@echo "compiling $@"
|
||||
@$(CC) $(INCL) $(FLAGS) -o $@ $@.o $(BIND)/termbox.a
|
||||
|
||||
paint:paint.o
|
||||
@echo "compiling $@"
|
||||
@$(CC) $(INCL) $(FLAGS) -o $@ $@.o $(BIND)/termbox.a
|
||||
|
||||
truecolor:truecolor.o
|
||||
@echo "compiling $@"
|
||||
@$(CC) $(INCL) $(FLAGS) -o $@ $@.o $(BIND)/termbox.a
|
||||
|
||||
clean:
|
||||
@echo "cleaning workspace"
|
||||
@rm -rf *.o keyboard output paint truecolor
|
@ -1,156 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../termbox.h"
|
||||
|
||||
static const char chars[] = "nnnnnnnnnbbbbbbbbbuuuuuuuuuBBBBBBBBB";
|
||||
|
||||
static const uint32_t all_attrs[] =
|
||||
{
|
||||
0,
|
||||
TB_BOLD,
|
||||
TB_UNDERLINE,
|
||||
TB_BOLD | TB_UNDERLINE,
|
||||
};
|
||||
|
||||
static int next_char(int current)
|
||||
{
|
||||
current++;
|
||||
|
||||
if (!chars[current])
|
||||
{
|
||||
current = 0;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
static void draw_line(int x, int y, uint32_t bg)
|
||||
{
|
||||
int a, c;
|
||||
int current_char = 0;
|
||||
|
||||
for (a = 0; a < 4; a++)
|
||||
{
|
||||
for (c = TB_DEFAULT; c <= TB_WHITE; c++)
|
||||
{
|
||||
uint32_t fg = all_attrs[a] | c;
|
||||
tb_change_cell(x, y, chars[current_char], fg, bg);
|
||||
current_char = next_char(current_char);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void print_combinations_table(int sx, int sy, const uint32_t* attrs,
|
||||
int attrs_n)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
for (i = 0; i < attrs_n; i++)
|
||||
{
|
||||
for (c = TB_DEFAULT; c <= TB_WHITE; c++)
|
||||
{
|
||||
uint32_t bg = attrs[i] | c;
|
||||
draw_line(sx, sy, bg);
|
||||
sy++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_all()
|
||||
{
|
||||
tb_clear();
|
||||
|
||||
tb_select_output_mode(TB_OUTPUT_NORMAL);
|
||||
static const uint32_t col1[] = {0, TB_BOLD};
|
||||
static const uint32_t col2[] = {TB_REVERSE};
|
||||
print_combinations_table(1, 1, col1, 2);
|
||||
print_combinations_table(2 + strlen(chars), 1, col2, 1);
|
||||
tb_present();
|
||||
|
||||
tb_select_output_mode(TB_OUTPUT_GRAYSCALE);
|
||||
int c, x, y;
|
||||
|
||||
for (x = 0, y = 23; x < 24; ++x)
|
||||
{
|
||||
tb_change_cell(x, y, '@', x, 0);
|
||||
tb_change_cell(x + 25, y, ' ', 0, x);
|
||||
}
|
||||
|
||||
tb_present();
|
||||
|
||||
tb_select_output_mode(TB_OUTPUT_216);
|
||||
y++;
|
||||
|
||||
for (c = 0, x = 0; c < 216; ++c, ++x)
|
||||
{
|
||||
if (!(x % 24))
|
||||
{
|
||||
x = 0;
|
||||
++y;
|
||||
}
|
||||
|
||||
tb_change_cell(x, y, '@', c, 0);
|
||||
tb_change_cell(x + 25, y, ' ', 0, c);
|
||||
}
|
||||
|
||||
tb_present();
|
||||
|
||||
tb_select_output_mode(TB_OUTPUT_256);
|
||||
y++;
|
||||
|
||||
for (c = 0, x = 0; c < 256; ++c, ++x)
|
||||
{
|
||||
if (!(x % 24))
|
||||
{
|
||||
x = 0;
|
||||
++y;
|
||||
}
|
||||
|
||||
tb_change_cell(x, y, '+', c | ((y & 1) ? TB_UNDERLINE : 0), 0);
|
||||
tb_change_cell(x + 25, y, ' ', 0, c);
|
||||
}
|
||||
|
||||
tb_present();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
int ret = tb_init();
|
||||
|
||||
if (ret)
|
||||
{
|
||||
fprintf(stderr, "tb_init() failed with error code %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
draw_all();
|
||||
|
||||
struct tb_event ev;
|
||||
|
||||
while (tb_poll_event(&ev))
|
||||
{
|
||||
switch (ev.type)
|
||||
{
|
||||
case TB_EVENT_KEY:
|
||||
switch (ev.key)
|
||||
{
|
||||
case TB_KEY_ESC:
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TB_EVENT_RESIZE:
|
||||
draw_all();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
tb_shutdown();
|
||||
return 0;
|
||||
}
|
@ -1,183 +0,0 @@
|
||||
#include "../termbox.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static int curCol = 0;
|
||||
static int curRune = 0;
|
||||
static struct tb_cell* backbuf;
|
||||
static int bbw = 0, bbh = 0;
|
||||
|
||||
static const uint32_t runes[] =
|
||||
{
|
||||
0x20, // ' '
|
||||
0x2591, // '░'
|
||||
0x2592, // '▒'
|
||||
0x2593, // '▓'
|
||||
0x2588, // '█'
|
||||
};
|
||||
|
||||
#define len(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
static const uint32_t colors[] =
|
||||
{
|
||||
TB_BLACK,
|
||||
TB_RED,
|
||||
TB_GREEN,
|
||||
TB_YELLOW,
|
||||
TB_BLUE,
|
||||
TB_MAGENTA,
|
||||
TB_CYAN,
|
||||
TB_WHITE,
|
||||
};
|
||||
|
||||
void updateAndDrawButtons(int* current, int x, int y, int mx, int my, int n,
|
||||
void (*attrFunc)(int, uint32_t*, uint32_t*, uint32_t*))
|
||||
{
|
||||
int lx = x;
|
||||
int ly = y;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
if (lx <= mx && mx <= lx + 3 && ly <= my && my <= ly + 1)
|
||||
{
|
||||
*current = i;
|
||||
}
|
||||
|
||||
uint32_t r;
|
||||
uint32_t fg, bg;
|
||||
(*attrFunc)(i, &r, &fg, &bg);
|
||||
tb_change_cell(lx + 0, ly + 0, r, fg, bg);
|
||||
tb_change_cell(lx + 1, ly + 0, r, fg, bg);
|
||||
tb_change_cell(lx + 2, ly + 0, r, fg, bg);
|
||||
tb_change_cell(lx + 3, ly + 0, r, fg, bg);
|
||||
tb_change_cell(lx + 0, ly + 1, r, fg, bg);
|
||||
tb_change_cell(lx + 1, ly + 1, r, fg, bg);
|
||||
tb_change_cell(lx + 2, ly + 1, r, fg, bg);
|
||||
tb_change_cell(lx + 3, ly + 1, r, fg, bg);
|
||||
lx += 4;
|
||||
}
|
||||
|
||||
lx = x;
|
||||
ly = y;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
if (*current == i)
|
||||
{
|
||||
uint32_t fg = TB_RED | TB_BOLD;
|
||||
uint32_t bg = TB_DEFAULT;
|
||||
tb_change_cell(lx + 0, ly + 2, '^', fg, bg);
|
||||
tb_change_cell(lx + 1, ly + 2, '^', fg, bg);
|
||||
tb_change_cell(lx + 2, ly + 2, '^', fg, bg);
|
||||
tb_change_cell(lx + 3, ly + 2, '^', fg, bg);
|
||||
}
|
||||
|
||||
lx += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void runeAttrFunc(int i, uint32_t* r, uint32_t* fg, uint32_t* bg)
|
||||
{
|
||||
*r = runes[i];
|
||||
*fg = TB_DEFAULT;
|
||||
*bg = TB_DEFAULT;
|
||||
}
|
||||
|
||||
void colorAttrFunc(int i, uint32_t* r, uint32_t* fg, uint32_t* bg)
|
||||
{
|
||||
*r = ' ';
|
||||
*fg = TB_DEFAULT;
|
||||
*bg = colors[i];
|
||||
}
|
||||
|
||||
void updateAndRedrawAll(int mx, int my)
|
||||
{
|
||||
tb_clear();
|
||||
|
||||
if (mx != -1 && my != -1)
|
||||
{
|
||||
backbuf[bbw * my + mx].ch = runes[curRune];
|
||||
backbuf[bbw * my + mx].fg = colors[curCol];
|
||||
}
|
||||
|
||||
memcpy(tb_cell_buffer(), backbuf, sizeof(struct tb_cell)*bbw * bbh);
|
||||
int h = tb_height();
|
||||
updateAndDrawButtons(&curRune, 0, 0, mx, my, len(runes), runeAttrFunc);
|
||||
updateAndDrawButtons(&curCol, 0, h - 3, mx, my, len(colors), colorAttrFunc);
|
||||
tb_present();
|
||||
}
|
||||
|
||||
void reallocBackBuffer(int w, int h)
|
||||
{
|
||||
bbw = w;
|
||||
bbh = h;
|
||||
|
||||
if (backbuf)
|
||||
{
|
||||
free(backbuf);
|
||||
}
|
||||
|
||||
backbuf = calloc(sizeof(struct tb_cell), w * h);
|
||||
}
|
||||
|
||||
int main(int argv, char** argc)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
int code = tb_init();
|
||||
|
||||
if (code < 0)
|
||||
{
|
||||
fprintf(stderr, "termbox init failed, code: %d\n", code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tb_select_input_mode(TB_INPUT_ESC | TB_INPUT_MOUSE);
|
||||
int w = tb_width();
|
||||
int h = tb_height();
|
||||
reallocBackBuffer(w, h);
|
||||
updateAndRedrawAll(-1, -1);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
struct tb_event ev;
|
||||
int mx = -1;
|
||||
int my = -1;
|
||||
int t = tb_poll_event(&ev);
|
||||
|
||||
if (t == -1)
|
||||
{
|
||||
tb_shutdown();
|
||||
fprintf(stderr, "termbox poll event error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (t)
|
||||
{
|
||||
case TB_EVENT_KEY:
|
||||
if (ev.key == TB_KEY_ESC)
|
||||
{
|
||||
tb_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TB_EVENT_MOUSE:
|
||||
if (ev.key == TB_KEY_MOUSE_LEFT)
|
||||
{
|
||||
mx = ev.x;
|
||||
my = ev.y;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TB_EVENT_RESIZE:
|
||||
reallocBackBuffer(ev.w, ev.h);
|
||||
break;
|
||||
}
|
||||
|
||||
updateAndRedrawAll(mx, my);
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
#include "termbox.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
tb_init();
|
||||
tb_select_output_mode(TB_OUTPUT_TRUECOLOR);
|
||||
int w = tb_width();
|
||||
int h = tb_height();
|
||||
uint32_t bg = 0x000000, fg = 0x000000;
|
||||
tb_clear();
|
||||
int z = 0;
|
||||
|
||||
for (int y = 1; y < h; y++)
|
||||
{
|
||||
for (int x = 1; x < w; x++)
|
||||
{
|
||||
uint32_t ch;
|
||||
utf8_char_to_unicode(&ch, "x");
|
||||
fg = 0;
|
||||
|
||||
if (z % 2 == 0)
|
||||
{
|
||||
fg |= TB_BOLD;
|
||||
}
|
||||
|
||||
if (z % 3 == 0)
|
||||
{
|
||||
fg |= TB_UNDERLINE;
|
||||
}
|
||||
|
||||
if (z % 5 == 0)
|
||||
{
|
||||
fg |= TB_REVERSE;
|
||||
}
|
||||
|
||||
tb_change_cell(x, y, ch, fg, bg);
|
||||
bg += 0x000101;
|
||||
z++;
|
||||
}
|
||||
|
||||
bg += 0x080000;
|
||||
|
||||
if (bg > 0xFFFFFF)
|
||||
{
|
||||
bg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
tb_present();
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct tb_event ev;
|
||||
int t = tb_poll_event(&ev);
|
||||
|
||||
if (t == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (t == TB_EVENT_KEY)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tb_shutdown();
|
||||
return 0;
|
||||
}
|
@ -1,319 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "term.h"
|
||||
|
||||
#define BUFFER_SIZE_MAX 16
|
||||
|
||||
// if s1 starts with s2 returns 1, else 0
|
||||
static int starts_with(const char* s1, const char* s2)
|
||||
{
|
||||
// nice huh?
|
||||
while (*s2)
|
||||
{
|
||||
if (*s1++ != *s2++)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int parse_mouse_event(struct tb_event* event, const char* buf, int len)
|
||||
{
|
||||
if ((len >= 6) && starts_with(buf, "\033[M"))
|
||||
{
|
||||
// X10 mouse encoding, the simplest one
|
||||
// \033 [ M Cb Cx Cy
|
||||
int b = buf[3] - 32;
|
||||
|
||||
switch (b & 3)
|
||||
{
|
||||
case 0:
|
||||
if ((b & 64) != 0)
|
||||
{
|
||||
event->key = TB_KEY_MOUSE_WHEEL_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
event->key = TB_KEY_MOUSE_LEFT;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if ((b & 64) != 0)
|
||||
{
|
||||
event->key = TB_KEY_MOUSE_WHEEL_DOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
event->key = TB_KEY_MOUSE_MIDDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
event->key = TB_KEY_MOUSE_RIGHT;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
event->key = TB_KEY_MOUSE_RELEASE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -6;
|
||||
}
|
||||
|
||||
event->type = TB_EVENT_MOUSE; // TB_EVENT_KEY by default
|
||||
|
||||
if ((b & 32) != 0)
|
||||
{
|
||||
event->mod |= TB_MOD_MOTION;
|
||||
}
|
||||
|
||||
// the coord is 1,1 for upper left
|
||||
event->x = (uint8_t)buf[4] - 1 - 32;
|
||||
event->y = (uint8_t)buf[5] - 1 - 32;
|
||||
return 6;
|
||||
}
|
||||
else if (starts_with(buf, "\033[<") || starts_with(buf, "\033["))
|
||||
{
|
||||
// xterm 1006 extended mode or urxvt 1015 extended mode
|
||||
// xterm: \033 [ < Cb ; Cx ; Cy (M or m)
|
||||
// urxvt: \033 [ Cb ; Cx ; Cy M
|
||||
int i, mi = -1, starti = -1;
|
||||
int isM, isU, s1 = -1, s2 = -1;
|
||||
int n1 = 0, n2 = 0, n3 = 0;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
// We search the first (s1) and the last (s2) ';'
|
||||
if (buf[i] == ';')
|
||||
{
|
||||
if (s1 == -1)
|
||||
{
|
||||
s1 = i;
|
||||
}
|
||||
|
||||
s2 = i;
|
||||
}
|
||||
|
||||
// We search for the first 'm' or 'M'
|
||||
if ((buf[i] == 'm' || buf[i] == 'M') && mi == -1)
|
||||
{
|
||||
mi = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mi == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// whether it's a capital M or not
|
||||
isM = (buf[mi] == 'M');
|
||||
|
||||
if (buf[2] == '<')
|
||||
{
|
||||
isU = 0;
|
||||
starti = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
isU = 1;
|
||||
starti = 2;
|
||||
}
|
||||
|
||||
if (s1 == -1 || s2 == -1 || s1 == s2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
n1 = strtoul(&buf[starti], NULL, 10);
|
||||
n2 = strtoul(&buf[s1 + 1], NULL, 10);
|
||||
n3 = strtoul(&buf[s2 + 1], NULL, 10);
|
||||
|
||||
if (isU)
|
||||
{
|
||||
n1 -= 32;
|
||||
}
|
||||
|
||||
switch (n1 & 3)
|
||||
{
|
||||
case 0:
|
||||
if ((n1 & 64) != 0)
|
||||
{
|
||||
event->key = TB_KEY_MOUSE_WHEEL_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
event->key = TB_KEY_MOUSE_LEFT;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if ((n1 & 64) != 0)
|
||||
{
|
||||
event->key = TB_KEY_MOUSE_WHEEL_DOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
event->key = TB_KEY_MOUSE_MIDDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
event->key = TB_KEY_MOUSE_RIGHT;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
event->key = TB_KEY_MOUSE_RELEASE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return mi + 1;
|
||||
}
|
||||
|
||||
if (!isM)
|
||||
{
|
||||
// on xterm mouse release is signaled by lowercase m
|
||||
event->key = TB_KEY_MOUSE_RELEASE;
|
||||
}
|
||||
|
||||
event->type = TB_EVENT_MOUSE; // TB_EVENT_KEY by default
|
||||
|
||||
if ((n1 & 32) != 0)
|
||||
{
|
||||
event->mod |= TB_MOD_MOTION;
|
||||
}
|
||||
|
||||
event->x = (uint8_t)n2 - 1;
|
||||
event->y = (uint8_t)n3 - 1;
|
||||
return mi + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// convert escape sequence to event, and return consumed bytes on success (failure == 0)
|
||||
static int parse_escape_seq(struct tb_event* event, const char* buf, int len)
|
||||
{
|
||||
int mouse_parsed = parse_mouse_event(event, buf, len);
|
||||
|
||||
if (mouse_parsed != 0)
|
||||
{
|
||||
return mouse_parsed;
|
||||
}
|
||||
|
||||
// it's pretty simple here, find 'starts_with' match and return success, else return failure
|
||||
int i;
|
||||
|
||||
for (i = 0; keys[i]; i++)
|
||||
{
|
||||
if (starts_with(buf, keys[i]))
|
||||
{
|
||||
event->ch = 0;
|
||||
event->key = 0xFFFF - i;
|
||||
return strlen(keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool extract_event(struct tb_event* event, struct ringbuffer* inbuf,
|
||||
int inputmode)
|
||||
{
|
||||
char buf[BUFFER_SIZE_MAX + 1];
|
||||
int nbytes = ringbuffer_data_size(inbuf);
|
||||
|
||||
if (nbytes > BUFFER_SIZE_MAX)
|
||||
{
|
||||
nbytes = BUFFER_SIZE_MAX;
|
||||
}
|
||||
|
||||
if (nbytes == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ringbuffer_read(inbuf, buf, nbytes);
|
||||
buf[nbytes] = '\0';
|
||||
|
||||
if (buf[0] == '\033')
|
||||
{
|
||||
int n = parse_escape_seq(event, buf, nbytes);
|
||||
|
||||
if (n != 0)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
success = false;
|
||||
n = -n;
|
||||
}
|
||||
|
||||
ringbuffer_pop(inbuf, 0, n);
|
||||
return success;
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's not escape sequence, then it's ALT or ESC, check inputmode
|
||||
if (inputmode & TB_INPUT_ESC)
|
||||
{
|
||||
// if we're in escape mode, fill ESC event, pop buffer, return success
|
||||
event->ch = 0;
|
||||
event->key = TB_KEY_ESC;
|
||||
event->mod = 0;
|
||||
ringbuffer_pop(inbuf, 0, 1);
|
||||
return true;
|
||||
}
|
||||
else if (inputmode & TB_INPUT_ALT)
|
||||
{
|
||||
// if we're in alt mode, set ALT modifier to event and redo parsing
|
||||
event->mod = TB_MOD_ALT;
|
||||
ringbuffer_pop(inbuf, 0, 1);
|
||||
return extract_event(event, inbuf, inputmode);
|
||||
}
|
||||
|
||||
assert(!"never got here");
|
||||
}
|
||||
}
|
||||
|
||||
// if we're here, this is not an escape sequence and not an alt sequence
|
||||
// so, it's a FUNCTIONAL KEY or a UNICODE character
|
||||
|
||||
// first of all check if it's a functional key*/
|
||||
if ((unsigned char)buf[0] <= TB_KEY_SPACE ||
|
||||
(unsigned char)buf[0] == TB_KEY_BACKSPACE2)
|
||||
{
|
||||
// fill event, pop buffer, return success
|
||||
event->ch = 0;
|
||||
event->key = (uint16_t)buf[0];
|
||||
ringbuffer_pop(inbuf, 0, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// feh... we got utf8 here
|
||||
|
||||
// check if there is all bytes
|
||||
if (nbytes >= utf8_char_length(buf[0]))
|
||||
{
|
||||
// everything ok, fill event, pop buffer, return success
|
||||
utf8_char_to_unicode(&event->ch, buf);
|
||||
event->key = 0;
|
||||
ringbuffer_pop(inbuf, 0, utf8_char_length(buf[0]));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "memstream.h"
|
||||
|
||||
void memstream_init(struct memstream* s, int fd, void* buffer, size_t len)
|
||||
{
|
||||
s->file = fd;
|
||||
s->data = buffer;
|
||||
s->pos = 0;
|
||||
s->capa = len;
|
||||
}
|
||||
|
||||
void memstream_flush(struct memstream* s)
|
||||
{
|
||||
write(s->file, s->data, s->pos);
|
||||
s->pos = 0;
|
||||
}
|
||||
|
||||
void memstream_write(struct memstream* s, void* source, size_t len)
|
||||
{
|
||||
unsigned char* data = source;
|
||||
|
||||
if (s->pos + len > s->capa)
|
||||
{
|
||||
memstream_flush(s);
|
||||
}
|
||||
|
||||
memcpy(s->data + s->pos, data, len);
|
||||
s->pos += len;
|
||||
}
|
||||
|
||||
void memstream_puts(struct memstream* s, const char* str)
|
||||
{
|
||||
memstream_write(s, (void*) str, strlen(str));
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#ifndef H_MEMSTREAM
|
||||
#define H_MEMSTREAM
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct memstream
|
||||
{
|
||||
size_t pos;
|
||||
size_t capa;
|
||||
int file;
|
||||
unsigned char* data;
|
||||
};
|
||||
|
||||
void memstream_init(struct memstream* s, int fd, void* buffer, size_t len);
|
||||
void memstream_flush(struct memstream* s);
|
||||
void memstream_write(struct memstream* s, void* source, size_t len);
|
||||
void memstream_puts(struct memstream* s, const char* str);
|
||||
|
||||
#endif
|
@ -1,195 +0,0 @@
|
||||
#include "ringbuffer.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h> // for ptrdiff_t
|
||||
|
||||
int init_ringbuffer(struct ringbuffer* r, size_t size)
|
||||
{
|
||||
r->buf = (char*)malloc(size);
|
||||
|
||||
if (!r->buf)
|
||||
{
|
||||
return ERINGBUFFER_ALLOC_FAIL;
|
||||
}
|
||||
|
||||
r->size = size;
|
||||
clear_ringbuffer(r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_ringbuffer(struct ringbuffer* r)
|
||||
{
|
||||
free(r->buf);
|
||||
}
|
||||
|
||||
void clear_ringbuffer(struct ringbuffer* r)
|
||||
{
|
||||
r->begin = 0;
|
||||
r->end = 0;
|
||||
}
|
||||
|
||||
size_t ringbuffer_free_space(struct ringbuffer* r)
|
||||
{
|
||||
if (r->begin == 0 && r->end == 0)
|
||||
{
|
||||
return r->size;
|
||||
}
|
||||
|
||||
if (r->begin < r->end)
|
||||
{
|
||||
return r->size - (r->end - r->begin) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return r->begin - r->end - 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ringbuffer_data_size(struct ringbuffer* r)
|
||||
{
|
||||
if (r->begin == 0 && r->end == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (r->begin <= r->end)
|
||||
{
|
||||
return r->end - r->begin + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return r->size - (r->begin - r->end) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ringbuffer_push(struct ringbuffer* r, const void* data, size_t size)
|
||||
{
|
||||
if (ringbuffer_free_space(r) < size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (r->begin == 0 && r->end == 0)
|
||||
{
|
||||
memcpy(r->buf, data, size);
|
||||
r->begin = r->buf;
|
||||
r->end = r->buf + size - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
r->end++;
|
||||
|
||||
if (r->begin < r->end)
|
||||
{
|
||||
if ((size_t)(r->buf + (ptrdiff_t)r->size - r->begin) >= size)
|
||||
{
|
||||
// we can fit without cut
|
||||
memcpy(r->end, data, size);
|
||||
r->end += size - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// make a cut
|
||||
size_t s = r->buf + r->size - r->end;
|
||||
memcpy(r->end, data, s);
|
||||
size -= s;
|
||||
memcpy(r->buf, (char*)data + s, size);
|
||||
r->end = r->buf + size - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(r->end, data, size);
|
||||
r->end += size - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ringbuffer_pop(struct ringbuffer* r, void* data, size_t size)
|
||||
{
|
||||
if (ringbuffer_data_size(r) < size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int need_clear = 0;
|
||||
|
||||
if (ringbuffer_data_size(r) == size)
|
||||
{
|
||||
need_clear = 1;
|
||||
}
|
||||
|
||||
if (r->begin < r->end)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
memcpy(data, r->begin, size);
|
||||
}
|
||||
|
||||
r->begin += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((size_t)(r->buf + (ptrdiff_t)r->size - r->begin) >= size)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
memcpy(data, r->begin, size);
|
||||
}
|
||||
|
||||
r->begin += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t s = r->buf + r->size - r->begin;
|
||||
|
||||
if (data)
|
||||
{
|
||||
memcpy(data, r->begin, s);
|
||||
}
|
||||
|
||||
size -= s;
|
||||
|
||||
if (data)
|
||||
{
|
||||
memcpy((char*)data + s, r->buf, size);
|
||||
}
|
||||
|
||||
r->begin = r->buf + size;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_clear)
|
||||
{
|
||||
clear_ringbuffer(r);
|
||||
}
|
||||
}
|
||||
|
||||
void ringbuffer_read(struct ringbuffer* r, void* data, size_t size)
|
||||
{
|
||||
if (ringbuffer_data_size(r) < size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (r->begin < r->end)
|
||||
{
|
||||
memcpy(data, r->begin, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((size_t)(r->buf + (ptrdiff_t)r->size - r->begin) >= size)
|
||||
{
|
||||
memcpy(data, r->begin, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t s = r->buf + r->size - r->begin;
|
||||
memcpy(data, r->begin, s);
|
||||
size -= s;
|
||||
memcpy((char*)data + s, r->buf, size);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
#ifndef H_RINGBUFFER
|
||||
#define H_RINGBUFFER
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define ERINGBUFFER_ALLOC_FAIL -1
|
||||
|
||||
struct ringbuffer
|
||||
{
|
||||
char* buf;
|
||||
size_t size;
|
||||
|
||||
char* begin;
|
||||
char* end;
|
||||
};
|
||||
|
||||
int init_ringbuffer(struct ringbuffer* r, size_t size);
|
||||
void free_ringbuffer(struct ringbuffer* r);
|
||||
void clear_ringbuffer(struct ringbuffer* r);
|
||||
size_t ringbuffer_free_space(struct ringbuffer* r);
|
||||
size_t ringbuffer_data_size(struct ringbuffer* r);
|
||||
void ringbuffer_push(struct ringbuffer* r, const void* data, size_t size);
|
||||
void ringbuffer_pop(struct ringbuffer* r, void* data, size_t size);
|
||||
void ringbuffer_read(struct ringbuffer* r, void* data, size_t size);
|
||||
|
||||
#endif
|
@ -1,412 +0,0 @@
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "term.h"
|
||||
#define ENTER_MOUSE_SEQ "\x1b[?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h"
|
||||
#define EXIT_MOUSE_SEQ "\x1b[?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l"
|
||||
|
||||
#define EUNSUPPORTED_TERM -1
|
||||
|
||||
// rxvt-256color
|
||||
static const char* rxvt_256color_keys[] =
|
||||
{
|
||||
"\033[11~", "\033[12~", "\033[13~", "\033[14~", "\033[15~", "\033[17~",
|
||||
"\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~",
|
||||
"\033[2~", "\033[3~", "\033[7~", "\033[8~", "\033[5~", "\033[6~",
|
||||
"\033[A", "\033[B", "\033[D", "\033[C", NULL
|
||||
};
|
||||
static const char* rxvt_256color_funcs[] =
|
||||
{
|
||||
"\0337\033[?47h", "\033[2J\033[?47l\0338", "\033[?25h", "\033[?25l",
|
||||
"\033[H\033[2J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m",
|
||||
"\033=", "\033>", ENTER_MOUSE_SEQ, EXIT_MOUSE_SEQ,
|
||||
};
|
||||
|
||||
// Eterm
|
||||
static const char* eterm_keys[] =
|
||||
{
|
||||
"\033[11~", "\033[12~", "\033[13~", "\033[14~", "\033[15~", "\033[17~",
|
||||
"\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~",
|
||||
"\033[2~", "\033[3~", "\033[7~", "\033[8~", "\033[5~", "\033[6~",
|
||||
"\033[A", "\033[B", "\033[D", "\033[C", NULL
|
||||
};
|
||||
static const char* eterm_funcs[] =
|
||||
{
|
||||
"\0337\033[?47h", "\033[2J\033[?47l\0338", "\033[?25h", "\033[?25l",
|
||||
"\033[H\033[2J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m",
|
||||
"", "", "", "",
|
||||
};
|
||||
|
||||
// screen
|
||||
static const char* screen_keys[] =
|
||||
{
|
||||
"\033OP", "\033OQ", "\033OR", "\033OS", "\033[15~", "\033[17~",
|
||||
"\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~",
|
||||
"\033[2~", "\033[3~", "\033[1~", "\033[4~", "\033[5~", "\033[6~",
|
||||
"\033OA", "\033OB", "\033OD", "\033OC", NULL
|
||||
};
|
||||
static const char* screen_funcs[] =
|
||||
{
|
||||
"\033[?1049h", "\033[?1049l", "\033[34h\033[?25h", "\033[?25l",
|
||||
"\033[H\033[J", "\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m",
|
||||
"\033[?1h\033=", "\033[?1l\033>", ENTER_MOUSE_SEQ, EXIT_MOUSE_SEQ,
|
||||
};
|
||||
|
||||
// rxvt-unicode
|
||||
static const char* rxvt_unicode_keys[] =
|
||||
{
|
||||
"\033[11~", "\033[12~", "\033[13~", "\033[14~", "\033[15~", "\033[17~",
|
||||
"\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~",
|
||||
"\033[2~", "\033[3~", "\033[7~", "\033[8~", "\033[5~", "\033[6~",
|
||||
"\033[A", "\033[B", "\033[D", "\033[C", NULL
|
||||
};
|
||||
static const char* rxvt_unicode_funcs[] =
|
||||
{
|
||||
"\033[?1049h", "\033[r\033[?1049l", "\033[?25h", "\033[?25l",
|
||||
"\033[H\033[2J", "\033[m\033(B", "\033[4m", "\033[1m", "\033[5m",
|
||||
"\033[7m", "\033=", "\033>", ENTER_MOUSE_SEQ, EXIT_MOUSE_SEQ,
|
||||
};
|
||||
|
||||
// linux
|
||||
static const char* linux_keys[] =
|
||||
{
|
||||
"\033[[A", "\033[[B", "\033[[C", "\033[[D", "\033[[E", "\033[17~",
|
||||
"\033[18~", "\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~",
|
||||
"\033[2~", "\033[3~", "\033[1~", "\033[4~", "\033[5~", "\033[6~",
|
||||
"\033[A", "\033[B", "\033[D", "\033[C", NULL
|
||||
};
|
||||
static const char* linux_funcs[] =
|
||||
{
|
||||
"", "", "\033[?25h\033[?0c", "\033[?25l\033[?1c", "\033[H\033[J",
|
||||
"\033[0;10m", "\033[4m", "\033[1m", "\033[5m", "\033[7m", "", "", "", "",
|
||||
};
|
||||
|
||||
// xterm
|
||||
static const char* xterm_keys[] =
|
||||
{
|
||||
"\033OP", "\033OQ", "\033OR", "\033OS", "\033[15~", "\033[17~", "\033[18~",
|
||||
"\033[19~", "\033[20~", "\033[21~", "\033[23~", "\033[24~", "\033[2~",
|
||||
"\033[3~", "\033OH", "\033OF", "\033[5~", "\033[6~", "\033OA", "\033OB",
|
||||
"\033OD", "\033OC", NULL
|
||||
};
|
||||
static const char* xterm_funcs[] =
|
||||
{
|
||||
"\033[?1049h", "\033[?1049l", "\033[?12l\033[?25h", "\033[?25l",
|
||||
"\033[H\033[2J", "\033(B\033[m", "\033[4m", "\033[1m", "\033[5m", "\033[7m",
|
||||
"\033[?1h\033=", "\033[?1l\033>", ENTER_MOUSE_SEQ, EXIT_MOUSE_SEQ,
|
||||
};
|
||||
|
||||
struct term
|
||||
{
|
||||
const char* name;
|
||||
const char** keys;
|
||||
const char** funcs;
|
||||
};
|
||||
|
||||
static struct term terms[] =
|
||||
{
|
||||
{"rxvt-256color", rxvt_256color_keys, rxvt_256color_funcs},
|
||||
{"Eterm", eterm_keys, eterm_funcs},
|
||||
{"screen", screen_keys, screen_funcs},
|
||||
{"rxvt-unicode", rxvt_unicode_keys, rxvt_unicode_funcs},
|
||||
{"linux", linux_keys, linux_funcs},
|
||||
{"xterm", xterm_keys, xterm_funcs},
|
||||
{0, 0, 0},
|
||||
};
|
||||
|
||||
static int init_from_terminfo = 0;
|
||||
const char** keys;
|
||||
const char** funcs;
|
||||
|
||||
static int try_compatible(const char* term, const char* name,
|
||||
const char** tkeys, const char** tfuncs)
|
||||
{
|
||||
if (strstr(term, name))
|
||||
{
|
||||
keys = tkeys;
|
||||
funcs = tfuncs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return EUNSUPPORTED_TERM;
|
||||
}
|
||||
|
||||
static int init_term_builtin(void)
|
||||
{
|
||||
int i;
|
||||
const char* term = getenv("TERM");
|
||||
|
||||
if (term)
|
||||
{
|
||||
for (i = 0; terms[i].name; i++)
|
||||
{
|
||||
if (!strcmp(terms[i].name, term))
|
||||
{
|
||||
keys = terms[i].keys;
|
||||
funcs = terms[i].funcs;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// let's do some heuristic, maybe it's a compatible terminal
|
||||
if (try_compatible(term, "xterm", xterm_keys, xterm_funcs) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (try_compatible(term, "rxvt", rxvt_unicode_keys, rxvt_unicode_funcs) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (try_compatible(term, "linux", linux_keys, linux_funcs) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (try_compatible(term, "Eterm", eterm_keys, eterm_funcs) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (try_compatible(term, "screen", screen_keys, screen_funcs) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// let's assume that 'cygwin' is xterm compatible
|
||||
if (try_compatible(term, "cygwin", xterm_keys, xterm_funcs) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return EUNSUPPORTED_TERM;
|
||||
}
|
||||
|
||||
// terminfo
|
||||
static char* read_file(const char* file)
|
||||
{
|
||||
FILE* f = fopen(file, "rb");
|
||||
|
||||
if (!f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fileno(f), &st) != 0)
|
||||
{
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* data = malloc(st.st_size);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fread(data, 1, st.st_size, f) != (size_t)st.st_size)
|
||||
{
|
||||
fclose(f);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return data;
|
||||
}
|
||||
|
||||
static char* terminfo_try_path(const char* path, const char* term)
|
||||
{
|
||||
char tmp[4096];
|
||||
snprintf(tmp, sizeof(tmp), "%s/%c/%s", path, term[0], term);
|
||||
tmp[sizeof(tmp) - 1] = '\0';
|
||||
char* data = read_file(tmp);
|
||||
|
||||
if (data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
// fallback to darwin specific dirs structure
|
||||
snprintf(tmp, sizeof(tmp), "%s/%x/%s", path, term[0], term);
|
||||
tmp[sizeof(tmp) - 1] = '\0';
|
||||
return read_file(tmp);
|
||||
}
|
||||
|
||||
static char* load_terminfo(void)
|
||||
{
|
||||
char tmp[4096];
|
||||
const char* term = getenv("TERM");
|
||||
|
||||
if (!term)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if TERMINFO is set, no other directory should be searched
|
||||
const char* terminfo = getenv("TERMINFO");
|
||||
|
||||
if (terminfo)
|
||||
{
|
||||
return terminfo_try_path(terminfo, term);
|
||||
}
|
||||
|
||||
// next, consider ~/.terminfo
|
||||
const char* home = getenv("HOME");
|
||||
|
||||
if (home)
|
||||
{
|
||||
snprintf(tmp, sizeof(tmp), "%s/.terminfo", home);
|
||||
tmp[sizeof(tmp) - 1] = '\0';
|
||||
char* data = terminfo_try_path(tmp, term);
|
||||
|
||||
if (data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// next, TERMINFO_DIRS
|
||||
const char* dirs = getenv("TERMINFO_DIRS");
|
||||
|
||||
if (dirs)
|
||||
{
|
||||
snprintf(tmp, sizeof(tmp), "%s", dirs);
|
||||
tmp[sizeof(tmp) - 1] = '\0';
|
||||
char* dir = strtok(tmp, ":");
|
||||
|
||||
while (dir)
|
||||
{
|
||||
const char* cdir = dir;
|
||||
|
||||
if (strcmp(cdir, "") == 0)
|
||||
{
|
||||
cdir = "/usr/share/terminfo";
|
||||
}
|
||||
|
||||
char* data = terminfo_try_path(cdir, term);
|
||||
|
||||
if (data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
dir = strtok(0, ":");
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to /usr/share/terminfo
|
||||
return terminfo_try_path("/usr/share/terminfo", term);
|
||||
}
|
||||
|
||||
#define TI_MAGIC 0432
|
||||
#define TI_ALT_MAGIC 542
|
||||
#define TI_HEADER_LENGTH 12
|
||||
#define TB_KEYS_NUM 22
|
||||
|
||||
static const char* terminfo_copy_string(char* data, int str, int table)
|
||||
{
|
||||
const int16_t off = *(int16_t*)(data + str);
|
||||
const char* src = data + table + off;
|
||||
int len = strlen(src);
|
||||
char* dst = malloc(len + 1);
|
||||
strcpy(dst, src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
const int16_t ti_funcs[] =
|
||||
{
|
||||
28, 40, 16, 13, 5, 39, 36, 27, 26, 34, 89, 88,
|
||||
};
|
||||
|
||||
const int16_t ti_keys[] =
|
||||
{
|
||||
// apparently not a typo; 67 is F10 for whatever reason
|
||||
66, 68, 69, 70, 71, 72, 73, 74, 75, 67, 216, 217, 77, 59, 76, 164, 82,
|
||||
81, 87, 61, 79, 83,
|
||||
};
|
||||
|
||||
int init_term(void)
|
||||
{
|
||||
int i;
|
||||
char* data = load_terminfo();
|
||||
|
||||
if (!data)
|
||||
{
|
||||
init_from_terminfo = 0;
|
||||
return init_term_builtin();
|
||||
}
|
||||
|
||||
int16_t* header = (int16_t*)data;
|
||||
|
||||
const int number_sec_len = header[0] == TI_ALT_MAGIC ? 4 : 2;
|
||||
|
||||
if ((header[1] + header[2]) % 2)
|
||||
{
|
||||
// old quirk to align everything on word boundaries
|
||||
header[2] += 1;
|
||||
}
|
||||
|
||||
const int str_offset = TI_HEADER_LENGTH +
|
||||
header[1] + header[2] + number_sec_len * header[3];
|
||||
const int table_offset = str_offset + 2 * header[4];
|
||||
|
||||
keys = malloc(sizeof(const char*) * (TB_KEYS_NUM + 1));
|
||||
|
||||
for (i = 0; i < TB_KEYS_NUM; i++)
|
||||
{
|
||||
keys[i] = terminfo_copy_string(data,
|
||||
str_offset + 2 * ti_keys[i], table_offset);
|
||||
}
|
||||
|
||||
keys[i] = NULL;
|
||||
|
||||
funcs = malloc(sizeof(const char*) * T_FUNCS_NUM);
|
||||
|
||||
// the last two entries are reserved for mouse. because the table offset is
|
||||
// not there, the two entries have to fill in manually
|
||||
for (i = 0; i < T_FUNCS_NUM - 2; i++)
|
||||
{
|
||||
funcs[i] = terminfo_copy_string(data,
|
||||
str_offset + 2 * ti_funcs[i], table_offset);
|
||||
}
|
||||
|
||||
funcs[T_FUNCS_NUM - 2] = ENTER_MOUSE_SEQ;
|
||||
funcs[T_FUNCS_NUM - 1] = EXIT_MOUSE_SEQ;
|
||||
init_from_terminfo = 1;
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void shutdown_term(void)
|
||||
{
|
||||
if (init_from_terminfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < TB_KEYS_NUM; i++)
|
||||
{
|
||||
free((void*)keys[i]);
|
||||
}
|
||||
|
||||
// the last two entries are reserved for mouse. because the table offset
|
||||
// is not there, the two entries have to fill in manually and do not
|
||||
// need to be freed.
|
||||
for (i = 0; i < T_FUNCS_NUM - 2; i++)
|
||||
{
|
||||
free((void*)funcs[i]);
|
||||
}
|
||||
|
||||
free(keys);
|
||||
free(funcs);
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
#ifndef H_TERM
|
||||
#define H_TERM
|
||||
|
||||
#include "termbox.h"
|
||||
#include "ringbuffer.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define EUNSUPPORTED_TERM -1
|
||||
|
||||
enum
|
||||
{
|
||||
T_ENTER_CA,
|
||||
T_EXIT_CA,
|
||||
T_SHOW_CURSOR,
|
||||
T_HIDE_CURSOR,
|
||||
T_CLEAR_SCREEN,
|
||||
T_SGR0,
|
||||
T_UNDERLINE,
|
||||
T_BOLD,
|
||||
T_BLINK,
|
||||
T_REVERSE,
|
||||
T_ENTER_KEYPAD,
|
||||
T_EXIT_KEYPAD,
|
||||
T_ENTER_MOUSE,
|
||||
T_EXIT_MOUSE,
|
||||
T_FUNCS_NUM,
|
||||
};
|
||||
|
||||
extern const char** keys;
|
||||
extern const char** funcs;
|
||||
|
||||
// true on success, false on failure
|
||||
bool extract_event(struct tb_event* event, struct ringbuffer* inbuf,
|
||||
int inputmode);
|
||||
int init_term(void);
|
||||
void shutdown_term(void);
|
||||
|
||||
#endif
|
@ -1,885 +0,0 @@
|
||||
#include "term.h"
|
||||
#include "termbox.h"
|
||||
#include "memstream.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <wchar.h>
|
||||
|
||||
struct cellbuf
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
struct tb_cell* cells;
|
||||
};
|
||||
|
||||
#define CELL(buf, x, y) (buf)->cells[(y) * (buf)->width + (x)]
|
||||
#define IS_CURSOR_HIDDEN(cx, cy) (cx == -1 || cy == -1)
|
||||
#define LAST_COORD_INIT -1
|
||||
|
||||
static struct termios orig_tios;
|
||||
|
||||
static struct cellbuf back_buffer;
|
||||
static struct cellbuf front_buffer;
|
||||
static unsigned char write_buffer_data[32 * 1024];
|
||||
static struct memstream write_buffer;
|
||||
|
||||
static int termw = -1;
|
||||
static int termh = -1;
|
||||
|
||||
static int inputmode = TB_INPUT_ESC;
|
||||
static int outputmode = TB_OUTPUT_NORMAL;
|
||||
|
||||
static struct ringbuffer inbuf;
|
||||
|
||||
static int out;
|
||||
static FILE* in;
|
||||
|
||||
static int out_fileno;
|
||||
static int in_fileno;
|
||||
|
||||
static int winch_fds[2];
|
||||
|
||||
static int lastx = LAST_COORD_INIT;
|
||||
static int lasty = LAST_COORD_INIT;
|
||||
static int cursor_x = -1;
|
||||
static int cursor_y = -1;
|
||||
|
||||
static uint32_t background = TB_DEFAULT;
|
||||
static uint32_t foreground = TB_DEFAULT;
|
||||
|
||||
static void write_cursor(int x, int y);
|
||||
static void write_sgr(uint32_t fg, uint32_t bg);
|
||||
|
||||
static void cellbuf_init(struct cellbuf* buf, int width, int height);
|
||||
static void cellbuf_resize(struct cellbuf* buf, int width, int height);
|
||||
static void cellbuf_clear(struct cellbuf* buf);
|
||||
static void cellbuf_free(struct cellbuf* buf);
|
||||
|
||||
static void update_size(void);
|
||||
static void update_term_size(void);
|
||||
static void send_attr(uint32_t fg, uint32_t bg);
|
||||
static void send_char(int x, int y, uint32_t c);
|
||||
static void send_clear(void);
|
||||
static void sigwinch_handler(int xxx);
|
||||
static int wait_fill_event(struct tb_event* event, struct timeval* timeout);
|
||||
|
||||
// may happen in a different thread
|
||||
static volatile int buffer_size_change_request;
|
||||
|
||||
int tb_init_file(const char* name)
|
||||
{
|
||||
out = open(name, O_WRONLY);
|
||||
in = fopen(name, "r");
|
||||
|
||||
if (out == -1 || !in)
|
||||
{
|
||||
if (out != -1)
|
||||
{
|
||||
close(out);
|
||||
}
|
||||
|
||||
if (in)
|
||||
{
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
return TB_EFAILED_TO_OPEN_TTY;
|
||||
}
|
||||
|
||||
out_fileno = out;
|
||||
in_fileno = fileno(in);
|
||||
|
||||
if (init_term() < 0)
|
||||
{
|
||||
close(out);
|
||||
fclose(in);
|
||||
|
||||
return TB_EUNSUPPORTED_TERMINAL;
|
||||
}
|
||||
|
||||
if (pipe(winch_fds) < 0)
|
||||
{
|
||||
close(out);
|
||||
fclose(in);
|
||||
|
||||
return TB_EPIPE_TRAP_ERROR;
|
||||
}
|
||||
|
||||
struct sigaction sa;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = sigwinch_handler;
|
||||
sa.sa_flags = 0;
|
||||
sigaction(SIGWINCH, &sa, 0);
|
||||
tcgetattr(out_fileno, &orig_tios);
|
||||
|
||||
struct termios tios;
|
||||
|
||||
memcpy(&tios, &orig_tios, sizeof(tios));
|
||||
tios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
|
||||
| INLCR | IGNCR | ICRNL | IXON);
|
||||
tios.c_oflag &= ~OPOST;
|
||||
tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
tios.c_cflag &= ~(CSIZE | PARENB);
|
||||
tios.c_cflag |= CS8;
|
||||
tios.c_cc[VMIN] = 0;
|
||||
tios.c_cc[VTIME] = 0;
|
||||
tcsetattr(out_fileno, TCSAFLUSH, &tios);
|
||||
|
||||
memstream_init(&write_buffer, out_fileno, write_buffer_data,
|
||||
sizeof(write_buffer_data));
|
||||
memstream_puts(&write_buffer, funcs[T_ENTER_CA]);
|
||||
memstream_puts(&write_buffer, funcs[T_ENTER_KEYPAD]);
|
||||
memstream_puts(&write_buffer, funcs[T_HIDE_CURSOR]);
|
||||
send_clear();
|
||||
|
||||
update_term_size();
|
||||
cellbuf_init(&back_buffer, termw, termh);
|
||||
cellbuf_init(&front_buffer, termw, termh);
|
||||
cellbuf_clear(&back_buffer);
|
||||
cellbuf_clear(&front_buffer);
|
||||
init_ringbuffer(&inbuf, 4096);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tb_init(void)
|
||||
{
|
||||
return tb_init_file("/dev/tty");
|
||||
}
|
||||
|
||||
void tb_shutdown(void)
|
||||
{
|
||||
if (termw == -1)
|
||||
{
|
||||
fputs("tb_shutdown() should not be called twice.", stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
memstream_puts(&write_buffer, funcs[T_SHOW_CURSOR]);
|
||||
memstream_puts(&write_buffer, funcs[T_SGR0]);
|
||||
memstream_puts(&write_buffer, funcs[T_CLEAR_SCREEN]);
|
||||
memstream_puts(&write_buffer, funcs[T_EXIT_CA]);
|
||||
memstream_puts(&write_buffer, funcs[T_EXIT_KEYPAD]);
|
||||
memstream_puts(&write_buffer, funcs[T_EXIT_MOUSE]);
|
||||
memstream_flush(&write_buffer);
|
||||
tcsetattr(out_fileno, TCSAFLUSH, &orig_tios);
|
||||
|
||||
shutdown_term();
|
||||
close(out);
|
||||
fclose(in);
|
||||
close(winch_fds[0]);
|
||||
close(winch_fds[1]);
|
||||
|
||||
cellbuf_free(&back_buffer);
|
||||
cellbuf_free(&front_buffer);
|
||||
free_ringbuffer(&inbuf);
|
||||
termw = termh = -1;
|
||||
}
|
||||
|
||||
void tb_present(void)
|
||||
{
|
||||
int x, y, w, i;
|
||||
struct tb_cell* back, *front;
|
||||
|
||||
// invalidate cursor position
|
||||
lastx = LAST_COORD_INIT;
|
||||
lasty = LAST_COORD_INIT;
|
||||
|
||||
if (buffer_size_change_request)
|
||||
{
|
||||
update_size();
|
||||
buffer_size_change_request = 0;
|
||||
}
|
||||
|
||||
for (y = 0; y < front_buffer.height; ++y)
|
||||
{
|
||||
for (x = 0; x < front_buffer.width;)
|
||||
{
|
||||
back = &CELL(&back_buffer, x, y);
|
||||
front = &CELL(&front_buffer, x, y);
|
||||
w = wcwidth(back->ch);
|
||||
|
||||
if (w < 1)
|
||||
{
|
||||
w = 1;
|
||||
}
|
||||
|
||||
if (memcmp(back, front, sizeof(struct tb_cell)) == 0)
|
||||
{
|
||||
x += w;
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(front, back, sizeof(struct tb_cell));
|
||||
send_attr(back->fg, back->bg);
|
||||
|
||||
if (w > 1 && x >= front_buffer.width - (w - 1))
|
||||
{
|
||||
// Not enough room for wide ch, so send spaces
|
||||
for (i = x; i < front_buffer.width; ++i)
|
||||
{
|
||||
send_char(i, y, ' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
send_char(x, y, back->ch);
|
||||
|
||||
for (i = 1; i < w; ++i)
|
||||
{
|
||||
front = &CELL(&front_buffer, x + i, y);
|
||||
front->ch = 0;
|
||||
front->fg = back->fg;
|
||||
front->bg = back->bg;
|
||||
}
|
||||
}
|
||||
|
||||
x += w;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y))
|
||||
{
|
||||
write_cursor(cursor_x, cursor_y);
|
||||
}
|
||||
|
||||
memstream_flush(&write_buffer);
|
||||
}
|
||||
|
||||
void tb_set_cursor(int cx, int cy)
|
||||
{
|
||||
if (IS_CURSOR_HIDDEN(cursor_x, cursor_y) && !IS_CURSOR_HIDDEN(cx, cy))
|
||||
{
|
||||
memstream_puts(&write_buffer, funcs[T_SHOW_CURSOR]);
|
||||
}
|
||||
|
||||
if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y) && IS_CURSOR_HIDDEN(cx, cy))
|
||||
{
|
||||
memstream_puts(&write_buffer, funcs[T_HIDE_CURSOR]);
|
||||
}
|
||||
|
||||
cursor_x = cx;
|
||||
cursor_y = cy;
|
||||
|
||||
if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y))
|
||||
{
|
||||
write_cursor(cursor_x, cursor_y);
|
||||
}
|
||||
}
|
||||
|
||||
void tb_put_cell(int x, int y, const struct tb_cell* cell)
|
||||
{
|
||||
if ((unsigned)x >= (unsigned)back_buffer.width)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((unsigned)y >= (unsigned)back_buffer.height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CELL(&back_buffer, x, y) = *cell;
|
||||
}
|
||||
|
||||
void tb_change_cell(int x, int y, uint32_t ch, uint32_t fg, uint32_t bg)
|
||||
{
|
||||
struct tb_cell c = {ch, fg, bg};
|
||||
tb_put_cell(x, y, &c);
|
||||
}
|
||||
|
||||
void tb_blit(int x, int y, int w, int h, const struct tb_cell* cells)
|
||||
{
|
||||
if (x + w < 0 || x >= back_buffer.width)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (y + h < 0 || y >= back_buffer.height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int xo = 0, yo = 0, ww = w, hh = h;
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
xo = -x;
|
||||
ww -= xo;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
if (y < 0)
|
||||
{
|
||||
yo = -y;
|
||||
hh -= yo;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if (ww > back_buffer.width - x)
|
||||
{
|
||||
ww = back_buffer.width - x;
|
||||
}
|
||||
|
||||
if (hh > back_buffer.height - y)
|
||||
{
|
||||
hh = back_buffer.height - y;
|
||||
}
|
||||
|
||||
int sy;
|
||||
struct tb_cell* dst = &CELL(&back_buffer, x, y);
|
||||
const struct tb_cell* src = cells + yo * w + xo;
|
||||
size_t size = sizeof(struct tb_cell) * ww;
|
||||
|
||||
for (sy = 0; sy < hh; ++sy)
|
||||
{
|
||||
memcpy(dst, src, size);
|
||||
dst += back_buffer.width;
|
||||
src += w;
|
||||
}
|
||||
}
|
||||
|
||||
struct tb_cell* tb_cell_buffer(void)
|
||||
{
|
||||
return back_buffer.cells;
|
||||
}
|
||||
|
||||
int tb_poll_event(struct tb_event* event)
|
||||
{
|
||||
return wait_fill_event(event, 0);
|
||||
}
|
||||
|
||||
int tb_peek_event(struct tb_event* event, int timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
|
||||
return wait_fill_event(event, &tv);
|
||||
}
|
||||
|
||||
int tb_width(void)
|
||||
{
|
||||
return termw;
|
||||
}
|
||||
|
||||
int tb_height(void)
|
||||
{
|
||||
return termh;
|
||||
}
|
||||
|
||||
void tb_clear(void)
|
||||
{
|
||||
if (buffer_size_change_request)
|
||||
{
|
||||
update_size();
|
||||
buffer_size_change_request = 0;
|
||||
}
|
||||
|
||||
cellbuf_clear(&back_buffer);
|
||||
}
|
||||
|
||||
int tb_select_input_mode(int mode)
|
||||
{
|
||||
if (mode)
|
||||
{
|
||||
if ((mode & (TB_INPUT_ESC | TB_INPUT_ALT)) == 0)
|
||||
{
|
||||
mode |= TB_INPUT_ESC;
|
||||
}
|
||||
|
||||
// technically termbox can handle that, but let's be nice
|
||||
// and show here what mode is actually used
|
||||
if ((mode & (TB_INPUT_ESC | TB_INPUT_ALT)) == (TB_INPUT_ESC | TB_INPUT_ALT))
|
||||
{
|
||||
mode &= ~TB_INPUT_ALT;
|
||||
}
|
||||
|
||||
inputmode = mode;
|
||||
|
||||
if (mode & TB_INPUT_MOUSE)
|
||||
{
|
||||
memstream_puts(&write_buffer, funcs[T_ENTER_MOUSE]);
|
||||
memstream_flush(&write_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
memstream_puts(&write_buffer, funcs[T_EXIT_MOUSE]);
|
||||
memstream_flush(&write_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return inputmode;
|
||||
}
|
||||
|
||||
int tb_select_output_mode(int mode)
|
||||
{
|
||||
if (mode)
|
||||
{
|
||||
outputmode = mode;
|
||||
}
|
||||
|
||||
return outputmode;
|
||||
}
|
||||
|
||||
void tb_set_clear_attributes(uint32_t fg, uint32_t bg)
|
||||
{
|
||||
foreground = fg;
|
||||
background = bg;
|
||||
}
|
||||
|
||||
static unsigned convertnum(uint32_t num, char* buf)
|
||||
{
|
||||
unsigned i, l = 0;
|
||||
int ch;
|
||||
|
||||
do
|
||||
{
|
||||
buf[l++] = '0' + (num % 10);
|
||||
num /= 10;
|
||||
}
|
||||
while (num);
|
||||
|
||||
for (i = 0; i < l / 2; i++)
|
||||
{
|
||||
ch = buf[i];
|
||||
buf[i] = buf[l - 1 - i];
|
||||
buf[l - 1 - i] = ch;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
#define WRITE_LITERAL(X) memstream_write(&write_buffer, (X), sizeof(X) -1)
|
||||
#define WRITE_INT(X) memstream_write(&write_buffer, buf, convertnum((X), buf))
|
||||
|
||||
static void write_cursor(int x, int y)
|
||||
{
|
||||
char buf[32];
|
||||
WRITE_LITERAL("\033[");
|
||||
WRITE_INT(y + 1);
|
||||
WRITE_LITERAL(";");
|
||||
WRITE_INT(x + 1);
|
||||
WRITE_LITERAL("H");
|
||||
}
|
||||
|
||||
static void write_sgr(uint32_t fg, uint32_t bg)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
if (outputmode != TB_OUTPUT_TRUECOLOR && fg == TB_DEFAULT && bg == TB_DEFAULT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (outputmode)
|
||||
{
|
||||
case TB_OUTPUT_TRUECOLOR:
|
||||
WRITE_LITERAL("\033[38;2;");
|
||||
WRITE_INT(fg >> 16 & 0xFF);
|
||||
WRITE_LITERAL(";");
|
||||
WRITE_INT(fg >> 8 & 0xFF);
|
||||
WRITE_LITERAL(";");
|
||||
WRITE_INT(fg & 0xFF);
|
||||
WRITE_LITERAL(";48;2;");
|
||||
WRITE_INT(bg >> 16 & 0xFF);
|
||||
WRITE_LITERAL(";");
|
||||
WRITE_INT(bg >> 8 & 0xFF);
|
||||
WRITE_LITERAL(";");
|
||||
WRITE_INT(bg & 0xFF);
|
||||
WRITE_LITERAL("m");
|
||||
break;
|
||||
|
||||
case TB_OUTPUT_256:
|
||||
case TB_OUTPUT_216:
|
||||
case TB_OUTPUT_GRAYSCALE:
|
||||
WRITE_LITERAL("\033[");
|
||||
|
||||
if (fg != TB_DEFAULT)
|
||||
{
|
||||
WRITE_LITERAL("38;5;");
|
||||
WRITE_INT(fg);
|
||||
|
||||
if (bg != TB_DEFAULT)
|
||||
{
|
||||
WRITE_LITERAL(";");
|
||||
}
|
||||
}
|
||||
|
||||
if (bg != TB_DEFAULT)
|
||||
{
|
||||
WRITE_LITERAL("48;5;");
|
||||
WRITE_INT(bg);
|
||||
}
|
||||
|
||||
WRITE_LITERAL("m");
|
||||
break;
|
||||
|
||||
case TB_OUTPUT_NORMAL:
|
||||
default:
|
||||
WRITE_LITERAL("\033[");
|
||||
|
||||
if (fg != TB_DEFAULT)
|
||||
{
|
||||
WRITE_LITERAL("3");
|
||||
WRITE_INT(fg - 1);
|
||||
|
||||
if (bg != TB_DEFAULT)
|
||||
{
|
||||
WRITE_LITERAL(";");
|
||||
}
|
||||
}
|
||||
|
||||
if (bg != TB_DEFAULT)
|
||||
{
|
||||
WRITE_LITERAL("4");
|
||||
WRITE_INT(bg - 1);
|
||||
}
|
||||
|
||||
WRITE_LITERAL("m");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cellbuf_init(struct cellbuf* buf, int width, int height)
|
||||
{
|
||||
buf->cells = (struct tb_cell*)malloc(sizeof(struct tb_cell) * width * height);
|
||||
assert(buf->cells);
|
||||
buf->width = width;
|
||||
buf->height = height;
|
||||
}
|
||||
|
||||
static void cellbuf_resize(struct cellbuf* buf, int width, int height)
|
||||
{
|
||||
if (buf->width == width && buf->height == height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int oldw = buf->width;
|
||||
int oldh = buf->height;
|
||||
struct tb_cell* oldcells = buf->cells;
|
||||
|
||||
cellbuf_init(buf, width, height);
|
||||
cellbuf_clear(buf);
|
||||
|
||||
int minw = (width < oldw) ? width : oldw;
|
||||
int minh = (height < oldh) ? height : oldh;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < minh; ++i)
|
||||
{
|
||||
struct tb_cell* csrc = oldcells + (i * oldw);
|
||||
struct tb_cell* cdst = buf->cells + (i * width);
|
||||
memcpy(cdst, csrc, sizeof(struct tb_cell) * minw);
|
||||
}
|
||||
|
||||
free(oldcells);
|
||||
}
|
||||
|
||||
static void cellbuf_clear(struct cellbuf* buf)
|
||||
{
|
||||
int i;
|
||||
int ncells = buf->width * buf->height;
|
||||
|
||||
for (i = 0; i < ncells; ++i)
|
||||
{
|
||||
buf->cells[i].ch = ' ';
|
||||
buf->cells[i].fg = foreground;
|
||||
buf->cells[i].bg = background;
|
||||
}
|
||||
}
|
||||
|
||||
static void cellbuf_free(struct cellbuf* buf)
|
||||
{
|
||||
free(buf->cells);
|
||||
}
|
||||
|
||||
static void get_term_size(int* w, int* h)
|
||||
{
|
||||
struct winsize sz;
|
||||
memset(&sz, 0, sizeof(sz));
|
||||
|
||||
ioctl(out_fileno, TIOCGWINSZ, &sz);
|
||||
|
||||
if (w)
|
||||
{
|
||||
*w = sz.ws_col;
|
||||
}
|
||||
|
||||
if (h)
|
||||
{
|
||||
*h = sz.ws_row;
|
||||
}
|
||||
}
|
||||
|
||||
static void send_attr(uint32_t fg, uint32_t bg)
|
||||
{
|
||||
#define LAST_ATTR_INIT 0xFFFFFFFF
|
||||
static uint32_t lastfg = LAST_ATTR_INIT, lastbg = LAST_ATTR_INIT;
|
||||
|
||||
if (fg != lastfg || bg != lastbg)
|
||||
{
|
||||
memstream_puts(&write_buffer, funcs[T_SGR0]);
|
||||
uint32_t fgcol;
|
||||
uint32_t bgcol;
|
||||
|
||||
switch (outputmode)
|
||||
{
|
||||
case TB_OUTPUT_TRUECOLOR:
|
||||
fgcol = fg;
|
||||
bgcol = bg;
|
||||
break;
|
||||
|
||||
case TB_OUTPUT_256:
|
||||
fgcol = fg & 0xFF;
|
||||
bgcol = bg & 0xFF;
|
||||
break;
|
||||
|
||||
case TB_OUTPUT_216:
|
||||
fgcol = fg & 0xFF;
|
||||
|
||||
if (fgcol > 215)
|
||||
{
|
||||
fgcol = 7;
|
||||
}
|
||||
|
||||
bgcol = bg & 0xFF;
|
||||
|
||||
if (bgcol > 215)
|
||||
{
|
||||
bgcol = 0;
|
||||
}
|
||||
|
||||
fgcol += 0x10;
|
||||
bgcol += 0x10;
|
||||
break;
|
||||
|
||||
case TB_OUTPUT_GRAYSCALE:
|
||||
fgcol = fg & 0xFF;
|
||||
|
||||
if (fgcol > 23)
|
||||
{
|
||||
fgcol = 23;
|
||||
}
|
||||
|
||||
bgcol = bg & 0xFF;
|
||||
|
||||
if (bgcol > 23)
|
||||
{
|
||||
bgcol = 0;
|
||||
}
|
||||
|
||||
fgcol += 0xe8;
|
||||
bgcol += 0xe8;
|
||||
break;
|
||||
|
||||
case TB_OUTPUT_NORMAL:
|
||||
default:
|
||||
fgcol = fg & 0x0F;
|
||||
bgcol = bg & 0x0F;
|
||||
}
|
||||
|
||||
if (fg & TB_BOLD)
|
||||
{
|
||||
memstream_puts(&write_buffer, funcs[T_BOLD]);
|
||||
}
|
||||
|
||||
if (bg & TB_BOLD)
|
||||
{
|
||||
memstream_puts(&write_buffer, funcs[T_BLINK]);
|
||||
}
|
||||
|
||||
if (fg & TB_UNDERLINE)
|
||||
{
|
||||
memstream_puts(&write_buffer, funcs[T_UNDERLINE]);
|
||||
}
|
||||
|
||||
if ((fg & TB_REVERSE) || (bg & TB_REVERSE))
|
||||
{
|
||||
memstream_puts(&write_buffer, funcs[T_REVERSE]);
|
||||
}
|
||||
|
||||
write_sgr(fgcol, bgcol);
|
||||
|
||||
lastfg = fg;
|
||||
lastbg = bg;
|
||||
}
|
||||
}
|
||||
|
||||
static void send_char(int x, int y, uint32_t c)
|
||||
{
|
||||
char buf[7];
|
||||
int bw = utf8_unicode_to_char(buf, c);
|
||||
buf[bw] = '\0';
|
||||
|
||||
if (x - 1 != lastx || y != lasty)
|
||||
{
|
||||
write_cursor(x, y);
|
||||
}
|
||||
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
|
||||
if (!c)
|
||||
{
|
||||
buf[0] = ' '; // replace 0 with whitespace
|
||||
}
|
||||
|
||||
memstream_puts(&write_buffer, buf);
|
||||
}
|
||||
|
||||
static void send_clear(void)
|
||||
{
|
||||
send_attr(foreground, background);
|
||||
memstream_puts(&write_buffer, funcs[T_CLEAR_SCREEN]);
|
||||
|
||||
if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y))
|
||||
{
|
||||
write_cursor(cursor_x, cursor_y);
|
||||
}
|
||||
|
||||
memstream_flush(&write_buffer);
|
||||
|
||||
// we need to invalidate cursor position too and these two vars are
|
||||
// used only for simple cursor positioning optimization, cursor
|
||||
// actually may be in the correct place, but we simply discard
|
||||
// optimization once and it gives us simple solution for the case when
|
||||
// cursor moved
|
||||
lastx = LAST_COORD_INIT;
|
||||
lasty = LAST_COORD_INIT;
|
||||
}
|
||||
|
||||
static void sigwinch_handler(int xxx)
|
||||
{
|
||||
(void) xxx;
|
||||
const int zzz = 1;
|
||||
write(winch_fds[1], &zzz, sizeof(int));
|
||||
}
|
||||
|
||||
static void update_size(void)
|
||||
{
|
||||
update_term_size();
|
||||
cellbuf_resize(&back_buffer, termw, termh);
|
||||
cellbuf_resize(&front_buffer, termw, termh);
|
||||
cellbuf_clear(&front_buffer);
|
||||
send_clear();
|
||||
}
|
||||
|
||||
static void update_term_size(void)
|
||||
{
|
||||
struct winsize sz;
|
||||
memset(&sz, 0, sizeof(sz));
|
||||
|
||||
ioctl(out_fileno, TIOCGWINSZ, &sz);
|
||||
|
||||
termw = sz.ws_col;
|
||||
termh = sz.ws_row;
|
||||
}
|
||||
|
||||
static int wait_fill_event(struct tb_event* event, struct timeval* timeout)
|
||||
{
|
||||
#define ENOUGH_DATA_FOR_INPUT_PARSING 128
|
||||
int result;
|
||||
char buf[ENOUGH_DATA_FOR_INPUT_PARSING];
|
||||
fd_set events;
|
||||
memset(event, 0, sizeof(struct tb_event));
|
||||
|
||||
// try to extract event from input buffer, return on success
|
||||
event->type = TB_EVENT_KEY;
|
||||
|
||||
if (extract_event(event, &inbuf, inputmode))
|
||||
{
|
||||
return event->type;
|
||||
}
|
||||
|
||||
// it looks like input buffer is incomplete, let's try the short path
|
||||
size_t r = fread(buf, 1, ENOUGH_DATA_FOR_INPUT_PARSING, in);
|
||||
|
||||
if (r < ENOUGH_DATA_FOR_INPUT_PARSING && feof(in))
|
||||
{
|
||||
clearerr(in);
|
||||
}
|
||||
|
||||
if (r > 0)
|
||||
{
|
||||
if (ringbuffer_free_space(&inbuf) < r)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ringbuffer_push(&inbuf, buf, r);
|
||||
|
||||
if (extract_event(event, &inbuf, inputmode))
|
||||
{
|
||||
return event->type;
|
||||
}
|
||||
}
|
||||
|
||||
// no stuff in FILE's internal buffer, block in select
|
||||
while (1)
|
||||
{
|
||||
FD_ZERO(&events);
|
||||
FD_SET(in_fileno, &events);
|
||||
FD_SET(winch_fds[0], &events);
|
||||
int maxfd = (winch_fds[0] > in_fileno) ? winch_fds[0] : in_fileno;
|
||||
result = select(maxfd + 1, &events, 0, 0, timeout);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FD_ISSET(in_fileno, &events))
|
||||
{
|
||||
event->type = TB_EVENT_KEY;
|
||||
size_t r = fread(buf, 1, ENOUGH_DATA_FOR_INPUT_PARSING, in);
|
||||
|
||||
if (r < ENOUGH_DATA_FOR_INPUT_PARSING && feof(in))
|
||||
{
|
||||
clearerr(in);
|
||||
}
|
||||
|
||||
if (r == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if there is no free space in input buffer, return error
|
||||
if (ringbuffer_free_space(&inbuf) < r)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// fill buffer
|
||||
ringbuffer_push(&inbuf, buf, r);
|
||||
|
||||
if (extract_event(event, &inbuf, inputmode))
|
||||
{
|
||||
return event->type;
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(winch_fds[0], &events))
|
||||
{
|
||||
event->type = TB_EVENT_RESIZE;
|
||||
int zzz = 0;
|
||||
read(winch_fds[0], &zzz, sizeof(int));
|
||||
buffer_size_change_request = 1;
|
||||
get_term_size(&event->w, &event->h);
|
||||
return TB_EVENT_RESIZE;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,307 +0,0 @@
|
||||
#ifndef H_TERMBOX
|
||||
#define H_TERMBOX
|
||||
#include <stdint.h>
|
||||
|
||||
// shared objects
|
||||
#if __GNUC__ >= 4
|
||||
#define SO_IMPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define SO_IMPORT
|
||||
#endif
|
||||
|
||||
// c++
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Key constants. See also struct tb_event's key field.
|
||||
// These are a safe subset of terminfo keys, which exist on all popular
|
||||
// terminals. Termbox uses only them to stay truly portable.
|
||||
#define TB_KEY_F1 (0xFFFF-0)
|
||||
#define TB_KEY_F2 (0xFFFF-1)
|
||||
#define TB_KEY_F3 (0xFFFF-2)
|
||||
#define TB_KEY_F4 (0xFFFF-3)
|
||||
#define TB_KEY_F5 (0xFFFF-4)
|
||||
#define TB_KEY_F6 (0xFFFF-5)
|
||||
#define TB_KEY_F7 (0xFFFF-6)
|
||||
#define TB_KEY_F8 (0xFFFF-7)
|
||||
#define TB_KEY_F9 (0xFFFF-8)
|
||||
#define TB_KEY_F10 (0xFFFF-9)
|
||||
#define TB_KEY_F11 (0xFFFF-10)
|
||||
#define TB_KEY_F12 (0xFFFF-11)
|
||||
#define TB_KEY_INSERT (0xFFFF-12)
|
||||
#define TB_KEY_DELETE (0xFFFF-13)
|
||||
#define TB_KEY_HOME (0xFFFF-14)
|
||||
#define TB_KEY_END (0xFFFF-15)
|
||||
#define TB_KEY_PGUP (0xFFFF-16)
|
||||
#define TB_KEY_PGDN (0xFFFF-17)
|
||||
#define TB_KEY_ARROW_UP (0xFFFF-18)
|
||||
#define TB_KEY_ARROW_DOWN (0xFFFF-19)
|
||||
#define TB_KEY_ARROW_LEFT (0xFFFF-20)
|
||||
#define TB_KEY_ARROW_RIGHT (0xFFFF-21)
|
||||
#define TB_KEY_MOUSE_LEFT (0xFFFF-22)
|
||||
#define TB_KEY_MOUSE_RIGHT (0xFFFF-23)
|
||||
#define TB_KEY_MOUSE_MIDDLE (0xFFFF-24)
|
||||
#define TB_KEY_MOUSE_RELEASE (0xFFFF-25)
|
||||
#define TB_KEY_MOUSE_WHEEL_UP (0xFFFF-26)
|
||||
#define TB_KEY_MOUSE_WHEEL_DOWN (0xFFFF-27)
|
||||
|
||||
// These are all ASCII code points below SPACE character and a BACKSPACE key.
|
||||
#define TB_KEY_CTRL_TILDE 0x00
|
||||
#define TB_KEY_CTRL_2 0x00 // clash with 'CTRL_TILDE'
|
||||
#define TB_KEY_CTRL_A 0x01
|
||||
#define TB_KEY_CTRL_B 0x02
|
||||
#define TB_KEY_CTRL_C 0x03
|
||||
#define TB_KEY_CTRL_D 0x04
|
||||
#define TB_KEY_CTRL_E 0x05
|
||||
#define TB_KEY_CTRL_F 0x06
|
||||
#define TB_KEY_CTRL_G 0x07
|
||||
#define TB_KEY_BACKSPACE 0x08
|
||||
#define TB_KEY_CTRL_H 0x08 // clash with 'CTRL_BACKSPACE'
|
||||
#define TB_KEY_TAB 0x09
|
||||
#define TB_KEY_CTRL_I 0x09 // clash with 'TAB'
|
||||
#define TB_KEY_CTRL_J 0x0A
|
||||
#define TB_KEY_CTRL_K 0x0B
|
||||
#define TB_KEY_CTRL_L 0x0C
|
||||
#define TB_KEY_ENTER 0x0D
|
||||
#define TB_KEY_CTRL_M 0x0D // clash with 'ENTER'
|
||||
#define TB_KEY_CTRL_N 0x0E
|
||||
#define TB_KEY_CTRL_O 0x0F
|
||||
#define TB_KEY_CTRL_P 0x10
|
||||
#define TB_KEY_CTRL_Q 0x11
|
||||
#define TB_KEY_CTRL_R 0x12
|
||||
#define TB_KEY_CTRL_S 0x13
|
||||
#define TB_KEY_CTRL_T 0x14
|
||||
#define TB_KEY_CTRL_U 0x15
|
||||
#define TB_KEY_CTRL_V 0x16
|
||||
#define TB_KEY_CTRL_W 0x17
|
||||
#define TB_KEY_CTRL_X 0x18
|
||||
#define TB_KEY_CTRL_Y 0x19
|
||||
#define TB_KEY_CTRL_Z 0x1A
|
||||
#define TB_KEY_ESC 0x1B
|
||||
#define TB_KEY_CTRL_LSQ_BRACKET 0x1B // clash with 'ESC'
|
||||
#define TB_KEY_CTRL_3 0x1B // clash with 'ESC'
|
||||
#define TB_KEY_CTRL_4 0x1C
|
||||
#define TB_KEY_CTRL_BACKSLASH 0x1C // clash with 'CTRL_4'
|
||||
#define TB_KEY_CTRL_5 0x1D
|
||||
#define TB_KEY_CTRL_RSQ_BRACKET 0x1D // clash with 'CTRL_5'
|
||||
#define TB_KEY_CTRL_6 0x1E
|
||||
#define TB_KEY_CTRL_7 0x1F
|
||||
#define TB_KEY_CTRL_SLASH 0x1F // clash with 'CTRL_7'
|
||||
#define TB_KEY_CTRL_UNDERSCORE 0x1F // clash with 'CTRL_7'
|
||||
#define TB_KEY_SPACE 0x20
|
||||
#define TB_KEY_BACKSPACE2 0x7F
|
||||
#define TB_KEY_CTRL_8 0x7F // clash with 'BACKSPACE2'
|
||||
|
||||
// These are non-existing ones.
|
||||
// #define TB_KEY_CTRL_1 clash with '1'
|
||||
// #define TB_KEY_CTRL_9 clash with '9'
|
||||
// #define TB_KEY_CTRL_0 clash with '0'
|
||||
|
||||
// Alt modifier constant, see tb_event.mod field and tb_select_input_mode function.
|
||||
// Mouse-motion modifier
|
||||
#define TB_MOD_ALT 0x01
|
||||
#define TB_MOD_MOTION 0x02
|
||||
|
||||
// Colors (see struct tb_cell's fg and bg fields).
|
||||
#define TB_DEFAULT 0x00
|
||||
#define TB_BLACK 0x01
|
||||
#define TB_RED 0x02
|
||||
#define TB_GREEN 0x03
|
||||
#define TB_YELLOW 0x04
|
||||
#define TB_BLUE 0x05
|
||||
#define TB_MAGENTA 0x06
|
||||
#define TB_CYAN 0x07
|
||||
#define TB_WHITE 0x08
|
||||
|
||||
// Attributes, it is possible to use multiple attributes by combining them
|
||||
// using bitwise OR ('|'). Although, colors cannot be combined. But you can
|
||||
// combine attributes and a single color. See also struct tb_cell's fg and bg
|
||||
// fields.
|
||||
#define TB_BOLD 0x01000000
|
||||
#define TB_UNDERLINE 0x02000000
|
||||
#define TB_REVERSE 0x04000000
|
||||
|
||||
// A cell, single conceptual entity on the terminal screen. The terminal screen
|
||||
// is basically a 2d array of cells. It has the following fields:
|
||||
// - 'ch' is a unicode character
|
||||
// - 'fg' foreground color and attributes
|
||||
// - 'bg' background color and attributes
|
||||
struct tb_cell
|
||||
{
|
||||
uint32_t ch;
|
||||
uint32_t fg;
|
||||
uint32_t bg;
|
||||
};
|
||||
|
||||
#define TB_EVENT_KEY 1
|
||||
#define TB_EVENT_RESIZE 2
|
||||
#define TB_EVENT_MOUSE 3
|
||||
|
||||
// An event, single interaction from the user. The 'mod' and 'ch' fields are
|
||||
// valid if 'type' is TB_EVENT_KEY. The 'w' and 'h' fields are valid if 'type'
|
||||
// is TB_EVENT_RESIZE. The 'x' and 'y' fields are valid if 'type' is
|
||||
// TB_EVENT_MOUSE. The 'key' field is valid if 'type' is either TB_EVENT_KEY
|
||||
// or TB_EVENT_MOUSE. The fields 'key' and 'ch' are mutually exclusive; only
|
||||
// one of them can be non-zero at a time.
|
||||
struct tb_event
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t mod; // modifiers to either 'key' or 'ch' below
|
||||
uint16_t key; // one of the TB_KEY_* constants
|
||||
uint32_t ch; // unicode character
|
||||
int32_t w;
|
||||
int32_t h;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
};
|
||||
|
||||
// Error codes returned by tb_init(). All of them are self-explanatory, except
|
||||
// the pipe trap error. Termbox uses unix pipes in order to deliver a message
|
||||
// from a signal handler (SIGWINCH) to the main event reading loop. Honestly in
|
||||
// most cases you should just check the returned code as < 0.
|
||||
#define TB_EUNSUPPORTED_TERMINAL -1
|
||||
#define TB_EFAILED_TO_OPEN_TTY -2
|
||||
#define TB_EPIPE_TRAP_ERROR -3
|
||||
|
||||
// Initializes the termbox library. This function should be called before any
|
||||
// other functions. Function tb_init is same as tb_init_file("/dev/tty"). After successful initialization, the library must be
|
||||
// finalized using the tb_shutdown() function.
|
||||
SO_IMPORT int tb_init(void);
|
||||
SO_IMPORT int tb_init_file(const char* name);
|
||||
SO_IMPORT void tb_shutdown(void);
|
||||
|
||||
// Returns the size of the internal back buffer (which is the same as
|
||||
// terminal's window size in characters). The internal buffer can be resized
|
||||
// after tb_clear() or tb_present() function calls. Both dimensions have an
|
||||
// unspecified negative value when called before tb_init() or after
|
||||
// tb_shutdown().
|
||||
SO_IMPORT int tb_width(void);
|
||||
SO_IMPORT int tb_height(void);
|
||||
|
||||
// Clears the internal back buffer using TB_DEFAULT color or the
|
||||
// color/attributes set by tb_set_clear_attributes() function.
|
||||
SO_IMPORT void tb_clear(void);
|
||||
SO_IMPORT void tb_set_clear_attributes(uint32_t fg, uint32_t bg);
|
||||
|
||||
// Synchronizes the internal back buffer with the terminal.
|
||||
SO_IMPORT void tb_present(void);
|
||||
|
||||
#define TB_HIDE_CURSOR -1
|
||||
|
||||
// Sets the position of the cursor. Upper-left character is (0, 0). If you pass
|
||||
// TB_HIDE_CURSOR as both coordinates, then the cursor will be hidden. Cursor
|
||||
// is hidden by default.
|
||||
SO_IMPORT void tb_set_cursor(int cx, int cy);
|
||||
|
||||
// Changes cell's parameters in the internal back buffer at the specified
|
||||
// position.
|
||||
SO_IMPORT void tb_put_cell(int x, int y, const struct tb_cell* cell);
|
||||
SO_IMPORT void tb_change_cell(int x, int y, uint32_t ch, uint32_t fg,
|
||||
uint32_t bg);
|
||||
|
||||
// Copies the buffer from 'cells' at the specified position, assuming the
|
||||
// buffer is a two-dimensional array of size ('w' x 'h'), represented as a
|
||||
// one-dimensional buffer containing lines of cells starting from the top.
|
||||
// (DEPRECATED: use tb_cell_buffer() instead and copy memory on your own)
|
||||
SO_IMPORT void tb_blit(int x, int y, int w, int h, const struct tb_cell* cells);
|
||||
|
||||
// Returns a pointer to internal cell back buffer. You can get its dimensions
|
||||
// using tb_width() and tb_height() functions. The pointer stays valid as long
|
||||
// as no tb_clear() and tb_present() calls are made. The buffer is
|
||||
// one-dimensional buffer containing lines of cells starting from the top.
|
||||
SO_IMPORT struct tb_cell* tb_cell_buffer(void);
|
||||
|
||||
#define TB_INPUT_CURRENT 0 // 000
|
||||
#define TB_INPUT_ESC 1 // 001
|
||||
#define TB_INPUT_ALT 2 // 010
|
||||
#define TB_INPUT_MOUSE 4 // 100
|
||||
|
||||
// Sets the termbox input mode. Termbox has two input modes:
|
||||
// 1. Esc input mode.
|
||||
// When ESC sequence is in the buffer and it doesn't match any known
|
||||
// ESC sequence => ESC means TB_KEY_ESC.
|
||||
// 2. Alt input mode.
|
||||
// When ESC sequence is in the buffer and it doesn't match any known
|
||||
// sequence => ESC enables TB_MOD_ALT modifier for the next keyboard event.
|
||||
//
|
||||
// You can also apply TB_INPUT_MOUSE via bitwise OR operation to either of the
|
||||
// modes (e.g. TB_INPUT_ESC | TB_INPUT_MOUSE). If none of the main two modes
|
||||
// were set, but the mouse mode was, TB_INPUT_ESC mode is used. If for some
|
||||
// reason you've decided to use (TB_INPUT_ESC | TB_INPUT_ALT) combination, it
|
||||
// will behave as if only TB_INPUT_ESC was selected.
|
||||
//
|
||||
// If 'mode' is TB_INPUT_CURRENT, it returns the current input mode.
|
||||
//
|
||||
// Default termbox input mode is TB_INPUT_ESC.
|
||||
SO_IMPORT int tb_select_input_mode(int mode);
|
||||
|
||||
#define TB_OUTPUT_CURRENT 0
|
||||
#define TB_OUTPUT_NORMAL 1
|
||||
#define TB_OUTPUT_256 2
|
||||
#define TB_OUTPUT_216 3
|
||||
#define TB_OUTPUT_GRAYSCALE 4
|
||||
#define TB_OUTPUT_TRUECOLOR 5
|
||||
|
||||
// Sets the termbox output mode. Termbox has three output options:
|
||||
// 1. TB_OUTPUT_NORMAL => [1..8]
|
||||
// This mode provides 8 different colors:
|
||||
// black, red, green, yellow, blue, magenta, cyan, white
|
||||
// Shortcut: TB_BLACK, TB_RED, ...
|
||||
// Attributes: TB_BOLD, TB_UNDERLINE, TB_REVERSE
|
||||
//
|
||||
// Example usage:
|
||||
// tb_change_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED);
|
||||
//
|
||||
// 2. TB_OUTPUT_256 => [0..256]
|
||||
// In this mode you can leverage the 256 terminal mode:
|
||||
// 0x00 - 0x07: the 8 colors as in TB_OUTPUT_NORMAL
|
||||
// 0x08 - 0x0f: TB_* | TB_BOLD
|
||||
// 0x10 - 0xe7: 216 different colors
|
||||
// 0xe8 - 0xff: 24 different shades of grey
|
||||
//
|
||||
// Example usage:
|
||||
// tb_change_cell(x, y, '@', 184, 240);
|
||||
// tb_change_cell(x, y, '@', 0xb8, 0xf0);
|
||||
//
|
||||
// 3. TB_OUTPUT_216 => [0..216]
|
||||
// This mode supports the 3rd range of the 256 mode only.
|
||||
// But you don't need to provide an offset.
|
||||
//
|
||||
// 4. TB_OUTPUT_GRAYSCALE => [0..23]
|
||||
// This mode supports the 4th range of the 256 mode only.
|
||||
// But you dont need to provide an offset.
|
||||
//
|
||||
// 5. TB_OUTPUT_TRUECOLOR => [0x000000..0xFFFFFF]
|
||||
// This mode supports 24-bit true color. Format is 0xRRGGBB.
|
||||
//
|
||||
// Execute build/src/demo/output to see its impact on your terminal.
|
||||
//
|
||||
// If 'mode' is TB_OUTPUT_CURRENT, it returns the current output mode.
|
||||
//
|
||||
// Default termbox output mode is TB_OUTPUT_NORMAL.
|
||||
SO_IMPORT int tb_select_output_mode(int mode);
|
||||
|
||||
// Wait for an event up to 'timeout' milliseconds and fill the 'event'
|
||||
// structure with it, when the event is available. Returns the type of the
|
||||
// event (one of TB_EVENT_* constants) or -1 if there was an error or 0 in case
|
||||
// there were no event during 'timeout' period.
|
||||
SO_IMPORT int tb_peek_event(struct tb_event* event, int timeout);
|
||||
|
||||
// Wait for an event forever and fill the 'event' structure with it, when the
|
||||
// event is available. Returns the type of the event (one of TB_EVENT_
|
||||
// constants) or -1 if there was an error.
|
||||
SO_IMPORT int tb_poll_event(struct tb_event* event);
|
||||
|
||||
// Utility utf8 functions.
|
||||
#define TB_EOF -1
|
||||
SO_IMPORT int utf8_char_length(char c);
|
||||
SO_IMPORT int utf8_char_to_unicode(uint32_t* out, const char* c);
|
||||
SO_IMPORT int utf8_unicode_to_char(char* out, uint32_t c);
|
||||
|
||||
// c++
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,106 +0,0 @@
|
||||
#include "termbox.h"
|
||||
|
||||
static const unsigned char utf8_length[256] =
|
||||
{
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
|
||||
};
|
||||
|
||||
static const unsigned char utf8_mask[6] =
|
||||
{
|
||||
0x7F,
|
||||
0x1F,
|
||||
0x0F,
|
||||
0x07,
|
||||
0x03,
|
||||
0x01
|
||||
};
|
||||
|
||||
int utf8_char_length(char c)
|
||||
{
|
||||
return utf8_length[(unsigned char)c];
|
||||
}
|
||||
|
||||
int utf8_char_to_unicode(uint32_t* out, const char* c)
|
||||
{
|
||||
if (*c == 0)
|
||||
{
|
||||
return TB_EOF;
|
||||
}
|
||||
|
||||
int i;
|
||||
unsigned char len = utf8_char_length(*c);
|
||||
unsigned char mask = utf8_mask[len - 1];
|
||||
uint32_t result = c[0] & mask;
|
||||
|
||||
for (i = 1; i < len; ++i)
|
||||
{
|
||||
result <<= 6;
|
||||
result |= c[i] & 0x3f;
|
||||
}
|
||||
|
||||
*out = result;
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
int utf8_unicode_to_char(char* out, uint32_t c)
|
||||
{
|
||||
int len = 0;
|
||||
int first;
|
||||
int i;
|
||||
|
||||
if (c < 0x80)
|
||||
{
|
||||
first = 0;
|
||||
len = 1;
|
||||
}
|
||||
else if (c < 0x800)
|
||||
{
|
||||
first = 0xc0;
|
||||
len = 2;
|
||||
}
|
||||
else if (c < 0x10000)
|
||||
{
|
||||
first = 0xe0;
|
||||
len = 3;
|
||||
}
|
||||
else if (c < 0x200000)
|
||||
{
|
||||
first = 0xf0;
|
||||
len = 4;
|
||||
}
|
||||
else if (c < 0x4000000)
|
||||
{
|
||||
first = 0xf8;
|
||||
len = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = 0xfc;
|
||||
len = 6;
|
||||
}
|
||||
|
||||
for (i = len - 1; i > 0; --i)
|
||||
{
|
||||
out[i] = (c & 0x3f) | 0x80;
|
||||
c >>= 6;
|
||||
}
|
||||
|
||||
out[0] = c | first;
|
||||
|
||||
return len;
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
--style=break
|
||||
--indent=force-tab=4
|
||||
--indent-classes
|
||||
--indent-switches
|
||||
--indent-namespaces
|
||||
--indent-after-parens
|
||||
--indent-continuation=1
|
||||
--indent-preproc-block
|
||||
--indent-preproc-define
|
||||
--indent-preproc-cond
|
||||
--indent-col1-comments
|
||||
--min-conditional-indent=0
|
||||
--max-continuation-indent=40
|
||||
--break-blocks
|
||||
--pad-oper
|
||||
--pad-comma
|
||||
--pad-header
|
||||
--unpad-paren
|
||||
--align-pointer=type
|
||||
--align-reference=type
|
||||
--break-one-line-headers
|
||||
--add-braces
|
||||
--attach-return-type
|
||||
--attach-return-type-decl
|
||||
--remove-comment-prefix
|
||||
--max-code-length=80
|
||||
--mode=c
|
@ -1,108 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, os, subprocess
|
||||
|
||||
def escaped(s):
|
||||
return s.replace("\033", "\\033")
|
||||
|
||||
def tput(term, name):
|
||||
try:
|
||||
return subprocess.check_output(['tput', '-T%s' % term, name]).decode()
|
||||
except subprocess.CalledProcessError as e:
|
||||
return e.output.decode()
|
||||
|
||||
|
||||
def w(s):
|
||||
if s == None:
|
||||
return
|
||||
sys.stdout.write(s)
|
||||
|
||||
terminals = {
|
||||
'xterm' : 'xterm',
|
||||
'rxvt-256color' : 'rxvt_256color',
|
||||
'rxvt-unicode' : 'rxvt_unicode',
|
||||
'linux' : 'linux',
|
||||
'Eterm' : 'eterm',
|
||||
'screen' : 'screen'
|
||||
}
|
||||
|
||||
keys = [
|
||||
"F1", "kf1",
|
||||
"F2", "kf2",
|
||||
"F3", "kf3",
|
||||
"F4", "kf4",
|
||||
"F5", "kf5",
|
||||
"F6", "kf6",
|
||||
"F7", "kf7",
|
||||
"F8", "kf8",
|
||||
"F9", "kf9",
|
||||
"F10", "kf10",
|
||||
"F11", "kf11",
|
||||
"F12", "kf12",
|
||||
"INSERT", "kich1",
|
||||
"DELETE", "kdch1",
|
||||
"HOME", "khome",
|
||||
"END", "kend",
|
||||
"PGUP", "kpp",
|
||||
"PGDN", "knp",
|
||||
"KEY_UP", "kcuu1",
|
||||
"KEY_DOWN", "kcud1",
|
||||
"KEY_LEFT", "kcub1",
|
||||
"KEY_RIGHT", "kcuf1"
|
||||
]
|
||||
|
||||
funcs = [
|
||||
"T_ENTER_CA", "smcup",
|
||||
"T_EXIT_CA", "rmcup",
|
||||
"T_SHOW_CURSOR", "cnorm",
|
||||
"T_HIDE_CURSOR", "civis",
|
||||
"T_CLEAR_SCREEN", "clear",
|
||||
"T_SGR0", "sgr0",
|
||||
"T_UNDERLINE", "smul",
|
||||
"T_BOLD", "bold",
|
||||
"T_BLINK", "blink",
|
||||
"T_REVERSE", "rev",
|
||||
"T_ENTER_KEYPAD", "smkx",
|
||||
"T_EXIT_KEYPAD", "rmkx"
|
||||
]
|
||||
|
||||
def iter_pairs(iterable):
|
||||
iterable = iter(iterable)
|
||||
while True:
|
||||
yield (next(iterable), next(iterable))
|
||||
|
||||
def do_term(term, nick):
|
||||
w("// %s\n" % term)
|
||||
w("static const char *%s_keys[] = {\n\t" % nick)
|
||||
for k, v in iter_pairs(keys):
|
||||
w('"')
|
||||
w(escaped(tput(term, v)))
|
||||
w('",')
|
||||
w(" 0\n};\n")
|
||||
w("static const char *%s_funcs[] = {\n\t" % nick)
|
||||
for k,v in iter_pairs(funcs):
|
||||
w('"')
|
||||
if v == "sgr":
|
||||
w("\\033[3%d;4%dm")
|
||||
elif v == "cup":
|
||||
w("\\033[%d;%dH")
|
||||
else:
|
||||
w(escaped(tput(term, v)))
|
||||
w('", ')
|
||||
w("\n};\n\n")
|
||||
|
||||
def do_terms(d):
|
||||
w("static struct term {\n")
|
||||
w("\tconst char *name;\n")
|
||||
w("\tconst char **keys;\n")
|
||||
w("\tconst char **funcs;\n")
|
||||
w("} terms[] = {\n")
|
||||
for k, v in d.items():
|
||||
w('\t{"%s", %s_keys, %s_funcs},\n' % (k, v, v))
|
||||
w("\t{0, 0, 0},\n")
|
||||
w("};\n")
|
||||
|
||||
for k,v in terminals.items():
|
||||
do_term(k, v)
|
||||
|
||||
do_terms(terminals)
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue