input.c (16980B)
1 #include <assert.h> 2 #include <limits.h> 3 #include <stdbool.h> 4 #include <stdint.h> 5 #include <stdio.h> 6 #include <string.h> 7 #include <uv.h> 8 9 #include "nvim/api/private/defs.h" 10 #include "nvim/ascii_defs.h" 11 #include "nvim/autocmd.h" 12 #include "nvim/autocmd_defs.h" 13 #include "nvim/buffer_defs.h" 14 #include "nvim/event/loop.h" 15 #include "nvim/event/multiqueue.h" 16 #include "nvim/event/rstream.h" 17 #include "nvim/getchar.h" 18 #include "nvim/gettext_defs.h" 19 #include "nvim/globals.h" 20 #include "nvim/keycodes.h" 21 #include "nvim/log.h" 22 #include "nvim/macros_defs.h" 23 #include "nvim/main.h" 24 #include "nvim/msgpack_rpc/channel.h" 25 #include "nvim/option_vars.h" 26 #include "nvim/os/input.h" 27 #include "nvim/os/os_defs.h" 28 #include "nvim/os/time.h" 29 #include "nvim/profile.h" 30 #include "nvim/state.h" 31 #include "nvim/state_defs.h" 32 #include "nvim/types_defs.h" 33 34 #define READ_BUFFER_SIZE 0xfff 35 #define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN) 36 37 static RStream read_stream = { .s.closed = true }; // Input before UI starts. 38 static char input_buffer[INPUT_BUFFER_SIZE]; 39 static char *input_read_pos = input_buffer; 40 static char *input_write_pos = input_buffer; 41 42 static bool input_eof = false; 43 static bool blocking = false; 44 static int cursorhold_time = 0; ///< time waiting for CursorHold event 45 static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting started 46 47 #include "os/input.c.generated.h" 48 49 void input_start(void) 50 { 51 if (!read_stream.s.closed) { 52 return; 53 } 54 55 used_stdin = true; 56 rstream_init_fd(&main_loop, &read_stream, STDIN_FILENO); 57 rstream_start(&read_stream, input_read_cb, NULL); 58 } 59 60 void input_stop(void) 61 { 62 if (read_stream.s.closed) { 63 return; 64 } 65 66 rstream_stop(&read_stream); 67 rstream_may_close(&read_stream); 68 } 69 70 static void cursorhold_event(void **argv) 71 { 72 event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD; 73 apply_autocmds(event, NULL, NULL, false, curbuf); 74 did_cursorhold = true; 75 } 76 77 static void create_cursorhold_event(bool events_enabled) 78 { 79 // If events are enabled and the queue has any items, this function should not 80 // have been called (`inbuf_poll` would return `kTrue`). 81 // TODO(tarruda): Cursorhold should be implemented as a timer set during the 82 // `state_check` callback for the states where it can be triggered. 83 assert(!events_enabled || multiqueue_empty(main_loop.events)); 84 multiqueue_put(main_loop.events, cursorhold_event, NULL); 85 } 86 87 static void reset_cursorhold_wait(int tb_change_cnt) 88 { 89 cursorhold_time = 0; 90 cursorhold_tb_change_cnt = tb_change_cnt; 91 } 92 93 /// Reads OS input into `buf`, and consumes pending events while waiting (if `ms != 0`). 94 /// 95 /// - Consumes available input received from the OS. 96 /// - Consumes pending events. 97 /// - Manages CursorHold events. 98 /// - Handles EOF conditions. 99 /// 100 /// Originally based on the Vim `mch_inchar` function. 101 /// 102 /// @param buf Buffer to store consumed input. 103 /// @param maxlen Maximum bytes to read into `buf`, or 0 to skip reading. 104 /// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait. 105 /// @param tb_change_cnt Used to detect when typeahead changes. 106 /// @param events (optional) Events to process. 107 /// @return Bytes read into buf, or 0 if no input was read 108 int input_get(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events) 109 { 110 // This check is needed so that feeding typeahead from RPC can prevent CursorHold. 111 if (tb_change_cnt != cursorhold_tb_change_cnt) { 112 reset_cursorhold_wait(tb_change_cnt); 113 } 114 115 #define TRY_READ() \ 116 do { \ 117 if (maxlen && input_available()) { \ 118 reset_cursorhold_wait(tb_change_cnt); \ 119 assert(maxlen >= 0); \ 120 size_t to_read = MIN((size_t)maxlen, input_available()); \ 121 memcpy(buf, input_read_pos, to_read); \ 122 input_read_pos += to_read; \ 123 /* This is safe because INPUT_BUFFER_SIZE fits in an int. */ \ 124 assert(to_read <= INT_MAX); \ 125 return (int)to_read; \ 126 } \ 127 } while (0) 128 129 TRY_READ(); 130 131 // No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped. 132 if ((mapped_ctrl_c | curbuf->b_mapped_ctrl_c) & get_real_state()) { 133 ctrl_c_interrupts = false; 134 } 135 136 TriState result; ///< inbuf_poll result. 137 if (ms >= 0) { 138 if ((result = inbuf_poll(ms, events)) == kFalse) { 139 return 0; 140 } 141 } else { 142 uint64_t wait_start = os_hrtime(); 143 cursorhold_time = MIN(cursorhold_time, (int)p_ut); 144 if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kFalse) { 145 if (read_stream.s.closed && silent_mode) { 146 // Drained eventloop & initial input; exit silent/batch-mode (-es/-Es). 147 read_error_exit(); 148 } 149 reset_cursorhold_wait(tb_change_cnt); 150 if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) { 151 create_cursorhold_event(events == main_loop.events); 152 } else { 153 before_blocking(); 154 result = inbuf_poll(-1, events); 155 } 156 } else { 157 cursorhold_time += (int)((os_hrtime() - wait_start) / 1000000); 158 } 159 } 160 161 ctrl_c_interrupts = true; 162 163 // If input was put directly in typeahead buffer bail out here. 164 if (typebuf_changed(tb_change_cnt)) { 165 return 0; 166 } 167 168 TRY_READ(); 169 170 // If there are events, return the keys directly 171 if (maxlen && pending_events(events)) { 172 return push_event_key(buf, maxlen); 173 } 174 175 if (result == kNone && ms != 0) { 176 read_error_exit(); 177 } 178 179 return 0; 180 181 #undef TRY_READ 182 } 183 184 // Check if a character is available for reading 185 bool os_char_avail(void) 186 { 187 return inbuf_poll(0, NULL) == kTrue; 188 } 189 190 /// Poll for fast events. `got_int` will be set to `true` if CTRL-C was typed. 191 /// 192 /// This invokes a full libuv loop iteration which can be quite costly. 193 /// Prefer `line_breakcheck()` if called in a busy inner loop. 194 /// 195 /// Caller must at least check `got_int` before calling this function again. 196 /// checking for other low-level input state like `input_available()` might 197 /// also be relevant (i e to throttle idle processing when user input is 198 /// available) 199 void os_breakcheck(void) 200 { 201 if (got_int) { 202 return; 203 } 204 205 loop_poll_events(&main_loop, 0); 206 } 207 208 #define BREAKCHECK_SKIP 1000 209 static int breakcheck_count = 0; 210 211 /// Check for CTRL-C pressed, but only once in a while. 212 /// 213 /// Should be used instead of os_breakcheck() for functions that check for 214 /// each line in the file. Calling os_breakcheck() each time takes too much 215 /// time, because it will use system calls to check for input. 216 void line_breakcheck(void) 217 { 218 if (++breakcheck_count >= BREAKCHECK_SKIP) { 219 breakcheck_count = 0; 220 os_breakcheck(); 221 } 222 } 223 224 /// Like line_breakcheck() but check 10 times less often. 225 void fast_breakcheck(void) 226 { 227 if (++breakcheck_count >= BREAKCHECK_SKIP * 10) { 228 breakcheck_count = 0; 229 os_breakcheck(); 230 } 231 } 232 233 /// Like line_breakcheck() but check 100 times less often. 234 void veryfast_breakcheck(void) 235 { 236 if (++breakcheck_count >= BREAKCHECK_SKIP * 100) { 237 breakcheck_count = 0; 238 os_breakcheck(); 239 } 240 } 241 242 /// Test whether a file descriptor refers to a terminal. 243 /// 244 /// @param fd File descriptor. 245 /// @return `true` if file descriptor refers to a terminal. 246 bool os_isatty(int fd) 247 { 248 return uv_guess_handle(fd) == UV_TTY; 249 } 250 251 size_t input_available(void) 252 { 253 return (size_t)(input_write_pos - input_read_pos); 254 } 255 256 static size_t input_space(void) 257 { 258 return (size_t)(input_buffer + INPUT_BUFFER_SIZE - input_write_pos); 259 } 260 261 void input_enqueue_raw(const char *data, size_t size) 262 { 263 if (input_read_pos > input_buffer) { 264 size_t available = input_available(); 265 memmove(input_buffer, input_read_pos, available); 266 input_read_pos = input_buffer; 267 input_write_pos = input_buffer + available; 268 } 269 270 size_t to_write = MIN(size, input_space()); 271 memcpy(input_write_pos, data, to_write); 272 input_write_pos += to_write; 273 } 274 275 size_t input_enqueue(uint64_t chan_id, String keys) 276 { 277 current_ui = chan_id; 278 279 const char *ptr = keys.data; 280 const char *end = ptr + keys.size; 281 282 while (input_space() >= 19 && ptr < end) { 283 // A "<x>" form occupies at least 1 characters, and produces up 284 // to 19 characters (1 + 5 * 3 for the char and 3 for a modifier). 285 // In the case of K_SPECIAL (0x80), 3 bytes are escaped and needed, 286 // but since the keys are UTF-8, so the first byte cannot be 287 // K_SPECIAL (0x80). 288 uint8_t buf[19] = { 0 }; 289 // Do not simplify the keys here. Simplification will be done later. 290 unsigned new_size 291 = trans_special(&ptr, (size_t)(end - ptr), (char *)buf, FSK_KEYCODE, true, NULL); 292 293 if (new_size > 0) { 294 if ((new_size = handle_mouse_event(&ptr, buf, new_size)) > 0) { 295 input_enqueue_raw((char *)buf, new_size); 296 } 297 continue; 298 } 299 300 if (*ptr == '<') { 301 const char *old_ptr = ptr; 302 // Invalid or incomplete key sequence, skip until the next '>' or *end. 303 do { 304 ptr++; 305 } while (ptr < end && *ptr != '>'); 306 if (*ptr != '>') { 307 // Incomplete key sequence, return without consuming. 308 ptr = old_ptr; 309 break; 310 } 311 ptr++; 312 continue; 313 } 314 315 // copy the character, escaping K_SPECIAL 316 if ((uint8_t)(*ptr) == K_SPECIAL) { 317 input_enqueue_raw((char *)&(uint8_t){ K_SPECIAL }, 1); 318 input_enqueue_raw((char *)&(uint8_t){ KS_SPECIAL }, 1); 319 input_enqueue_raw((char *)&(uint8_t){ KE_FILLER }, 1); 320 } else { 321 input_enqueue_raw(ptr, 1); 322 } 323 ptr++; 324 } 325 326 size_t rv = (size_t)(ptr - keys.data); 327 process_ctrl_c(); 328 return rv; 329 } 330 331 static uint8_t check_multiclick(int code, int grid, int row, int col, bool *skip_event) 332 { 333 static int orig_num_clicks = 0; 334 static int orig_mouse_code = 0; 335 static int orig_mouse_grid = 0; 336 static int orig_mouse_col = 0; 337 static int orig_mouse_row = 0; 338 static uint64_t orig_mouse_time = 0; // time of previous mouse click 339 340 if (code >= KE_MOUSEDOWN && code <= KE_MOUSERIGHT) { 341 return 0; 342 } 343 344 bool no_move = orig_mouse_grid == grid && orig_mouse_col == col && orig_mouse_row == row; 345 346 if (code == KE_MOUSEMOVE) { 347 if (no_move) { 348 *skip_event = true; 349 return 0; 350 } 351 } else if (code == KE_LEFTMOUSE || code == KE_RIGHTMOUSE || code == KE_MIDDLEMOUSE 352 || code == KE_X1MOUSE || code == KE_X2MOUSE) { 353 // For click events the number of clicks is updated. 354 uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns) 355 // Compute the time elapsed since the previous mouse click. 356 uint64_t timediff = mouse_time - orig_mouse_time; 357 // Convert 'mousetime' from ms to ns. 358 uint64_t mouset = (uint64_t)p_mouset * 1000000; 359 if (code == orig_mouse_code 360 && no_move 361 && timediff < mouset 362 && orig_num_clicks != 4) { 363 orig_num_clicks++; 364 } else { 365 orig_num_clicks = 1; 366 } 367 orig_mouse_code = code; 368 orig_mouse_time = mouse_time; 369 } 370 // For drag and release events the number of clicks is kept. 371 372 orig_mouse_grid = grid; 373 orig_mouse_col = col; 374 orig_mouse_row = row; 375 376 uint8_t modifiers = 0; 377 if (code != KE_MOUSEMOVE) { 378 if (orig_num_clicks == 2) { 379 modifiers |= MOD_MASK_2CLICK; 380 } else if (orig_num_clicks == 3) { 381 modifiers |= MOD_MASK_3CLICK; 382 } else if (orig_num_clicks == 4) { 383 modifiers |= MOD_MASK_4CLICK; 384 } 385 } 386 return modifiers; 387 } 388 389 /// Mouse event handling code (extract row/col if available and detect multiple clicks) 390 static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufsize) 391 { 392 int mouse_code = 0; 393 int type = 0; 394 395 if (bufsize == 3) { 396 mouse_code = buf[2]; 397 type = buf[1]; 398 } else if (bufsize == 6) { 399 // prefixed with K_SPECIAL KS_MODIFIER mod 400 mouse_code = buf[5]; 401 type = buf[4]; 402 } 403 404 if (type != KS_EXTRA 405 || !((mouse_code >= KE_LEFTMOUSE && mouse_code <= KE_RIGHTRELEASE) 406 || (mouse_code >= KE_X1MOUSE && mouse_code <= KE_X2RELEASE) 407 || (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT) 408 || mouse_code == KE_MOUSEMOVE)) { 409 return bufsize; 410 } 411 412 // A <[COL],[ROW]> sequence can follow and will set the mouse_row/mouse_col 413 // global variables. This is ugly but its how the rest of the code expects to 414 // find mouse coordinates, and it would be too expensive to refactor this 415 // now. 416 int col, row, advance; 417 if (sscanf(*ptr, "<%d,%d>%n", &col, &row, &advance) != EOF && advance) { 418 if (col >= 0 && row >= 0) { 419 // Make sure the mouse position is valid. Some terminals may 420 // return weird values. 421 if (col >= Columns) { 422 col = Columns - 1; 423 } 424 if (row >= Rows) { 425 row = Rows - 1; 426 } 427 mouse_grid = 0; 428 mouse_row = row; 429 mouse_col = col; 430 } 431 *ptr += advance; 432 } 433 434 bool skip_event = false; 435 uint8_t modifiers = check_multiclick(mouse_code, mouse_grid, 436 mouse_row, mouse_col, &skip_event); 437 if (skip_event) { 438 return 0; 439 } 440 441 if (modifiers) { 442 if (buf[1] != KS_MODIFIER) { 443 // no modifiers in the buffer yet, shift the bytes 3 positions 444 memcpy(buf + 3, buf, 3); 445 // add the modifier sequence 446 buf[0] = K_SPECIAL; 447 buf[1] = KS_MODIFIER; 448 buf[2] = modifiers; 449 bufsize += 3; 450 } else { 451 buf[2] |= modifiers; 452 } 453 } 454 455 return bufsize; 456 } 457 458 void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col) 459 { 460 bool skip_event = false; 461 modifier |= check_multiclick(code, grid, row, col, &skip_event); 462 if (skip_event) { 463 return; 464 } 465 uint8_t buf[7]; 466 uint8_t *p = buf; 467 if (modifier) { 468 p[0] = K_SPECIAL; 469 p[1] = KS_MODIFIER; 470 p[2] = modifier; 471 p += 3; 472 } 473 p[0] = K_SPECIAL; 474 p[1] = KS_EXTRA; 475 p[2] = (uint8_t)code; 476 477 mouse_grid = grid; 478 mouse_row = row; 479 mouse_col = col; 480 481 size_t written = 3 + (size_t)(p - buf); 482 input_enqueue_raw((char *)buf, written); 483 } 484 485 /// @return true if the main loop is blocked and waiting for input. 486 bool input_blocking(void) 487 { 488 return blocking; 489 } 490 491 /// Checks for (but does not read) available input, and consumes `main_loop.events` while waiting. 492 /// 493 /// @param ms Timeout in milliseconds. -1 for indefinite wait, 0 for no wait. 494 /// @param events (optional) Queue to check for pending events. 495 /// @return TriState: 496 /// - kTrue: Input/events available 497 /// - kFalse: No input/events 498 /// - kNone: EOF reached on the input stream 499 static TriState inbuf_poll(int ms, MultiQueue *events) 500 { 501 if (os_input_ready(events)) { 502 return kTrue; 503 } 504 505 if (do_profiling == PROF_YES && ms) { 506 prof_input_start(); 507 } 508 509 if ((ms == -1 || ms > 0) && events != main_loop.events && !input_eof) { 510 // The pending input provoked a blocking wait. Do special events now. #6247 511 blocking = true; 512 multiqueue_process_events(ch_before_blocking_events); 513 } 514 DLOG("blocking... events=%s", !!events ? "true" : "false"); 515 LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, ms, os_input_ready(events) || input_eof); 516 blocking = false; 517 518 if (do_profiling == PROF_YES && ms) { 519 prof_input_end(); 520 } 521 522 if (os_input_ready(events)) { 523 return kTrue; 524 } 525 return input_eof ? kNone : kFalse; 526 } 527 528 static size_t input_read_cb(RStream *stream, const char *buf, size_t c, void *data, bool at_eof) 529 { 530 if (at_eof) { 531 input_eof = true; 532 } 533 534 assert(input_space() >= c); 535 input_enqueue_raw(buf, c); 536 return c; 537 } 538 539 static void process_ctrl_c(void) 540 { 541 if (!ctrl_c_interrupts) { 542 return; 543 } 544 545 size_t available = input_available(); 546 ssize_t i; 547 for (i = (ssize_t)available - 1; i >= 0; i--) { // Reverse-search input for Ctrl_C. 548 uint8_t c = (uint8_t)input_read_pos[i]; 549 if (c == Ctrl_C 550 || (c == 'C' && i >= 3 551 && (uint8_t)input_read_pos[i - 3] == K_SPECIAL 552 && (uint8_t)input_read_pos[i - 2] == KS_MODIFIER 553 && (uint8_t)input_read_pos[i - 1] == MOD_MASK_CTRL)) { 554 input_read_pos[i] = Ctrl_C; 555 got_int = true; 556 break; 557 } 558 } 559 560 if (got_int && i > 0) { 561 // Remove all unprocessed input (typeahead) before the CTRL-C. 562 input_read_pos += i; 563 } 564 } 565 566 /// Pushes bytes from the "event" key sequence (KE_EVENT) partially between calls to input_get when 567 /// `maxlen < 3`. 568 static int push_event_key(uint8_t *buf, int maxlen) 569 { 570 static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT }; 571 static int key_idx = 0; 572 int buf_idx = 0; 573 574 do { 575 buf[buf_idx++] = key[key_idx++]; 576 key_idx %= 3; 577 } while (key_idx > 0 && buf_idx < maxlen); 578 579 return buf_idx; 580 } 581 582 /// Check if there's pending input already in typebuf or `events` 583 bool os_input_ready(MultiQueue *events) 584 { 585 return (typebuf_was_filled // API call filled typeahead 586 || input_available() // Input buffer filled 587 || pending_events(events)); // Events must be processed 588 } 589 590 // Exit because of an input read error. 591 static void read_error_exit(void) 592 FUNC_ATTR_NORETURN 593 { 594 if (silent_mode) { // Normal way to exit for "nvim -es". 595 getout(0); 596 } 597 preserve_exit(_("Nvim: Error reading input, exiting...\n")); 598 } 599 600 static bool pending_events(MultiQueue *events) 601 { 602 return events && !multiqueue_empty(events); 603 }