240 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package termbox
 | 
						|
 | 
						|
import (
 | 
						|
	"syscall"
 | 
						|
)
 | 
						|
 | 
						|
// public API
 | 
						|
 | 
						|
// Initializes termbox library. This function should be called before any other functions.
 | 
						|
// After successful initialization, the library must be finalized using 'Close' function.
 | 
						|
//
 | 
						|
// Example usage:
 | 
						|
//      err := termbox.Init()
 | 
						|
//      if err != nil {
 | 
						|
//              panic(err)
 | 
						|
//      }
 | 
						|
//      defer termbox.Close()
 | 
						|
func Init() error {
 | 
						|
	var err error
 | 
						|
 | 
						|
	interrupt, err = create_event()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	in, err = syscall.Open("CONIN$", syscall.O_RDWR, 0)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	out, err = syscall.Open("CONOUT$", syscall.O_RDWR, 0)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = get_console_mode(in, &orig_mode)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = set_console_mode(in, enable_window_input)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	orig_size = get_term_size(out)
 | 
						|
	win_size := get_win_size(out)
 | 
						|
 | 
						|
	err = set_console_screen_buffer_size(out, win_size)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	err = get_console_cursor_info(out, &orig_cursor_info)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	show_cursor(false)
 | 
						|
	term_size = get_term_size(out)
 | 
						|
	back_buffer.init(int(term_size.x), int(term_size.y))
 | 
						|
	front_buffer.init(int(term_size.x), int(term_size.y))
 | 
						|
	back_buffer.clear()
 | 
						|
	front_buffer.clear()
 | 
						|
	clear()
 | 
						|
 | 
						|
	diffbuf = make([]diff_msg, 0, 32)
 | 
						|
 | 
						|
	go input_event_producer()
 | 
						|
	IsInit = true
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Finalizes termbox library, should be called after successful initialization
 | 
						|
// when termbox's functionality isn't required anymore.
 | 
						|
func Close() {
 | 
						|
	// we ignore errors here, because we can't really do anything about them
 | 
						|
	Clear(0, 0)
 | 
						|
	Flush()
 | 
						|
 | 
						|
	// stop event producer
 | 
						|
	cancel_comm <- true
 | 
						|
	set_event(interrupt)
 | 
						|
	select {
 | 
						|
	case <-input_comm:
 | 
						|
	default:
 | 
						|
	}
 | 
						|
	<-cancel_done_comm
 | 
						|
 | 
						|
	set_console_cursor_info(out, &orig_cursor_info)
 | 
						|
	set_console_cursor_position(out, coord{})
 | 
						|
	set_console_screen_buffer_size(out, orig_size)
 | 
						|
	set_console_mode(in, orig_mode)
 | 
						|
	syscall.Close(in)
 | 
						|
	syscall.Close(out)
 | 
						|
	syscall.Close(interrupt)
 | 
						|
	IsInit = false
 | 
						|
}
 | 
						|
 | 
						|
// Interrupt an in-progress call to PollEvent by causing it to return
 | 
						|
// EventInterrupt.  Note that this function will block until the PollEvent
 | 
						|
// function has successfully been interrupted.
 | 
						|
func Interrupt() {
 | 
						|
	interrupt_comm <- struct{}{}
 | 
						|
}
 | 
						|
 | 
						|
// Synchronizes the internal back buffer with the terminal.
 | 
						|
func Flush() error {
 | 
						|
	update_size_maybe()
 | 
						|
	prepare_diff_messages()
 | 
						|
	for _, diff := range diffbuf {
 | 
						|
		r := small_rect{
 | 
						|
			left:   0,
 | 
						|
			top:    diff.pos,
 | 
						|
			right:  term_size.x - 1,
 | 
						|
			bottom: diff.pos + diff.lines - 1,
 | 
						|
		}
 | 
						|
		write_console_output(out, diff.chars, r)
 | 
						|
	}
 | 
						|
	if !is_cursor_hidden(cursor_x, cursor_y) {
 | 
						|
		move_cursor(cursor_x, cursor_y)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Sets the position of the cursor. See also HideCursor().
 | 
						|
func SetCursor(x, y int) {
 | 
						|
	if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) {
 | 
						|
		show_cursor(true)
 | 
						|
	}
 | 
						|
 | 
						|
	if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) {
 | 
						|
		show_cursor(false)
 | 
						|
	}
 | 
						|
 | 
						|
	cursor_x, cursor_y = x, y
 | 
						|
	if !is_cursor_hidden(cursor_x, cursor_y) {
 | 
						|
		move_cursor(cursor_x, cursor_y)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// The shortcut for SetCursor(-1, -1).
 | 
						|
func HideCursor() {
 | 
						|
	SetCursor(cursor_hidden, cursor_hidden)
 | 
						|
}
 | 
						|
 | 
						|
// Changes cell's parameters in the internal back buffer at the specified
 | 
						|
// position.
 | 
						|
func SetCell(x, y int, ch rune, fg, bg Attribute) {
 | 
						|
	if x < 0 || x >= back_buffer.width {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if y < 0 || y >= back_buffer.height {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg}
 | 
						|
}
 | 
						|
 | 
						|
// Returns a slice into the termbox's back buffer. You can get its dimensions
 | 
						|
// using 'Size' function. The slice remains valid as long as no 'Clear' or
 | 
						|
// 'Flush' function calls were made after call to this function.
 | 
						|
func CellBuffer() []Cell {
 | 
						|
	return back_buffer.cells
 | 
						|
}
 | 
						|
 | 
						|
// Wait for an event and return it. This is a blocking function call.
 | 
						|
func PollEvent() Event {
 | 
						|
	select {
 | 
						|
	case ev := <-input_comm:
 | 
						|
		return ev
 | 
						|
	case <-interrupt_comm:
 | 
						|
		return Event{Type: EventInterrupt}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Returns the size of the internal back buffer (which is mostly the same as
 | 
						|
// console's window size in characters). But it doesn't always match the size
 | 
						|
// of the console window, after the console size has changed, the internal back
 | 
						|
// buffer will get in sync only after Clear or Flush function calls.
 | 
						|
func Size() (int, int) {
 | 
						|
	return int(term_size.x), int(term_size.y)
 | 
						|
}
 | 
						|
 | 
						|
// Clears the internal back buffer.
 | 
						|
func Clear(fg, bg Attribute) error {
 | 
						|
	foreground, background = fg, bg
 | 
						|
	update_size_maybe()
 | 
						|
	back_buffer.clear()
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Sets 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 sequence. ESC means KeyEsc. This is the default input mode.
 | 
						|
//
 | 
						|
// 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match
 | 
						|
// any known sequence. ESC enables ModAlt modifier for the next keyboard event.
 | 
						|
//
 | 
						|
// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will
 | 
						|
// enable mouse button press/release and drag events.
 | 
						|
//
 | 
						|
// If 'mode' is InputCurrent, returns the current input mode. See also Input*
 | 
						|
// constants.
 | 
						|
func SetInputMode(mode InputMode) InputMode {
 | 
						|
	if mode == InputCurrent {
 | 
						|
		return input_mode
 | 
						|
	}
 | 
						|
	if mode&InputMouse != 0 {
 | 
						|
		err := set_console_mode(in, enable_window_input|enable_mouse_input|enable_extended_flags)
 | 
						|
		if err != nil {
 | 
						|
			panic(err)
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		err := set_console_mode(in, enable_window_input)
 | 
						|
		if err != nil {
 | 
						|
			panic(err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	input_mode = mode
 | 
						|
	return input_mode
 | 
						|
}
 | 
						|
 | 
						|
// Sets the termbox output mode.
 | 
						|
//
 | 
						|
// Windows console does not support extra colour modes,
 | 
						|
// so this will always set and return OutputNormal.
 | 
						|
func SetOutputMode(mode OutputMode) OutputMode {
 | 
						|
	return OutputNormal
 | 
						|
}
 | 
						|
 | 
						|
// Sync comes handy when something causes desync between termbox's understanding
 | 
						|
// of a terminal buffer and the reality. Such as a third party process. Sync
 | 
						|
// forces a complete resync between the termbox and a terminal, it may not be
 | 
						|
// visually pretty though. At the moment on Windows it does nothing.
 | 
						|
func Sync() error {
 | 
						|
	return nil
 | 
						|
}
 |