File indexing completed on 2024-11-24 05:00:23

0001 /*
0002     GDK - The GIMP Drawing Kit
0003     SPDX-FileCopyrightText: 1995-1997 Peter Mattis
0004     SPDX-FileCopyrightText: 1995-1997 Spencer Kimball
0005     SPDX-FileCopyrightText: 1995-1997 Josh MacDonald
0006     SPDX-FileCopyrightText: 2005, 2006, 2007, 2009 GNOME Foundation
0007 
0008     SPDX-License-Identifier: LGPL-2.0-or-later
0009 */
0010 #include <glib.h>
0011 #include <string.h>
0012 #include <stdlib.h>
0013 #include "gdkkeysyms_p.h"
0014 #include "gtkaccelparse_p.h"
0015 #include "gdkkeynames_p.h"
0016 
0017 static inline gboolean
0018 is_alt (const gchar *string)
0019 {
0020     // clang-format off
0021     return ((string[0] == '<') &&
0022           (string[1] == 'a' || string[1] == 'A') &&
0023           (string[2] == 'l' || string[2] == 'L') &&
0024           (string[3] == 't' || string[3] == 'T') &&
0025           (string[4] == '>'));
0026     // clang-format on
0027 }
0028 
0029 static inline gboolean
0030 is_ctl (const gchar *string)
0031 {
0032     // clang-format off
0033     return ((string[0] == '<') &&
0034           (string[1] == 'c' || string[1] == 'C') &&
0035           (string[2] == 't' || string[2] == 'T') &&
0036           (string[3] == 'l' || string[3] == 'L') &&
0037           (string[4] == '>'));
0038     // clang-format on
0039 }
0040 
0041 static inline gboolean
0042 is_modx (const gchar *string)
0043 {
0044     // clang-format off
0045     return ((string[0] == '<') &&
0046           (string[1] == 'm' || string[1] == 'M') &&
0047           (string[2] == 'o' || string[2] == 'O') &&
0048           (string[3] == 'd' || string[3] == 'D') &&
0049           (string[4] >= '1' && string[4] <= '5') &&
0050           (string[5] == '>'));
0051     // clang-format on
0052 }
0053 
0054 static inline gboolean
0055 is_ctrl (const gchar *string)
0056 {
0057     // clang-format off
0058     return ((string[0] == '<') &&
0059           (string[1] == 'c' || string[1] == 'C') &&
0060           (string[2] == 't' || string[2] == 'T') &&
0061           (string[3] == 'r' || string[3] == 'R') &&
0062           (string[4] == 'l' || string[4] == 'L') &&
0063           (string[5] == '>'));
0064     // clang-format on
0065 }
0066 
0067 static inline gboolean
0068 is_shft (const gchar *string)
0069 {
0070     // clang-format off
0071   return ((string[0] == '<') &&
0072           (string[1] == 's' || string[1] == 'S') &&
0073           (string[2] == 'h' || string[2] == 'H') &&
0074           (string[3] == 'f' || string[3] == 'F') &&
0075           (string[4] == 't' || string[4] == 'T') &&
0076           (string[5] == '>'));
0077     // clang-format on
0078 }
0079 
0080 static inline gboolean
0081 is_shift (const gchar *string)
0082 {
0083     // clang-format off
0084     return ((string[0] == '<') &&
0085           (string[1] == 's' || string[1] == 'S') &&
0086           (string[2] == 'h' || string[2] == 'H') &&
0087           (string[3] == 'i' || string[3] == 'I') &&
0088           (string[4] == 'f' || string[4] == 'F') &&
0089           (string[5] == 't' || string[5] == 'T') &&
0090           (string[6] == '>'));
0091     // clang-format on
0092 }
0093 
0094 static inline gboolean
0095 is_control (const gchar *string)
0096 {
0097     // clang-format off
0098     return  ((string[0] == '<') &&
0099           (string[1] == 'c' || string[1] == 'C') &&
0100           (string[2] == 'o' || string[2] == 'O') &&
0101           (string[3] == 'n' || string[3] == 'N') &&
0102           (string[4] == 't' || string[4] == 'T') &&
0103           (string[5] == 'r' || string[5] == 'R') &&
0104           (string[6] == 'o' || string[6] == 'O') &&
0105           (string[7] == 'l' || string[7] == 'L') &&
0106           (string[8] == '>'));
0107     // clang-format on
0108 }
0109 
0110 static inline gboolean
0111 is_release (const gchar *string)
0112 {
0113     // clang-format off
0114     return  ((string[0] == '<') &&
0115           (string[1] == 'r' || string[1] == 'R') &&
0116           (string[2] == 'e' || string[2] == 'E') &&
0117           (string[3] == 'l' || string[3] == 'L') &&
0118           (string[4] == 'e' || string[4] == 'E') &&
0119           (string[5] == 'a' || string[5] == 'A') &&
0120           (string[6] == 's' || string[6] == 'S') &&
0121           (string[7] == 'e' || string[7] == 'E') &&
0122           (string[8] == '>'));
0123     // clang-format on
0124 }
0125 
0126 static inline gboolean
0127 is_meta (const gchar *string)
0128 {
0129     // clang-format off
0130     return  ((string[0] == '<') &&
0131           (string[1] == 'm' || string[1] == 'M') &&
0132           (string[2] == 'e' || string[2] == 'E') &&
0133           (string[3] == 't' || string[3] == 'T') &&
0134           (string[4] == 'a' || string[4] == 'A') &&
0135           (string[5] == '>'));
0136     // clang-format on
0137 }
0138 
0139 static inline gboolean
0140 is_super (const gchar *string)
0141 {
0142     // clang-format off
0143     return  ((string[0] == '<') &&
0144           (string[1] == 's' || string[1] == 'S') &&
0145           (string[2] == 'u' || string[2] == 'U') &&
0146           (string[3] == 'p' || string[3] == 'P') &&
0147           (string[4] == 'e' || string[4] == 'E') &&
0148           (string[5] == 'r' || string[5] == 'R') &&
0149           (string[6] == '>'));
0150     // clang-format on
0151 }
0152 
0153 static inline gboolean
0154 is_hyper (const gchar *string)
0155 {
0156     // clang-format off
0157     return  ((string[0] == '<') &&
0158           (string[1] == 'h' || string[1] == 'H') &&
0159           (string[2] == 'y' || string[2] == 'Y') &&
0160           (string[3] == 'p' || string[3] == 'P') &&
0161           (string[4] == 'e' || string[4] == 'E') &&
0162           (string[5] == 'r' || string[5] == 'R') &&
0163           (string[6] == '>'));
0164     // clang-format on
0165 }
0166 
0167 static inline gboolean
0168 is_keycode (const gchar *string)
0169 {
0170     // clang-format off
0171     return (string[0] == '0' &&
0172           string[1] == 'x' &&
0173           g_ascii_isxdigit (string[2]) &&
0174           g_ascii_isxdigit (string[3]));
0175     // clang-format on
0176 }
0177 
0178 void
0179 _gtk_accelerator_parse (const gchar     *accelerator,
0180                         guint           *accelerator_key,
0181                         GdkModifierType *accelerator_mods)
0182 {
0183   guint keyval;
0184   GdkModifierType mods;
0185   gint len;
0186   gboolean error;
0187 
0188   if (accelerator_key)
0189     *accelerator_key = 0;
0190   if (accelerator_mods)
0191     *accelerator_mods = 0;
0192 
0193   g_return_if_fail (accelerator != NULL);
0194 
0195   error = FALSE;
0196   keyval = 0;
0197   mods = 0;
0198   len = strlen (accelerator);
0199   while (len)
0200     {
0201       if (*accelerator == '<')
0202         {
0203           if (len >= 9 && is_release (accelerator))
0204             {
0205               accelerator += 9;
0206               len -= 9;
0207               mods |= GDK_RELEASE_MASK;
0208             }
0209           else if (len >= 9 && is_control (accelerator))
0210             {
0211               accelerator += 9;
0212               len -= 9;
0213               mods |= GDK_CONTROL_MASK;
0214             }
0215           else if (len >= 7 && is_shift (accelerator))
0216             {
0217               accelerator += 7;
0218               len -= 7;
0219               mods |= GDK_SHIFT_MASK;
0220             }
0221           else if (len >= 6 && is_shft (accelerator))
0222             {
0223               accelerator += 6;
0224               len -= 6;
0225               mods |= GDK_SHIFT_MASK;
0226             }
0227           else if (len >= 6 && is_ctrl (accelerator))
0228             {
0229               accelerator += 6;
0230               len -= 6;
0231               mods |= GDK_CONTROL_MASK;
0232             }
0233           else if (len >= 6 && is_modx (accelerator))
0234             {
0235               static const guint mod_vals[] = {
0236                 GDK_MOD1_MASK, GDK_MOD2_MASK, GDK_MOD3_MASK,
0237                 GDK_MOD4_MASK, GDK_MOD5_MASK
0238               };
0239 
0240               len -= 6;
0241               accelerator += 4;
0242               mods |= mod_vals[*accelerator - '1'];
0243               accelerator += 2;
0244             }
0245           else if (len >= 5 && is_ctl (accelerator))
0246             {
0247               accelerator += 5;
0248               len -= 5;
0249               mods |= GDK_CONTROL_MASK;
0250             }
0251           else if (len >= 5 && is_alt (accelerator))
0252             {
0253               accelerator += 5;
0254               len -= 5;
0255               mods |= GDK_MOD1_MASK;
0256             }
0257           else if (len >= 6 && is_meta (accelerator))
0258             {
0259               accelerator += 6;
0260               len -= 6;
0261               // mods |= GDK_META_MASK;
0262             }
0263           else if (len >= 7 && is_hyper (accelerator))
0264             {
0265               accelerator += 7;
0266               len -= 7;
0267               mods |= GDK_MOD4_MASK;
0268             }
0269           else if (len >= 7 && is_super (accelerator))
0270             {
0271               accelerator += 7;
0272               len -= 7;
0273               mods |= GDK_MOD4_MASK;
0274             }
0275           else
0276             {
0277               gchar last_ch;
0278 
0279               last_ch = *accelerator;
0280               while (last_ch && last_ch != '>')
0281                 {
0282                   last_ch = *accelerator;
0283                   accelerator += 1;
0284                   len -= 1;
0285                 }
0286             }
0287         }
0288       else
0289         {
0290           if (len >= 4 && is_keycode (accelerator))
0291             {
0292                char keystring[5];
0293                gchar *endptr;
0294 
0295                memcpy (keystring, accelerator, 4);
0296                keystring [4] = '\000';
0297 
0298                strtol (keystring, &endptr, 16);
0299 
0300                if (endptr == NULL || *endptr != '\000')
0301                  {
0302                    error = TRUE;
0303                    goto out;
0304                  }
0305                else
0306                  {
0307                    /* There was a keycode in the string, but
0308                     * we cannot store it, so we have an error */
0309                    error = TRUE;
0310                    goto out;
0311                  }
0312             }
0313       else
0314         {
0315           keyval = _gdk_keyval_from_name (accelerator);
0316           if (keyval == GDK_KEY_VoidSymbol)
0317             {
0318               error = TRUE;
0319               goto out;
0320         }
0321         }
0322 
0323           accelerator += len;
0324           len -= len;
0325         }
0326     }
0327 
0328 out:
0329   if (error)
0330     keyval = mods = 0;
0331 
0332   if (accelerator_key)
0333     *accelerator_key = keyval;
0334   if (accelerator_mods)
0335     *accelerator_mods = mods;
0336 }