mirror of
http://mpg123.de/trunk/.git
synced 2025-08-06 10:02:38 +03:00
term: the new switchery to later enable term_type=win32
git-svn-id: svn://scm.orgis.org/mpg123/trunk@5082 35dc7657-300d-0410-a2e5-dc2837fedb53
This commit is contained in:
199
src/term_posix.c
Normal file
199
src/term_posix.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
term_posix: POSIX-specifc terminal functionality
|
||||
|
||||
HAVE_TERMIOS is a prerequisite.
|
||||
|
||||
copyright 2008-2022 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Thomas Orgis
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#ifndef HAVE_TERMIOS
|
||||
#error "No TERMIOS? Here?"
|
||||
#endif
|
||||
|
||||
// for param struct
|
||||
#include "mpg123app.h"
|
||||
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "terms.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
static int term_is_fun = -1;
|
||||
// This now always refers to a ;freshly opened terminal descriptor (e.g. /dev/tty).
|
||||
// Printouts to stderr are independent of this.
|
||||
static int term_fd = -1;
|
||||
static struct termios old_tio;
|
||||
|
||||
/* Buffered key from a signal or whatnot.
|
||||
We ignore the null character... */
|
||||
static char prekey = 0;
|
||||
|
||||
int term_have_fun(int fd, int want_visuals)
|
||||
{
|
||||
if(term_is_fun > -1)
|
||||
return term_is_fun;
|
||||
else
|
||||
term_is_fun = 0;
|
||||
if(term_width(fd) > 0 && want_visuals)
|
||||
{
|
||||
/* Only play with non-dumb terminals. */
|
||||
char *tname = compat_getenv("TERM");
|
||||
if(tname)
|
||||
{
|
||||
if(strcmp(tname, "") && strcmp(tname, "dumb"))
|
||||
term_is_fun = 1;
|
||||
free(tname);
|
||||
}
|
||||
}
|
||||
return term_is_fun;
|
||||
}
|
||||
|
||||
/* Also serves as a way to detect if we have an interactive terminal. */
|
||||
int term_width(int fd)
|
||||
{
|
||||
struct winsize geometry;
|
||||
geometry.ws_col = 0;
|
||||
if(ioctl(fd, TIOCGWINSZ, &geometry) >= 0)
|
||||
return (int)geometry.ws_col;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int term_setup_detail(struct termios *pattern);
|
||||
|
||||
static void term_sigcont(int sig)
|
||||
{
|
||||
if(term_setup_detail(&old_tio) < 0)
|
||||
{
|
||||
debug("Can't set terminal attributes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void term_sigusr(int sig)
|
||||
{
|
||||
switch(sig)
|
||||
{
|
||||
case SIGUSR1: prekey=*param.term_usr1; break;
|
||||
case SIGUSR2: prekey=*param.term_usr2; break;
|
||||
}
|
||||
}
|
||||
|
||||
/* This must call only functions safe inside a signal handler. */
|
||||
static int term_setup_detail(struct termios *pattern)
|
||||
{
|
||||
mdebug("setup on fd %d", term_fd);
|
||||
|
||||
/* One might want to use sigaction instead. */
|
||||
signal(SIGCONT, term_sigcont);
|
||||
signal(SIGUSR1, term_sigusr);
|
||||
signal(SIGUSR2, term_sigusr);
|
||||
struct termios tio = *pattern;
|
||||
tio.c_lflag &= ~(ICANON|ECHO);
|
||||
tio.c_cc[VMIN] = 1;
|
||||
tio.c_cc[VTIME] = 0;
|
||||
#ifdef __OS2__
|
||||
// Do not care for the error until OS/2 is known to work.
|
||||
tcsetattr(term_fd,TCSANOW,&tio);
|
||||
return 0;
|
||||
#else
|
||||
return tcsetattr(term_fd,TCSANOW,&tio);
|
||||
#endif
|
||||
}
|
||||
|
||||
int term_setup(void)
|
||||
{
|
||||
if(term_fd < 0)
|
||||
{
|
||||
const char *term_name;
|
||||
#ifdef HAVE_CTERMID
|
||||
term_name = ctermid(NULL);
|
||||
#else
|
||||
term_name = "/dev/tty";
|
||||
#endif
|
||||
if(term_name)
|
||||
mdebug("accessing terminal for control via %s", term_name);
|
||||
else
|
||||
{
|
||||
error("no controlling terminal");
|
||||
return -1;
|
||||
}
|
||||
term_fd = open(term_name, O_RDONLY);
|
||||
if(term_fd < 0)
|
||||
{
|
||||
merror("failed to open terminal: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(tcgetattr(term_fd, &old_tio) < 0)
|
||||
{
|
||||
// For now, this always fails on OS/2, but they might fix things.
|
||||
// So just try to move on.
|
||||
#ifndef __OS2__
|
||||
merror("failed to get terminal attributes: %s", strerror(errno));
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if(term_setup_detail(&old_tio) < 0)
|
||||
{
|
||||
close(term_fd);
|
||||
term_fd = -1;
|
||||
if(errno)
|
||||
merror("failure setting terminal attributes: %s", strerror(errno));
|
||||
else
|
||||
error("failure setting terminal attributes");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the next pressed key, if any.
|
||||
Returns 1 when there is a key, 0 if not. */
|
||||
int term_get_key(int do_delay, char *val)
|
||||
{
|
||||
fd_set r;
|
||||
struct timeval t;
|
||||
|
||||
/* Shortcut: If some other means sent a key, use it. */
|
||||
if(prekey)
|
||||
{
|
||||
debug1("Got prekey: %c\n", prekey);
|
||||
*val = prekey;
|
||||
prekey = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
t.tv_sec=0;
|
||||
t.tv_usec=(do_delay) ? 10*1000 : 0;
|
||||
|
||||
FD_ZERO(&r);
|
||||
FD_SET(term_fd,&r);
|
||||
if(select(term_fd+1,&r,NULL,NULL,&t) > 0 && FD_ISSET(term_fd,&r))
|
||||
{
|
||||
if(read(term_fd,val,1) <= 0)
|
||||
return 0; /* Well, we couldn't read the key, so there is none. */
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void term_restore(void)
|
||||
{
|
||||
debug("reset attrbutes");
|
||||
tcsetattr(term_fd,TCSAFLUSH,&old_tio);
|
||||
|
||||
if(term_fd > -1)
|
||||
close(term_fd);
|
||||
term_fd = -1;
|
||||
}
|
Reference in New Issue
Block a user