1 /**************************************************************************
2 **
3 ** sngrep - SIP Messages flow viewer
4 **
5 ** Copyright (C) 2013-2018 Ivan Alonso (Kaian)
6 ** Copyright (C) 2013-2018 Irontec SL. All rights reserved.
7 **
8 ** This program is free software: you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License as published by
10 ** the Free Software Foundation, either version 3 of the License, or
11 ** (at your option) any later version.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with this program. If not, see <http://www.gnu.org/licenses/>.
20 **
21 ****************************************************************************/
22 /**
23 * @file group.c
24 * @author Ivan Alonso [aka Kaian] <kaian@irontec.com>
25 *
26 * @brief Source code of functions defined in keybinding.h
27 *
28 */
29
30 #include "config.h"
31 #include <ctype.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include "setting.h"
35 #include "keybinding.h"
36 #include "curses/ui_manager.h"
37
38 //! sngrep keybindings
39 key_binding_t bindings[ACTION_SENTINEL] = {
40 { ACTION_PRINTABLE, "", { }, 0 },
41 { ACTION_UP, "up", { KEY_UP, 'k' }, 2 },
42 { ACTION_DOWN, "down", { KEY_DOWN, 'j' }, 2 },
43 { ACTION_LEFT, "left", { KEY_LEFT, 'h' }, 2 },
44 { ACTION_RIGHT, "right", { KEY_RIGHT, 'l'}, 2 },
45 { ACTION_DELETE, "delete", { KEY_DC }, 1 },
46 { ACTION_BACKSPACE, "backspace", { KEY_BACKSPACE, KEY_BACKSPACE2, KEY_BACKSPACE3 }, 3 },
47 { ACTION_NPAGE, "npage", { KEY_NPAGE, KEY_CTRL('F') }, 2 },
48 { ACTION_PPAGE, "ppage", { KEY_PPAGE, KEY_CTRL('B') }, 2 },
49 { ACTION_HNPAGE, "hnpage", { KEY_CTRL('D') }, 1 },
50 { ACTION_HPPAGE, "hppage", { KEY_CTRL('U') }, 2 },
51 { ACTION_BEGIN, "begin", { KEY_HOME, KEY_CTRL('A') }, 2 },
52 { ACTION_END, "end", { KEY_END, KEY_CTRL('E') }, 2 },
53 { ACTION_PREV_FIELD, "pfield", { KEY_UP }, 1 },
54 { ACTION_NEXT_FIELD, "nfield", { KEY_DOWN, KEY_TAB }, 2 },
55 { ACTION_RESIZE_SCREEN, "", { KEY_RESIZE }, 1 },
56 { ACTION_CLEAR, "clear", { KEY_CTRL('U'), KEY_CTRL('W')}, 2 },
57 { ACTION_CLEAR_CALLS, "clearcalls", { KEY_F(5), KEY_CTRL('L')}, 2 },
58 { ACTION_CLEAR_CALLS_SOFT, "clearcallssoft", {KEY_F(9)}, 2 },
59 { ACTION_TOGGLE_SYNTAX, "togglesyntax", { KEY_F(8), 'C' }, 2 },
60 { ACTION_CYCLE_COLOR, "colormode", { 'c' }, 1 },
61 { ACTION_COMPRESS, "compress", { 's' }, 1 },
62 { ACTION_SHOW_ALIAS, "togglealias", { 'a' }, 1 },
63 { ACTION_TOGGLE_PAUSE, "pause", { 'p' }, 1 },
64 { ACTION_PREV_SCREEN, "prevscreen", { KEY_ESC, 'q', 'Q' }, 3 },
65 { ACTION_SHOW_HELP, "help", { KEY_F(1), 'h', 'H', '?' }, 4 },
66 { ACTION_SHOW_RAW, "raw", { KEY_F(6), 'R', 'r' }, 3 },
67 { ACTION_SHOW_FLOW, "flow", { KEY_INTRO }, 1 },
68 { ACTION_SHOW_FLOW_EX, "flowex", { KEY_F(4), 'x' }, 2 },
69 { ACTION_SHOW_FILTERS, "filters", { KEY_F(7), 'f', 'F' }, 3 },
70 { ACTION_SHOW_COLUMNS, "columns", { KEY_F(10), 't', 'T' }, 3 },
71 { ACTION_SHOW_SETTINGS, "settings", { KEY_F(8), 'o', 'O' }, 3 },
72 { ACTION_SHOW_STATS, "stats", { 'i' }, 1 },
73 { ACTION_COLUMN_MOVE_UP, "columnup", { '-' }, 1 },
74 { ACTION_COLUMN_MOVE_DOWN, "columndown", { '+' }, 1 },
75 { ACTION_SDP_INFO, "sdpinfo", { KEY_F(2), 'd' }, 2 },
76 { ACTION_DISP_FILTER, "search", { KEY_F(3), '/', KEY_TAB }, 3 },
77 { ACTION_SAVE, "save", { KEY_F(2), 's', 'S'}, 3 },
78 { ACTION_SELECT, "select", { KEY_SPACE }, 1 },
79 { ACTION_CONFIRM, "confirm", { KEY_INTRO }, 1 },
80 { ACTION_TOGGLE_MEDIA, "togglemedia", { KEY_F(3), 'm' }, 2 },
81 { ACTION_ONLY_MEDIA, "onlymedia", { 'M' }, 1 },
82 { ACTION_TOGGLE_RAW, "rawpreview", { 't' }, 1 },
83 { ACTION_INCREASE_RAW, "morerawpreview", { '9' }, 1 },
84 { ACTION_DECREASE_RAW, "lessrawpreview", { '0' }, 1 },
85 { ACTION_RESET_RAW, "resetrawpreview", { 'T' }, 1 },
86 { ACTION_ONLY_SDP, "onlysdp", { 'D' }, 1 },
87 { ACTION_AUTOSCROLL, "autoscroll", { 'A' }, 1 },
88 { ACTION_TOGGLE_HINT, "hintalt", { 'K' }, 1 },
89 { ACTION_SORT_PREV, "sortprev", { '<' }, 1 },
90 { ACTION_SORT_NEXT, "sortnext", { '>' }, 1 },
91 { ACTION_SORT_SWAP, "sortswap", { 'z' }, 1 },
92 { ACTION_TOGGLE_TIME, "toggletime", { 'w' }, 1 },
93 };
94
95 void
key_bindings_dump()96 key_bindings_dump()
97 {
98 int i, j;
99 for (i = 1; i < ACTION_SENTINEL; i++) {
100 for (j = 0; j < bindings[i].bindcnt; j++) {
101 printf("ActionID: %d\t ActionName: %-21s Key: %d (%s)\n",
102 bindings[i].id,
103 bindings[i].name,
104 bindings[i].keys[j],
105 key_to_str(bindings[i].keys[j]));
106 }
107 }
108 }
109
110 key_binding_t *
key_binding_data(int action)111 key_binding_data(int action)
112 {
113 int i;
114 for (i = 1; i < ACTION_SENTINEL; i++) {
115 if (bindings[i].id == action)
116 return &bindings[i];
117 }
118
119 return NULL;
120 }
121
122 void
key_bind_action(int action,int key)123 key_bind_action(int action, int key)
124 {
125 key_binding_t *bind;
126
127 if (!(bind = key_binding_data(action)))
128 return;
129
130 if (bind->bindcnt == MAX_BINDINGS)
131 return;
132
133 bind->keys[bind->bindcnt++] = key;
134 }
135
136 void
key_unbind_action(int action,int key)137 key_unbind_action(int action, int key)
138 {
139 key_binding_t tmp, *bind;
140 int i;
141
142 // Action is not valid
143 if (!(bind = key_binding_data(action)))
144 return;
145
146 // Copy binding to temporal struct
147 memcpy(&tmp, bind, sizeof(key_binding_t));
148
149 // Reset bindings for this action
150 memset(&bind->keys, 0, sizeof(int) * MAX_BINDINGS);
151
152 // Add all bindings but the unbinded
153 for (i=0; i < tmp.bindcnt; i++) {
154 if (tmp.keys[i] != key) {
155 key_bind_action(action, tmp.keys[i]);
156 }
157 }
158 }
159
160 int
key_find_action(int key,int start)161 key_find_action(int key, int start)
162 {
163 int i, j;
164 for (i = start + 1; i < ACTION_SENTINEL; i++) {
165
166 if (i == ACTION_PRINTABLE && key_is_printable(key))
167 return ACTION_PRINTABLE;
168
169 for (j = 0; j < bindings[i].bindcnt; j++)
170 if (bindings[i].keys[j] == key)
171 return bindings[i].id;
172 }
173 return -1;
174 }
175
176 int
key_action_id(const char * action)177 key_action_id(const char *action)
178 {
179 int i;
180 for (i = 1; i < ACTION_SENTINEL; i++) {
181 if (!strcasecmp(action, bindings[i].name))
182 return bindings[i].id;
183
184 }
185 return -1;
186 }
187
188 int
key_is_printable(int key)189 key_is_printable(int key)
190 {
191 return key == ' ' || (key > 33 && key < 126) || (key > 160 && key < 255);
192 }
193
194 const char *
key_to_str(int key)195 key_to_str(int key)
196 {
197 //! Check function keys and Special keys
198 switch(key) {
199 case KEY_F(1):
200 return "F1";
201 case KEY_F(2):
202 return "F2";
203 case KEY_F(3):
204 return "F3";
205 case KEY_F(4):
206 return "F4";
207 case KEY_F(5):
208 return "F5";
209 case KEY_F(6):
210 return "F6";
211 case KEY_F(7):
212 return "F7";
213 case KEY_F(8):
214 return "F8";
215 case KEY_F(9):
216 return "F9";
217 case KEY_F(10):
218 return "F10";
219 case KEY_ESC:
220 return "Esc";
221 case KEY_INTRO:
222 return "Enter";
223 case ' ':
224 return "Space";
225 default:
226 if (key_is_printable(key))
227 return keyname(key);
228 }
229
230 return "";
231 }
232
233 int
key_from_str(const char * key)234 key_from_str(const char *key)
235 {
236 if (!key)
237 return 0;
238
239 // Single character string
240 if (strlen(key) == 1)
241 return *key;
242
243 // Function keys
244 if (*key == 'F')
245 return KEY_F(atoi(key+1));
246
247 // Control Secuences
248 if (*key == '^')
249 return KEY_CTRL(toupper(*(key+1)));
250 if (!strncasecmp(key, "Ctrl-", 5))
251 return KEY_CTRL(toupper(*(key+5)));
252
253 // Special Name characters
254 if (!strcasecmp(key, "Esc"))
255 return KEY_ESC;
256 if (!strcasecmp(key, "Space"))
257 return ' ';
258 if (!strcasecmp(key, "Enter"))
259 return KEY_INTRO;
260
261 return 0;
262 }
263
264 const char *
key_action_key_str(int action)265 key_action_key_str(int action)
266 {
267 key_binding_t *bind;
268
269 if (!(bind = key_binding_data(action)))
270 return NULL;
271
272 if (setting_enabled(SETTING_ALTKEY_HINT) && bind->bindcnt > 1) {
273 // First alt keybinding
274 return key_to_str(bind->keys[1]);
275 } else {
276 // Default keybinding
277 return key_to_str(bind->keys[0]);
278 }
279 }
280
281 int
key_action_key(int action)282 key_action_key(int action)
283 {
284 key_binding_t *bind;
285
286 if (!(bind = key_binding_data(action)))
287 return -1;
288
289 if (setting_enabled(SETTING_ALTKEY_HINT) && bind->bindcnt > 1) {
290 // First alt keybinding
291 return bind->keys[1];
292 } else {
293 // Default keybinding
294 return bind->keys[0];
295 }
296
297 return -1;
298 }
299