api_windows.go

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