1package termbox 2 3import ( 4 "syscall" 5) 6 7// public API 8 9// Initializes termbox library. This function should be called before any other functions. 10// After successful initialization, the library must be finalized using 'Close' function. 11// 12// Example usage: 13// err := termbox.Init() 14// if err != nil { 15// panic(err) 16// } 17// defer termbox.Close() 18func Init() error { 19 var err error 20 21 interrupt, err = create_event() 22 if err != nil { 23 return err 24 } 25 26 in, err = syscall.Open("CONIN$", syscall.O_RDWR, 0) 27 if err != nil { 28 return err 29 } 30 out, err = syscall.Open("CONOUT$", syscall.O_RDWR, 0) 31 if err != nil { 32 return err 33 } 34 35 err = get_console_mode(in, &orig_mode) 36 if err != nil { 37 return err 38 } 39 40 err = set_console_mode(in, enable_window_input) 41 if err != nil { 42 return err 43 } 44 45 orig_size = get_term_size(out) 46 win_size := get_win_size(out) 47 48 err = set_console_screen_buffer_size(out, win_size) 49 if err != nil { 50 return err 51 } 52 53 err = get_console_cursor_info(out, &orig_cursor_info) 54 if err != nil { 55 return err 56 } 57 58 show_cursor(false) 59 term_size = get_term_size(out) 60 back_buffer.init(int(term_size.x), int(term_size.y)) 61 front_buffer.init(int(term_size.x), int(term_size.y)) 62 back_buffer.clear() 63 front_buffer.clear() 64 clear() 65 66 diffbuf = make([]diff_msg, 0, 32) 67 68 go input_event_producer() 69 IsInit = true 70 return nil 71} 72 73// Finalizes termbox library, should be called after successful initialization 74// when termbox's functionality isn't required anymore. 75func Close() { 76 // we ignore errors here, because we can't really do anything about them 77 Clear(0, 0) 78 Flush() 79 80 // stop event producer 81 cancel_comm <- true 82 set_event(interrupt) 83 select { 84 case <-input_comm: 85 default: 86 } 87 <-cancel_done_comm 88 89 set_console_cursor_info(out, &orig_cursor_info) 90 set_console_cursor_position(out, coord{}) 91 set_console_screen_buffer_size(out, orig_size) 92 set_console_mode(in, orig_mode) 93 syscall.Close(in) 94 syscall.Close(out) 95 syscall.Close(interrupt) 96 IsInit = false 97} 98 99// Interrupt an in-progress call to PollEvent by causing it to return 100// EventInterrupt. Note that this function will block until the PollEvent 101// function has successfully been interrupted. 102func Interrupt() { 103 interrupt_comm <- struct{}{} 104} 105 106// Synchronizes the internal back buffer with the terminal. 107func Flush() error { 108 update_size_maybe() 109 prepare_diff_messages() 110 for _, diff := range diffbuf { 111 r := small_rect{ 112 left: 0, 113 top: diff.pos, 114 right: term_size.x - 1, 115 bottom: diff.pos + diff.lines - 1, 116 } 117 write_console_output(out, diff.chars, r) 118 } 119 if !is_cursor_hidden(cursor_x, cursor_y) { 120 move_cursor(cursor_x, cursor_y) 121 } 122 return nil 123} 124 125// Sets the position of the cursor. See also HideCursor(). 126func SetCursor(x, y int) { 127 if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) { 128 show_cursor(true) 129 } 130 131 if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) { 132 show_cursor(false) 133 } 134 135 cursor_x, cursor_y = x, y 136 if !is_cursor_hidden(cursor_x, cursor_y) { 137 move_cursor(cursor_x, cursor_y) 138 } 139} 140 141// The shortcut for SetCursor(-1, -1). 142func HideCursor() { 143 SetCursor(cursor_hidden, cursor_hidden) 144} 145 146// Changes cell's parameters in the internal back buffer at the specified 147// position. 148func SetCell(x, y int, ch rune, fg, bg Attribute) { 149 if x < 0 || x >= back_buffer.width { 150 return 151 } 152 if y < 0 || y >= back_buffer.height { 153 return 154 } 155 156 back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg} 157} 158 159// Returns a slice into the termbox's back buffer. You can get its dimensions 160// using 'Size' function. The slice remains valid as long as no 'Clear' or 161// 'Flush' function calls were made after call to this function. 162func CellBuffer() []Cell { 163 return back_buffer.cells 164} 165 166// Wait for an event and return it. This is a blocking function call. 167func PollEvent() Event { 168 select { 169 case ev := <-input_comm: 170 return ev 171 case <-interrupt_comm: 172 return Event{Type: EventInterrupt} 173 } 174} 175 176// Returns the size of the internal back buffer (which is mostly the same as 177// console's window size in characters). But it doesn't always match the size 178// of the console window, after the console size has changed, the internal back 179// buffer will get in sync only after Clear or Flush function calls. 180func Size() (int, int) { 181 return int(term_size.x), int(term_size.y) 182} 183 184// Clears the internal back buffer. 185func Clear(fg, bg Attribute) error { 186 foreground, background = fg, bg 187 update_size_maybe() 188 back_buffer.clear() 189 return nil 190} 191 192// Sets termbox input mode. Termbox has two input modes: 193// 194// 1. Esc input mode. When ESC sequence is in the buffer and it doesn't match 195// any known sequence. ESC means KeyEsc. This is the default input mode. 196// 197// 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match 198// any known sequence. ESC enables ModAlt modifier for the next keyboard event. 199// 200// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will 201// enable mouse button press/release and drag events. 202// 203// If 'mode' is InputCurrent, returns the current input mode. See also Input* 204// constants. 205func SetInputMode(mode InputMode) InputMode { 206 if mode == InputCurrent { 207 return input_mode 208 } 209 if mode&InputMouse != 0 { 210 err := set_console_mode(in, enable_window_input|enable_mouse_input|enable_extended_flags) 211 if err != nil { 212 panic(err) 213 } 214 } else { 215 err := set_console_mode(in, enable_window_input) 216 if err != nil { 217 panic(err) 218 } 219 } 220 221 input_mode = mode 222 return input_mode 223} 224 225// Sets the termbox output mode. 226// 227// Windows console does not support extra colour modes, 228// so this will always set and return OutputNormal. 229func SetOutputMode(mode OutputMode) OutputMode { 230 return OutputNormal 231} 232 233// Sync comes handy when something causes desync between termbox's understanding 234// of a terminal buffer and the reality. Such as a third party process. Sync 235// forces a complete resync between the termbox and a terminal, it may not be 236// visually pretty though. At the moment on Windows it does nothing. 237func Sync() error { 238 return nil 239} 240