| 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), nil |
| } |
| |
| 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), nil |
| } |
| |
| 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] |
| |
| 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 cell_to_char_info(c Cell) (attr word, wc [2]wchar) { |
| attr = color_table_fg[c.Fg&0x0F] | color_table_bg[c.Bg&0x0F] |
| 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_state = dword(0) |
| 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)) |
| |
| // single or double click |
| switch mr.event_flags { |
| case 0: |
| cur_state := mr.button_state |
| switch { |
| case last_state&mouse_lmb == 0 && cur_state&mouse_lmb != 0: |
| last_button = MouseLeft |
| case last_state&mouse_rmb == 0 && cur_state&mouse_rmb != 0: |
| last_button = MouseRight |
| case last_state&mouse_mmb == 0 && cur_state&mouse_mmb != 0: |
| last_button = MouseMiddle |
| default: |
| last_state = cur_state |
| continue |
| } |
| last_state = cur_state |
| fallthrough |
| case 2: |
| input_comm <- Event{ |
| Type: EventMouse, |
| Key: last_button, |
| MouseX: int(mr.mouse_pos.x), |
| MouseY: int(mr.mouse_pos.y), |
| } |
| } |
| } |
| } |
| } |