Shift+Tab for previous input

pull/606/head
Kinzie 3 weeks ago
parent 1d3148201c
commit 4122dfac16
No known key found for this signature in database
GPG Key ID: EF86FC12BB84F79E

@ -17,19 +17,6 @@ pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const c_args = [_][]const u8{
"-std=c99",
"-pedantic",
"-g",
"-Wall",
"-Wextra",
"-Werror=vla",
"-Wno-unused-parameter",
"-D_DEFAULT_SOURCE",
"-D_POSIX_C_SOURCE=200809L",
"-D_XOPEN_SOURCE",
};
const exe = b.addExecutable(.{
.name = "ly",
.root_source_file = .{ .path = "src/main.zig" },
@ -45,19 +32,11 @@ pub fn build(b: *std.Build) void {
const clap = b.dependency("clap", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("clap", clap.module("clap"));
exe.addIncludePath(.{ .path = "include" });
exe.linkSystemLibrary("pam");
exe.linkSystemLibrary("xcb");
exe.linkLibC();
exe.addIncludePath(.{ .path = "dep/termbox_next/src" });
exe.addCSourceFile(.{ .file = .{ .path = "dep/termbox_next/src/input.c" }, .flags = &c_args });
exe.addCSourceFile(.{ .file = .{ .path = "dep/termbox_next/src/memstream.c" }, .flags = &c_args });
exe.addCSourceFile(.{ .file = .{ .path = "dep/termbox_next/src/ringbuffer.c" }, .flags = &c_args });
exe.addCSourceFile(.{ .file = .{ .path = "dep/termbox_next/src/term.c" }, .flags = &c_args });
exe.addCSourceFile(.{ .file = .{ .path = "dep/termbox_next/src/termbox.c" }, .flags = &c_args });
exe.addCSourceFile(.{ .file = .{ .path = "dep/termbox_next/src/utf8.c" }, .flags = &c_args });
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);

@ -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

@ -145,15 +145,15 @@ pub fn draw(self: *Matrix) void {
var y: u64 = 1;
while (y <= self.terminal_buffer.height) : (y += 1) {
const dot = self.dots[buf_width * y + x];
var fg: u32 = @intCast(termbox.TB_GREEN);
var fg: u16 = @intCast(termbox.TB_GREEN);
if (dot.value == -1 or dot.value == ' ') {
termbox.tb_change_cell(@intCast(x), @intCast(y - 1), ' ', fg, termbox.TB_DEFAULT);
_ = termbox.tb_set_cell(@intCast(x), @intCast(y - 1), ' ', fg, termbox.TB_DEFAULT);
continue;
}
if (dot.is_head) fg = @intCast(termbox.TB_WHITE | termbox.TB_BOLD);
termbox.tb_change_cell(@intCast(x), @intCast(y - 1), @intCast(dot.value), fg, termbox.TB_DEFAULT);
_ = termbox.tb_set_cell(@intCast(x), @intCast(y - 1), @intCast(dot.value), fg, termbox.TB_DEFAULT);
}
}
}

@ -3,7 +3,8 @@ const builtin = @import("builtin");
const Allocator = std.mem.Allocator;
pub const termbox = @cImport({
@cInclude("termbox.h");
@cDefine("TB_IMPL", {});
@cInclude("termbox2.h");
});
pub const pam = @cImport({

@ -33,7 +33,7 @@ pub fn signalHandler(i: c_int) callconv(.C) void {
_ = std.c.waitpid(session_pid, &status, 0);
}
termbox.tb_shutdown();
_ = termbox.tb_shutdown();
std.c.exit(i);
}
@ -143,7 +143,7 @@ pub fn main() !void {
// Initialize termbox
_ = termbox.tb_init();
defer termbox.tb_shutdown();
defer _ = termbox.tb_shutdown();
const act = std.posix.Sigaction{
.handler = .{ .handler = &signalHandler },
@ -152,8 +152,8 @@ pub fn main() !void {
};
try std.posix.sigaction(std.posix.SIG.TERM, &act, null);
_ = termbox.tb_select_output_mode(termbox.TB_OUTPUT_NORMAL);
termbox.tb_clear();
_ = termbox.tb_set_output_mode(termbox.TB_OUTPUT_NORMAL);
_ = termbox.tb_clear();
// Needed to reset termbox after auth
const tb_termios = try std.posix.tcgetattr(std.posix.STDIN_FILENO);
@ -271,7 +271,7 @@ pub fn main() !void {
if (!update or config.animation != .none) {
if (!update) std.time.sleep(std.time.ns_per_ms * 100);
termbox.tb_present(); // Required to update tb_width(), tb_height() and tb_cell_buffer()
_ = termbox.tb_present(); // Required to update tb_width(), tb_height() and tb_cell_buffer()
const width: u64 = @intCast(termbox.tb_width());
const height: u64 = @intCast(termbox.tb_height());
@ -307,7 +307,7 @@ pub fn main() !void {
if (update) {
// If the user entered a wrong password 10 times in a row, play a cascade animation, else update normally
if (auth_fails < 10) {
termbox.tb_clear();
_ = termbox.tb_clear();
switch (config.animation) {
.none => {},
@ -435,7 +435,7 @@ pub fn main() !void {
}
}
termbox.tb_present();
_ = termbox.tb_present();
}
var timeout: i32 = -1;
@ -513,6 +513,15 @@ pub fn main() !void {
};
update = true;
},
termbox.TB_KEY_BACK_TAB => {
active_input = switch (active_input) {
.session => .password,
.login => .session,
.password => .login,
};
update = true;
},
termbox.TB_KEY_ENTER => {
if (config.save) save_last_settings: {
var file = std.fs.cwd().createFile(save_path, .{}) catch break :save_last_settings;
@ -566,8 +575,8 @@ pub fn main() !void {
try std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, tb_termios);
if (auth_fails < 10) {
termbox.tb_clear();
termbox.tb_present();
_ = termbox.tb_clear();
_ = termbox.tb_present();
}
update = true;

@ -110,25 +110,25 @@ pub fn drawBoxCenter(self: *TerminalBuffer, show_borders: bool, blank_box: bool)
self.box_y = y1;
if (show_borders) {
termbox.tb_change_cell(@intCast(x1 - 1), @intCast(y1 - 1), self.box_chars.left_up, self.border_fg, self.bg);
termbox.tb_change_cell(@intCast(x2), @intCast(y1 - 1), self.box_chars.right_up, self.border_fg, self.bg);
termbox.tb_change_cell(@intCast(x1 - 1), @intCast(y2), self.box_chars.left_down, self.border_fg, self.bg);
termbox.tb_change_cell(@intCast(x2), @intCast(y2), self.box_chars.right_down, self.border_fg, self.bg);
_ = termbox.tb_set_cell(@intCast(x1 - 1), @intCast(y1 - 1), self.box_chars.left_up, self.border_fg, self.bg);
_ = termbox.tb_set_cell(@intCast(x2), @intCast(y1 - 1), self.box_chars.right_up, self.border_fg, self.bg);
_ = termbox.tb_set_cell(@intCast(x1 - 1), @intCast(y2), self.box_chars.left_down, self.border_fg, self.bg);
_ = termbox.tb_set_cell(@intCast(x2), @intCast(y2), self.box_chars.right_down, self.border_fg, self.bg);
var c1 = utils.initCell(self.box_chars.top, self.border_fg, self.bg);
var c2 = utils.initCell(self.box_chars.bottom, self.border_fg, self.bg);
for (0..self.box_width) |i| {
termbox.tb_put_cell(@intCast(x1 + i), @intCast(y1 - 1), &c1);
termbox.tb_put_cell(@intCast(x1 + i), @intCast(y2), &c2);
_ = utils.putCell(@intCast(x1 + i), @intCast(y1 - 1), &c1);
_ = utils.putCell(@intCast(x1 + i), @intCast(y2), &c2);
}
c1.ch = self.box_chars.left;
c2.ch = self.box_chars.right;
for (0..self.box_height) |i| {
termbox.tb_put_cell(@intCast(x1 - 1), @intCast(y1 + i), &c1);
termbox.tb_put_cell(@intCast(x2), @intCast(y1 + i), &c2);
_ = utils.putCell(@intCast(x1 - 1), @intCast(y1 + i), &c1);
_ = utils.putCell(@intCast(x2), @intCast(y1 + i), &c2);
}
}
@ -137,7 +137,7 @@ pub fn drawBoxCenter(self: *TerminalBuffer, show_borders: bool, blank_box: bool)
for (0..self.box_height) |y| {
for (0..self.box_width) |x| {
termbox.tb_put_cell(@intCast(x1 + x), @intCast(y1 + y), &blank);
_ = utils.putCell(@intCast(x1 + x), @intCast(y1 + y), &blank);
}
}
}
@ -166,7 +166,7 @@ pub fn drawLabel(self: TerminalBuffer, text: []const u8, x: u64, y: u64) void {
var i = x;
while (utf8.nextCodepoint()) |codepoint| : (i += 1) {
termbox.tb_change_cell(@intCast(i), yc, codepoint, self.fg, self.bg);
_ = termbox.tb_set_cell(@intCast(i), yc, codepoint, self.fg, self.bg);
}
}
@ -180,7 +180,7 @@ pub fn drawConfinedLabel(self: TerminalBuffer, text: []const u8, x: u64, y: u64,
var i = x;
while (utf8.nextCodepoint()) |codepoint| : (i += 1) {
termbox.tb_change_cell(@intCast(i), yc, codepoint, self.fg, self.bg);
_ = termbox.tb_set_cell(@intCast(i), yc, codepoint, self.fg, self.bg);
}
}
@ -188,5 +188,5 @@ pub fn drawCharMultiple(self: TerminalBuffer, char: u8, x: u64, y: u64, length:
const yc: c_int = @intCast(y);
const cell = utils.initCell(char, self.fg, self.bg);
for (0..length) |xx| termbox.tb_put_cell(@intCast(x + xx), yc, &cell);
for (0..length) |xx| _ = utils.putCell(@intCast(x + xx), yc, &cell);
}

@ -185,7 +185,7 @@ pub fn handle(self: *Desktop, maybe_event: ?*termbox.tb_event, insert_mode: bool
}
}
termbox.tb_set_cursor(@intCast(self.x + 2), @intCast(self.y));
_ = termbox.tb_set_cursor(@intCast(self.x + 2), @intCast(self.y));
}
pub fn draw(self: Desktop) void {
@ -198,8 +198,8 @@ pub fn draw(self: Desktop) void {
const y = self.buffer.box_y + self.buffer.margin_box_v + 2;
self.buffer.drawLabel(environment.specifier, x, y);
termbox.tb_change_cell(@intCast(self.x), @intCast(self.y), '<', self.buffer.fg, self.buffer.bg);
termbox.tb_change_cell(@intCast(self.x + self.visible_length - 1), @intCast(self.y), '>', self.buffer.fg, self.buffer.bg);
_ = termbox.tb_set_cell(@intCast(self.x), @intCast(self.y), '<', self.buffer.fg, self.buffer.bg);
_ = termbox.tb_set_cell(@intCast(self.x + self.visible_length - 1), @intCast(self.y), '>', self.buffer.fg, self.buffer.bg);
self.buffer.drawLabel(environment.name, self.x + 2, self.y);
}

@ -78,14 +78,21 @@ pub fn handle(self: *Text, maybe_event: ?*termbox.tb_event, insert_mode: bool) !
}
}
termbox.tb_set_cursor(@intCast(self.x + (self.cursor - self.visible_start)), @intCast(self.y));
_ = termbox.tb_set_cursor(@intCast(self.x + (self.cursor - self.visible_start)), @intCast(self.y));
}
pub fn draw(self: Text) void {
const length = @min(self.text.items.len, self.visible_length);
if (length == 0) return;
const visible_slice = if (self.text.items.len > self.visible_length and self.cursor < self.text.items.len) self.text.items[self.visible_start..(self.visible_length + self.visible_start)] else self.text.items[self.visible_start..];
const visible_slice = vs: {
if (self.text.items.len > self.visible_length and self.cursor < self.text.items.len) {
break :vs self.text.items[self.visible_start..(self.visible_length + self.visible_start)];
} else {
break :vs self.text.items[self.visible_start..];
}
};
self.buffer.drawLabel(visible_slice, self.x, self.y);
}

@ -3,7 +3,7 @@ const interop = @import("../interop.zig");
const termbox = interop.termbox;
pub fn initCell(ch: u32, fg: u32, bg: u32) termbox.tb_cell {
pub fn initCell(ch: u32, fg: u16, bg: u16) termbox.tb_cell {
return .{
.ch = ch,
.fg = fg,
@ -11,6 +11,10 @@ pub fn initCell(ch: u32, fg: u32, bg: u32) termbox.tb_cell {
};
}
pub fn putCell(x: i32, y: i32, cell: *const termbox.tb_cell) c_int {
return termbox.tb_set_cell(x, y, cell.ch, cell.fg, cell.bg);
}
// Every codepoint is assumed to have a width of 1.
// Since ly should be running in a tty, this should be fine.
pub fn strWidth(str: []const u8) !u8 {

Loading…
Cancel
Save