keymap.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /*
  2. Handle keyspresses and bind them to events.
  3. Copyright (C) 2005-2014
  4. Free Software Foundation, Inc.
  5. Written by:
  6. Vitja Makarov, 2005
  7. Ilia Maslakov <il.smind@gmail.com>, 2009, 2012
  8. Andrew Borodin <aborodin@vmail.ru>, 2009, 2010, 2011, 2012
  9. Totally rewritten by:
  10. Slava Zanko <slavazanko@gmail.com>, 2014
  11. This file is part of the Midnight Commander.
  12. The Midnight Commander is free software: you can redistribute it
  13. and/or modify it under the terms of the GNU General Public License as
  14. published by the Free Software Foundation, either version 3 of the License,
  15. or (at your option) any later version.
  16. The Midnight Commander is distributed in the hope that it will be useful,
  17. but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. GNU General Public License for more details.
  20. You should have received a copy of the GNU General Public License
  21. along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. #include <config.h>
  24. #include "lib/global.h"
  25. #include "lib/event.h"
  26. #include "lib/keymap.h"
  27. #include "lib/tty/key.h"
  28. /*** global variables ****************************************************************************/
  29. /*** file scope macro definitions ****************************************************************/
  30. #define MC_KEYMAP_EVENT_GROUP "keymap"
  31. #define MC_KEYMAP_EVENT_SWITCH_GROUP_NAME "switch_group"
  32. #define KEYMAP_ERR_NOT_INITIALIZED N_ ("Keymap system not initialized")
  33. #define KEYMAP_ERR_INPUT_DATA N_ ("Check input data! Some of parameters are NULL!")
  34. /*** file scope type declarations ****************************************************************/
  35. typedef struct
  36. {
  37. long code;
  38. const char *name;
  39. } mc_keymap_keycode_t;
  40. typedef struct
  41. {
  42. char *group;
  43. char *name;
  44. char *switch_group;
  45. } mc_keymap_event_t;
  46. typedef struct
  47. {
  48. GTree *keymap_group;
  49. const char *name;
  50. } mc_keymap_clear_keycodes_t;
  51. /*** file scope variables ************************************************************************/
  52. static GTree *all_key_codes = NULL;
  53. static GTree *all_key_events = NULL;
  54. static const char *switched_group = NULL;
  55. static gboolean switch_group_cmd_was_called = FALSE;
  56. /*** file scope functions ************************************************************************/
  57. /* --------------------------------------------------------------------------------------------- */
  58. /* event callback */
  59. static gboolean
  60. mc_keymap_cmd_switch_group (event_info_t * event_info, gpointer data, GError ** error)
  61. {
  62. (void) event_info;
  63. (void) error;
  64. switched_group = (const char *) data;
  65. switch_group_cmd_was_called = TRUE;
  66. return TRUE;
  67. }
  68. /* --------------------------------------------------------------------------------------------- */
  69. static gboolean
  70. mc_keymap_is_initialised (GError ** error)
  71. {
  72. if (all_key_codes == NULL)
  73. {
  74. g_propagate_error (error, g_error_new (MC_ERROR, 1, _(KEYMAP_ERR_NOT_INITIALIZED)));
  75. return FALSE;
  76. }
  77. return TRUE;
  78. }
  79. /* --------------------------------------------------------------------------------------------- */
  80. static gint
  81. mc_keymap_keycode_compare (gconstpointer a, gconstpointer b)
  82. {
  83. return (a > b) ? 1 : (a < b) ? -1 : 0;
  84. }
  85. /* --------------------------------------------------------------------------------------------- */
  86. static GTree *
  87. mc_keymap_get_key_group (const char *group, GError ** error)
  88. {
  89. GTree *keymap_group;
  90. keymap_group = (GTree *) g_tree_lookup (all_key_codes, (gconstpointer) group);
  91. if (keymap_group == NULL)
  92. {
  93. keymap_group =
  94. g_tree_new_full ((GCompareDataFunc) mc_keymap_keycode_compare, NULL, NULL,
  95. (GDestroyNotify) g_free);
  96. if (keymap_group == NULL)
  97. g_propagate_error (error,
  98. g_error_new (MC_ERROR, 1,
  99. _("Unable to create group '%s' for keymaps!"), group));
  100. else
  101. g_tree_insert (all_key_codes, g_strdup (group), (gpointer) keymap_group);
  102. }
  103. return keymap_group;
  104. }
  105. /* --------------------------------------------------------------------------------------------- */
  106. static gboolean
  107. mc_keymap_clear_keycodes (gpointer key, gpointer value, gpointer data)
  108. {
  109. mc_keymap_clear_keycodes_t *keymap_data = (mc_keymap_clear_keycodes_t *) data;
  110. if (strcmp (value, keymap_data->name) == 0)
  111. g_tree_remove (keymap_data->keymap_group, key);
  112. return FALSE;
  113. }
  114. /* --------------------------------------------------------------------------------------------- */
  115. static void
  116. mc_keymap_add_keycode_to_group (GTree * keymap_group, const char *name,
  117. const char *pressed_keynames, gboolean isDeleteOld)
  118. {
  119. char **keyname_list, **one_keyname;
  120. keyname_list = g_strsplit_set (pressed_keynames, ";", -1);
  121. if (isDeleteOld)
  122. {
  123. mc_keymap_clear_keycodes_t data = {
  124. .keymap_group = keymap_group,
  125. .name = name
  126. };
  127. g_tree_foreach (keymap_group, mc_keymap_clear_keycodes, &data);
  128. }
  129. for (one_keyname = keyname_list; one_keyname != NULL && *one_keyname != NULL; one_keyname++)
  130. {
  131. long keycode;
  132. char *caption = NULL;
  133. if ((*one_keyname)[0] == '\0')
  134. continue;
  135. keycode = lookup_key (*one_keyname, &caption);
  136. g_tree_replace (keymap_group, (void *) keycode, g_strdup (name));
  137. g_free (caption);
  138. }
  139. g_strfreev (keyname_list);
  140. }
  141. /* --------------------------------------------------------------------------------------------- */
  142. static char *
  143. keymap_make_event_key (const char *group, const char *name)
  144. {
  145. return g_strdup_printf ("[%s][%s]", group, name);
  146. }
  147. /* --------------------------------------------------------------------------------------------- */
  148. static mc_keymap_event_t *
  149. keymap_get_event (const char *group, const char *name)
  150. {
  151. char *event_key;
  152. mc_keymap_event_t *ret_value;
  153. event_key = keymap_make_event_key (group, name);
  154. ret_value = (mc_keymap_event_t *) g_tree_lookup (all_key_events, (gconstpointer) event_key);
  155. g_free (event_key);
  156. return ret_value;
  157. }
  158. /* --------------------------------------------------------------------------------------------- */
  159. static void
  160. keymap_event_free (mc_keymap_event_t * keymap_event)
  161. {
  162. g_free (keymap_event->group);
  163. g_free (keymap_event->name);
  164. g_free (keymap_event->switch_group);
  165. g_free (keymap_event);
  166. }
  167. /* --------------------------------------------------------------------------------------------- */
  168. static gboolean
  169. mc_keymap_bind_event_with_data (const char *group, const char *name, const char *event_group,
  170. const char *event_name, const char *switch_group, GError ** error)
  171. {
  172. char *event_key;
  173. mc_keymap_event_t *keymap_event;
  174. if (!mc_keymap_is_initialised (error))
  175. return FALSE;
  176. event_key = keymap_make_event_key (group, name);
  177. keymap_event = g_new (mc_keymap_event_t, 1);
  178. keymap_event->group = g_strdup (event_group);
  179. keymap_event->name = g_strdup (event_name);
  180. keymap_event->switch_group = g_strdup (switch_group);
  181. g_tree_replace (all_key_events, event_key, (gpointer) keymap_event);
  182. return TRUE;
  183. }
  184. /* --------------------------------------------------------------------------------------------- */
  185. /*** public functions ****************************************************************************/
  186. /* --------------------------------------------------------------------------------------------- */
  187. gboolean
  188. mc_keymap_init (GError ** error)
  189. {
  190. if (all_key_codes != NULL)
  191. {
  192. g_propagate_error (error,
  193. g_error_new (MC_ERROR, 1, _("Keymap system already initialized")));
  194. return FALSE;
  195. }
  196. all_key_codes =
  197. g_tree_new_full ((GCompareDataFunc) g_ascii_strcasecmp,
  198. NULL, (GDestroyNotify) g_free, (GDestroyNotify) g_tree_destroy);
  199. if (all_key_codes == NULL)
  200. {
  201. g_propagate_error (error, g_error_new (MC_ERROR, 2, _(KEYMAP_ERR_NOT_INITIALIZED)));
  202. return FALSE;
  203. }
  204. all_key_events = g_tree_new_full ((GCompareDataFunc) g_ascii_strcasecmp,
  205. NULL, (GDestroyNotify) g_free,
  206. (GDestroyNotify) keymap_event_free);
  207. if (all_key_events == NULL)
  208. {
  209. g_propagate_error (error, g_error_new (MC_ERROR, 2, _(KEYMAP_ERR_NOT_INITIALIZED)));
  210. g_tree_destroy (all_key_codes);
  211. return FALSE;
  212. }
  213. mc_event_add (MC_KEYMAP_EVENT_GROUP, MC_KEYMAP_EVENT_SWITCH_GROUP_NAME,
  214. mc_keymap_cmd_switch_group, NULL, error);
  215. return TRUE;
  216. }
  217. /* --------------------------------------------------------------------------------------------- */
  218. gboolean
  219. mc_keymap_deinit (GError ** error)
  220. {
  221. if (!mc_keymap_is_initialised (error))
  222. return FALSE;
  223. g_tree_destroy (all_key_codes);
  224. all_key_codes = NULL;
  225. g_tree_destroy (all_key_events);
  226. all_key_events = NULL;
  227. return TRUE;
  228. }
  229. /* --------------------------------------------------------------------------------------------- */
  230. gboolean
  231. mc_keymap_bind_keycode (const char *group, const char *name, const char *pressed_keynames,
  232. gboolean isDeleteOld, GError ** error)
  233. {
  234. GTree *keymap_group;
  235. if (!mc_keymap_is_initialised (error))
  236. return FALSE;
  237. if (group == NULL || name == NULL)
  238. {
  239. g_propagate_error (error, g_error_new (MC_ERROR, 1, _(KEYMAP_ERR_INPUT_DATA)));
  240. return FALSE;
  241. }
  242. keymap_group = mc_keymap_get_key_group (group, error);
  243. if (keymap_group == NULL)
  244. return FALSE;
  245. mc_keymap_add_keycode_to_group (keymap_group, name, pressed_keynames, isDeleteOld);
  246. return TRUE;
  247. }
  248. /* --------------------------------------------------------------------------------------------- */
  249. gboolean
  250. mc_keymap_bind_event (const char *group, const char *name, const char *event_group,
  251. const char *event_name, GError ** error)
  252. {
  253. return mc_keymap_bind_event_with_data (group, name, event_group, event_name, NULL, error);
  254. }
  255. /* --------------------------------------------------------------------------------------------- */
  256. gboolean
  257. mc_keymap_bind_switch_event (const char *group, const char *name, const char *switch_group,
  258. GError ** error)
  259. {
  260. return mc_keymap_bind_event_with_data (group, name, MC_KEYMAP_EVENT_GROUP,
  261. MC_KEYMAP_EVENT_SWITCH_GROUP_NAME, switch_group, error);
  262. }
  263. /* --------------------------------------------------------------------------------------------- */
  264. gboolean
  265. mc_keymap_mass_bind_event (const mc_keymap_event_init_t * group_keymap_events, GError ** error)
  266. {
  267. size_t array_group_index;
  268. gboolean ret_value = TRUE;
  269. for (array_group_index = 0; group_keymap_events[array_group_index].group != NULL;
  270. array_group_index++)
  271. {
  272. size_t array_index;
  273. const char *group_name = group_keymap_events[array_group_index].group;
  274. const mc_keymap_event_init_group_t *keymap_events =
  275. group_keymap_events[array_group_index].keymap_events;
  276. for (array_index = 0; keymap_events[array_index].name != NULL; array_index++)
  277. if (!mc_keymap_bind_event (group_name, keymap_events[array_index].name,
  278. keymap_events[array_index].event_group,
  279. keymap_events[array_index].event_name, error))
  280. {
  281. ret_value = FALSE;
  282. break;
  283. }
  284. }
  285. return ret_value;
  286. }
  287. /* --------------------------------------------------------------------------------------------- */
  288. gboolean
  289. mc_keymap_process_group (const char *group, long pressed_keycode, void *data, event_return_t * ret,
  290. GError ** error)
  291. {
  292. const char *key_name;
  293. mc_keymap_event_t *keymap_event;
  294. gboolean ret_value;
  295. if (switched_group != NULL)
  296. {
  297. group = switched_group;
  298. switched_group = NULL;
  299. }
  300. key_name = mc_keymap_get_key_name_by_code (group, pressed_keycode, error);
  301. if (key_name == NULL)
  302. return FALSE;
  303. keymap_event = keymap_get_event (group, key_name);
  304. if (keymap_event == NULL)
  305. return FALSE;
  306. if (keymap_event->switch_group != NULL)
  307. data = keymap_event->switch_group;
  308. ret_value = mc_event_dispatch (keymap_event->group, keymap_event->name, data, ret, error);
  309. if (switch_group_cmd_was_called && switched_group == NULL)
  310. {
  311. switched_group = group;
  312. switch_group_cmd_was_called = FALSE;
  313. }
  314. return ret_value;
  315. }
  316. /* --------------------------------------------------------------------------------------------- */
  317. const char *
  318. mc_keymap_get_key_name_by_code (const char *group, long pressed_keycode, GError ** error)
  319. {
  320. GTree *keymap_group;
  321. keymap_group = mc_keymap_get_key_group (group, error);
  322. if (keymap_group == NULL)
  323. return FALSE;
  324. return (const char *) g_tree_lookup (keymap_group, (gconstpointer) pressed_keycode);
  325. }
  326. /* --------------------------------------------------------------------------------------------- */