1 /**
2  * \file ui-keymap.c
3  * \brief Keymap handling
4  *
5  * Copyright (c) 2011 Andi Sidwell
6  *
7  * This work is free software; you can redistribute it and/or modify it
8  * under the terms of either:
9  *
10  * a) the GNU General Public License as published by the Free Software
11  *    Foundation, version 2, or
12  *
13  * b) the "Angband licence":
14  *    This software may be copied and distributed for educational, research,
15  *    and not for profit purposes provided that this copyright and statement
16  *    are included in all such copies.  Other copyrights may also apply.
17  */
18 #include "angband.h"
19 #include "ui-keymap.h"
20 #include "ui-term.h"
21 
22 /**
23  * Keymap implementation.
24  *
25  * Keymaps are defined in pref files and map onto the internal game keyset,
26  * which is roughly what you get if you have roguelike keys turned off.
27  *
28  * We store keymaps by pairing triggers with actions; the trigger is a single
29  * keypress and the action is stored as a string of keypresses, terminated
30  * with a keypress with type == EVT_NONE.
31  *
32  * XXX We should note when we read in keymaps that are "official game" keymaps
33  * and ones which are user-defined.  Then we can avoid writing out official
34  * game ones and messing up everyone's pref files with a load of junk.
35  */
36 
37 
38 /**
39  * Struct for a keymap.
40  */
41 struct keymap {
42 	struct keypress key;
43 	struct keypress *actions;
44 
45 	bool user;		/* User-defined keymap */
46 
47 	struct keymap *next;
48 };
49 
50 
51 /**
52  * List of keymaps.
53  */
54 static struct keymap *keymaps[KEYMAP_MODE_MAX];
55 
56 
57 /**
58  * Find a keymap, given a keypress.
59  */
keymap_find(int keymap,struct keypress kc)60 const struct keypress *keymap_find(int keymap, struct keypress kc)
61 {
62 	struct keymap *k;
63 	assert(keymap >= 0 && keymap < KEYMAP_MODE_MAX);
64 	for (k = keymaps[keymap]; k; k = k->next) {
65 		if (k->key.code == kc.code && k->key.mods == kc.mods)
66 			return k->actions;
67 	}
68 
69 	return NULL;
70 }
71 
72 
73 /**
74  * Duplicate a given keypress string and return the duplicate.
75  */
keymap_make(const struct keypress * actions)76 static struct keypress *keymap_make(const struct keypress *actions)
77 {
78 	struct keypress *new;
79 	size_t n = 0;
80 	while (actions[n].type) {
81 		n++;
82 	}
83 
84 	/* Make room for the terminator */
85 	n += 1;
86 
87 	new = mem_zalloc(sizeof *new * n);
88 	memcpy(new, actions, sizeof *new * n);
89 
90 	new[n - 1].type = EVT_NONE;
91 
92 	return new;
93 }
94 
95 
96 /**
97  * Add a keymap to the mappings table.
98  */
keymap_add(int keymap,struct keypress trigger,struct keypress * actions,bool user)99 void keymap_add(int keymap, struct keypress trigger, struct keypress *actions, bool user)
100 {
101 	struct keymap *k = mem_zalloc(sizeof *k);
102 	assert(keymap >= 0 && keymap < KEYMAP_MODE_MAX);
103 
104 	keymap_remove(keymap, trigger);
105 
106 	k->key = trigger;
107 	k->actions = keymap_make(actions);
108 	k->user = user;
109 
110 	k->next = keymaps[keymap];
111 	keymaps[keymap] = k;
112 
113 	return;
114 }
115 
116 
117 /**
118  * Remove a keymap.  Return true if one was removed.
119  */
keymap_remove(int keymap,struct keypress trigger)120 bool keymap_remove(int keymap, struct keypress trigger)
121 {
122 	struct keymap *k;
123 	struct keymap *prev = NULL;
124 	assert(keymap >= 0 && keymap < KEYMAP_MODE_MAX);
125 
126 	for (k = keymaps[keymap]; k; k = k->next) {
127 		if (k->key.code == trigger.code && k->key.mods == trigger.mods) {
128 			mem_free(k->actions);
129 			if (prev)
130 				prev->next = k->next;
131 			else
132 				keymaps[keymap] = k->next;
133 			mem_free(k);
134 			return true;
135 		}
136 
137 		prev = k;
138 	}
139 
140 	return false;
141 }
142 
143 
144 /**
145  * Forget and free all keymaps.
146  */
keymap_free(void)147 void keymap_free(void)
148 {
149 	size_t i;
150 	struct keymap *k;
151 	for (i = 0; i < N_ELEMENTS(keymaps); i++) {
152 		k = keymaps[i];
153 		while (k) {
154 			struct keymap *next = k->next;
155 			mem_free(k->actions);
156 			mem_free(k);
157 			k = next;
158 		}
159 	}
160 }
161 
162 
163 /**
164  * Append active keymaps to a given file.
165  */
keymap_dump(ang_file * fff)166 void keymap_dump(ang_file *fff)
167 {
168 	int mode;
169 	struct keymap *k;
170 
171 	if (OPT(player, rogue_like_commands))
172 		mode = KEYMAP_MODE_ROGUE;
173 	else
174 		mode = KEYMAP_MODE_ORIG;
175 
176 	for (k = keymaps[mode]; k; k = k->next) {
177 		char buf[1024];
178 		struct keypress key[2] = { KEYPRESS_NULL, KEYPRESS_NULL };
179 
180 		if (!k->user) continue;
181 
182 		/* Encode the action */
183 		keypress_to_text(buf, sizeof(buf), k->actions, false);
184 		file_putf(fff, "keymap-act:%s\n", buf);
185 
186 		/* Convert the key into a string */
187 		key[0] = k->key;
188 		keypress_to_text(buf, sizeof(buf), key, true);
189 		file_putf(fff, "keymap-input:%d:%s\n", mode, buf);
190 
191 		file_putf(fff, "\n");
192 	}
193 }
194