289b30715d
This commit converts the dependency management from Godeps to the vendor folder, also switching the tool from godep to trash. Since the upstream tool lacks a few features proposed via a few PRs, until those PRs are merged in (if), use github.com/karalabe/trash. You can update dependencies via trash --update. All dependencies have been updated to their latest version. Parts of the build system are reworked to drop old notions of Godeps and invocation of the go vet command so that it doesn't run against the vendor folder, as that will just blow up during vetting. The conversion drops OpenCL (and hence GPU mining support) from ethash and our codebase. The short reasoning is that there's noone to maintain and having opencl libs in our deps messes up builds as go install ./... tries to build them, failing with unsatisfied link errors for the C OpenCL deps. golang.org/x/net/context is not vendored in. We expect it to be fetched by the user (i.e. using go get). To keep ci.go builds reproducible the package is "vendored" in build/_vendor.
857 lines
20 KiB
Go
857 lines
20 KiB
Go
package termbox
|
|
|
|
import "syscall"
|
|
import "unsafe"
|
|
import "unicode/utf16"
|
|
import "github.com/mattn/go-runewidth"
|
|
|
|
type (
|
|
wchar uint16
|
|
short int16
|
|
dword uint32
|
|
word uint16
|
|
char_info struct {
|
|
char wchar
|
|
attr word
|
|
}
|
|
coord struct {
|
|
x short
|
|
y short
|
|
}
|
|
small_rect struct {
|
|
left short
|
|
top short
|
|
right short
|
|
bottom short
|
|
}
|
|
console_screen_buffer_info struct {
|
|
size coord
|
|
cursor_position coord
|
|
attributes word
|
|
window small_rect
|
|
maximum_window_size coord
|
|
}
|
|
console_cursor_info struct {
|
|
size dword
|
|
visible int32
|
|
}
|
|
input_record struct {
|
|
event_type word
|
|
_ [2]byte
|
|
event [16]byte
|
|
}
|
|
key_event_record struct {
|
|
key_down int32
|
|
repeat_count word
|
|
virtual_key_code word
|
|
virtual_scan_code word
|
|
unicode_char wchar
|
|
control_key_state dword
|
|
}
|
|
window_buffer_size_record struct {
|
|
size coord
|
|
}
|
|
mouse_event_record struct {
|
|
mouse_pos coord
|
|
button_state dword
|
|
control_key_state dword
|
|
event_flags dword
|
|
}
|
|
)
|
|
|
|
const (
|
|
mouse_lmb = 0x1
|
|
mouse_rmb = 0x2
|
|
mouse_mmb = 0x4 | 0x8 | 0x10
|
|
)
|
|
|
|
func (this coord) uintptr() uintptr {
|
|
return uintptr(*(*int32)(unsafe.Pointer(&this)))
|
|
}
|
|
|
|
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
var is_cjk = runewidth.IsEastAsian()
|
|
|
|
var (
|
|
proc_set_console_active_screen_buffer = kernel32.NewProc("SetConsoleActiveScreenBuffer")
|
|
proc_set_console_screen_buffer_size = kernel32.NewProc("SetConsoleScreenBufferSize")
|
|
proc_create_console_screen_buffer = kernel32.NewProc("CreateConsoleScreenBuffer")
|
|
proc_get_console_screen_buffer_info = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
|
proc_write_console_output = kernel32.NewProc("WriteConsoleOutputW")
|
|
proc_write_console_output_character = kernel32.NewProc("WriteConsoleOutputCharacterW")
|
|
proc_write_console_output_attribute = kernel32.NewProc("WriteConsoleOutputAttribute")
|
|
proc_set_console_cursor_info = kernel32.NewProc("SetConsoleCursorInfo")
|
|
proc_set_console_cursor_position = kernel32.NewProc("SetConsoleCursorPosition")
|
|
proc_get_console_cursor_info = kernel32.NewProc("GetConsoleCursorInfo")
|
|
proc_read_console_input = kernel32.NewProc("ReadConsoleInputW")
|
|
proc_get_console_mode = kernel32.NewProc("GetConsoleMode")
|
|
proc_set_console_mode = kernel32.NewProc("SetConsoleMode")
|
|
proc_fill_console_output_character = kernel32.NewProc("FillConsoleOutputCharacterW")
|
|
proc_fill_console_output_attribute = kernel32.NewProc("FillConsoleOutputAttribute")
|
|
proc_create_event = kernel32.NewProc("CreateEventW")
|
|
proc_wait_for_multiple_objects = kernel32.NewProc("WaitForMultipleObjects")
|
|
proc_set_event = kernel32.NewProc("SetEvent")
|
|
)
|
|
|
|
func set_console_active_screen_buffer(h syscall.Handle) (err error) {
|
|
r0, _, e1 := syscall.Syscall(proc_set_console_active_screen_buffer.Addr(),
|
|
1, uintptr(h), 0, 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func set_console_screen_buffer_size(h syscall.Handle, size coord) (err error) {
|
|
r0, _, e1 := syscall.Syscall(proc_set_console_screen_buffer_size.Addr(),
|
|
2, uintptr(h), size.uintptr(), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func create_console_screen_buffer() (h syscall.Handle, err error) {
|
|
r0, _, e1 := syscall.Syscall6(proc_create_console_screen_buffer.Addr(),
|
|
5, uintptr(generic_read|generic_write), 0, 0, console_textmode_buffer, 0, 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return syscall.Handle(r0), err
|
|
}
|
|
|
|
func get_console_screen_buffer_info(h syscall.Handle, info *console_screen_buffer_info) (err error) {
|
|
r0, _, e1 := syscall.Syscall(proc_get_console_screen_buffer_info.Addr(),
|
|
2, uintptr(h), uintptr(unsafe.Pointer(info)), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func write_console_output(h syscall.Handle, chars []char_info, dst small_rect) (err error) {
|
|
tmp_coord = coord{dst.right - dst.left + 1, dst.bottom - dst.top + 1}
|
|
tmp_rect = dst
|
|
r0, _, e1 := syscall.Syscall6(proc_write_console_output.Addr(),
|
|
5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), tmp_coord.uintptr(),
|
|
tmp_coord0.uintptr(), uintptr(unsafe.Pointer(&tmp_rect)), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func write_console_output_character(h syscall.Handle, chars []wchar, pos coord) (err error) {
|
|
r0, _, e1 := syscall.Syscall6(proc_write_console_output_character.Addr(),
|
|
5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), uintptr(len(chars)),
|
|
pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func write_console_output_attribute(h syscall.Handle, attrs []word, pos coord) (err error) {
|
|
r0, _, e1 := syscall.Syscall6(proc_write_console_output_attribute.Addr(),
|
|
5, uintptr(h), uintptr(unsafe.Pointer(&attrs[0])), uintptr(len(attrs)),
|
|
pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func set_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) {
|
|
r0, _, e1 := syscall.Syscall(proc_set_console_cursor_info.Addr(),
|
|
2, uintptr(h), uintptr(unsafe.Pointer(info)), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func get_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) {
|
|
r0, _, e1 := syscall.Syscall(proc_get_console_cursor_info.Addr(),
|
|
2, uintptr(h), uintptr(unsafe.Pointer(info)), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func set_console_cursor_position(h syscall.Handle, pos coord) (err error) {
|
|
r0, _, e1 := syscall.Syscall(proc_set_console_cursor_position.Addr(),
|
|
2, uintptr(h), pos.uintptr(), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func read_console_input(h syscall.Handle, record *input_record) (err error) {
|
|
r0, _, e1 := syscall.Syscall6(proc_read_console_input.Addr(),
|
|
4, uintptr(h), uintptr(unsafe.Pointer(record)), 1, uintptr(unsafe.Pointer(&tmp_arg)), 0, 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func get_console_mode(h syscall.Handle, mode *dword) (err error) {
|
|
r0, _, e1 := syscall.Syscall(proc_get_console_mode.Addr(),
|
|
2, uintptr(h), uintptr(unsafe.Pointer(mode)), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func set_console_mode(h syscall.Handle, mode dword) (err error) {
|
|
r0, _, e1 := syscall.Syscall(proc_set_console_mode.Addr(),
|
|
2, uintptr(h), uintptr(mode), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func fill_console_output_character(h syscall.Handle, char wchar, n int) (err error) {
|
|
r0, _, e1 := syscall.Syscall6(proc_fill_console_output_character.Addr(),
|
|
5, uintptr(h), uintptr(char), uintptr(n), tmp_coord.uintptr(),
|
|
uintptr(unsafe.Pointer(&tmp_arg)), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func fill_console_output_attribute(h syscall.Handle, attr word, n int) (err error) {
|
|
r0, _, e1 := syscall.Syscall6(proc_fill_console_output_attribute.Addr(),
|
|
5, uintptr(h), uintptr(attr), uintptr(n), tmp_coord.uintptr(),
|
|
uintptr(unsafe.Pointer(&tmp_arg)), 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func create_event() (out syscall.Handle, err error) {
|
|
r0, _, e1 := syscall.Syscall6(proc_create_event.Addr(),
|
|
4, 0, 0, 0, 0, 0, 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return syscall.Handle(r0), err
|
|
}
|
|
|
|
func wait_for_multiple_objects(objects []syscall.Handle) (err error) {
|
|
r0, _, e1 := syscall.Syscall6(proc_wait_for_multiple_objects.Addr(),
|
|
4, uintptr(len(objects)), uintptr(unsafe.Pointer(&objects[0])),
|
|
0, 0xFFFFFFFF, 0, 0)
|
|
if uint32(r0) == 0xFFFFFFFF {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func set_event(ev syscall.Handle) (err error) {
|
|
r0, _, e1 := syscall.Syscall(proc_set_event.Addr(),
|
|
1, uintptr(ev), 0, 0)
|
|
if int(r0) == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
type diff_msg struct {
|
|
pos short
|
|
lines short
|
|
chars []char_info
|
|
}
|
|
|
|
type input_event struct {
|
|
event Event
|
|
err error
|
|
}
|
|
|
|
var (
|
|
orig_cursor_info console_cursor_info
|
|
orig_size coord
|
|
orig_mode dword
|
|
orig_screen syscall.Handle
|
|
back_buffer cellbuf
|
|
front_buffer cellbuf
|
|
term_size coord
|
|
input_mode = InputEsc
|
|
cursor_x = cursor_hidden
|
|
cursor_y = cursor_hidden
|
|
foreground = ColorDefault
|
|
background = ColorDefault
|
|
in syscall.Handle
|
|
out syscall.Handle
|
|
interrupt syscall.Handle
|
|
charbuf []char_info
|
|
diffbuf []diff_msg
|
|
beg_x = -1
|
|
beg_y = -1
|
|
beg_i = -1
|
|
input_comm = make(chan Event)
|
|
interrupt_comm = make(chan struct{})
|
|
cancel_comm = make(chan bool, 1)
|
|
cancel_done_comm = make(chan bool)
|
|
alt_mode_esc = false
|
|
|
|
// these ones just to prevent heap allocs at all costs
|
|
tmp_info console_screen_buffer_info
|
|
tmp_arg dword
|
|
tmp_coord0 = coord{0, 0}
|
|
tmp_coord = coord{0, 0}
|
|
tmp_rect = small_rect{0, 0, 0, 0}
|
|
)
|
|
|
|
func get_cursor_position(out syscall.Handle) coord {
|
|
err := get_console_screen_buffer_info(out, &tmp_info)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return tmp_info.cursor_position
|
|
}
|
|
|
|
func get_term_size(out syscall.Handle) coord {
|
|
err := get_console_screen_buffer_info(out, &tmp_info)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return tmp_info.size
|
|
}
|
|
|
|
func get_win_size(out syscall.Handle) coord {
|
|
err := get_console_screen_buffer_info(out, &tmp_info)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return coord{
|
|
x: tmp_info.window.right - tmp_info.window.left + 1,
|
|
y: tmp_info.window.bottom - tmp_info.window.top + 1,
|
|
}
|
|
}
|
|
|
|
func update_size_maybe() {
|
|
size := get_term_size(out)
|
|
if size.x != term_size.x || size.y != term_size.y {
|
|
term_size = size
|
|
back_buffer.resize(int(size.x), int(size.y))
|
|
front_buffer.resize(int(size.x), int(size.y))
|
|
front_buffer.clear()
|
|
clear()
|
|
|
|
area := int(size.x) * int(size.y)
|
|
if cap(charbuf) < area {
|
|
charbuf = make([]char_info, 0, area)
|
|
}
|
|
}
|
|
}
|
|
|
|
var color_table_bg = []word{
|
|
0, // default (black)
|
|
0, // black
|
|
background_red,
|
|
background_green,
|
|
background_red | background_green, // yellow
|
|
background_blue,
|
|
background_red | background_blue, // magenta
|
|
background_green | background_blue, // cyan
|
|
background_red | background_blue | background_green, // white
|
|
}
|
|
|
|
var color_table_fg = []word{
|
|
foreground_red | foreground_blue | foreground_green, // default (white)
|
|
0,
|
|
foreground_red,
|
|
foreground_green,
|
|
foreground_red | foreground_green, // yellow
|
|
foreground_blue,
|
|
foreground_red | foreground_blue, // magenta
|
|
foreground_green | foreground_blue, // cyan
|
|
foreground_red | foreground_blue | foreground_green, // white
|
|
}
|
|
|
|
const (
|
|
replacement_char = '\uFFFD'
|
|
max_rune = '\U0010FFFF'
|
|
surr1 = 0xd800
|
|
surr2 = 0xdc00
|
|
surr3 = 0xe000
|
|
surr_self = 0x10000
|
|
)
|
|
|
|
func append_diff_line(y int) int {
|
|
n := 0
|
|
for x := 0; x < front_buffer.width; {
|
|
cell_offset := y*front_buffer.width + x
|
|
back := &back_buffer.cells[cell_offset]
|
|
front := &front_buffer.cells[cell_offset]
|
|
attr, char := cell_to_char_info(*back)
|
|
charbuf = append(charbuf, char_info{attr: attr, char: char[0]})
|
|
*front = *back
|
|
n++
|
|
w := runewidth.RuneWidth(back.Ch)
|
|
if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) {
|
|
w = 1
|
|
}
|
|
x += w
|
|
// If not CJK, fill trailing space with whitespace
|
|
if !is_cjk && w == 2 {
|
|
charbuf = append(charbuf, char_info{attr: attr, char: ' '})
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
// compares 'back_buffer' with 'front_buffer' and prepares all changes in the form of
|
|
// 'diff_msg's in the 'diff_buf'
|
|
func prepare_diff_messages() {
|
|
// clear buffers
|
|
diffbuf = diffbuf[:0]
|
|
charbuf = charbuf[:0]
|
|
|
|
var diff diff_msg
|
|
gbeg := 0
|
|
for y := 0; y < front_buffer.height; y++ {
|
|
same := true
|
|
line_offset := y * front_buffer.width
|
|
for x := 0; x < front_buffer.width; x++ {
|
|
cell_offset := line_offset + x
|
|
back := &back_buffer.cells[cell_offset]
|
|
front := &front_buffer.cells[cell_offset]
|
|
if *back != *front {
|
|
same = false
|
|
break
|
|
}
|
|
}
|
|
if same && diff.lines > 0 {
|
|
diffbuf = append(diffbuf, diff)
|
|
diff = diff_msg{}
|
|
}
|
|
if !same {
|
|
beg := len(charbuf)
|
|
end := beg + append_diff_line(y)
|
|
if diff.lines == 0 {
|
|
diff.pos = short(y)
|
|
gbeg = beg
|
|
}
|
|
diff.lines++
|
|
diff.chars = charbuf[gbeg:end]
|
|
}
|
|
}
|
|
if diff.lines > 0 {
|
|
diffbuf = append(diffbuf, diff)
|
|
diff = diff_msg{}
|
|
}
|
|
}
|
|
|
|
func get_ct(table []word, idx int) word {
|
|
idx = idx & 0x0F
|
|
if idx >= len(table) {
|
|
idx = len(table) - 1
|
|
}
|
|
return table[idx]
|
|
}
|
|
|
|
func cell_to_char_info(c Cell) (attr word, wc [2]wchar) {
|
|
attr = get_ct(color_table_fg, int(c.Fg)) | get_ct(color_table_bg, int(c.Bg))
|
|
if c.Fg&AttrReverse|c.Bg&AttrReverse != 0 {
|
|
attr = (attr&0xF0)>>4 | (attr&0x0F)<<4
|
|
}
|
|
if c.Fg&AttrBold != 0 {
|
|
attr |= foreground_intensity
|
|
}
|
|
if c.Bg&AttrBold != 0 {
|
|
attr |= background_intensity
|
|
}
|
|
|
|
r0, r1 := utf16.EncodeRune(c.Ch)
|
|
if r0 == 0xFFFD {
|
|
wc[0] = wchar(c.Ch)
|
|
wc[1] = ' '
|
|
} else {
|
|
wc[0] = wchar(r0)
|
|
wc[1] = wchar(r1)
|
|
}
|
|
return
|
|
}
|
|
|
|
func move_cursor(x, y int) {
|
|
err := set_console_cursor_position(out, coord{short(x), short(y)})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func show_cursor(visible bool) {
|
|
var v int32
|
|
if visible {
|
|
v = 1
|
|
}
|
|
|
|
var info console_cursor_info
|
|
info.size = 100
|
|
info.visible = v
|
|
err := set_console_cursor_info(out, &info)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func clear() {
|
|
var err error
|
|
attr, char := cell_to_char_info(Cell{
|
|
' ',
|
|
foreground,
|
|
background,
|
|
})
|
|
|
|
area := int(term_size.x) * int(term_size.y)
|
|
err = fill_console_output_attribute(out, attr, area)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
err = fill_console_output_character(out, char[0], area)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if !is_cursor_hidden(cursor_x, cursor_y) {
|
|
move_cursor(cursor_x, cursor_y)
|
|
}
|
|
}
|
|
|
|
func key_event_record_to_event(r *key_event_record) (Event, bool) {
|
|
if r.key_down == 0 {
|
|
return Event{}, false
|
|
}
|
|
|
|
e := Event{Type: EventKey}
|
|
if input_mode&InputAlt != 0 {
|
|
if alt_mode_esc {
|
|
e.Mod = ModAlt
|
|
alt_mode_esc = false
|
|
}
|
|
if r.control_key_state&(left_alt_pressed|right_alt_pressed) != 0 {
|
|
e.Mod = ModAlt
|
|
}
|
|
}
|
|
|
|
ctrlpressed := r.control_key_state&(left_ctrl_pressed|right_ctrl_pressed) != 0
|
|
|
|
if r.virtual_key_code >= vk_f1 && r.virtual_key_code <= vk_f12 {
|
|
switch r.virtual_key_code {
|
|
case vk_f1:
|
|
e.Key = KeyF1
|
|
case vk_f2:
|
|
e.Key = KeyF2
|
|
case vk_f3:
|
|
e.Key = KeyF3
|
|
case vk_f4:
|
|
e.Key = KeyF4
|
|
case vk_f5:
|
|
e.Key = KeyF5
|
|
case vk_f6:
|
|
e.Key = KeyF6
|
|
case vk_f7:
|
|
e.Key = KeyF7
|
|
case vk_f8:
|
|
e.Key = KeyF8
|
|
case vk_f9:
|
|
e.Key = KeyF9
|
|
case vk_f10:
|
|
e.Key = KeyF10
|
|
case vk_f11:
|
|
e.Key = KeyF11
|
|
case vk_f12:
|
|
e.Key = KeyF12
|
|
default:
|
|
panic("unreachable")
|
|
}
|
|
|
|
return e, true
|
|
}
|
|
|
|
if r.virtual_key_code <= vk_delete {
|
|
switch r.virtual_key_code {
|
|
case vk_insert:
|
|
e.Key = KeyInsert
|
|
case vk_delete:
|
|
e.Key = KeyDelete
|
|
case vk_home:
|
|
e.Key = KeyHome
|
|
case vk_end:
|
|
e.Key = KeyEnd
|
|
case vk_pgup:
|
|
e.Key = KeyPgup
|
|
case vk_pgdn:
|
|
e.Key = KeyPgdn
|
|
case vk_arrow_up:
|
|
e.Key = KeyArrowUp
|
|
case vk_arrow_down:
|
|
e.Key = KeyArrowDown
|
|
case vk_arrow_left:
|
|
e.Key = KeyArrowLeft
|
|
case vk_arrow_right:
|
|
e.Key = KeyArrowRight
|
|
case vk_backspace:
|
|
if ctrlpressed {
|
|
e.Key = KeyBackspace2
|
|
} else {
|
|
e.Key = KeyBackspace
|
|
}
|
|
case vk_tab:
|
|
e.Key = KeyTab
|
|
case vk_enter:
|
|
e.Key = KeyEnter
|
|
case vk_esc:
|
|
switch {
|
|
case input_mode&InputEsc != 0:
|
|
e.Key = KeyEsc
|
|
case input_mode&InputAlt != 0:
|
|
alt_mode_esc = true
|
|
return Event{}, false
|
|
}
|
|
case vk_space:
|
|
if ctrlpressed {
|
|
// manual return here, because KeyCtrlSpace is zero
|
|
e.Key = KeyCtrlSpace
|
|
return e, true
|
|
} else {
|
|
e.Key = KeySpace
|
|
}
|
|
}
|
|
|
|
if e.Key != 0 {
|
|
return e, true
|
|
}
|
|
}
|
|
|
|
if ctrlpressed {
|
|
if Key(r.unicode_char) >= KeyCtrlA && Key(r.unicode_char) <= KeyCtrlRsqBracket {
|
|
e.Key = Key(r.unicode_char)
|
|
if input_mode&InputAlt != 0 && e.Key == KeyEsc {
|
|
alt_mode_esc = true
|
|
return Event{}, false
|
|
}
|
|
return e, true
|
|
}
|
|
switch r.virtual_key_code {
|
|
case 192, 50:
|
|
// manual return here, because KeyCtrl2 is zero
|
|
e.Key = KeyCtrl2
|
|
return e, true
|
|
case 51:
|
|
if input_mode&InputAlt != 0 {
|
|
alt_mode_esc = true
|
|
return Event{}, false
|
|
}
|
|
e.Key = KeyCtrl3
|
|
case 52:
|
|
e.Key = KeyCtrl4
|
|
case 53:
|
|
e.Key = KeyCtrl5
|
|
case 54:
|
|
e.Key = KeyCtrl6
|
|
case 189, 191, 55:
|
|
e.Key = KeyCtrl7
|
|
case 8, 56:
|
|
e.Key = KeyCtrl8
|
|
}
|
|
|
|
if e.Key != 0 {
|
|
return e, true
|
|
}
|
|
}
|
|
|
|
if r.unicode_char != 0 {
|
|
e.Ch = rune(r.unicode_char)
|
|
return e, true
|
|
}
|
|
|
|
return Event{}, false
|
|
}
|
|
|
|
func input_event_producer() {
|
|
var r input_record
|
|
var err error
|
|
var last_button Key
|
|
var last_button_pressed Key
|
|
var last_state = dword(0)
|
|
var last_x, last_y = -1, -1
|
|
handles := []syscall.Handle{in, interrupt}
|
|
for {
|
|
err = wait_for_multiple_objects(handles)
|
|
if err != nil {
|
|
input_comm <- Event{Type: EventError, Err: err}
|
|
}
|
|
|
|
select {
|
|
case <-cancel_comm:
|
|
cancel_done_comm <- true
|
|
return
|
|
default:
|
|
}
|
|
|
|
err = read_console_input(in, &r)
|
|
if err != nil {
|
|
input_comm <- Event{Type: EventError, Err: err}
|
|
}
|
|
|
|
switch r.event_type {
|
|
case key_event:
|
|
kr := (*key_event_record)(unsafe.Pointer(&r.event))
|
|
ev, ok := key_event_record_to_event(kr)
|
|
if ok {
|
|
for i := 0; i < int(kr.repeat_count); i++ {
|
|
input_comm <- ev
|
|
}
|
|
}
|
|
case window_buffer_size_event:
|
|
sr := *(*window_buffer_size_record)(unsafe.Pointer(&r.event))
|
|
input_comm <- Event{
|
|
Type: EventResize,
|
|
Width: int(sr.size.x),
|
|
Height: int(sr.size.y),
|
|
}
|
|
case mouse_event:
|
|
mr := *(*mouse_event_record)(unsafe.Pointer(&r.event))
|
|
ev := Event{Type: EventMouse}
|
|
switch mr.event_flags {
|
|
case 0, 2:
|
|
// single or double click
|
|
cur_state := mr.button_state
|
|
switch {
|
|
case last_state&mouse_lmb == 0 && cur_state&mouse_lmb != 0:
|
|
last_button = MouseLeft
|
|
last_button_pressed = last_button
|
|
case last_state&mouse_rmb == 0 && cur_state&mouse_rmb != 0:
|
|
last_button = MouseRight
|
|
last_button_pressed = last_button
|
|
case last_state&mouse_mmb == 0 && cur_state&mouse_mmb != 0:
|
|
last_button = MouseMiddle
|
|
last_button_pressed = last_button
|
|
case last_state&mouse_lmb != 0 && cur_state&mouse_lmb == 0:
|
|
last_button = MouseRelease
|
|
case last_state&mouse_rmb != 0 && cur_state&mouse_rmb == 0:
|
|
last_button = MouseRelease
|
|
case last_state&mouse_mmb != 0 && cur_state&mouse_mmb == 0:
|
|
last_button = MouseRelease
|
|
default:
|
|
last_state = cur_state
|
|
continue
|
|
}
|
|
last_state = cur_state
|
|
ev.Key = last_button
|
|
last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y)
|
|
ev.MouseX = last_x
|
|
ev.MouseY = last_y
|
|
case 1:
|
|
// mouse motion
|
|
x, y := int(mr.mouse_pos.x), int(mr.mouse_pos.y)
|
|
if last_state != 0 && (last_x != x || last_y != y) {
|
|
ev.Key = last_button_pressed
|
|
ev.Mod = ModMotion
|
|
ev.MouseX = x
|
|
ev.MouseY = y
|
|
last_x, last_y = x, y
|
|
} else {
|
|
ev.Type = EventNone
|
|
}
|
|
case 4:
|
|
// mouse wheel
|
|
n := int16(mr.button_state >> 16)
|
|
if n > 0 {
|
|
ev.Key = MouseWheelUp
|
|
} else {
|
|
ev.Key = MouseWheelDown
|
|
}
|
|
last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y)
|
|
ev.MouseX = last_x
|
|
ev.MouseY = last_y
|
|
default:
|
|
ev.Type = EventNone
|
|
}
|
|
if ev.Type != EventNone {
|
|
input_comm <- ev
|
|
}
|
|
}
|
|
}
|
|
}
|