2014-04-07 14:48:16 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 Red Hat
|
|
|
|
*
|
|
|
|
* This program 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 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
* 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* Written by:
|
|
|
|
* Jasper St. Pierre <jstpierre@mecheye.net>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "core/meta-accel-parse.h"
|
2014-04-07 14:48:16 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
2018-07-10 08:36:24 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <xkbcommon/xkbcommon.h>
|
|
|
|
|
|
|
|
#include "core/keybindings-private.h"
|
2014-04-07 14:48:16 +00:00
|
|
|
|
2014-04-07 15:25:16 +00:00
|
|
|
/* This is copied from GTK+ and modified to work with mutter's
|
|
|
|
* internal structures. Originating code comes from gtk/gtkaccelgroup.c
|
|
|
|
*/
|
|
|
|
|
2014-04-07 14:54:21 +00:00
|
|
|
static inline gboolean
|
|
|
|
is_alt (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 'a' || string[1] == 'A') &&
|
|
|
|
(string[2] == 'l' || string[2] == 'L') &&
|
|
|
|
(string[3] == 't' || string[3] == 'T') &&
|
|
|
|
(string[4] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_ctl (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 'c' || string[1] == 'C') &&
|
|
|
|
(string[2] == 't' || string[2] == 'T') &&
|
|
|
|
(string[3] == 'l' || string[3] == 'L') &&
|
|
|
|
(string[4] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_modx (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 'm' || string[1] == 'M') &&
|
|
|
|
(string[2] == 'o' || string[2] == 'O') &&
|
|
|
|
(string[3] == 'd' || string[3] == 'D') &&
|
|
|
|
(string[4] >= '1' && string[4] <= '5') &&
|
|
|
|
(string[5] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_ctrl (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 'c' || string[1] == 'C') &&
|
|
|
|
(string[2] == 't' || string[2] == 'T') &&
|
|
|
|
(string[3] == 'r' || string[3] == 'R') &&
|
|
|
|
(string[4] == 'l' || string[4] == 'L') &&
|
|
|
|
(string[5] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_shft (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 's' || string[1] == 'S') &&
|
|
|
|
(string[2] == 'h' || string[2] == 'H') &&
|
|
|
|
(string[3] == 'f' || string[3] == 'F') &&
|
|
|
|
(string[4] == 't' || string[4] == 'T') &&
|
|
|
|
(string[5] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_shift (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 's' || string[1] == 'S') &&
|
|
|
|
(string[2] == 'h' || string[2] == 'H') &&
|
|
|
|
(string[3] == 'i' || string[3] == 'I') &&
|
|
|
|
(string[4] == 'f' || string[4] == 'F') &&
|
|
|
|
(string[5] == 't' || string[5] == 'T') &&
|
|
|
|
(string[6] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_control (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 'c' || string[1] == 'C') &&
|
|
|
|
(string[2] == 'o' || string[2] == 'O') &&
|
|
|
|
(string[3] == 'n' || string[3] == 'N') &&
|
|
|
|
(string[4] == 't' || string[4] == 'T') &&
|
|
|
|
(string[5] == 'r' || string[5] == 'R') &&
|
|
|
|
(string[6] == 'o' || string[6] == 'O') &&
|
|
|
|
(string[7] == 'l' || string[7] == 'L') &&
|
|
|
|
(string[8] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_meta (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 'm' || string[1] == 'M') &&
|
|
|
|
(string[2] == 'e' || string[2] == 'E') &&
|
|
|
|
(string[3] == 't' || string[3] == 'T') &&
|
|
|
|
(string[4] == 'a' || string[4] == 'A') &&
|
|
|
|
(string[5] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_super (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 's' || string[1] == 'S') &&
|
|
|
|
(string[2] == 'u' || string[2] == 'U') &&
|
|
|
|
(string[3] == 'p' || string[3] == 'P') &&
|
|
|
|
(string[4] == 'e' || string[4] == 'E') &&
|
|
|
|
(string[5] == 'r' || string[5] == 'R') &&
|
|
|
|
(string[6] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_hyper (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 'h' || string[1] == 'H') &&
|
|
|
|
(string[2] == 'y' || string[2] == 'Y') &&
|
|
|
|
(string[3] == 'p' || string[3] == 'P') &&
|
|
|
|
(string[4] == 'e' || string[4] == 'E') &&
|
|
|
|
(string[5] == 'r' || string[5] == 'R') &&
|
|
|
|
(string[6] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_primary (const gchar *string)
|
|
|
|
{
|
|
|
|
return ((string[0] == '<') &&
|
|
|
|
(string[1] == 'p' || string[1] == 'P') &&
|
|
|
|
(string[2] == 'r' || string[2] == 'R') &&
|
|
|
|
(string[3] == 'i' || string[3] == 'I') &&
|
|
|
|
(string[4] == 'm' || string[4] == 'M') &&
|
|
|
|
(string[5] == 'a' || string[5] == 'A') &&
|
|
|
|
(string[6] == 'r' || string[6] == 'R') &&
|
|
|
|
(string[7] == 'y' || string[7] == 'Y') &&
|
|
|
|
(string[8] == '>'));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean
|
|
|
|
is_keycode (const gchar *string)
|
|
|
|
{
|
|
|
|
return (string[0] == '0' &&
|
|
|
|
string[1] == 'x' &&
|
|
|
|
g_ascii_isxdigit (string[2]) &&
|
|
|
|
g_ascii_isxdigit (string[3]));
|
|
|
|
}
|
|
|
|
|
2014-04-07 15:20:27 +00:00
|
|
|
static gboolean
|
2014-04-07 15:09:27 +00:00
|
|
|
accelerator_parse (const gchar *accelerator,
|
2015-01-07 02:59:53 +00:00
|
|
|
MetaKeyCombo *combo)
|
2014-04-07 14:54:21 +00:00
|
|
|
{
|
2014-04-07 15:05:46 +00:00
|
|
|
guint keyval, keycode;
|
2014-04-07 15:09:27 +00:00
|
|
|
MetaVirtualModifier mods;
|
2014-04-07 14:54:21 +00:00
|
|
|
gint len;
|
|
|
|
|
2015-01-07 02:59:53 +00:00
|
|
|
combo->keysym = 0;
|
|
|
|
combo->keycode = 0;
|
|
|
|
combo->modifiers = 0;
|
2014-04-07 14:54:21 +00:00
|
|
|
|
2014-04-07 15:20:27 +00:00
|
|
|
if (accelerator == NULL)
|
2015-05-30 00:17:34 +00:00
|
|
|
return FALSE;
|
2014-04-07 15:20:27 +00:00
|
|
|
|
2014-04-07 14:54:21 +00:00
|
|
|
keyval = 0;
|
2014-04-23 01:07:02 +00:00
|
|
|
keycode = 0;
|
2014-04-07 14:54:21 +00:00
|
|
|
mods = 0;
|
|
|
|
len = strlen (accelerator);
|
|
|
|
while (len)
|
|
|
|
{
|
|
|
|
if (*accelerator == '<')
|
|
|
|
{
|
2014-04-07 15:06:55 +00:00
|
|
|
if (len >= 9 && is_primary (accelerator))
|
2014-04-07 14:54:21 +00:00
|
|
|
{
|
|
|
|
/* Primary is treated the same as Control */
|
|
|
|
accelerator += 9;
|
|
|
|
len -= 9;
|
2014-04-07 15:09:27 +00:00
|
|
|
mods |= META_VIRTUAL_CONTROL_MASK;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
else if (len >= 9 && is_control (accelerator))
|
|
|
|
{
|
|
|
|
accelerator += 9;
|
|
|
|
len -= 9;
|
2014-04-07 15:09:27 +00:00
|
|
|
mods |= META_VIRTUAL_CONTROL_MASK;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
else if (len >= 7 && is_shift (accelerator))
|
|
|
|
{
|
|
|
|
accelerator += 7;
|
|
|
|
len -= 7;
|
2014-04-07 15:09:27 +00:00
|
|
|
mods |= META_VIRTUAL_SHIFT_MASK;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
else if (len >= 6 && is_shft (accelerator))
|
|
|
|
{
|
|
|
|
accelerator += 6;
|
|
|
|
len -= 6;
|
2014-04-07 15:09:27 +00:00
|
|
|
mods |= META_VIRTUAL_SHIFT_MASK;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
else if (len >= 6 && is_ctrl (accelerator))
|
|
|
|
{
|
|
|
|
accelerator += 6;
|
|
|
|
len -= 6;
|
2014-04-07 15:09:27 +00:00
|
|
|
mods |= META_VIRTUAL_CONTROL_MASK;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
else if (len >= 6 && is_modx (accelerator))
|
|
|
|
{
|
|
|
|
static const guint mod_vals[] = {
|
2014-04-07 15:09:27 +00:00
|
|
|
META_VIRTUAL_ALT_MASK,
|
|
|
|
META_VIRTUAL_MOD2_MASK,
|
|
|
|
META_VIRTUAL_MOD3_MASK,
|
|
|
|
META_VIRTUAL_MOD4_MASK,
|
|
|
|
META_VIRTUAL_MOD5_MASK,
|
2014-04-07 14:54:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
len -= 6;
|
|
|
|
accelerator += 4;
|
|
|
|
mods |= mod_vals[*accelerator - '1'];
|
|
|
|
accelerator += 2;
|
|
|
|
}
|
|
|
|
else if (len >= 5 && is_ctl (accelerator))
|
|
|
|
{
|
|
|
|
accelerator += 5;
|
|
|
|
len -= 5;
|
2014-04-07 15:09:27 +00:00
|
|
|
mods |= META_VIRTUAL_CONTROL_MASK;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
else if (len >= 5 && is_alt (accelerator))
|
|
|
|
{
|
|
|
|
accelerator += 5;
|
|
|
|
len -= 5;
|
2014-04-07 15:09:27 +00:00
|
|
|
mods |= META_VIRTUAL_ALT_MASK;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
else if (len >= 6 && is_meta (accelerator))
|
|
|
|
{
|
|
|
|
accelerator += 6;
|
|
|
|
len -= 6;
|
2014-04-07 15:09:27 +00:00
|
|
|
mods |= META_VIRTUAL_META_MASK;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
else if (len >= 7 && is_hyper (accelerator))
|
|
|
|
{
|
|
|
|
accelerator += 7;
|
|
|
|
len -= 7;
|
2014-04-07 15:09:27 +00:00
|
|
|
mods |= META_VIRTUAL_HYPER_MASK;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
else if (len >= 7 && is_super (accelerator))
|
|
|
|
{
|
|
|
|
accelerator += 7;
|
|
|
|
len -= 7;
|
2014-04-07 15:09:27 +00:00
|
|
|
mods |= META_VIRTUAL_SUPER_MASK;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gchar last_ch;
|
|
|
|
|
|
|
|
last_ch = *accelerator;
|
|
|
|
while (last_ch && last_ch != '>')
|
|
|
|
{
|
|
|
|
last_ch = *accelerator;
|
|
|
|
accelerator += 1;
|
|
|
|
len -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (len >= 4 && is_keycode (accelerator))
|
|
|
|
{
|
2014-04-07 15:05:46 +00:00
|
|
|
keycode = strtoul (accelerator, NULL, 16);
|
2014-04-07 14:54:21 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2014-04-07 15:03:10 +00:00
|
|
|
else if (strcmp (accelerator, "Above_Tab") == 0)
|
|
|
|
{
|
|
|
|
keyval = META_KEY_ABOVE_TAB;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
else
|
2014-04-07 14:54:21 +00:00
|
|
|
{
|
2014-04-07 15:12:14 +00:00
|
|
|
keyval = xkb_keysym_from_name (accelerator, XKB_KEYSYM_CASE_INSENSITIVE);
|
|
|
|
if (keyval == XKB_KEY_NoSymbol)
|
2014-04-07 14:54:21 +00:00
|
|
|
{
|
2014-04-10 18:58:32 +00:00
|
|
|
char *with_xf86 = g_strconcat ("XF86", accelerator, NULL);
|
|
|
|
keyval = xkb_keysym_from_name (with_xf86, XKB_KEYSYM_CASE_INSENSITIVE);
|
|
|
|
g_free (with_xf86);
|
|
|
|
|
|
|
|
if (keyval == XKB_KEY_NoSymbol)
|
2015-05-30 00:17:34 +00:00
|
|
|
return FALSE;
|
2014-04-10 18:58:32 +00:00
|
|
|
}
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
accelerator += len;
|
|
|
|
len -= len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-30 00:17:34 +00:00
|
|
|
out:
|
2015-01-07 02:59:53 +00:00
|
|
|
combo->keysym = keyval;
|
|
|
|
combo->keycode = keycode;
|
|
|
|
combo->modifiers = mods;
|
2014-04-07 15:20:27 +00:00
|
|
|
return TRUE;
|
2014-04-07 14:54:21 +00:00
|
|
|
}
|
|
|
|
|
2014-04-07 14:48:16 +00:00
|
|
|
gboolean
|
2015-01-07 02:59:53 +00:00
|
|
|
meta_parse_accelerator (const char *accel,
|
|
|
|
MetaKeyCombo *combo)
|
2014-04-07 14:48:16 +00:00
|
|
|
{
|
2016-05-11 16:07:49 +00:00
|
|
|
g_return_val_if_fail (combo != NULL, FALSE);
|
|
|
|
|
|
|
|
*combo = (MetaKeyCombo) { 0 };
|
|
|
|
|
2014-04-07 14:48:16 +00:00
|
|
|
if (!accel[0] || strcmp (accel, "disabled") == 0)
|
|
|
|
return TRUE;
|
2014-04-07 15:24:23 +00:00
|
|
|
|
2015-01-07 02:59:53 +00:00
|
|
|
return accelerator_parse (accel, combo);
|
2014-04-07 14:48:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_parse_modifier (const char *accel,
|
|
|
|
MetaVirtualModifier *mask)
|
|
|
|
{
|
2016-05-11 16:07:49 +00:00
|
|
|
MetaKeyCombo combo = { 0 };
|
|
|
|
|
|
|
|
g_return_val_if_fail (mask != NULL, FALSE);
|
|
|
|
|
|
|
|
*mask = 0;
|
2015-01-07 02:59:53 +00:00
|
|
|
|
2014-04-07 14:48:16 +00:00
|
|
|
if (accel == NULL || !accel[0] || strcmp (accel, "disabled") == 0)
|
|
|
|
return TRUE;
|
2014-04-07 15:09:27 +00:00
|
|
|
|
2015-01-07 02:59:53 +00:00
|
|
|
if (!accelerator_parse (accel, &combo))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
*mask = combo.modifiers;
|
|
|
|
return TRUE;
|
2014-04-07 14:48:16 +00:00
|
|
|
}
|