diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 20:22:09 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 20:22:09 +0100 |
| commit | 5a8dbc6347b3541e84fe669b22c17ad3b715e258 (patch) | |
| tree | b148c450939688caaaeb4adac6f2faa1eaffe649 /vendor/github.com/nsf/termbox-go/termbox_windows.go | |
| download | qwe-editor-5a8dbc6347b3541e84fe669b22c17ad3b715e258.tar.gz | |
Engage!
Diffstat (limited to 'vendor/github.com/nsf/termbox-go/termbox_windows.go')
| -rw-r--r-- | vendor/github.com/nsf/termbox-go/termbox_windows.go | 952 |
1 files changed, 952 insertions, 0 deletions
diff --git a/vendor/github.com/nsf/termbox-go/termbox_windows.go b/vendor/github.com/nsf/termbox-go/termbox_windows.go new file mode 100644 index 0000000..d46eb04 --- /dev/null +++ b/vendor/github.com/nsf/termbox-go/termbox_windows.go | |||
| @@ -0,0 +1,952 @@ | |||
| 1 | package termbox | ||
| 2 | |||
| 3 | import "math" | ||
| 4 | import "syscall" | ||
| 5 | import "unsafe" | ||
| 6 | import "unicode/utf16" | ||
| 7 | import "github.com/mattn/go-runewidth" | ||
| 8 | |||
| 9 | type ( | ||
| 10 | wchar uint16 | ||
| 11 | short int16 | ||
| 12 | dword uint32 | ||
| 13 | word uint16 | ||
| 14 | char_info struct { | ||
| 15 | char wchar | ||
| 16 | attr word | ||
| 17 | } | ||
| 18 | coord struct { | ||
| 19 | x short | ||
| 20 | y short | ||
| 21 | } | ||
| 22 | small_rect struct { | ||
| 23 | left short | ||
| 24 | top short | ||
| 25 | right short | ||
| 26 | bottom short | ||
| 27 | } | ||
| 28 | console_screen_buffer_info struct { | ||
| 29 | size coord | ||
| 30 | cursor_position coord | ||
| 31 | attributes word | ||
| 32 | window small_rect | ||
| 33 | maximum_window_size coord | ||
| 34 | } | ||
| 35 | console_cursor_info struct { | ||
| 36 | size dword | ||
| 37 | visible int32 | ||
| 38 | } | ||
| 39 | input_record struct { | ||
| 40 | event_type word | ||
| 41 | _ [2]byte | ||
| 42 | event [16]byte | ||
| 43 | } | ||
| 44 | key_event_record struct { | ||
| 45 | key_down int32 | ||
| 46 | repeat_count word | ||
| 47 | virtual_key_code word | ||
| 48 | virtual_scan_code word | ||
| 49 | unicode_char wchar | ||
| 50 | control_key_state dword | ||
| 51 | } | ||
| 52 | window_buffer_size_record struct { | ||
| 53 | size coord | ||
| 54 | } | ||
| 55 | mouse_event_record struct { | ||
| 56 | mouse_pos coord | ||
| 57 | button_state dword | ||
| 58 | control_key_state dword | ||
| 59 | event_flags dword | ||
| 60 | } | ||
| 61 | console_font_info struct { | ||
| 62 | font uint32 | ||
| 63 | font_size coord | ||
| 64 | } | ||
| 65 | ) | ||
| 66 | |||
| 67 | const ( | ||
| 68 | mouse_lmb = 0x1 | ||
| 69 | mouse_rmb = 0x2 | ||
| 70 | mouse_mmb = 0x4 | 0x8 | 0x10 | ||
| 71 | SM_CXMIN = 28 | ||
| 72 | SM_CYMIN = 29 | ||
| 73 | ) | ||
| 74 | |||
| 75 | func (this coord) uintptr() uintptr { | ||
| 76 | return uintptr(*(*int32)(unsafe.Pointer(&this))) | ||
| 77 | } | ||
| 78 | |||
| 79 | func (this *small_rect) uintptr() uintptr { | ||
| 80 | return uintptr(unsafe.Pointer(this)) | ||
| 81 | } | ||
| 82 | |||
| 83 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") | ||
| 84 | var moduser32 = syscall.NewLazyDLL("user32.dll") | ||
| 85 | var is_cjk = runewidth.IsEastAsian() | ||
| 86 | |||
| 87 | var ( | ||
| 88 | proc_set_console_active_screen_buffer = kernel32.NewProc("SetConsoleActiveScreenBuffer") | ||
| 89 | proc_set_console_screen_buffer_size = kernel32.NewProc("SetConsoleScreenBufferSize") | ||
| 90 | proc_set_console_window_info = kernel32.NewProc("SetConsoleWindowInfo") | ||
| 91 | proc_create_console_screen_buffer = kernel32.NewProc("CreateConsoleScreenBuffer") | ||
| 92 | proc_get_console_screen_buffer_info = kernel32.NewProc("GetConsoleScreenBufferInfo") | ||
| 93 | proc_write_console_output = kernel32.NewProc("WriteConsoleOutputW") | ||
| 94 | proc_write_console_output_character = kernel32.NewProc("WriteConsoleOutputCharacterW") | ||
| 95 | proc_write_console_output_attribute = kernel32.NewProc("WriteConsoleOutputAttribute") | ||
| 96 | proc_set_console_cursor_info = kernel32.NewProc("SetConsoleCursorInfo") | ||
| 97 | proc_set_console_cursor_position = kernel32.NewProc("SetConsoleCursorPosition") | ||
| 98 | proc_get_console_cursor_info = kernel32.NewProc("GetConsoleCursorInfo") | ||
| 99 | proc_read_console_input = kernel32.NewProc("ReadConsoleInputW") | ||
| 100 | proc_get_console_mode = kernel32.NewProc("GetConsoleMode") | ||
| 101 | proc_set_console_mode = kernel32.NewProc("SetConsoleMode") | ||
| 102 | proc_fill_console_output_character = kernel32.NewProc("FillConsoleOutputCharacterW") | ||
| 103 | proc_fill_console_output_attribute = kernel32.NewProc("FillConsoleOutputAttribute") | ||
| 104 | proc_create_event = kernel32.NewProc("CreateEventW") | ||
| 105 | proc_wait_for_multiple_objects = kernel32.NewProc("WaitForMultipleObjects") | ||
| 106 | proc_set_event = kernel32.NewProc("SetEvent") | ||
| 107 | proc_get_current_console_font = kernel32.NewProc("GetCurrentConsoleFont") | ||
| 108 | get_system_metrics = moduser32.NewProc("GetSystemMetrics") | ||
| 109 | ) | ||
| 110 | |||
| 111 | func set_console_active_screen_buffer(h syscall.Handle) (err error) { | ||
| 112 | r0, _, e1 := syscall.Syscall(proc_set_console_active_screen_buffer.Addr(), | ||
| 113 | 1, uintptr(h), 0, 0) | ||
| 114 | if int(r0) == 0 { | ||
| 115 | if e1 != 0 { | ||
| 116 | err = error(e1) | ||
| 117 | } else { | ||
| 118 | err = syscall.EINVAL | ||
| 119 | } | ||
| 120 | } | ||
| 121 | return | ||
| 122 | } | ||
| 123 | |||
| 124 | func set_console_screen_buffer_size(h syscall.Handle, size coord) (err error) { | ||
| 125 | r0, _, e1 := syscall.Syscall(proc_set_console_screen_buffer_size.Addr(), | ||
| 126 | 2, uintptr(h), size.uintptr(), 0) | ||
| 127 | if int(r0) == 0 { | ||
| 128 | if e1 != 0 { | ||
| 129 | err = error(e1) | ||
| 130 | } else { | ||
| 131 | err = syscall.EINVAL | ||
| 132 | } | ||
| 133 | } | ||
| 134 | return | ||
| 135 | } | ||
| 136 | |||
| 137 | func set_console_window_info(h syscall.Handle, window *small_rect) (err error) { | ||
| 138 | var absolute uint32 | ||
| 139 | absolute = 1 | ||
| 140 | r0, _, e1 := syscall.Syscall(proc_set_console_window_info.Addr(), | ||
| 141 | 3, uintptr(h), uintptr(absolute), window.uintptr()) | ||
| 142 | if int(r0) == 0 { | ||
| 143 | if e1 != 0 { | ||
| 144 | err = error(e1) | ||
| 145 | } else { | ||
| 146 | err = syscall.EINVAL | ||
| 147 | } | ||
| 148 | } | ||
| 149 | return | ||
| 150 | } | ||
| 151 | |||
| 152 | func create_console_screen_buffer() (h syscall.Handle, err error) { | ||
| 153 | r0, _, e1 := syscall.Syscall6(proc_create_console_screen_buffer.Addr(), | ||
| 154 | 5, uintptr(generic_read|generic_write), 0, 0, console_textmode_buffer, 0, 0) | ||
| 155 | if int(r0) == 0 { | ||
| 156 | if e1 != 0 { | ||
| 157 | err = error(e1) | ||
| 158 | } else { | ||
| 159 | err = syscall.EINVAL | ||
| 160 | } | ||
| 161 | } | ||
| 162 | return syscall.Handle(r0), err | ||
| 163 | } | ||
| 164 | |||
| 165 | func get_console_screen_buffer_info(h syscall.Handle, info *console_screen_buffer_info) (err error) { | ||
| 166 | r0, _, e1 := syscall.Syscall(proc_get_console_screen_buffer_info.Addr(), | ||
| 167 | 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0) | ||
| 168 | if int(r0) == 0 { | ||
| 169 | if e1 != 0 { | ||
| 170 | err = error(e1) | ||
| 171 | } else { | ||
| 172 | err = syscall.EINVAL | ||
| 173 | } | ||
| 174 | } | ||
| 175 | return | ||
| 176 | } | ||
| 177 | |||
| 178 | func write_console_output(h syscall.Handle, chars []char_info, dst small_rect) (err error) { | ||
| 179 | tmp_coord = coord{dst.right - dst.left + 1, dst.bottom - dst.top + 1} | ||
| 180 | tmp_rect = dst | ||
| 181 | r0, _, e1 := syscall.Syscall6(proc_write_console_output.Addr(), | ||
| 182 | 5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), tmp_coord.uintptr(), | ||
| 183 | tmp_coord0.uintptr(), uintptr(unsafe.Pointer(&tmp_rect)), 0) | ||
| 184 | if int(r0) == 0 { | ||
| 185 | if e1 != 0 { | ||
| 186 | err = error(e1) | ||
| 187 | } else { | ||
| 188 | err = syscall.EINVAL | ||
| 189 | } | ||
| 190 | } | ||
| 191 | return | ||
| 192 | } | ||
| 193 | |||
| 194 | func write_console_output_character(h syscall.Handle, chars []wchar, pos coord) (err error) { | ||
| 195 | r0, _, e1 := syscall.Syscall6(proc_write_console_output_character.Addr(), | ||
| 196 | 5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), uintptr(len(chars)), | ||
| 197 | pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0) | ||
| 198 | if int(r0) == 0 { | ||
| 199 | if e1 != 0 { | ||
| 200 | err = error(e1) | ||
| 201 | } else { | ||
| 202 | err = syscall.EINVAL | ||
| 203 | } | ||
| 204 | } | ||
| 205 | return | ||
| 206 | } | ||
| 207 | |||
| 208 | func write_console_output_attribute(h syscall.Handle, attrs []word, pos coord) (err error) { | ||
| 209 | r0, _, e1 := syscall.Syscall6(proc_write_console_output_attribute.Addr(), | ||
| 210 | 5, uintptr(h), uintptr(unsafe.Pointer(&attrs[0])), uintptr(len(attrs)), | ||
| 211 | pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0) | ||
| 212 | if int(r0) == 0 { | ||
| 213 | if e1 != 0 { | ||
| 214 | err = error(e1) | ||
| 215 | } else { | ||
| 216 | err = syscall.EINVAL | ||
| 217 | } | ||
| 218 | } | ||
| 219 | return | ||
| 220 | } | ||
| 221 | |||
| 222 | func set_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) { | ||
| 223 | r0, _, e1 := syscall.Syscall(proc_set_console_cursor_info.Addr(), | ||
| 224 | 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0) | ||
| 225 | if int(r0) == 0 { | ||
| 226 | if e1 != 0 { | ||
| 227 | err = error(e1) | ||
| 228 | } else { | ||
| 229 | err = syscall.EINVAL | ||
| 230 | } | ||
| 231 | } | ||
| 232 | return | ||
| 233 | } | ||
| 234 | |||
| 235 | func get_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) { | ||
| 236 | r0, _, e1 := syscall.Syscall(proc_get_console_cursor_info.Addr(), | ||
| 237 | 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0) | ||
| 238 | if int(r0) == 0 { | ||
| 239 | if e1 != 0 { | ||
| 240 | err = error(e1) | ||
| 241 | } else { | ||
| 242 | err = syscall.EINVAL | ||
| 243 | } | ||
| 244 | } | ||
| 245 | return | ||
| 246 | } | ||
| 247 | |||
| 248 | func set_console_cursor_position(h syscall.Handle, pos coord) (err error) { | ||
| 249 | r0, _, e1 := syscall.Syscall(proc_set_console_cursor_position.Addr(), | ||
| 250 | 2, uintptr(h), pos.uintptr(), 0) | ||
| 251 | if int(r0) == 0 { | ||
| 252 | if e1 != 0 { | ||
| 253 | err = error(e1) | ||
| 254 | } else { | ||
| 255 | err = syscall.EINVAL | ||
| 256 | } | ||
| 257 | } | ||
| 258 | return | ||
| 259 | } | ||
| 260 | |||
| 261 | func read_console_input(h syscall.Handle, record *input_record) (err error) { | ||
| 262 | r0, _, e1 := syscall.Syscall6(proc_read_console_input.Addr(), | ||
| 263 | 4, uintptr(h), uintptr(unsafe.Pointer(record)), 1, uintptr(unsafe.Pointer(&tmp_arg)), 0, 0) | ||
| 264 | if int(r0) == 0 { | ||
| 265 | if e1 != 0 { | ||
| 266 | err = error(e1) | ||
| 267 | } else { | ||
| 268 | err = syscall.EINVAL | ||
| 269 | } | ||
| 270 | } | ||
| 271 | return | ||
| 272 | } | ||
| 273 | |||
| 274 | func get_console_mode(h syscall.Handle, mode *dword) (err error) { | ||
| 275 | r0, _, e1 := syscall.Syscall(proc_get_console_mode.Addr(), | ||
| 276 | 2, uintptr(h), uintptr(unsafe.Pointer(mode)), 0) | ||
| 277 | if int(r0) == 0 { | ||
| 278 | if e1 != 0 { | ||
| 279 | err = error(e1) | ||
| 280 | } else { | ||
| 281 | err = syscall.EINVAL | ||
| 282 | } | ||
| 283 | } | ||
| 284 | return | ||
| 285 | } | ||
| 286 | |||
| 287 | func set_console_mode(h syscall.Handle, mode dword) (err error) { | ||
| 288 | r0, _, e1 := syscall.Syscall(proc_set_console_mode.Addr(), | ||
| 289 | 2, uintptr(h), uintptr(mode), 0) | ||
| 290 | if int(r0) == 0 { | ||
| 291 | if e1 != 0 { | ||
| 292 | err = error(e1) | ||
| 293 | } else { | ||
| 294 | err = syscall.EINVAL | ||
| 295 | } | ||
| 296 | } | ||
| 297 | return | ||
| 298 | } | ||
| 299 | |||
| 300 | func fill_console_output_character(h syscall.Handle, char wchar, n int) (err error) { | ||
| 301 | tmp_coord = coord{0, 0} | ||
| 302 | r0, _, e1 := syscall.Syscall6(proc_fill_console_output_character.Addr(), | ||
| 303 | 5, uintptr(h), uintptr(char), uintptr(n), tmp_coord.uintptr(), | ||
| 304 | uintptr(unsafe.Pointer(&tmp_arg)), 0) | ||
| 305 | if int(r0) == 0 { | ||
| 306 | if e1 != 0 { | ||
| 307 | err = error(e1) | ||
| 308 | } else { | ||
| 309 | err = syscall.EINVAL | ||
| 310 | } | ||
| 311 | } | ||
| 312 | return | ||
| 313 | } | ||
| 314 | |||
| 315 | func fill_console_output_attribute(h syscall.Handle, attr word, n int) (err error) { | ||
| 316 | tmp_coord = coord{0, 0} | ||
| 317 | r0, _, e1 := syscall.Syscall6(proc_fill_console_output_attribute.Addr(), | ||
| 318 | 5, uintptr(h), uintptr(attr), uintptr(n), tmp_coord.uintptr(), | ||
| 319 | uintptr(unsafe.Pointer(&tmp_arg)), 0) | ||
| 320 | if int(r0) == 0 { | ||
| 321 | if e1 != 0 { | ||
| 322 | err = error(e1) | ||
| 323 | } else { | ||
| 324 | err = syscall.EINVAL | ||
| 325 | } | ||
| 326 | } | ||
| 327 | return | ||
| 328 | } | ||
| 329 | |||
| 330 | func create_event() (out syscall.Handle, err error) { | ||
| 331 | r0, _, e1 := syscall.Syscall6(proc_create_event.Addr(), | ||
| 332 | 4, 0, 0, 0, 0, 0, 0) | ||
| 333 | if int(r0) == 0 { | ||
| 334 | if e1 != 0 { | ||
| 335 | err = error(e1) | ||
| 336 | } else { | ||
| 337 | err = syscall.EINVAL | ||
| 338 | } | ||
| 339 | } | ||
| 340 | return syscall.Handle(r0), err | ||
| 341 | } | ||
| 342 | |||
| 343 | func wait_for_multiple_objects(objects []syscall.Handle) (err error) { | ||
| 344 | r0, _, e1 := syscall.Syscall6(proc_wait_for_multiple_objects.Addr(), | ||
| 345 | 4, uintptr(len(objects)), uintptr(unsafe.Pointer(&objects[0])), | ||
| 346 | 0, 0xFFFFFFFF, 0, 0) | ||
| 347 | if uint32(r0) == 0xFFFFFFFF { | ||
| 348 | if e1 != 0 { | ||
| 349 | err = error(e1) | ||
| 350 | } else { | ||
| 351 | err = syscall.EINVAL | ||
| 352 | } | ||
| 353 | } | ||
| 354 | return | ||
| 355 | } | ||
| 356 | |||
| 357 | func set_event(ev syscall.Handle) (err error) { | ||
| 358 | r0, _, e1 := syscall.Syscall(proc_set_event.Addr(), | ||
| 359 | 1, uintptr(ev), 0, 0) | ||
| 360 | if int(r0) == 0 { | ||
| 361 | if e1 != 0 { | ||
| 362 | err = error(e1) | ||
| 363 | } else { | ||
| 364 | err = syscall.EINVAL | ||
| 365 | } | ||
| 366 | } | ||
| 367 | return | ||
| 368 | } | ||
| 369 | |||
| 370 | func get_current_console_font(h syscall.Handle, info *console_font_info) (err error) { | ||
| 371 | r0, _, e1 := syscall.Syscall(proc_get_current_console_font.Addr(), | ||
| 372 | 3, uintptr(h), 0, uintptr(unsafe.Pointer(info))) | ||
| 373 | if int(r0) == 0 { | ||
| 374 | if e1 != 0 { | ||
| 375 | err = error(e1) | ||
| 376 | } else { | ||
| 377 | err = syscall.EINVAL | ||
| 378 | } | ||
| 379 | } | ||
| 380 | return | ||
| 381 | } | ||
| 382 | |||
| 383 | type diff_msg struct { | ||
| 384 | pos short | ||
| 385 | lines short | ||
| 386 | chars []char_info | ||
| 387 | } | ||
| 388 | |||
| 389 | type input_event struct { | ||
| 390 | event Event | ||
| 391 | err error | ||
| 392 | } | ||
| 393 | |||
| 394 | var ( | ||
| 395 | orig_cursor_info console_cursor_info | ||
| 396 | orig_size coord | ||
| 397 | orig_window small_rect | ||
| 398 | orig_mode dword | ||
| 399 | orig_screen syscall.Handle | ||
| 400 | back_buffer cellbuf | ||
| 401 | front_buffer cellbuf | ||
| 402 | term_size coord | ||
| 403 | input_mode = InputEsc | ||
| 404 | cursor_x = cursor_hidden | ||
| 405 | cursor_y = cursor_hidden | ||
| 406 | foreground = ColorDefault | ||
| 407 | background = ColorDefault | ||
| 408 | in syscall.Handle | ||
| 409 | out syscall.Handle | ||
| 410 | interrupt syscall.Handle | ||
| 411 | charbuf []char_info | ||
| 412 | diffbuf []diff_msg | ||
| 413 | beg_x = -1 | ||
| 414 | beg_y = -1 | ||
| 415 | beg_i = -1 | ||
| 416 | input_comm = make(chan Event) | ||
| 417 | interrupt_comm = make(chan struct{}) | ||
| 418 | cancel_comm = make(chan bool, 1) | ||
| 419 | cancel_done_comm = make(chan bool) | ||
| 420 | alt_mode_esc = false | ||
| 421 | |||
| 422 | // these ones just to prevent heap allocs at all costs | ||
| 423 | tmp_info console_screen_buffer_info | ||
| 424 | tmp_arg dword | ||
| 425 | tmp_coord0 = coord{0, 0} | ||
| 426 | tmp_coord = coord{0, 0} | ||
| 427 | tmp_rect = small_rect{0, 0, 0, 0} | ||
| 428 | tmp_finfo console_font_info | ||
| 429 | ) | ||
| 430 | |||
| 431 | func get_cursor_position(out syscall.Handle) coord { | ||
| 432 | err := get_console_screen_buffer_info(out, &tmp_info) | ||
| 433 | if err != nil { | ||
| 434 | panic(err) | ||
| 435 | } | ||
| 436 | return tmp_info.cursor_position | ||
| 437 | } | ||
| 438 | |||
| 439 | func get_term_size(out syscall.Handle) (coord, small_rect) { | ||
| 440 | err := get_console_screen_buffer_info(out, &tmp_info) | ||
| 441 | if err != nil { | ||
| 442 | panic(err) | ||
| 443 | } | ||
| 444 | return tmp_info.size, tmp_info.window | ||
| 445 | } | ||
| 446 | |||
| 447 | func get_win_min_size(out syscall.Handle) coord { | ||
| 448 | x, _, err := get_system_metrics.Call(SM_CXMIN) | ||
| 449 | y, _, err := get_system_metrics.Call(SM_CYMIN) | ||
| 450 | |||
| 451 | if x == 0 || y == 0 { | ||
| 452 | if err != nil { | ||
| 453 | panic(err) | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | err1 := get_current_console_font(out, &tmp_finfo) | ||
| 458 | if err1 != nil { | ||
| 459 | panic(err1) | ||
| 460 | } | ||
| 461 | |||
| 462 | return coord{ | ||
| 463 | x: short(math.Ceil(float64(x) / float64(tmp_finfo.font_size.x))), | ||
| 464 | y: short(math.Ceil(float64(y) / float64(tmp_finfo.font_size.y))), | ||
| 465 | } | ||
| 466 | } | ||
| 467 | |||
| 468 | func get_win_size(out syscall.Handle) coord { | ||
| 469 | err := get_console_screen_buffer_info(out, &tmp_info) | ||
| 470 | if err != nil { | ||
| 471 | panic(err) | ||
| 472 | } | ||
| 473 | |||
| 474 | min_size := get_win_min_size(out) | ||
| 475 | |||
| 476 | size := coord{ | ||
| 477 | x: tmp_info.window.right - tmp_info.window.left + 1, | ||
| 478 | y: tmp_info.window.bottom - tmp_info.window.top + 1, | ||
| 479 | } | ||
| 480 | |||
| 481 | if size.x < min_size.x { | ||
| 482 | size.x = min_size.x | ||
| 483 | } | ||
| 484 | |||
| 485 | if size.y < min_size.y { | ||
| 486 | size.y = min_size.y | ||
| 487 | } | ||
| 488 | |||
| 489 | return size | ||
| 490 | } | ||
| 491 | |||
| 492 | func fix_win_size(out syscall.Handle, size coord) (err error) { | ||
| 493 | window := small_rect{} | ||
| 494 | window.top = 0 | ||
| 495 | window.bottom = size.y - 1 | ||
| 496 | window.left = 0 | ||
| 497 | window.right = size.x - 1 | ||
| 498 | return set_console_window_info(out, &window) | ||
| 499 | } | ||
| 500 | |||
| 501 | func update_size_maybe() { | ||
| 502 | size := get_win_size(out) | ||
| 503 | if size.x != term_size.x || size.y != term_size.y { | ||
| 504 | set_console_screen_buffer_size(out, size) | ||
| 505 | fix_win_size(out, size) | ||
| 506 | term_size = size | ||
| 507 | back_buffer.resize(int(size.x), int(size.y)) | ||
| 508 | front_buffer.resize(int(size.x), int(size.y)) | ||
| 509 | front_buffer.clear() | ||
| 510 | clear() | ||
| 511 | |||
| 512 | area := int(size.x) * int(size.y) | ||
| 513 | if cap(charbuf) < area { | ||
| 514 | charbuf = make([]char_info, 0, area) | ||
| 515 | } | ||
| 516 | } | ||
| 517 | } | ||
| 518 | |||
| 519 | var color_table_bg = []word{ | ||
| 520 | 0, // default (black) | ||
| 521 | 0, // black | ||
| 522 | background_red, | ||
| 523 | background_green, | ||
| 524 | background_red | background_green, // yellow | ||
| 525 | background_blue, | ||
| 526 | background_red | background_blue, // magenta | ||
| 527 | background_green | background_blue, // cyan | ||
| 528 | background_red | background_blue | background_green, // white | ||
| 529 | } | ||
| 530 | |||
| 531 | var color_table_fg = []word{ | ||
| 532 | foreground_red | foreground_blue | foreground_green, // default (white) | ||
| 533 | 0, | ||
| 534 | foreground_red, | ||
| 535 | foreground_green, | ||
| 536 | foreground_red | foreground_green, // yellow | ||
| 537 | foreground_blue, | ||
| 538 | foreground_red | foreground_blue, // magenta | ||
| 539 | foreground_green | foreground_blue, // cyan | ||
| 540 | foreground_red | foreground_blue | foreground_green, // white | ||
| 541 | } | ||
| 542 | |||
| 543 | const ( | ||
| 544 | replacement_char = '\uFFFD' | ||
| 545 | max_rune = '\U0010FFFF' | ||
| 546 | surr1 = 0xd800 | ||
| 547 | surr2 = 0xdc00 | ||
| 548 | surr3 = 0xe000 | ||
| 549 | surr_self = 0x10000 | ||
| 550 | ) | ||
| 551 | |||
| 552 | func append_diff_line(y int) int { | ||
| 553 | n := 0 | ||
| 554 | for x := 0; x < front_buffer.width; { | ||
| 555 | cell_offset := y*front_buffer.width + x | ||
| 556 | back := &back_buffer.cells[cell_offset] | ||
| 557 | front := &front_buffer.cells[cell_offset] | ||
| 558 | attr, char := cell_to_char_info(*back) | ||
| 559 | charbuf = append(charbuf, char_info{attr: attr, char: char[0]}) | ||
| 560 | *front = *back | ||
| 561 | n++ | ||
| 562 | w := runewidth.RuneWidth(back.Ch) | ||
| 563 | if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) { | ||
| 564 | w = 1 | ||
| 565 | } | ||
| 566 | x += w | ||
| 567 | // If not CJK, fill trailing space with whitespace | ||
| 568 | if !is_cjk && w == 2 { | ||
| 569 | charbuf = append(charbuf, char_info{attr: attr, char: ' '}) | ||
| 570 | } | ||
| 571 | } | ||
| 572 | return n | ||
| 573 | } | ||
| 574 | |||
| 575 | // compares 'back_buffer' with 'front_buffer' and prepares all changes in the form of | ||
| 576 | // 'diff_msg's in the 'diff_buf' | ||
| 577 | func prepare_diff_messages() { | ||
| 578 | // clear buffers | ||
| 579 | diffbuf = diffbuf[:0] | ||
| 580 | charbuf = charbuf[:0] | ||
| 581 | |||
| 582 | var diff diff_msg | ||
| 583 | gbeg := 0 | ||
| 584 | for y := 0; y < front_buffer.height; y++ { | ||
| 585 | same := true | ||
| 586 | line_offset := y * front_buffer.width | ||
| 587 | for x := 0; x < front_buffer.width; x++ { | ||
| 588 | cell_offset := line_offset + x | ||
| 589 | back := &back_buffer.cells[cell_offset] | ||
| 590 | front := &front_buffer.cells[cell_offset] | ||
| 591 | if *back != *front { | ||
| 592 | same = false | ||
| 593 | break | ||
| 594 | } | ||
| 595 | } | ||
| 596 | if same && diff.lines > 0 { | ||
| 597 | diffbuf = append(diffbuf, diff) | ||
| 598 | diff = diff_msg{} | ||
| 599 | } | ||
| 600 | if !same { | ||
| 601 | beg := len(charbuf) | ||
| 602 | end := beg + append_diff_line(y) | ||
| 603 | if diff.lines == 0 { | ||
| 604 | diff.pos = short(y) | ||
| 605 | gbeg = beg | ||
| 606 | } | ||
| 607 | diff.lines++ | ||
| 608 | diff.chars = charbuf[gbeg:end] | ||
| 609 | } | ||
| 610 | } | ||
| 611 | if diff.lines > 0 { | ||
| 612 | diffbuf = append(diffbuf, diff) | ||
| 613 | diff = diff_msg{} | ||
| 614 | } | ||
| 615 | } | ||
| 616 | |||
| 617 | func get_ct(table []word, idx int) word { | ||
| 618 | idx = idx & 0x0F | ||
| 619 | if idx >= len(table) { | ||
| 620 | idx = len(table) - 1 | ||
| 621 | } | ||
| 622 | return table[idx] | ||
| 623 | } | ||
| 624 | |||
| 625 | func cell_to_char_info(c Cell) (attr word, wc [2]wchar) { | ||
| 626 | attr = get_ct(color_table_fg, int(c.Fg)) | get_ct(color_table_bg, int(c.Bg)) | ||
| 627 | if c.Fg&AttrReverse|c.Bg&AttrReverse != 0 { | ||
| 628 | attr = (attr&0xF0)>>4 | (attr&0x0F)<<4 | ||
| 629 | } | ||
| 630 | if c.Fg&AttrBold != 0 { | ||
| 631 | attr |= foreground_intensity | ||
| 632 | } | ||
| 633 | if c.Bg&AttrBold != 0 { | ||
| 634 | attr |= background_intensity | ||
| 635 | } | ||
| 636 | |||
| 637 | r0, r1 := utf16.EncodeRune(c.Ch) | ||
| 638 | if r0 == 0xFFFD { | ||
| 639 | wc[0] = wchar(c.Ch) | ||
| 640 | wc[1] = ' ' | ||
| 641 | } else { | ||
| 642 | wc[0] = wchar(r0) | ||
| 643 | wc[1] = wchar(r1) | ||
| 644 | } | ||
| 645 | return | ||
| 646 | } | ||
| 647 | |||
| 648 | func move_cursor(x, y int) { | ||
| 649 | err := set_console_cursor_position(out, coord{short(x), short(y)}) | ||
| 650 | if err != nil { | ||
| 651 | panic(err) | ||
| 652 | } | ||
| 653 | } | ||
| 654 | |||
| 655 | func show_cursor(visible bool) { | ||
| 656 | var v int32 | ||
| 657 | if visible { | ||
| 658 | v = 1 | ||
| 659 | } | ||
| 660 | |||
| 661 | var info console_cursor_info | ||
| 662 | info.size = 100 | ||
| 663 | info.visible = v | ||
| 664 | err := set_console_cursor_info(out, &info) | ||
| 665 | if err != nil { | ||
| 666 | panic(err) | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 670 | func clear() { | ||
| 671 | var err error | ||
| 672 | attr, char := cell_to_char_info(Cell{ | ||
| 673 | ' ', | ||
| 674 | foreground, | ||
| 675 | background, | ||
| 676 | }) | ||
| 677 | |||
| 678 | area := int(term_size.x) * int(term_size.y) | ||
| 679 | err = fill_console_output_attribute(out, attr, area) | ||
| 680 | if err != nil { | ||
| 681 | panic(err) | ||
| 682 | } | ||
| 683 | err = fill_console_output_character(out, char[0], area) | ||
| 684 | if err != nil { | ||
| 685 | panic(err) | ||
| 686 | } | ||
| 687 | if !is_cursor_hidden(cursor_x, cursor_y) { | ||
| 688 | move_cursor(cursor_x, cursor_y) | ||
| 689 | } | ||
| 690 | } | ||
| 691 | |||
| 692 | func key_event_record_to_event(r *key_event_record) (Event, bool) { | ||
| 693 | if r.key_down == 0 { | ||
| 694 | return Event{}, false | ||
| 695 | } | ||
| 696 | |||
| 697 | e := Event{Type: EventKey} | ||
| 698 | if input_mode&InputAlt != 0 { | ||
| 699 | if alt_mode_esc { | ||
| 700 | e.Mod = ModAlt | ||
| 701 | alt_mode_esc = false | ||
| 702 | } | ||
| 703 | if r.control_key_state&(left_alt_pressed|right_alt_pressed) != 0 { | ||
| 704 | e.Mod = ModAlt | ||
| 705 | } | ||
| 706 | } | ||
| 707 | |||
| 708 | ctrlpressed := r.control_key_state&(left_ctrl_pressed|right_ctrl_pressed) != 0 | ||
| 709 | |||
| 710 | if r.virtual_key_code >= vk_f1 && r.virtual_key_code <= vk_f12 { | ||
| 711 | switch r.virtual_key_code { | ||
| 712 | case vk_f1: | ||
| 713 | e.Key = KeyF1 | ||
| 714 | case vk_f2: | ||
| 715 | e.Key = KeyF2 | ||
| 716 | case vk_f3: | ||
| 717 | e.Key = KeyF3 | ||
| 718 | case vk_f4: | ||
| 719 | e.Key = KeyF4 | ||
| 720 | case vk_f5: | ||
| 721 | e.Key = KeyF5 | ||
| 722 | case vk_f6: | ||
| 723 | e.Key = KeyF6 | ||
| 724 | case vk_f7: | ||
| 725 | e.Key = KeyF7 | ||
| 726 | case vk_f8: | ||
| 727 | e.Key = KeyF8 | ||
| 728 | case vk_f9: | ||
| 729 | e.Key = KeyF9 | ||
| 730 | case vk_f10: | ||
| 731 | e.Key = KeyF10 | ||
| 732 | case vk_f11: | ||
| 733 | e.Key = KeyF11 | ||
| 734 | case vk_f12: | ||
| 735 | e.Key = KeyF12 | ||
| 736 | default: | ||
| 737 | panic("unreachable") | ||
| 738 | } | ||
| 739 | |||
| 740 | return e, true | ||
| 741 | } | ||
| 742 | |||
| 743 | if r.virtual_key_code <= vk_delete { | ||
| 744 | switch r.virtual_key_code { | ||
| 745 | case vk_insert: | ||
| 746 | e.Key = KeyInsert | ||
| 747 | case vk_delete: | ||
| 748 | e.Key = KeyDelete | ||
| 749 | case vk_home: | ||
| 750 | e.Key = KeyHome | ||
| 751 | case vk_end: | ||
| 752 | e.Key = KeyEnd | ||
| 753 | case vk_pgup: | ||
| 754 | e.Key = KeyPgup | ||
| 755 | case vk_pgdn: | ||
| 756 | e.Key = KeyPgdn | ||
| 757 | case vk_arrow_up: | ||
| 758 | e.Key = KeyArrowUp | ||
| 759 | case vk_arrow_down: | ||
| 760 | e.Key = KeyArrowDown | ||
| 761 | case vk_arrow_left: | ||
| 762 | e.Key = KeyArrowLeft | ||
| 763 | case vk_arrow_right: | ||
| 764 | e.Key = KeyArrowRight | ||
| 765 | case vk_backspace: | ||
| 766 | if ctrlpressed { | ||
| 767 | e.Key = KeyBackspace2 | ||
| 768 | } else { | ||
| 769 | e.Key = KeyBackspace | ||
| 770 | } | ||
| 771 | case vk_tab: | ||
| 772 | e.Key = KeyTab | ||
| 773 | case vk_enter: | ||
| 774 | if ctrlpressed { | ||
| 775 | e.Key = KeyCtrlJ | ||
| 776 | } else { | ||
| 777 | e.Key = KeyEnter | ||
| 778 | } | ||
| 779 | case vk_esc: | ||
| 780 | switch { | ||
| 781 | case input_mode&InputEsc != 0: | ||
| 782 | e.Key = KeyEsc | ||
| 783 | case input_mode&InputAlt != 0: | ||
| 784 | alt_mode_esc = true | ||
| 785 | return Event{}, false | ||
| 786 | } | ||
| 787 | case vk_space: | ||
| 788 | if ctrlpressed { | ||
| 789 | // manual return here, because KeyCtrlSpace is zero | ||
| 790 | e.Key = KeyCtrlSpace | ||
| 791 | return e, true | ||
| 792 | } else { | ||
| 793 | e.Key = KeySpace | ||
| 794 | } | ||
| 795 | } | ||
| 796 | |||
| 797 | if e.Key != 0 { | ||
| 798 | return e, true | ||
| 799 | } | ||
| 800 | } | ||
| 801 | |||
| 802 | if ctrlpressed { | ||
| 803 | if Key(r.unicode_char) >= KeyCtrlA && Key(r.unicode_char) <= KeyCtrlRsqBracket { | ||
| 804 | e.Key = Key(r.unicode_char) | ||
| 805 | if input_mode&InputAlt != 0 && e.Key == KeyEsc { | ||
| 806 | alt_mode_esc = true | ||
| 807 | return Event{}, false | ||
| 808 | } | ||
| 809 | return e, true | ||
| 810 | } | ||
| 811 | switch r.virtual_key_code { | ||
| 812 | case 192, 50: | ||
| 813 | // manual return here, because KeyCtrl2 is zero | ||
| 814 | e.Key = KeyCtrl2 | ||
| 815 | return e, true | ||
| 816 | case 51: | ||
| 817 | if input_mode&InputAlt != 0 { | ||
| 818 | alt_mode_esc = true | ||
| 819 | return Event{}, false | ||
| 820 | } | ||
| 821 | e.Key = KeyCtrl3 | ||
| 822 | case 52: | ||
| 823 | e.Key = KeyCtrl4 | ||
| 824 | case 53: | ||
| 825 | e.Key = KeyCtrl5 | ||
| 826 | case 54: | ||
| 827 | e.Key = KeyCtrl6 | ||
| 828 | case 189, 191, 55: | ||
| 829 | e.Key = KeyCtrl7 | ||
| 830 | case 8, 56: | ||
| 831 | e.Key = KeyCtrl8 | ||
| 832 | } | ||
| 833 | |||
| 834 | if e.Key != 0 { | ||
| 835 | return e, true | ||
| 836 | } | ||
| 837 | } | ||
| 838 | |||
| 839 | if r.unicode_char != 0 { | ||
| 840 | e.Ch = rune(r.unicode_char) | ||
| 841 | return e, true | ||
| 842 | } | ||
| 843 | |||
| 844 | return Event{}, false | ||
| 845 | } | ||
| 846 | |||
| 847 | func input_event_producer() { | ||
| 848 | var r input_record | ||
| 849 | var err error | ||
| 850 | var last_button Key | ||
| 851 | var last_button_pressed Key | ||
| 852 | var last_state = dword(0) | ||
| 853 | var last_x, last_y = -1, -1 | ||
| 854 | handles := []syscall.Handle{in, interrupt} | ||
| 855 | for { | ||
| 856 | err = wait_for_multiple_objects(handles) | ||
| 857 | if err != nil { | ||
| 858 | input_comm <- Event{Type: EventError, Err: err} | ||
| 859 | } | ||
| 860 | |||
| 861 | select { | ||
| 862 | case <-cancel_comm: | ||
| 863 | cancel_done_comm <- true | ||
| 864 | return | ||
| 865 | default: | ||
| 866 | } | ||
| 867 | |||
| 868 | err = read_console_input(in, &r) | ||
| 869 | if err != nil { | ||
| 870 | input_comm <- Event{Type: EventError, Err: err} | ||
| 871 | } | ||
| 872 | |||
| 873 | switch r.event_type { | ||
| 874 | case key_event: | ||
| 875 | kr := (*key_event_record)(unsafe.Pointer(&r.event)) | ||
| 876 | ev, ok := key_event_record_to_event(kr) | ||
| 877 | if ok { | ||
| 878 | for i := 0; i < int(kr.repeat_count); i++ { | ||
| 879 | input_comm <- ev | ||
| 880 | } | ||
| 881 | } | ||
| 882 | case window_buffer_size_event: | ||
| 883 | sr := *(*window_buffer_size_record)(unsafe.Pointer(&r.event)) | ||
| 884 | input_comm <- Event{ | ||
| 885 | Type: EventResize, | ||
| 886 | Width: int(sr.size.x), | ||
| 887 | Height: int(sr.size.y), | ||
| 888 | } | ||
| 889 | case mouse_event: | ||
| 890 | mr := *(*mouse_event_record)(unsafe.Pointer(&r.event)) | ||
| 891 | ev := Event{Type: EventMouse} | ||
| 892 | switch mr.event_flags { | ||
| 893 | case 0, 2: | ||
| 894 | // single or double click | ||
| 895 | cur_state := mr.button_state | ||
| 896 | switch { | ||
| 897 | case last_state&mouse_lmb == 0 && cur_state&mouse_lmb != 0: | ||
| 898 | last_button = MouseLeft | ||
| 899 | last_button_pressed = last_button | ||
| 900 | case last_state&mouse_rmb == 0 && cur_state&mouse_rmb != 0: | ||
| 901 | last_button = MouseRight | ||
| 902 | last_button_pressed = last_button | ||
| 903 | case last_state&mouse_mmb == 0 && cur_state&mouse_mmb != 0: | ||
| 904 | last_button = MouseMiddle | ||
| 905 | last_button_pressed = last_button | ||
| 906 | case last_state&mouse_lmb != 0 && cur_state&mouse_lmb == 0: | ||
| 907 | last_button = MouseRelease | ||
| 908 | case last_state&mouse_rmb != 0 && cur_state&mouse_rmb == 0: | ||
| 909 | last_button = MouseRelease | ||
| 910 | case last_state&mouse_mmb != 0 && cur_state&mouse_mmb == 0: | ||
| 911 | last_button = MouseRelease | ||
| 912 | default: | ||
| 913 | last_state = cur_state | ||
| 914 | continue | ||
| 915 | } | ||
| 916 | last_state = cur_state | ||
| 917 | ev.Key = last_button | ||
| 918 | last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y) | ||
| 919 | ev.MouseX = last_x | ||
| 920 | ev.MouseY = last_y | ||
| 921 | case 1: | ||
| 922 | // mouse motion | ||
| 923 | x, y := int(mr.mouse_pos.x), int(mr.mouse_pos.y) | ||
| 924 | if last_state != 0 && (last_x != x || last_y != y) { | ||
| 925 | ev.Key = last_button_pressed | ||
| 926 | ev.Mod = ModMotion | ||
| 927 | ev.MouseX = x | ||
| 928 | ev.MouseY = y | ||
| 929 | last_x, last_y = x, y | ||
| 930 | } else { | ||
| 931 | ev.Type = EventNone | ||
| 932 | } | ||
| 933 | case 4: | ||
| 934 | // mouse wheel | ||
| 935 | n := int16(mr.button_state >> 16) | ||
| 936 | if n > 0 { | ||
| 937 | ev.Key = MouseWheelUp | ||
| 938 | } else { | ||
| 939 | ev.Key = MouseWheelDown | ||
| 940 | } | ||
| 941 | last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y) | ||
| 942 | ev.MouseX = last_x | ||
| 943 | ev.MouseY = last_y | ||
| 944 | default: | ||
| 945 | ev.Type = EventNone | ||
| 946 | } | ||
| 947 | if ev.Type != EventNone { | ||
| 948 | input_comm <- ev | ||
| 949 | } | ||
| 950 | } | ||
| 951 | } | ||
| 952 | } | ||
