2016-05-01 19:54:25 -07:00
|
|
|
// Implementation file for the low level input library.
|
2005-09-20 23:26:39 +10:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <unistd.h>
|
2019-10-13 15:50:48 -07:00
|
|
|
|
2019-05-05 12:09:25 +02:00
|
|
|
#include <cstring>
|
2006-08-11 05:02:46 +10:00
|
|
|
#ifdef HAVE_SYS_SELECT_H
|
|
|
|
|
#include <sys/select.h>
|
|
|
|
|
#endif
|
2016-04-20 23:00:54 -07:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
2016-05-06 21:22:28 -07:00
|
|
|
#include <sys/time.h>
|
2016-05-01 19:54:25 -07:00
|
|
|
#include <sys/types.h>
|
2017-02-10 18:47:02 -08:00
|
|
|
|
2019-10-13 15:50:48 -07:00
|
|
|
#include <cwchar>
|
2017-02-10 18:47:02 -08:00
|
|
|
#include <deque>
|
|
|
|
|
#include <list>
|
2016-05-01 19:54:25 -07:00
|
|
|
#include <memory>
|
2017-02-10 18:47:02 -08:00
|
|
|
#include <type_traits>
|
2018-02-18 18:39:03 -08:00
|
|
|
#include <utility>
|
2006-01-19 22:22:07 +10:00
|
|
|
|
2005-09-20 23:26:39 +10:00
|
|
|
#include "common.h"
|
2015-07-25 23:14:25 +08:00
|
|
|
#include "env.h"
|
2016-05-01 19:54:25 -07:00
|
|
|
#include "env_universal_common.h"
|
|
|
|
|
#include "fallback.h" // IWYU pragma: keep
|
2020-01-19 14:27:23 +01:00
|
|
|
#include "flog.h"
|
2019-05-04 17:32:40 -07:00
|
|
|
#include "global_safety.h"
|
2016-05-01 19:54:25 -07:00
|
|
|
#include "input_common.h"
|
2011-12-26 21:05:25 -08:00
|
|
|
#include "iothread.h"
|
2016-11-22 20:24:03 -08:00
|
|
|
#include "wutil.h"
|
2005-09-20 23:26:39 +10:00
|
|
|
|
2016-05-06 21:22:28 -07:00
|
|
|
/// Time in milliseconds to wait for another byte to be available for reading
|
2018-06-18 00:01:32 -05:00
|
|
|
/// after \x1B is read before assuming that escape key was pressed, and not an
|
2016-05-06 21:22:28 -07:00
|
|
|
/// escape sequence.
|
2019-02-07 12:08:24 +01:00
|
|
|
#define WAIT_ON_ESCAPE_DEFAULT 30
|
2016-01-14 21:46:53 -08:00
|
|
|
static int wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
|
2005-09-20 23:26:39 +10:00
|
|
|
|
2016-05-01 19:54:25 -07:00
|
|
|
/// Callback function for handling interrupts on reading.
|
2019-03-16 13:52:07 -07:00
|
|
|
static interrupt_func_t interrupt_handler;
|
2005-09-20 23:26:39 +10:00
|
|
|
|
2020-04-02 17:07:36 -07:00
|
|
|
void input_common_init(interrupt_func_t func) { interrupt_handler = func; }
|
2005-09-20 23:26:39 +10:00
|
|
|
|
2016-05-01 19:54:25 -07:00
|
|
|
/// Internal function used by input_common_readch to read one byte from fd 0. This function should
|
|
|
|
|
/// only be called by input_common_readch().
|
2019-06-02 15:41:23 -07:00
|
|
|
char_event_t input_event_queue_t::readb() {
|
2021-04-10 16:45:26 -07:00
|
|
|
select_wrapper_t fdset;
|
2019-04-28 22:08:40 -07:00
|
|
|
for (;;) {
|
2021-04-10 16:45:26 -07:00
|
|
|
fdset.clear();
|
|
|
|
|
fdset.add(in_);
|
2012-11-18 11:23:22 +01:00
|
|
|
|
2021-04-10 16:45:26 -07:00
|
|
|
int ioport = iothread_port();
|
2016-05-01 19:54:25 -07:00
|
|
|
if (ioport > 0) {
|
2021-04-10 16:45:26 -07:00
|
|
|
fdset.add(ioport);
|
2014-04-29 17:03:00 -07:00
|
|
|
}
|
2016-05-01 19:54:25 -07:00
|
|
|
|
|
|
|
|
// Get our uvar notifier.
|
2020-01-16 15:14:21 -08:00
|
|
|
universal_notifier_t& notifier = universal_notifier_t::default_notifier();
|
2014-04-30 15:50:03 -07:00
|
|
|
int notifier_fd = notifier.notification_fd();
|
2016-05-01 19:54:25 -07:00
|
|
|
if (notifier_fd > 0) {
|
2021-04-10 16:45:26 -07:00
|
|
|
fdset.add(notifier_fd);
|
2014-04-30 15:50:03 -07:00
|
|
|
}
|
2016-05-01 19:54:25 -07:00
|
|
|
|
|
|
|
|
// Get its suggested delay (possibly none).
|
2021-04-10 16:45:26 -07:00
|
|
|
uint64_t timeout_usec = select_wrapper_t::kNoTimeout;
|
|
|
|
|
if (auto notifier_usec_delay = notifier.usec_delay_between_polls()) {
|
|
|
|
|
timeout_usec = notifier_usec_delay;
|
2014-04-29 17:03:00 -07:00
|
|
|
}
|
2021-04-10 16:45:26 -07:00
|
|
|
int res = fdset.select(timeout_usec);
|
|
|
|
|
if (res < 0) {
|
2016-10-22 20:32:25 -07:00
|
|
|
if (errno == EINTR || errno == EAGAIN) {
|
2021-01-31 15:42:35 -08:00
|
|
|
// Some uvar notifiers rely on signals - see #7671.
|
|
|
|
|
if (notifier.poll()) {
|
|
|
|
|
env_universal_barrier();
|
|
|
|
|
}
|
2016-10-22 20:32:25 -07:00
|
|
|
if (interrupt_handler) {
|
2019-03-16 13:52:07 -07:00
|
|
|
if (auto interrupt_evt = interrupt_handler()) {
|
|
|
|
|
return *interrupt_evt;
|
2021-04-10 13:40:53 -07:00
|
|
|
} else if (auto mc = try_pop()) {
|
2019-03-15 01:11:15 -07:00
|
|
|
return *mc;
|
|
|
|
|
}
|
2012-11-19 00:31:03 -08:00
|
|
|
}
|
2016-10-22 20:32:25 -07:00
|
|
|
} else {
|
2019-03-16 12:35:49 -07:00
|
|
|
// The terminal has been closed.
|
2019-03-16 14:08:00 -07:00
|
|
|
return char_event_type_t::eof;
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2016-05-01 19:54:25 -07:00
|
|
|
} else {
|
|
|
|
|
// Check to see if we want a universal variable barrier.
|
2014-05-14 14:16:53 +08:00
|
|
|
bool barrier_from_poll = notifier.poll();
|
|
|
|
|
bool barrier_from_readability = false;
|
2021-04-10 16:45:26 -07:00
|
|
|
if (notifier_fd > 0 && fdset.test(notifier_fd)) {
|
2014-05-14 14:16:53 +08:00
|
|
|
barrier_from_readability = notifier.notification_fd_became_readable(notifier_fd);
|
2014-04-30 15:50:03 -07:00
|
|
|
}
|
2016-05-01 19:54:25 -07:00
|
|
|
if (barrier_from_poll || barrier_from_readability) {
|
2019-04-28 22:05:03 -07:00
|
|
|
if (env_universal_barrier()) {
|
|
|
|
|
// A variable change may have triggered a repaint, etc.
|
2021-04-10 13:40:53 -07:00
|
|
|
if (auto mc = try_pop()) {
|
2019-04-28 22:05:03 -07:00
|
|
|
return *mc;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-04-29 17:03:00 -07:00
|
|
|
}
|
2012-11-18 11:23:22 +01:00
|
|
|
|
2021-04-10 16:45:26 -07:00
|
|
|
if (fdset.test(in_)) {
|
2019-04-28 22:08:40 -07:00
|
|
|
unsigned char arr[1];
|
2020-10-31 18:14:50 +01:00
|
|
|
if (read_blocked(in_, arr, 1) != 1) {
|
2019-03-16 12:35:49 -07:00
|
|
|
// The teminal has been closed.
|
2019-03-16 14:08:00 -07:00
|
|
|
return char_event_type_t::eof;
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2012-11-18 11:23:22 +01:00
|
|
|
|
2016-05-01 19:54:25 -07:00
|
|
|
// We read from stdin, so don't loop.
|
2019-04-28 22:08:40 -07:00
|
|
|
return arr[0];
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2019-06-23 16:19:13 -07:00
|
|
|
|
|
|
|
|
// Check for iothread completions only if there is no data to be read from the stdin.
|
|
|
|
|
// This gives priority to the foreground.
|
2021-04-10 16:45:26 -07:00
|
|
|
if (ioport > 0 && fdset.test(ioport)) {
|
2021-02-06 18:43:43 -08:00
|
|
|
iothread_service_main();
|
2021-04-10 13:40:53 -07:00
|
|
|
if (auto mc = try_pop()) {
|
|
|
|
|
return mc.acquire();
|
2019-06-23 16:19:13 -07:00
|
|
|
}
|
|
|
|
|
}
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2019-04-28 22:08:40 -07:00
|
|
|
}
|
2005-09-20 23:26:39 +10:00
|
|
|
}
|
|
|
|
|
|
2016-05-01 19:54:25 -07:00
|
|
|
// Update the wait_on_escape_ms value in response to the fish_escape_delay_ms user variable being
|
|
|
|
|
// set.
|
2020-01-16 15:14:21 -08:00
|
|
|
void update_wait_on_escape_ms(const environment_t& vars) {
|
2018-09-17 21:26:21 -07:00
|
|
|
auto escape_time_ms = vars.get(L"fish_escape_delay_ms");
|
2016-05-01 19:54:25 -07:00
|
|
|
if (escape_time_ms.missing_or_empty()) {
|
2016-01-14 21:46:53 -08:00
|
|
|
wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-28 00:25:41 -07:00
|
|
|
long tmp = fish_wcstol(escape_time_ms->as_string().c_str());
|
2016-11-22 20:24:03 -08:00
|
|
|
if (errno || tmp < 10 || tmp >= 5000) {
|
2019-03-12 14:06:01 -07:00
|
|
|
std::fwprintf(stderr,
|
2019-05-05 12:09:25 +02:00
|
|
|
L"ignoring fish_escape_delay_ms: value '%ls' "
|
|
|
|
|
L"is not an integer or is < 10 or >= 5000 ms\n",
|
|
|
|
|
escape_time_ms->as_string().c_str());
|
2016-05-01 19:54:25 -07:00
|
|
|
} else {
|
2019-11-18 17:08:16 -08:00
|
|
|
wait_on_escape_ms = static_cast<int>(tmp);
|
2016-01-14 21:46:53 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-10 13:40:53 -07:00
|
|
|
maybe_t<char_event_t> input_event_queue_t::try_pop() {
|
|
|
|
|
if (queue_.empty()) {
|
|
|
|
|
return none();
|
|
|
|
|
}
|
|
|
|
|
auto result = std::move(queue_.front());
|
2019-06-02 15:41:23 -07:00
|
|
|
queue_.pop_front();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char_event_t input_event_queue_t::readch() {
|
2019-05-04 17:32:40 -07:00
|
|
|
ASSERT_IS_MAIN_THREAD();
|
2021-04-10 13:40:53 -07:00
|
|
|
if (auto mc = try_pop()) {
|
|
|
|
|
return mc.acquire();
|
2019-03-15 01:11:15 -07:00
|
|
|
}
|
|
|
|
|
wchar_t res;
|
|
|
|
|
mbstate_t state = {};
|
2019-11-25 16:36:13 -08:00
|
|
|
while (true) {
|
2019-03-16 14:08:00 -07:00
|
|
|
auto evt = readb();
|
2019-03-16 16:48:23 -07:00
|
|
|
if (!evt.is_char()) {
|
2019-03-16 14:08:00 -07:00
|
|
|
return evt;
|
2019-03-16 12:35:49 -07:00
|
|
|
}
|
2012-11-18 11:23:22 +01:00
|
|
|
|
2019-03-16 14:08:00 -07:00
|
|
|
wint_t b = evt.get_char();
|
2019-03-15 01:11:15 -07:00
|
|
|
if (MB_CUR_MAX == 1) {
|
|
|
|
|
return b; // single-byte locale, all values are legal
|
|
|
|
|
}
|
2012-11-18 11:23:22 +01:00
|
|
|
|
2019-03-15 01:11:15 -07:00
|
|
|
char bb = b;
|
|
|
|
|
size_t sz = std::mbrtowc(&res, &bb, 1, &state);
|
2012-11-18 11:23:22 +01:00
|
|
|
|
2019-03-15 01:11:15 -07:00
|
|
|
switch (sz) {
|
2019-11-18 17:08:16 -08:00
|
|
|
case static_cast<size_t>(-1): {
|
2019-03-15 01:11:15 -07:00
|
|
|
std::memset(&state, '\0', sizeof(state));
|
2020-01-19 14:27:23 +01:00
|
|
|
FLOG(reader, L"Illegal input");
|
2019-03-16 15:49:35 -07:00
|
|
|
return char_event_type_t::check_exit;
|
2016-07-11 20:31:30 -07:00
|
|
|
}
|
2019-11-18 17:08:16 -08:00
|
|
|
case static_cast<size_t>(-2): {
|
2019-03-15 01:11:15 -07:00
|
|
|
break;
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2019-03-15 01:11:15 -07:00
|
|
|
case 0: {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2019-05-05 12:09:25 +02:00
|
|
|
default: {
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2019-03-15 01:11:15 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-10 13:40:53 -07:00
|
|
|
maybe_t<char_event_t> input_event_queue_t::readch_timed() {
|
|
|
|
|
if (auto evt = try_pop()) {
|
|
|
|
|
return evt;
|
2012-11-18 16:30:30 -08:00
|
|
|
}
|
2021-04-10 13:40:53 -07:00
|
|
|
const uint64_t usec_per_msec = 1000;
|
|
|
|
|
uint64_t timeout_usec = static_cast<uint64_t>(wait_on_escape_ms) * usec_per_msec;
|
|
|
|
|
if (select_wrapper_t::is_fd_readable(in_, timeout_usec)) {
|
|
|
|
|
return readch();
|
2019-03-15 01:11:15 -07:00
|
|
|
}
|
2021-04-10 13:40:53 -07:00
|
|
|
return none();
|
2005-09-20 23:26:39 +10:00
|
|
|
}
|
|
|
|
|
|
2019-12-26 21:54:21 -08:00
|
|
|
void input_event_queue_t::push_back(const char_event_t& ch) { queue_.push_back(ch); }
|
2005-09-20 23:26:39 +10:00
|
|
|
|
2019-12-26 21:54:21 -08:00
|
|
|
void input_event_queue_t::push_front(const char_event_t& ch) { queue_.push_front(ch); }
|