1 module termbox; 2 3 public import color; 4 public import keyboard; 5 6 /* A cell, single conceptual entity on the terminal screen. The terminal screen 7 * is basically a 2d array of cells. It has the following fields: 8 * - 'ch' is a unicode character 9 * - 'fg' foreground color and attributes 10 * - 'bg' background color and attributes 11 */ 12 struct Cell { 13 uint ch; 14 ushort fg; 15 ushort bg; 16 }; 17 18 enum EventType { 19 key = cast(ubyte) 1, 20 resize = cast(ubyte) 2, 21 mouse = cast(ubyte) 3 22 } 23 24 /* An event, single interaction from the user. The 'mod' and 'ch' fields are 25 * valid if 'type' is TB_EVENT_KEY. The 'w' and 'h' fields are valid if 'type' 26 * is TB_EVENT_RESIZE. The 'x' and 'y' fields are valid if 'type' is 27 * TB_EVENT_MOUSE. The 'key' field is valid if 'type' is either TB_EVENT_KEY 28 * or TB_EVENT_MOUSE. The fields 'key' and 'ch' are mutually exclusive; only 29 * one of them can be non-zero at a time. 30 */ 31 struct Event { 32 ubyte type; 33 ubyte mod; /* modifiers to either 'key' or 'ch' below */ 34 ushort key; /* one of the TB_KEY_* constants */ 35 uint ch; /* unicode character */ 36 int w; 37 int h; 38 int x; 39 int y; 40 }; 41 42 /* Error codes returned by tb_init(). All of them are self-explanatory, except 43 * the pipe trap error. Termbox uses unix pipes in order to deliver a message 44 * from a signal handler (SIGWINCH) to the main event reading loop. Honestly in 45 * most cases you should just check the returned code as < 0. 46 */ 47 enum Error { 48 unsupportedTerminal = -1, 49 failedToOpenTTY = -2, 50 pipeTrapError = -3 51 } 52 53 /* Initializes the termbox library. This function should be called before any 54 * other functions. After successful initialization, the library must be 55 * finalized using the tb_shutdown() function. 56 */ 57 private extern (C) int tb_init(); 58 private extern (C) void tb_shutdown(); 59 60 /* Returns the size of the internal back buffer (which is the same as 61 * terminal's window size in characters). The internal buffer can be resized 62 * after tb_clear() or tb_present() function calls. Both dimensions have an 63 * unspecified negative value when called before tb_init() or after 64 * tb_shutdown(). 65 */ 66 private extern (C) int tb_width(); 67 private extern (C) int tb_height(); 68 69 /* Clears the internal back buffer using TB_DEFAULT color or the 70 * color/attributes set by tb_set_clear_attributes() function. 71 */ 72 private extern (C) void tb_clear(); 73 private extern (C) void tb_set_clear_attributes(ushort fg, ushort bg); 74 75 /* Synchronizes the internal back buffer with the terminal. */ 76 private extern (C) void tb_present(); 77 78 /* Sets the position of the cursor. Upper-left character is (0, 0). If you pass 79 * TB_HIDE_CURSOR as both coordinates, then the cursor will be hidden. Cursor 80 * is hidden by default. 81 */ 82 private extern (C) void tb_set_cursor(int cx, int cy); 83 84 /* Changes cell's parameters in the internal back buffer at the specified 85 * position. 86 */ 87 private extern (C) void tb_put_cell(int x, int y, Cell* cell); 88 private extern (C) void tb_change_cell(int x, int y, uint ch, uint fg, uint bg); 89 90 /* Returns a pointer to internal cell back buffer. You can get its dimensions 91 * using tb_width() and tb_height() functions. The pointer stays valid as long 92 * as no tb_clear() and tb_present() calls are made. The buffer is 93 * one-dimensional buffer containing lines of cells starting from the top. 94 */ 95 private extern (C) Cell* tb_cell_buffer(); 96 97 /* Sets the termbox input mode. Termbox has two input modes: 98 * 1. Esc input mode. 99 * When ESC sequence is in the buffer and it doesn't match any known 100 * ESC sequence => ESC means TB_KEY_ESC. 101 * 2. Alt input mode. 102 * When ESC sequence is in the buffer and it doesn't match any known 103 * sequence => ESC enables TB_MOD_ALT modifier for the next keyboard event. 104 * 105 * You can also apply TB_INPUT_MOUSE via bitwise OR operation to either of the 106 * modes (e.g. TB_INPUT_ESC | TB_INPUT_MOUSE). If none of the main two modes 107 * were set, but the mouse mode was, TB_INPUT_ESC mode is used. If for some 108 * reason you've decided to use (TB_INPUT_ESC | TB_INPUT_ALT) combination, it 109 * will behave as if only TB_INPUT_ESC was selected. 110 * 111 * If 'mode' is TB_INPUT_CURRENT, it returns the current input mode. 112 * 113 * Default termbox input mode is TB_INPUT_ESC. 114 */ 115 private extern (C) int tb_select_input_mode(int mode); 116 117 enum InputMode { 118 current = 0, 119 esc = 1, 120 alt = 2, 121 mouse = 4 122 } 123 124 enum OutputMode { 125 current = 0, 126 normal = 1, 127 out256 = 2, 128 out216 = 3, 129 grayscale = 4 130 } 131 132 /* Sets the termbox output mode. Termbox has three output options: 133 * 1. TB_OUTPUT_NORMAL => [1..8] 134 * This mode provides 8 different colors: 135 * black, red, green, yellow, blue, magenta, cyan, white 136 * Shortcut: TB_BLACK, TB_RED, ... 137 * Attributes: TB_BOLD, TB_UNDERLINE, TB_REVERSE 138 * 139 * Example usage: 140 * tb_change_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED); 141 * 142 * 2. TB_OUTPUT_256 => [0..256] 143 * In this mode you can leverage the 256 terminal mode: 144 * 0x00 - 0x07: the 8 colors as in TB_OUTPUT_NORMAL 145 * 0x08 - 0x0f: TB_* | TB_BOLD 146 * 0x10 - 0xe7: 216 different colors 147 * 0xe8 - 0xff: 24 different shades of grey 148 * 149 * Example usage: 150 * tb_change_cell(x, y, '@', 184, 240); 151 * tb_change_cell(x, y, '@', 0xb8, 0xf0); 152 * 153 * 2. TB_OUTPUT_216 => [0..216] 154 * This mode supports the 3rd range of the 256 mode only. 155 * But you don't need to provide an offset. 156 * 157 * 3. TB_OUTPUT_GRAYSCALE => [0..23] 158 * This mode supports the 4th range of the 256 mode only. 159 * But you dont need to provide an offset. 160 * 161 * Execute build/src/demo/output to see its impact on your terminal. 162 * 163 * If 'mode' is TB_OUTPUT_CURRENT, it returns the current output mode. 164 * 165 * Default termbox output mode is TB_OUTPUT_NORMAL. 166 */ 167 private extern (C) int tb_select_output_mode(int mode); 168 169 /* Wait for an event up to 'timeout' milliseconds and fill the 'event' 170 * structure with it, when the event is available. Returns the type of the 171 * event (one of TB_EVENT_* constants) or -1 if there was an error or 0 in case 172 * there were no event during 'timeout' period. 173 */ 174 private extern (C) int tb_peek_event(Event* event, int timeout); 175 176 /* Wait for an event forever and fill the 'event' structure with it, when the 177 * event is available. Returns the type of the event (one of TB_EVENT_* 178 * constants) or -1 if there was an error. 179 */ 180 private extern (C) int tb_poll_event(Event* event); 181 182 /* Utility utf8 functions. */ 183 enum TB_EOF = -1; 184 private extern (C) int tb_utf8_char_length(char c); 185 private extern (C) int tb_utf8_char_to_unicode(uint* out_, const char* c); 186 private extern (C) int tb_utf8_unicode_to_char(char* out_, uint c); 187 188 189 int init() { return tb_init(); } 190 void shutdown() { tb_shutdown(); } 191 192 int height() { return tb_height(); } 193 int width() { return tb_width(); } 194 195 void clear() { tb_clear(); } 196 void setClearAttributes(ushort fg, ushort bg) { tb_set_clear_attributes(fg, bg); } 197 198 void flush() { tb_present(); } 199 200 void setCursor(int cx, int cy) { tb_set_cursor(cx, cy); } 201 202 void putCell(int x, int y, Cell* cell) { tb_put_cell(x, y, cell); } 203 void setCell(int x, int y, uint ch, ushort fg, ushort bg) { tb_change_cell(x, y, ch, fg, bg); } 204 205 Cell* cellBuffer() { return tb_cell_buffer(); } 206 207 int setInputMode(InputMode mode) { return tb_select_input_mode(mode); } 208 int setOutputMode(OutputMode mode) { return tb_select_output_mode(mode); } 209 210 int peekEvent(Event* event, int timeout) { return tb_peek_event(event, timeout); } 211 int pollEvent(Event* event) { return tb_poll_event(event); } 212 213 int charLength(char c) { return tb_utf8_char_length(c); } 214 int charToUnicode(uint* out_, const char* c) { return tb_utf8_char_to_unicode(out_, c); } 215 int unicodeToChar(char* out_, uint c) { return tb_utf8_unicode_to_char(out_, c); } 216 217 void hideCursor() { setCursor(-1, -1); }