// Low level input function. int os_inchar(uint8_t *buf, int maxlen, int32_t ms, int tb_change_cnt) { InbufPollResult result; if (event_has_deferred()) { // Return pending event bytes return push_event_key(buf, maxlen); } if (ms >= 0) { if ((result = inbuf_poll(ms)) == kInputNone) { return 0; } } else { if ((result = inbuf_poll(p_ut)) == kInputNone) { if (trigger_cursorhold() && maxlen >= 3 && !typebuf_changed(tb_change_cnt)) { buf[0] = K_SPECIAL; buf[1] = KS_EXTRA; buf[2] = KE_CURSORHOLD; return 3; } before_blocking(); result = inbuf_poll(-1); } } // If there are deferred events, return the keys directly if (event_has_deferred()) { return push_event_key(buf, maxlen); } // If input was put directly in typeahead buffer bail out here. if (typebuf_changed(tb_change_cnt)) { return 0; } if (result == kInputEof) { read_error_exit(); return 0; } return read_from_input_buf(buf, (int64_t)maxlen); }
// Low level input function int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) { if (rbuffer_pending(input_buffer)) { return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); } InbufPollResult result; if (ms >= 0) { if ((result = inbuf_poll(ms)) == kInputNone) { return 0; } } else { if ((result = inbuf_poll((int)p_ut)) == kInputNone) { if (trigger_cursorhold() && maxlen >= 3 && !typebuf_changed(tb_change_cnt)) { buf[0] = K_SPECIAL; buf[1] = KS_EXTRA; buf[2] = KE_CURSORHOLD; return 3; } before_blocking(); result = inbuf_poll(-1); } } // If input was put directly in typeahead buffer bail out here. if (typebuf_changed(tb_change_cnt)) { return 0; } if (rbuffer_pending(input_buffer)) { // Safe to convert rbuffer_read to int, it will never overflow since we use // relatively small buffers. return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); } // If there are deferred events, return the keys directly if (event_has_deferred()) { return push_event_key(buf, maxlen); } if (result == kInputEof) { read_error_exit(); } return 0; }
// Wait for some event bool event_poll(int32_t ms) { uv_run_mode run_mode = UV_RUN_ONCE; if (input_ready()) { // If there's a pending input event to be consumed, do it now return true; } static int recursive = 0; if (!(recursive++)) { // Only needs to start the libuv handle the first time we enter here input_start(); } uv_timer_t timer; uv_prepare_t timer_prepare; TimerData timer_data = {.ms = ms, .timed_out = false, .timer = &timer}; if (ms > 0) { uv_timer_init(uv_default_loop(), &timer); // This prepare handle that actually starts the timer uv_prepare_init(uv_default_loop(), &timer_prepare); // Timeout passed as argument to the timer timer.data = &timer_data; // We only start the timer after the loop is running, for that we // use a prepare handle(pass the interval as data to it) timer_prepare.data = &timer_data; uv_prepare_start(&timer_prepare, timer_prepare_cb); } else if (ms == 0) { // For ms == 0, we need to do a non-blocking event poll by // setting the run mode to UV_RUN_NOWAIT. run_mode = UV_RUN_NOWAIT; } do { // Run one event loop iteration, blocking for events if run_mode is // UV_RUN_ONCE uv_run(uv_default_loop(), run_mode); // Process immediate events outside uv_run since libuv event loop not // support recursion(processing events may cause a recursive event_poll // call) event_process(false); } while ( // Continue running if ... !input_ready() && // we have no input !event_has_deferred() && // no events are waiting to be processed run_mode != UV_RUN_NOWAIT && // ms != 0 !timer_data.timed_out); // we didn't get a timeout if (!(--recursive)) { // Again, only stop when we leave the top-level invocation input_stop(); } if (ms > 0) { // Ensure the timer-related handles are closed and run the event loop // once more to let libuv perform it's cleanup uv_close((uv_handle_t *)&timer, NULL); uv_close((uv_handle_t *)&timer_prepare, NULL); uv_run(uv_default_loop(), UV_RUN_NOWAIT); event_process(false); } return input_ready() || event_has_deferred(); } bool event_has_deferred() { return !kl_empty(get_queue(true)); } // Push an event to the queue void event_push(Event event, bool deferred) { *kl_pushp(Event, get_queue(deferred)) = event; }
// Check if there's pending input static bool input_ready(void) { return typebuf_was_filled || // API call filled typeahead rbuffer_pending(input_buffer) > 0 || // Input buffer filled event_has_deferred(); // Events must be processed }