1 /*
2  * Copyright (c) 2011 Tim van der Molen <tim@kariliq.nl>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <errno.h>
18 #include <poll.h>
19 #include <pthread.h>
20 #include <signal.h>
21 #include <termios.h>
22 #include <unistd.h>
23 
24 #include "siren.h"
25 
26 static void			input_handle_signal(int);
27 
28 static enum input_mode		input_mode = INPUT_MODE_VIEW;
29 static pthread_mutex_t		input_mode_mtx = PTHREAD_MUTEX_INITIALIZER;
30 static volatile sig_atomic_t	input_quit;
31 #ifdef SIGWINCH
32 static volatile sig_atomic_t	input_sigwinch;
33 #endif
34 
35 void
36 input_end(void)
37 {
38 	input_quit = 1;
39 }
40 
41 void
42 input_init(void)
43 {
44 	struct sigaction	sa;
45 #ifdef VDSUSP
46 	struct termios		tio;
47 #endif
48 
49 	sa.sa_handler = input_handle_signal;
50 	sa.sa_flags = 0;
51 	sigemptyset(&sa.sa_mask);
52 
53 	if (sigaction(SIGINT, &sa, NULL) == -1)
54 		LOG_ERR("sigaction");
55 	if (sigaction(SIGQUIT, &sa, NULL) == -1)
56 		LOG_ERR("sigaction");
57 	if (sigaction(SIGTERM, &sa, NULL) == -1)
58 		LOG_ERR("sigaction");
59 #ifdef SIGWINCH
60 	if (sigaction(SIGWINCH, &sa, NULL) == -1)
61 		LOG_ERR("sigaction");
62 #endif
63 
64 #ifdef VDSUSP
65 	/*
66 	 * Check if the DSUSP special character is set to ^Y. If it is, disable
67 	 * it so that ^Y becomes an ordinary character that can be bound to a
68 	 * command.
69 	 */
70 	if (tcgetattr(STDIN_FILENO, &tio) == -1)
71 		LOG_ERR("tcgetattr");
72 	else
73 		if (tio.c_cc[VDSUSP] == K_CTRL('Y')) {
74 			tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
75 			if (tcsetattr(STDIN_FILENO, TCSANOW, &tio) == -1)
76 				LOG_ERR("tcsetattr");
77 		}
78 #endif
79 }
80 
81 enum input_mode
82 input_get_mode(void)
83 {
84 	enum input_mode mode;
85 
86 	XPTHREAD_MUTEX_LOCK(&input_mode_mtx);
87 	mode = input_mode;
88 	XPTHREAD_MUTEX_UNLOCK(&input_mode_mtx);
89 	return mode;
90 }
91 
92 void
93 input_handle_key(void)
94 {
95 	struct pollfd	pfd[1];
96 	int		key;
97 
98 	pfd[0].fd = STDIN_FILENO;
99 	pfd[0].events = POLLIN;
100 
101 	while (!input_quit) {
102 #ifdef SIGWINCH
103 		if (input_sigwinch) {
104 			input_sigwinch = 0;
105 			screen_refresh();
106 		}
107 #endif
108 
109 		if (poll(pfd, NELEMENTS(pfd), -1) == -1) {
110 			if (errno != EINTR)
111 				LOG_FATAL("poll");
112 		} else {
113 			if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))
114 				LOG_FATALX("poll() failed");
115 
116 			key = screen_get_key();
117 			if (input_mode == INPUT_MODE_VIEW)
118 				view_handle_key(key);
119 			else
120 				prompt_handle_key(key);
121 		}
122 	}
123 }
124 
125 static void
126 input_handle_signal(int sig)
127 {
128 	switch (sig) {
129 	case SIGINT:
130 	case SIGQUIT:
131 	case SIGTERM:
132 		input_quit = 1;
133 		break;
134 #ifdef SIGWINCH
135 	case SIGWINCH:
136 		input_sigwinch = 1;
137 		break;
138 #endif
139 	}
140 }
141 
142 void
143 input_set_mode(enum input_mode mode)
144 {
145 	XPTHREAD_MUTEX_LOCK(&input_mode_mtx);
146 	input_mode = mode;
147 	XPTHREAD_MUTEX_UNLOCK(&input_mode_mtx);
148 }
149