~nloomans/ft_select

ref: 1d90313037b5c7d0545be79e58d8f50a102501ff ft_select/src/event.c -rw-r--r-- 2.9 KiB
1d903130Noah Loomans handle CTRL+Z and fg 1 year, 10 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <assert.h>
#include <stddef.h>
#include <stdbool.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <ft_printf.h>
#include "event.h"
#include "terminal.h"
#include "action.h"
#include "read.h"
#include "error.h"

bool							g_event_sigwinch = false;
bool							g_event_sigcont = false;

void							handle_generic(int signum)
{
	*g_event_signal_map[signum].global = true;
}

static void						handle_suspend(int signum)
{
	(void)signum;
	terminal_configure(TERMINAL_CONFIGURE_RESTORE);
	signal(SIGTSTP, SIG_DFL);
	ioctl(STDIN_FILENO, TIOCSTI, "\032");
}

static void						handle_continue(int signum)
{
	terminal_configure(TERMINAL_CONFIGURE_SETUP);
	signal(SIGTSTP, handle_suspend);
	handle_generic(signum);
}

const struct s_event_signal_map	g_event_signal_map[] = {
	[ SIGWINCH ] =
		{ .global = &g_event_sigwinch, .action = action_update_size },
	[ SIGTSTP ] =
		{ .handler = handle_suspend },
	[ SIGCONT ] = {
		.handler = handle_continue,
		.global = &g_event_sigcont,
		.action = action_update_size,
	},
};

const t_action	g_event_key_map[READ_TYPE_AMOUNT][128] = {
	[ READ_TYPE_REG ] = {
		[ 'q' ] = action_quit,
		[ 'j' ] = action_down,
		[ 'k' ] = action_up,
		[ 'h' ] = action_left,
		[ 'l' ] = action_right,
		[ ' ' ] = action_select,
		[ '\x7f' ] = action_delete,
		[ '\n' ] = action_confirm,
	},
	[ READ_TYPE_ESC ] = {
		[ 'A' ] = action_up,
		[ 'B' ] = action_down,
		[ 'D' ] = action_left,
		[ 'C' ] = action_right,
	},
	[ READ_TYPE_ESC_SQL ] = {
		[ '3' ] = action_delete,
	},
};


t_error							event_init(void)
{
	size_t	signum;

	signum = 0;
	while (signum < sizeof(g_event_signal_map) / sizeof(*g_event_signal_map))
	{
		if (g_event_signal_map[signum].handler)
		{
			if (signal(signum, g_event_signal_map[signum].handler) == SIG_ERR)
				return (errorf("unable to bind signal: %s", strerror(errno)));
		}
		else if (g_event_signal_map[signum].action)
		{
			if (signal(signum, handle_generic) == SIG_ERR)
				return (errorf("unable to bind signal: %s", strerror(errno)));
		}
		signum++;
	}
	return (ERROR_NULL);
}

static t_action			next_signal(void)
{
	size_t	signum;

	signum = 0;
	while (signum < sizeof(g_event_signal_map) / sizeof(*g_event_signal_map))
	{
		if (g_event_signal_map[signum].action &&
			*g_event_signal_map[signum].global)
		{
			*g_event_signal_map[signum].global = false;
			return (g_event_signal_map[signum].action);
		}
		signum++;
	}
	return (NULL);
}

static t_error				next_key(t_action *dest)
{
	struct s_read_seq	seq;

	seq = read_seq();
	if (is_error(seq.error))
		return (errorf("failed to read input sequence: %s", seq.error.msg));
	*dest = g_event_key_map[seq.type][(unsigned char)seq.c];
	return (ERROR_NULL);
}

t_error						event_next(t_action *dest)
{
	t_error			error;

	*dest = next_signal();
	if (*dest != NULL)
		return (ERROR_NULL);
	error = next_key(dest);
	if (is_error(error) || *dest != NULL)
		return (error);
	return (ERROR_NULL);
}