Added new keymap implementation

Signed-off-by: Slava Zanko <slavazanko@gmail.com>
This commit is contained in:
Slava Zanko 2014-04-22 17:46:20 +03:00
parent 5d8d42c239
commit 785144d625
3 changed files with 487 additions and 0 deletions

View File

@ -38,6 +38,7 @@ libmc_la_SOURCES = \
glibcompat.c glibcompat.h \
global.c global.h \
keybind.c keybind.h \
keymap.c keymap.h \
lock.c lock.h \
serialize.c serialize.h \
timefmt.c timefmt.h \

435
lib/keymap.c Normal file
View File

@ -0,0 +1,435 @@
/*
Handle keyspresses and bind them to events.
Copyright (C) 2005-2014
Free Software Foundation, Inc.
Written by:
Vitja Makarov, 2005
Ilia Maslakov <il.smind@gmail.com>, 2009, 2012
Andrew Borodin <aborodin@vmail.ru>, 2009, 2010, 2011, 2012
Totally rewritten by:
Slava Zanko <slavazanko@gmail.com>, 2014
This file is part of the Midnight Commander.
The Midnight Commander is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
The Midnight Commander is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "lib/global.h"
#include "lib/event.h"
#include "lib/keymap.h"
#include "lib/tty/key.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
#define MC_KEYMAP_EVENT_GROUP "keymap"
#define MC_KEYMAP_EVENT_SWITCH_GROUP_NAME "switch_group"
#define KEYMAP_ERR_NOT_INITIALIZED N_ ("Keymap system not initialized")
#define KEYMAP_ERR_INPUT_DATA N_ ("Check input data! Some of parameters are NULL!")
/*** file scope type declarations ****************************************************************/
typedef struct
{
long code;
const char *name;
} mc_keymap_keycode_t;
typedef struct
{
char *group;
char *name;
char *switch_group;
} mc_keymap_event_t;
typedef struct
{
GTree *keymap_group;
const char *name;
} mc_keymap_clear_keycodes_t;
/*** file scope variables ************************************************************************/
static GTree *all_key_codes = NULL;
static GTree *all_key_events = NULL;
static const char *switched_group = NULL;
static gboolean switch_group_cmd_was_called = FALSE;
/*** file scope functions ************************************************************************/
/* --------------------------------------------------------------------------------------------- */
/* event callback */
static gboolean
mc_keymap_cmd_switch_group (event_info_t * event_info, gpointer data, GError ** error)
{
(void) event_info;
(void) error;
switched_group = (const char *) data;
switch_group_cmd_was_called = TRUE;
return TRUE;
}
/* --------------------------------------------------------------------------------------------- */
static gboolean
mc_keymap_is_initialised (GError ** error)
{
if (all_key_codes == NULL)
{
g_propagate_error (error, g_error_new (MC_ERROR, 1, _(KEYMAP_ERR_NOT_INITIALIZED)));
return FALSE;
}
return TRUE;
}
/* --------------------------------------------------------------------------------------------- */
static gint
mc_keymap_keycode_compare (gconstpointer a, gconstpointer b)
{
return (a > b) ? 1 : (a < b) ? -1 : 0;
}
/* --------------------------------------------------------------------------------------------- */
static GTree *
mc_keymap_get_key_group (const char *group, GError ** error)
{
GTree *keymap_group;
keymap_group = (GTree *) g_tree_lookup (all_key_codes, (gconstpointer) group);
if (keymap_group == NULL)
{
keymap_group =
g_tree_new_full ((GCompareDataFunc) mc_keymap_keycode_compare, NULL, NULL,
(GDestroyNotify) g_free);
if (keymap_group == NULL)
g_propagate_error (error,
g_error_new (MC_ERROR, 1,
_("Unable to create group '%s' for keymaps!"), group));
else
g_tree_insert (all_key_codes, g_strdup (group), (gpointer) keymap_group);
}
return keymap_group;
}
/* --------------------------------------------------------------------------------------------- */
static gboolean
mc_keymap_clear_keycodes (gpointer key, gpointer value, gpointer data)
{
mc_keymap_clear_keycodes_t *keymap_data = (mc_keymap_clear_keycodes_t *) data;
if (strcmp (value, keymap_data->name) == 0)
g_tree_remove (keymap_data->keymap_group, key);
return FALSE;
}
/* --------------------------------------------------------------------------------------------- */
static void
mc_keymap_add_keycode_to_group (GTree * keymap_group, const char *name,
const char *pressed_keynames, gboolean isDeleteOld)
{
char **keyname_list, **one_keyname;
keyname_list = g_strsplit_set (pressed_keynames, ";", -1);
if (isDeleteOld)
{
mc_keymap_clear_keycodes_t data = {
.keymap_group = keymap_group,
.name = name
};
g_tree_foreach (keymap_group, mc_keymap_clear_keycodes, &data);
}
for (one_keyname = keyname_list; one_keyname != NULL && *one_keyname != NULL; one_keyname++)
{
long keycode;
char *caption = NULL;
if ((*one_keyname)[0] == '\0')
continue;
keycode = lookup_key (*one_keyname, &caption);
g_tree_replace (keymap_group, (void *) keycode, g_strdup (name));
g_free (caption);
}
g_strfreev (keyname_list);
}
/* --------------------------------------------------------------------------------------------- */
static char *
keymap_make_event_key (const char *group, const char *name)
{
return g_strdup_printf ("[%s][%s]", group, name);
}
/* --------------------------------------------------------------------------------------------- */
static mc_keymap_event_t *
keymap_get_event (const char *group, const char *name)
{
char *event_key;
mc_keymap_event_t *ret_value;
event_key = keymap_make_event_key (group, name);
ret_value = (mc_keymap_event_t *) g_tree_lookup (all_key_events, (gconstpointer) event_key);
g_free (event_key);
return ret_value;
}
/* --------------------------------------------------------------------------------------------- */
static void
keymap_event_free (mc_keymap_event_t * keymap_event)
{
g_free (keymap_event->group);
g_free (keymap_event->name);
g_free (keymap_event->switch_group);
g_free (keymap_event);
}
/* --------------------------------------------------------------------------------------------- */
static gboolean
mc_keymap_bind_event_with_data (const char *group, const char *name, const char *event_group,
const char *event_name, const char *switch_group, GError ** error)
{
char *event_key;
mc_keymap_event_t *keymap_event;
if (!mc_keymap_is_initialised (error))
return FALSE;
event_key = keymap_make_event_key (group, name);
keymap_event = g_new (mc_keymap_event_t, 1);
keymap_event->group = g_strdup (event_group);
keymap_event->name = g_strdup (event_name);
keymap_event->switch_group = g_strdup (switch_group);
g_tree_replace (all_key_events, event_key, (gpointer) keymap_event);
return TRUE;
}
/* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */
gboolean
mc_keymap_init (GError ** error)
{
if (all_key_codes != NULL)
{
g_propagate_error (error,
g_error_new (MC_ERROR, 1, _("Keymap system already initialized")));
return FALSE;
}
all_key_codes =
g_tree_new_full ((GCompareDataFunc) g_ascii_strcasecmp,
NULL, (GDestroyNotify) g_free, (GDestroyNotify) g_tree_destroy);
if (all_key_codes == NULL)
{
g_propagate_error (error, g_error_new (MC_ERROR, 2, _(KEYMAP_ERR_NOT_INITIALIZED)));
return FALSE;
}
all_key_events = g_tree_new_full ((GCompareDataFunc) g_ascii_strcasecmp,
NULL, (GDestroyNotify) g_free,
(GDestroyNotify) keymap_event_free);
if (all_key_events == NULL)
{
g_propagate_error (error, g_error_new (MC_ERROR, 2, _(KEYMAP_ERR_NOT_INITIALIZED)));
g_tree_destroy (all_key_codes);
return FALSE;
}
mc_event_add (MC_KEYMAP_EVENT_GROUP, MC_KEYMAP_EVENT_SWITCH_GROUP_NAME,
mc_keymap_cmd_switch_group, NULL, error);
return TRUE;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mc_keymap_deinit (GError ** error)
{
if (!mc_keymap_is_initialised (error))
return FALSE;
g_tree_destroy (all_key_codes);
all_key_codes = NULL;
g_tree_destroy (all_key_events);
all_key_events = NULL;
return TRUE;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mc_keymap_bind_keycode (const char *group, const char *name, const char *pressed_keynames,
gboolean isDeleteOld, GError ** error)
{
GTree *keymap_group;
if (!mc_keymap_is_initialised (error))
return FALSE;
if (group == NULL || name == NULL)
{
g_propagate_error (error, g_error_new (MC_ERROR, 1, _(KEYMAP_ERR_INPUT_DATA)));
return FALSE;
}
keymap_group = mc_keymap_get_key_group (group, error);
if (keymap_group == NULL)
return FALSE;
mc_keymap_add_keycode_to_group (keymap_group, name, pressed_keynames, isDeleteOld);
return TRUE;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mc_keymap_bind_event (const char *group, const char *name, const char *event_group,
const char *event_name, GError ** error)
{
return mc_keymap_bind_event_with_data (group, name, event_group, event_name, NULL, error);
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mc_keymap_bind_switch_event (const char *group, const char *name, const char *switch_group,
GError ** error)
{
return mc_keymap_bind_event_with_data (group, name, MC_KEYMAP_EVENT_GROUP,
MC_KEYMAP_EVENT_SWITCH_GROUP_NAME, switch_group, error);
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mc_keymap_mass_bind_event (const mc_keymap_event_init_t * group_keymap_events, GError ** error)
{
size_t array_group_index;
gboolean ret_value = TRUE;
for (array_group_index = 0; group_keymap_events[array_group_index].group != NULL;
array_group_index++)
{
size_t array_index;
const char *group_name = group_keymap_events[array_group_index].group;
const mc_keymap_event_init_group_t *keymap_events =
group_keymap_events[array_group_index].keymap_events;
for (array_index = 0; keymap_events[array_index].name != NULL; array_index++)
if (!mc_keymap_bind_event (group_name, keymap_events[array_index].name,
keymap_events[array_index].event_group,
keymap_events[array_index].event_name, error))
{
ret_value = FALSE;
break;
}
}
return ret_value;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
mc_keymap_process_group (const char *group, long pressed_keycode, void *data, event_return_t * ret,
GError ** error)
{
const char *key_name;
mc_keymap_event_t *keymap_event;
gboolean ret_value;
if (switched_group != NULL)
{
group = switched_group;
switched_group = NULL;
}
key_name = mc_keymap_get_key_name_by_code (group, pressed_keycode, error);
if (key_name == NULL)
return FALSE;
keymap_event = keymap_get_event (group, key_name);
if (keymap_event == NULL)
return FALSE;
if (keymap_event->switch_group != NULL)
data = keymap_event->switch_group;
ret_value = mc_event_raise (keymap_event->group, keymap_event->name, data, ret, error);
if (switch_group_cmd_was_called && switched_group == NULL)
{
switched_group = group;
switch_group_cmd_was_called = FALSE;
}
return ret_value;
}
/* --------------------------------------------------------------------------------------------- */
const char *
mc_keymap_get_key_name_by_code (const char *group, long pressed_keycode, GError ** error)
{
GTree *keymap_group;
keymap_group = mc_keymap_get_key_group (group, error);
if (keymap_group == NULL)
return FALSE;
return (const char *) g_tree_lookup (keymap_group, (gconstpointer) pressed_keycode);
}
/* --------------------------------------------------------------------------------------------- */

51
lib/keymap.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef MC__KEYMAP_H
#define MC__KEYMAP_H
#include "lib/event.h"
/*** typedefs(not structures) and defined constants **********************************************/
typedef struct
{
const char *name;
const char *event_group;
const char *event_name;
} mc_keymap_event_init_group_t;
typedef struct
{
const char *group;
const mc_keymap_event_init_group_t *keymap_events;
} mc_keymap_event_init_t;
/*** enums ***************************************************************************************/
/*** structures declarations (and typedefs of structures)*****************************************/
/*** global variables defined in .c file *********************************************************/
/*** declarations of public functions ************************************************************/
gboolean mc_keymap_init (GError ** error);
gboolean mc_keymap_deinit (GError ** error);
gboolean mc_keymap_bind_keycode (const char *group, const char *name, const char *pressed_keynames,
gboolean isDeleteOld, GError ** error);
gboolean mc_keymap_bind_event (const char *group, const char *name, const char *event_group,
const char *event_name, GError ** error);
gboolean mc_keymap_mass_bind_event (const mc_keymap_event_init_t *, GError ** error);
gboolean mc_keymap_bind_switch_event (const char *group, const char *name, const char *switch_group,
GError ** error);
gboolean mc_keymap_process_group (const char *group, long pressed_keycode, void *data,
event_return_t * ret, GError ** error);
const char *mc_keymap_get_key_name_by_code (const char *group, long pressed_keycode,
GError ** error);
/*** inline functions ****************************************************************************/
#endif /* MC__KEYMAP_H */