summaryrefslogtreecommitdiffstats
path: root/osdep/terminal-unix.c
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2017-07-18 11:53:37 -0400
committerJan Ekström <jeebjp@gmail.com>2017-12-08 01:30:42 +0200
commit8977fe5ed9d73dd56441d5071a0c2732636e7be3 (patch)
tree004998672b2dc39fb6577a20cf8279363e427a46 /osdep/terminal-unix.c
parent665173d8b24372672e81787ed2aff6415b5cc3a1 (diff)
downloadmpv-8977fe5ed9d73dd56441d5071a0c2732636e7be3.tar.bz2
mpv-8977fe5ed9d73dd56441d5071a0c2732636e7be3.tar.xz
Use /dev/tty instead of stdin for terminal input
Fixes #4190 This allows you to use terminal input even if you've piped something into mpv.
Diffstat (limited to 'osdep/terminal-unix.c')
-rw-r--r--osdep/terminal-unix.c61
1 files changed, 43 insertions, 18 deletions
diff --git a/osdep/terminal-unix.c b/osdep/terminal-unix.c
index da6ccfe7f2..c7309fbf50 100644
--- a/osdep/terminal-unix.c
+++ b/osdep/terminal-unix.c
@@ -25,12 +25,13 @@
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
+#include <sys/select.h>
#include <pthread.h>
+#include <time.h>
#include <assert.h>
#include <termios.h>
#include <unistd.h>
-#include <poll.h>
#include "osdep/io.h"
#include "osdep/threads.h"
@@ -45,6 +46,8 @@
static volatile struct termios tio_orig;
static volatile int tio_orig_set;
+static int tty_in, tty_out;
+
struct key_entry {
const char *seq;
int mpkey;
@@ -171,7 +174,7 @@ static struct termbuf buf;
static bool getch2(struct input_ctx *input_ctx)
{
- int retval = read(0, &buf.b[buf.len], BUF_LEN - buf.len);
+ int retval = read(tty_in, &buf.b[buf.len], BUF_LEN - buf.len);
/* Return false on EOF to stop running select() on the FD, as it'd
* trigger all the time. Note that it's possible to get temporary
* EOF on terminal if the user presses ctrl-d, but that shouldn't
@@ -259,9 +262,9 @@ static void enable_kx(bool enable)
// tty. Note that stderr being redirected away has no influence over mpv's
// I/O handling except for disabling the terminal OSD, and thus stderr
// shouldn't be relied on here either.
- if (isatty(STDOUT_FILENO)) {
+ if (isatty(tty_out)) {
char *cmd = enable ? "\033=" : "\033>";
- (void)write(STDOUT_FILENO, cmd, strlen(cmd));
+ (void)write(tty_out, cmd, strlen(cmd));
}
}
@@ -273,7 +276,7 @@ static void do_activate_getch2(void)
enable_kx(true);
struct termios tio_new;
- tcgetattr(0,&tio_new);
+ tcgetattr(tty_in,&tio_new);
if (!tio_orig_set) {
tio_orig = tio_new;
@@ -283,7 +286,7 @@ static void do_activate_getch2(void)
tio_new.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
tio_new.c_cc[VMIN] = 1;
tio_new.c_cc[VTIME] = 0;
- tcsetattr(0,TCSANOW,&tio_new);
+ tcsetattr(tty_in,TCSANOW,&tio_new);
getch2_active = 1;
}
@@ -298,7 +301,7 @@ static void do_deactivate_getch2(void)
if (tio_orig_set) {
// once set, it will never be set again
// so we can cast away volatile here
- tcsetattr(0, TCSANOW, (const struct termios *) &tio_orig);
+ tcsetattr(tty_in, TCSANOW, (const struct termios *) &tio_orig);
}
getch2_active = 0;
@@ -326,7 +329,7 @@ static void getch2_poll(void)
return;
// check if stdin is in the foreground process group
- int newstatus = (tcgetpgrp(0) == getpgrp());
+ int newstatus = (tcgetpgrp(tty_in) == getpgrp());
// and activate getch2 if it is, deactivate otherwise
if (newstatus)
@@ -365,6 +368,14 @@ static void close_death_pipe(void)
}
}
+static void close_tty(void)
+{
+ if (tty_in >= 0 && tty_in != STDIN_FILENO)
+ close(tty_in);
+
+ tty_in = tty_out = -1;
+}
+
static void quit_request_sighandler(int signum)
{
do_deactivate_getch2();
@@ -376,17 +387,23 @@ static void *terminal_thread(void *ptr)
{
mpthread_set_name("terminal");
bool stdin_ok = read_terminal; // if false, we still wait for SIGTERM
+ fd_set readfds;
+ int max = death_pipe[0] > tty_in ? death_pipe[0] : tty_in;
+ struct timeval timeout = { .tv_sec = 0, .tv_usec = 100000 };
while (1) {
+ FD_ZERO(&readfds);
+ FD_SET(death_pipe[0], &readfds);
+ FD_SET(tty_in, &readfds);
getch2_poll();
- struct pollfd fds[2] = {
- {.events = POLLIN, .fd = death_pipe[0]},
- {.events = POLLIN, .fd = STDIN_FILENO},
- };
- poll(fds, stdin_ok ? 2 : 1, -1);
- if (fds[0].revents)
+ int s = select(max + 1, &readfds, NULL, NULL, &timeout);
+ if (s == -1) {
break;
- if (fds[1].revents)
- stdin_ok = getch2(input_ctx);
+ } else if (s != 0) {
+ if (FD_ISSET(death_pipe[0], &readfds))
+ break;
+ if (stdin_ok && FD_ISSET(tty_in, &readfds))
+ stdin_ok = getch2(input_ctx);
+ }
}
char c;
bool quit = read(death_pipe[0], &c, 1) == 1 && c == 1;
@@ -407,16 +424,23 @@ void terminal_setup_getch(struct input_ctx *ictx)
if (mp_make_wakeup_pipe(death_pipe) < 0)
return;
+ tty_in = tty_out = open("/dev/tty", O_RDWR | O_CLOEXEC);
+ if (tty_in < 0) {
+ tty_in = STDIN_FILENO;
+ tty_out = STDOUT_FILENO;
+ }
+
// Disable reading from the terminal even if stdout is not a tty, to make
// mpv ... | less
// do the right thing.
- read_terminal = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
+ read_terminal = isatty(tty_in) && isatty(STDOUT_FILENO);
input_ctx = ictx;
if (pthread_create(&input_thread, NULL, terminal_thread, NULL)) {
input_ctx = NULL;
close_death_pipe();
+ close_tty();
return;
}
@@ -445,6 +469,7 @@ void terminal_uninit(void)
(void)write(death_pipe[1], &(char){0}, 1);
pthread_join(input_thread, NULL);
close_death_pipe();
+ close_tty();
input_ctx = NULL;
}
@@ -460,7 +485,7 @@ bool terminal_in_background(void)
void terminal_get_size(int *w, int *h)
{
struct winsize ws;
- if (ioctl(0, TIOCGWINSZ, &ws) < 0 || !ws.ws_row || !ws.ws_col)
+ if (ioctl(tty_in, TIOCGWINSZ, &ws) < 0 || !ws.ws_row || !ws.ws_col)
return;
*w = ws.ws_col;