1 #include <SDL_keyboard.h>
2 #include <SDL_keycode.h>
3 #include <SDL_scancode.h>
4 #include "errors.h"
5 #include "keys.h"
6 #include "asc.h"
7 #ifdef FASTER_MAP_LOAD
8 #include "io/elfilewrapper.h"
9 #endif
10 
11 // default definitions for keys
12 el_key_def K_QUIT = {SDLK_x, KMOD_LALT, "#K_QUIT"};
13 #ifdef WINDOWS
14 // Windows SDL reports [Alt Gr] as [Ctrl], which hinders German users typing '@',
15 // so don't use Ctrl-q as a symbol to exit
16 el_key_def K_QUIT_ALT = {SDLK_x, KMOD_LALT, "#K_QUIT_ALT"};
17 #elif OSX
18 el_key_def K_QUIT_ALT = {SDLK_q, KMOD_LGUI, "#K_QUIT_ALT"};
19 #else
20 el_key_def K_QUIT_ALT = {SDLK_q, KMOD_LCTRL, "#K_QUIT_ALT"};
21 #endif
22 el_key_def K_CAMERAUP = {SDLK_UP, KMOD_NONE, "#K_CAMERAUP"};
23 el_key_def K_CAMERADOWN = {SDLK_DOWN, KMOD_NONE, "#K_CAMERADOWN"};
24 el_key_def K_ZOOMOUT ={SDLK_PAGEDOWN, KMOD_NONE, "#K_ZOOMOUT"};
25 el_key_def K_ZOOMIN = {SDLK_PAGEUP, KMOD_NONE, "#K_ZOOMIN"};
26 el_key_def K_TURNLEFT = {SDLK_INSERT, KMOD_NONE, "#K_TURNLEFT"};
27 el_key_def K_TURNRIGHT = {SDLK_DELETE, KMOD_NONE, "#K_TURNRIGHT"};
28 el_key_def K_ADVANCE = {SDLK_HOME, KMOD_NONE, "#K_ADVANCE"};
29 el_key_def K_HEALTHBAR = {SDLK_h, KMOD_LALT, "#K_HEALTHBAR"};
30 el_key_def K_VIEWNAMES = {SDLK_n, KMOD_LALT, "#K_VIEWNAMES"};
31 el_key_def K_VIEWHP = {SDLK_b, KMOD_LALT, "#K_VIEWHP"};
32 el_key_def K_VIEWETHER = {SDLK_k, KMOD_LALT, "#K_VIEWETHER"};
33 el_key_def K_ETHERBARS = {SDLK_j, KMOD_LALT, "#K_ETHERBARS"};
34 el_key_def K_STATS = {SDLK_a, KMOD_LCTRL, "#K_STATS"};
35 el_key_def K_QUESTLOG = {SDLK_g, KMOD_LCTRL, "#K_QUESTLOG"};
36 el_key_def K_SESSION = {SDLK_z, KMOD_LCTRL, "#K_SESSION"};
37 el_key_def K_WALK = {SDLK_w, KMOD_LCTRL, "#K_WALK"};
38 el_key_def K_LOOK = {SDLK_l, KMOD_LCTRL, "#K_LOOK"};
39 el_key_def K_USE = {SDLK_u, KMOD_LCTRL, "#K_USE"};
40 el_key_def K_OPTIONS = {SDLK_o, KMOD_LCTRL, "#K_OPTIONS"};
41 el_key_def K_REPEATSPELL = {SDLK_r, KMOD_LCTRL, "#K_REPEATSPELL"};
42 el_key_def K_SIGILS = {SDLK_s, KMOD_LCTRL, "#K_SIGILS"};
43 el_key_def K_MANUFACTURE = {SDLK_m, KMOD_LCTRL, "#K_MANUFACTURE"};
44 el_key_def K_ITEMS = {SDLK_i, KMOD_LCTRL, "#K_ITEMS"};
45 el_key_def K_MAP = {SDLK_TAB, KMOD_NONE, "#K_MAP"};
46 el_key_def K_MINIMAP = {SDLK_m, KMOD_LALT, "#K_MINIMAP"};
47 el_key_def K_ROTATELEFT = {SDLK_LEFT, KMOD_NONE, "#K_ROTATELEFT"};
48 el_key_def K_ROTATERIGHT = {SDLK_RIGHT, KMOD_NONE, "#K_ROTATERIGHT"};
49 el_key_def K_FROTATELEFT = {SDLK_LEFT, KMOD_LSHIFT, "#K_FROTATELEFT"};
50 el_key_def K_FROTATERIGHT = {SDLK_RIGHT, KMOD_LSHIFT, "#K_FROTATERIGHT"};
51 el_key_def K_BROWSER = {SDLK_F2, KMOD_NONE, "#K_BROWSER"};
52 el_key_def K_BROWSERWIN = {SDLK_F2, KMOD_LCTRL, "#K_BROWSERWIN"};
53 el_key_def K_ESCAPE = {SDLK_ESCAPE, KMOD_NONE, "#K_ESCAPE"};
54 el_key_def K_CONSOLE = {SDLK_F1, KMOD_NONE, "#K_CONSOLE"};
55 el_key_def K_SHADOWS = {SDLK_F3, KMOD_NONE, "#K_SHADOWS"};
56 el_key_def K_KNOWLEDGE = {SDLK_k, KMOD_LCTRL, "#K_KNOWLEDGE"};
57 el_key_def K_ENCYCLOPEDIA = {SDLK_e, KMOD_LCTRL, "#K_ENCYCLOPEDIA"};
58 el_key_def K_HELP = {SDLK_h, KMOD_LCTRL, "#K_HELP"};
59 el_key_def K_NOTEPAD = {SDLK_n, KMOD_LCTRL, "#K_NOTEPAD"};
60 el_key_def K_HIDEWINS = {SDLK_d, KMOD_LALT, "#K_HIDEWINS"};
61 el_key_def K_ITEM1 = {SDLK_1, KMOD_LCTRL, "#K_ITEM1"};
62 el_key_def K_ITEM2 = {SDLK_2, KMOD_LCTRL, "#K_ITEM2"};
63 el_key_def K_ITEM3 = {SDLK_3, KMOD_LCTRL, "#K_ITEM3"};
64 el_key_def K_ITEM4 = {SDLK_4, KMOD_LCTRL, "#K_ITEM4"};
65 el_key_def K_ITEM5 = {SDLK_5, KMOD_LCTRL, "#K_ITEM5"};
66 el_key_def K_ITEM6 = {SDLK_6, KMOD_LCTRL, "#K_ITEM6"};
67 el_key_def K_ITEM7 = {SDLK_7, KMOD_LCTRL, "#K_ITEM7"};
68 el_key_def K_ITEM8 = {SDLK_8, KMOD_LCTRL, "#K_ITEM8"};
69 el_key_def K_ITEM9 = {SDLK_9, KMOD_LCTRL, "#K_ITEM9"};
70 el_key_def K_ITEM10 = {SDLK_0, KMOD_LCTRL, "#K_ITEM10"};
71 el_key_def K_ITEM11 = {SDLK_MINUS, KMOD_LCTRL, "#K_ITEM11"};
72 el_key_def K_ITEM12 = {SDLK_EQUALS, KMOD_LCTRL, "#K_ITEM12"};
73 el_key_def K_SCREENSHOT = {SDLK_p, KMOD_LCTRL, "#K_SCREENSHOT"};
74 el_key_def K_VIEWTEXTASOVERTEXT = {SDLK_o, KMOD_LALT, "#K_VIEWTEXTASOVERTEXT"};
75 el_key_def K_AFK = {SDLK_a, KMOD_LCTRL, "#K_AFK"};
76 el_key_def K_SIT = {SDLK_s, KMOD_LALT, "#K_SIT"};
77 el_key_def K_RANGINGLOCK = {SDLK_r, KMOD_LALT, "#K_RANGINGLOCK"};
78 el_key_def K_BUDDY = {SDLK_b, KMOD_LCTRL, "#K_BUDDY"};
79 el_key_def K_NEXT_CHAT_TAB = {SDLK_PAGEDOWN, KMOD_LCTRL, "#K_NEXT_CHAT_TAB"};
80 el_key_def K_PREV_CHAT_TAB = {SDLK_PAGEUP, KMOD_LCTRL, "#K_PREV_CHAT_TAB"};
81 el_key_def K_RULES = {SDLK_F5, KMOD_NONE, "#K_RULES"};
82 el_key_def K_SPELL1 = {SDLK_1, KMOD_LALT, "#K_SPELL1"};
83 el_key_def K_SPELL2 = {SDLK_2, KMOD_LALT, "#K_SPELL2"};
84 el_key_def K_SPELL3 = {SDLK_3, KMOD_LALT, "#K_SPELL3"};
85 el_key_def K_SPELL4 = {SDLK_4, KMOD_LALT, "#K_SPELL4"};
86 el_key_def K_SPELL5 = {SDLK_5, KMOD_LALT, "#K_SPELL5"};
87 el_key_def K_SPELL6 = {SDLK_6, KMOD_LALT, "#K_SPELL6"};
88 el_key_def K_SPELL7 = {SDLK_7, KMOD_LALT, "#K_SPELL7"};
89 el_key_def K_SPELL8 = {SDLK_8, KMOD_LALT, "#K_SPELL8"};
90 el_key_def K_SPELL9 = {SDLK_9, KMOD_LALT, "#K_SPELL9"};
91 el_key_def K_SPELL10 = {SDLK_0, KMOD_LALT, "#K_SPELL10"};
92 el_key_def K_SPELL11 = {SDLK_MINUS, KMOD_LALT, "#K_SPELL11"};
93 el_key_def K_SPELL12 = {SDLK_EQUALS, KMOD_LALT, "#K_SPELL12"};
94 el_key_def K_TABCOMPLETE = {SDLK_SPACE, KMOD_LCTRL, "#K_TABCOMPLETE"};
95 el_key_def K_WINDOWS_ON_TOP = {SDLK_w, KMOD_LALT, "#K_WINDOWS_ON_TOP"};
96 el_key_def K_MARKFILTER = {SDLK_f, KMOD_LCTRL, "#K_MARKFILTER"};
97 el_key_def K_OPAQUEWIN = {SDLK_d, KMOD_LCTRL, "#K_OPAQUEWIN"};
98 el_key_def K_GRAB_MOUSE = {SDLK_g, KMOD_LALT, "#K_GRAB_MOUSE"};
99 el_key_def K_FIRST_PERSON = {SDLK_f, KMOD_LALT, "#K_FIRST_PERSON"};
100 el_key_def K_EXTEND_CAM = {SDLK_e, KMOD_LALT, "#K_EXTEND_CAM"};
101 #ifndef OSX
102 el_key_def K_CUT = {SDLK_x, KMOD_LCTRL, "#K_CUT"};
103 el_key_def K_COPY = {SDLK_c, KMOD_LCTRL, "#K_COPY"};
104 el_key_def K_PASTE = {SDLK_v, KMOD_LCTRL, "#K_PASTE"};
105 #else
106 el_key_def K_CUT = {SDLK_x, KMOD_LGUI, "#K_CUT"};
107 el_key_def K_COPY = {SDLK_c, KMOD_LGUI, "#K_COPY"};
108 el_key_def K_PASTE = {SDLK_v, KMOD_LGUI, "#K_PASTE"};
109 #endif
110 el_key_def K_COPY_ALT = {SDLK_INSERT, KMOD_LCTRL, "#K_COPY_ALT"};
111 el_key_def K_PASTE_ALT = {SDLK_INSERT, KMOD_LSHIFT, "#K_PASTE_ALT"};
112 #ifdef ECDEBUGWIN
113 el_key_def K_ECDEBUGWIN = { SDLK_c, KMOD_LALT|KMOD_LCTRL, "#K_ECDEBUGWIN"};
114 #endif
115 el_key_def K_EMOTES = {SDLK_j, KMOD_LCTRL, "#K_EMOTES"};
116 el_key_def K_RANGINGWIN = {SDLK_t, KMOD_LCTRL, "#K_RANGINGWIN"};
117 el_key_def K_TARGET_CLOSE = {SDLK_t, KMOD_LALT, "#K_TARGET_CLOSE"};
118 el_key_def K_WINSCALEUP = {SDLK_UP, KMOD_LCTRL, "#K_WINSCALEUP"};
119 el_key_def K_WINSCALEDOWN = {SDLK_DOWN, KMOD_LCTRL, "#K_WINSCALEDOWN"};
120 el_key_def K_WINSCALEDEF = {SDLK_HOME, KMOD_LCTRL, "#K_WINSCALEDEF"};
121 el_key_def K_WINSCALEINIT = {SDLK_END, KMOD_LCTRL, "#K_WINSCALEINIT"};
122 el_key_def K_SUMMONINGMENU = {SDLK_u, KMOD_LALT, "#K_SUMMONINGMENU"};
123 el_key_def K_CHAT = {SDLK_c, KMOD_LALT, "#K_CHAT"};
124 // Dont forget to add to key_def_store[]
125 
126 // Remaining keys are not assigned to the keyboard but
127 // can be redefined or used by the #keypress command.
128 // They will get values at startup along with any keys
129 // undefined in key.ini
130 el_key_def K_COUNTERS = {SDLK_UNKNOWN, KMOD_NONE, "#K_COUNTERS"};
131 el_key_def K_HELPSKILLS = {SDLK_UNKNOWN, KMOD_NONE, "#K_HELPSKILLS"};
132 
133 // a table of key definition, so we can search for definitions
134 static el_key_def *key_def_store[] =
135 {
136 	&K_ADVANCE, &K_AFK, &K_BROWSER, &K_BROWSERWIN, &K_BUDDY, &K_CAMERADOWN, &K_CAMERAUP, &K_CHAT,
137 	&K_CONSOLE, &K_COPY, &K_COPY_ALT, &K_COUNTERS, &K_CUT, &K_EMOTES, &K_ENCYCLOPEDIA, &K_ESCAPE,
138 	&K_ETHERBARS, &K_EXTEND_CAM, &K_FIRST_PERSON, &K_FROTATELEFT, &K_FROTATERIGHT, &K_GRAB_MOUSE,
139 	&K_HEALTHBAR, &K_HELP, &K_HELPSKILLS, &K_HIDEWINS, &K_ITEM1, &K_ITEM10, &K_ITEM11, &K_ITEM12,
140 	&K_ITEM2, &K_ITEM3, &K_ITEM4, &K_ITEM5, &K_ITEM6, &K_ITEM7, &K_ITEM8, &K_ITEM9, &K_ITEMS,
141 	&K_KNOWLEDGE, &K_LOOK, &K_MANUFACTURE, &K_MAP, &K_MARKFILTER, &K_MINIMAP, &K_NEXT_CHAT_TAB,
142 	&K_NOTEPAD, &K_OPAQUEWIN, &K_OPTIONS, &K_PASTE, &K_PASTE_ALT, &K_PREV_CHAT_TAB, &K_QUESTLOG,
143 	&K_QUIT, &K_QUIT_ALT, &K_RANGINGLOCK, &K_RANGINGWIN, &K_REPEATSPELL, &K_ROTATELEFT,
144 	&K_ROTATERIGHT, &K_RULES, &K_SCREENSHOT, &K_SESSION, &K_SHADOWS, &K_SIGILS, &K_SIT, &K_SPELL1,
145 	&K_SPELL10, &K_SPELL11, &K_SPELL12, &K_SPELL2, &K_SPELL3, &K_SPELL4, &K_SPELL5, &K_SPELL6,
146 	&K_SPELL7, &K_SPELL8, &K_SPELL9, &K_STATS, &K_SUMMONINGMENU, &K_TABCOMPLETE, &K_TARGET_CLOSE,
147 	&K_TURNLEFT, &K_TURNRIGHT, &K_USE, &K_VIEWETHER, &K_VIEWHP, &K_VIEWNAMES,
148 	&K_VIEWTEXTASOVERTEXT, &K_WALK, &K_WINDOWS_ON_TOP, &K_WINSCALEDEF, &K_WINSCALEDOWN,
149 	&K_WINSCALEINIT, &K_WINSCALEUP, &K_ZOOMIN, &K_ZOOMOUT,
150 #ifdef ECDEBUGWIN
151 	&K_ECDEBUGWIN
152 #endif
153 };
154 
get_key_value(const char * name)155 el_key_def get_key_value(const char* name)
156 {
157 	size_t num_keys = sizeof(key_def_store)/sizeof(el_key_def *);
158 	el_key_def null_key_def = {SDLK_UNKNOWN, KMOD_NONE, ""};
159 	size_t i;
160 
161 	if ((name == NULL) || strlen(name) == 0)
162 	{
163 		LOG_ERROR("%s() empty name\n", __FUNCTION__);
164 		return null_key_def;
165 	}
166 	for (i=0; i<num_keys; i++)
167 	{
168 		if (strcasecmp(name, key_def_store[i]->name) == 0)
169 			return *key_def_store[i];
170 	}
171 	return null_key_def;
172 }
173 
CRC32(const char * data,int len)174 static Uint32 CRC32(const char *data, int len)
175 {
176 	unsigned int result = 0;
177 	int i, j;
178 	unsigned char octet;
179 
180 	for (i = 0; i < len; i++)
181 	{
182 		octet = *(data++);
183 		for (j = 0; j < 8; j++)
184 		{
185 			if ((octet >> 7) ^ (result >> 31))
186 				result = (result << 1) ^ 0x04c11db7;
187 			else
188 				result = (result << 1);
189 			octet <<= 1;
190 		}
191 	}
192 
193 	return ~result;
194 }
195 
196 // Using the key names from https://wiki.libsdl.org/SDL_Keycode,
197 // we can convert a specified input from the key.ini (or defaults)
198 // to the actual key code to use.
add_to_key_def(el_key_def * key_def,char * name)199 static void add_to_key_def(el_key_def *key_def, char *name)
200 {
201 	SDL_Keycode key_code;
202 	size_t i;
203 
204 	// the key names can contain spaces so we replace space with underscore
205 	// when defining keys and convert them to real key name, here.
206 	for (i=0; i<strlen(name); i++)
207 		if (name[i] == '_')
208 			name[i] = ' ';
209 
210 	// the key code is found from the key name...
211 	key_code = SDL_GetKeyFromName(name);
212 	if (key_code != SDLK_UNKNOWN)
213 		key_def->key_code = key_code;
214 
215 	// ...any modifiers from this hash version of the string.
216 	else
217 	{
218 		int len = strlen(name);
219 		Uint32 crc = CRC32(name,len);
220 		switch(crc){
221 			case 0x6fa8765e: key_def->key_mod |= KMOD_RSHIFT; break; //RSHIFT
222 			case 0x5a59f8b9: key_def->key_mod |= KMOD_LSHIFT; break; //LSHIFT
223 			case 0xc535c663: key_def->key_mod |= KMOD_RCTRL; break; //RCTRL
224 			case 0xb5e083f0: key_def->key_mod |= KMOD_LCTRL; break; //LCTRL
225 			case 0xf7a834fb: key_def->key_mod |= KMOD_RALT; break; //RALT
226 			case 0x39b9e58e: key_def->key_mod |= KMOD_LALT; break; //LALT
227 			case 0x34796737: key_def->key_mod |= KMOD_RGUI; break; //RMETA
228 			case 0x44ac22a4: key_def->key_mod |= KMOD_LGUI; break; //LMETA
229 		}
230 	}
231 }
232 
parse_key_line(const char * line)233 static void parse_key_line(const char *line)
234 {
235 	char kstr[100]="", t1[100]="", t2[100]="", t3[100]="", t4[100]="";
236 	el_key_def key_def = {SDLK_UNKNOWN, KMOD_NONE, "Unassigned"};
237 	int nkey = sscanf(line, " #K_%99s = %99s %99s %99s %99s", kstr, t1, t2, t3, t4);
238 	size_t num_keys = sizeof(key_def_store)/sizeof(el_key_def *);
239 	size_t i;
240 
241 	if (nkey <= 1)
242 		return;
243 
244 	add_to_key_def(&key_def, t1);
245 	if (nkey > 2 && t2[0] != '#')
246 	{
247 		add_to_key_def(&key_def, t2);
248 		if (nkey > 3 && t3[0] != '#')
249 		{
250 			add_to_key_def(&key_def, t3);
251 			if (nkey > 4 && t4[0] != '#')
252 			{
253 				add_to_key_def(&key_def, t4);
254 			}
255 		}
256 	}
257 
258 	for (i=0; i<num_keys; i++)
259 		if (strcasecmp(kstr, &key_def_store[i]->name[3]) == 0) // skip "#K_"
260 		{
261 			key_def_store[i]->key_code = key_def.key_code;
262 			key_def_store[i]->key_mod = key_def.key_mod;
263 			//printf("Key def read: Name=%s New Keycode=%d,[%s] New Keymod=%d\n", key_def_store[i]->name, key_def_store[i]->key_code, SDL_GetKeyName(key_def_store[i]->key_code), key_def_store[i]->key_mod);
264 			break;
265 		}
266 }
267 
268 // load the dynamic definitions for keys
read_key_config(void)269 void read_key_config(void)
270 {
271 	char line[512];
272 	el_file_ptr f;
273 	size_t num_keys = sizeof(key_def_store)/sizeof(el_key_def *);
274 	size_t i;
275 	SDL_Keycode last_key_code_value = SDL_NUM_SCANCODES;
276 
277 	f = el_open_custom("key.ini");
278 	if (f)
279 	{
280 		while (el_fgets(line, sizeof(line), f))
281 			parse_key_line(line);
282 		el_close(f);
283 	}
284 
285 	// look for unassigned keys and assign one up from last defined key
286 	for (i=0; i<num_keys; i++)
287 		if (key_def_store[i]->key_code == SDLK_UNKNOWN)
288 			key_def_store[i]->key_code = SDL_SCANCODE_TO_KEYCODE(++last_key_code_value);
289 }
290 
291 // Returns (in the buffer provided) a string describing the specified keydef.
get_key_string(el_key_def keydef,char * buf,size_t buflen)292 const char *get_key_string(el_key_def keydef, char *buf, size_t buflen)
293 {
294 	size_t i;
295 	char *mod = "";
296 	if (keydef.key_mod & KMOD_LCTRL)
297 		mod = "lctrl-";
298 	else if (keydef.key_mod == KMOD_RCTRL)
299 		mod = "rctrl-";
300 	else if (keydef.key_mod == KMOD_CTRL)
301 		mod = "ctrl-";
302 	else if (keydef.key_mod == KMOD_LALT)
303 		mod = "lalt-";
304 	else if (keydef.key_mod == KMOD_RALT)
305 		mod = "ralt-";
306 	else if (keydef.key_mod == KMOD_ALT)
307 		mod = "alt-";
308 	else if (keydef.key_mod == KMOD_LSHIFT)
309 		mod = "lshift-";
310 	else if (keydef.key_mod == KMOD_RSHIFT)
311 		mod = "rshift-";
312 	else if (keydef.key_mod == KMOD_SHIFT)
313 		mod = "shift-";
314 	safe_snprintf(buf, buflen, "%s%s", mod, SDL_GetKeyName(keydef.key_code));
315 	for (i = 0; buf[i]; i++)
316 		buf[i] = tolower(buf[i]);
317 	return buf;
318 }
319