home · contact · privacy
Simplified client control library and interaction with it.
[plomrogue] / src / client / keybindings.c
1 /* src/client/keybindings.c */
2
3 #include "keybindings.h"
4 #include <ncurses.h> /* keycode defines, cbreak(), halfdelay(), getch() */
5 #include <stdio.h> /* FILE, sprintf(), snprintf() */
6 #include <stdint.h> /* uint8_t, uint16_t, uint32_t */
7 #include <stdlib.h> /* free(), atoi() */
8 #include <string.h> /* strlen(), strchr() */
9 #include "../common/readwrite.h" /* try_fopen(), textfile_sizes(), try_fgets(),
10                                   * try_fclose(), try_fclose_unlink_rename(),
11                                   * try_fwrite()
12                                   */
13 #include "../common/try_malloc.h" /* for try_malloc() */
14 #include "windows.h" /* draw_all_wins() */
15 #include "world.h" /* global world */
16
17
18
19 /* Return "n"-th keybinding in keybindings chain from "kb_p" on. */
20 static struct KeyBinding * get_keyb_of_n(struct KeyBinding * kb_p, uint16_t n);
21
22 /* Return number of keybindings in keybindings chain from "kb_p" on. */
23 static uint16_t get_n_of_keybs(struct KeyBinding * kb_p);
24
25 /* If "keycode_given" equals "keycode_match", copy "keyname_match" to "keyname"
26  * and return 1; otherwise return 0.
27  */
28 static uint8_t try_keycode(uint16_t keycode_given, char * keyname,
29                            uint16_t keycode_match, char * keyname_match);
30
31
32
33 static struct KeyBinding * get_keyb_of_n(struct KeyBinding * kb_p, uint16_t n)
34 {
35     uint16_t i = 0;
36     while (1)
37     {
38         if (n == i)
39         {
40             break;
41         }
42         i++;
43         kb_p = kb_p->next;
44     }
45     return kb_p;
46 }
47
48
49
50 static uint16_t get_n_of_keybs(struct KeyBinding * kb_p)
51 {
52     uint16_t i = 0;
53     while (1)
54     {
55         if (0 == kb_p)
56         {
57             break;
58         }
59         i++;
60         kb_p = kb_p->next;
61     }
62     return i;
63 }
64
65
66
67 static uint8_t try_keycode(uint16_t keycode_given, char * keyname,
68                            uint16_t keycode_match, char * keyname_match)
69 {
70     if (keycode_given == keycode_match)
71     {
72         sprintf(keyname, keyname_match);
73         return 1;
74     }
75     return 0;
76 }
77
78
79
80 extern struct Command * get_command_to_keycode(struct KeyBinding * kb_p,
81                                                uint16_t key)
82 {
83     while (0 != kb_p)
84     {
85         if (key == kb_p->key)
86         {
87             return kb_p->command;
88         }
89         kb_p = kb_p->next;
90     }
91     return NULL;
92 }
93
94
95
96 extern char * get_keyname_to_keycode(uint16_t keycode)
97 {
98     char * f_name = "get_name_to_keycode()";
99     char * keyname = try_malloc(15, f_name);                /* FIXME: Why 15? */
100     if (32 < keycode && keycode < 127)
101     {
102         sprintf(keyname, "%c", keycode);
103     }
104     else if (keycode >= KEY_F0 && keycode <= KEY_F(63))
105     {
106         uint16_t f = keycode - KEY_F0;
107         sprintf(keyname, "F%d", f);
108     }
109     else if (   try_keycode(keycode, keyname, 9, "TAB")
110              || try_keycode(keycode, keyname, 10, "RETURN")
111              || try_keycode(keycode, keyname, 27, "ESCAPE")
112              || try_keycode(keycode, keyname, 32, "SPACE")
113              || try_keycode(keycode, keyname, KEY_UP, "UP")
114              || try_keycode(keycode, keyname, KEY_DOWN, "DOWN")
115              || try_keycode(keycode, keyname, KEY_LEFT, "LEFT")
116              || try_keycode(keycode, keyname, KEY_RIGHT, "RIGHT")
117              || try_keycode(keycode, keyname, KEY_HOME, "HOME")
118              || try_keycode(keycode, keyname, KEY_BACKSPACE, "BACKSPACE")
119              || try_keycode(keycode, keyname, KEY_DC, "DELETE")
120              || try_keycode(keycode, keyname, KEY_IC, "INSERT")
121              || try_keycode(keycode, keyname, KEY_NPAGE, "NEXT PAGE")
122              || try_keycode(keycode, keyname, KEY_PPAGE, "PREV PAGE")
123              || try_keycode(keycode, keyname, KEY_END, "END"))
124     {
125         ;
126     }
127     else
128     {
129         sprintf(keyname, "(unknown)");
130     }
131     return keyname;
132 }
133
134
135
136 extern void init_keybindings(char * path, struct KeyBindingDB * kbd)
137 {
138     char * f_name = "init_keybindings()";
139     FILE * file = try_fopen(path, "r", f_name);
140     uint32_t lines;
141     uint32_t linemax = textfile_sizes(file, &lines);
142     char command[linemax + 1];
143     char * cmdptr;
144     struct KeyBinding ** loc_last_ptr = &kbd->kbs;
145     * loc_last_ptr = 0;
146     while (try_fgets(command, linemax + 1, file, f_name))
147     {
148         if ('\n' == command[0] || 0 == command[0])
149         {
150             break;
151         }
152         * loc_last_ptr = try_malloc(sizeof(struct KeyBinding), f_name);
153         struct KeyBinding * kb_p = * loc_last_ptr;
154         kb_p->next = 0;
155         kb_p->key = atoi(command);
156         cmdptr = strchr(command, ' ') + 1;
157         cmdptr[strlen(cmdptr) - 1] = '\0';
158         kb_p->command = get_command(cmdptr);
159         loc_last_ptr = & kb_p->next;
160     }
161     try_fclose(file, f_name);
162     kbd->edit = 0;
163     kbd->select = 0;
164 }
165
166
167
168 extern void save_keybindings(char * path, struct KeyBindingDB * kbd)
169 {
170     char * f_name = "save_keybindings()";
171     char path_tmp[strlen(path) + 4 + 1];
172     sprintf(path_tmp, "%s_tmp", path);
173     FILE * file = try_fopen(path_tmp, "w", f_name);
174     uint16_t linemax = 0;
175     struct KeyBinding * kb_p = kbd->kbs;
176     while (0 != kb_p)
177     {
178         if (strlen(kb_p->command->dsc_short) > linemax)
179         {
180             linemax = strlen(kb_p->command->dsc_short);
181         }
182         kb_p = kb_p->next;
183     }
184     linemax = linemax + 6;         /* + 6 = + 3 digits + whitespace + \n + \0 */
185     char line[linemax];
186     kb_p = kbd->kbs;
187     while (0 != kb_p)
188     {
189         snprintf(line, linemax, "%d %s\n", kb_p->key, kb_p->command->dsc_short);
190         try_fwrite(line, sizeof(char), strlen(line), file, f_name);
191         kb_p = kb_p->next;
192     }
193     try_fclose_unlink_rename(file, path_tmp, path, f_name);
194 }
195
196
197
198 extern void free_keybindings(struct KeyBinding * kb_start)
199 {
200     if (0 == kb_start)
201     {
202         return;
203     }
204     struct KeyBinding * kb_p = kb_start->next;
205     if (0 != kb_p)
206     {
207         free_keybindings(kb_p);
208     }
209     free(kb_start);
210 }
211
212
213
214 extern void mod_selected_keyb(struct KeyBindingDB * kbd)
215 {
216     kbd->edit = 1;
217     draw_all_wins();
218     cbreak();
219     int key = getch();
220     halfdelay(world.halfdelay);
221     if (key < 1000)
222     {
223         struct KeyBinding * kb_p = get_keyb_of_n(kbd->kbs, kbd->select);
224         kb_p->key = key;
225     }
226     kbd->edit = 0;
227 }
228
229
230
231 extern void move_keyb_mod_selection(struct KeyBindingDB * kbd, char dir)
232 {
233     if      ('u' == dir && kbd->select > 0)
234     {
235         kbd->select--;
236     }
237     else if ('d' == dir && kbd->select < get_n_of_keybs(kbd->kbs) - 1)
238     {
239         kbd->select++;
240     }
241 }