1 /*
2 * Copyright 2018 Jiri Techet <techet@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "keypress.h"
20 #include "utils.h"
21
22 #include <gdk/gdkkeysyms.h>
23
kp_from_event_key(GdkEventKey * ev)24 KeyPress *kp_from_event_key(GdkEventKey *ev)
25 {
26 KeyPress *kp;
27
28 /* ignore keypresses containing Alt and Command on macOS - no Vim command uses them */
29 if (ev->state & (GDK_MOD1_MASK | GDK_MOD2_MASK))
30 return NULL;
31
32 switch (ev->keyval)
33 {
34 case GDK_KEY_Shift_L:
35 case GDK_KEY_Shift_R:
36 case GDK_KEY_Control_L:
37 case GDK_KEY_Control_R:
38 case GDK_KEY_Caps_Lock:
39 case GDK_KEY_Shift_Lock:
40 case GDK_KEY_Meta_L:
41 case GDK_KEY_Meta_R:
42 case GDK_KEY_Alt_L:
43 case GDK_KEY_Alt_R:
44 case GDK_KEY_Super_L:
45 case GDK_KEY_Super_R:
46 case GDK_KEY_Hyper_L:
47 case GDK_KEY_Hyper_R:
48 return NULL;
49 }
50
51 kp = g_new0(KeyPress, 1);
52 kp->key = ev->keyval;
53 /* We are interested only in Ctrl presses - Alt is not used in Vim and
54 * shift is included in letter capitalisation implicitly. The only case
55 * we are interested in shift is for insert mode shift+arrow keystrokes. */
56 switch (ev->keyval)
57 {
58 case GDK_KEY_Left:
59 case GDK_KEY_KP_Left:
60 case GDK_KEY_leftarrow:
61 case GDK_KEY_Up:
62 case GDK_KEY_KP_Up:
63 case GDK_KEY_uparrow:
64 case GDK_KEY_Right:
65 case GDK_KEY_KP_Right:
66 case GDK_KEY_rightarrow:
67 case GDK_KEY_Down:
68 case GDK_KEY_KP_Down:
69 case GDK_KEY_downarrow:
70 kp->modif = ev->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK);
71 break;
72 default:
73 kp->modif = ev->state & GDK_CONTROL_MASK;
74 break;
75 }
76
77 return kp;
78 }
79
80
kp_to_str(KeyPress * kp)81 const gchar *kp_to_str(KeyPress *kp)
82 {
83 static gchar *utf8 = NULL;
84 gunichar key = gdk_keyval_to_unicode(kp->key);
85 gint len;
86
87 if (!utf8)
88 utf8 = g_malloc0(MAX_CHAR_SIZE);
89 len = g_unichar_to_utf8(key, utf8);
90 utf8[len] = '\0';
91 return utf8;
92 }
93
94
kp_todigit(KeyPress * kp)95 static gint kp_todigit(KeyPress *kp)
96 {
97 if (kp->modif != 0)
98 return -1;
99
100 switch (kp->key)
101 {
102 case GDK_KEY_0:
103 case GDK_KEY_KP_0:
104 return 0;
105 case GDK_KEY_1:
106 case GDK_KEY_KP_1:
107 return 1;
108 case GDK_KEY_2:
109 case GDK_KEY_KP_2:
110 return 2;
111 case GDK_KEY_3:
112 case GDK_KEY_KP_3:
113 return 3;
114 case GDK_KEY_4:
115 case GDK_KEY_KP_4:
116 return 4;
117 case GDK_KEY_5:
118 case GDK_KEY_KP_5:
119 return 5;
120 case GDK_KEY_6:
121 case GDK_KEY_KP_6:
122 return 6;
123 case GDK_KEY_7:
124 case GDK_KEY_KP_7:
125 return 7;
126 case GDK_KEY_8:
127 case GDK_KEY_KP_8:
128 return 8;
129 case GDK_KEY_9:
130 case GDK_KEY_KP_9:
131 return 9;
132 }
133 return -1;
134 }
135
136
kp_isdigit(KeyPress * kp)137 gboolean kp_isdigit(KeyPress *kp)
138 {
139 return kp_todigit(kp) != -1;
140 }
141
142
kpl_printf(GSList * kpl)143 void kpl_printf(GSList *kpl)
144 {
145 kpl = g_slist_reverse(kpl);
146 GSList *pos = kpl;
147 printf("kpl: ");
148 while (pos != NULL)
149 {
150 KeyPress *kp = pos->data;
151 printf("<%d>%s", kp->key, kp_to_str(kp));
152 pos = g_slist_next(pos);
153 }
154 printf("\n");
155 kpl = g_slist_reverse(kpl);
156 }
157
158
kpl_get_int(GSList * kpl,GSList ** new_kpl)159 gint kpl_get_int(GSList *kpl, GSList **new_kpl)
160 {
161 gint res = 0;
162 gint i = 0;
163 GSList *pos = kpl;
164 GSList *num_list = NULL;
165
166 if (new_kpl != NULL)
167 *new_kpl = kpl;
168
169 while (pos != NULL)
170 {
171 if (kp_isdigit(pos->data))
172 num_list = g_slist_prepend(num_list, pos->data);
173 else
174 break;
175 pos = g_slist_next(pos);
176 }
177
178 if (!num_list)
179 return -1;
180
181 if (new_kpl != NULL)
182 *new_kpl = pos;
183
184 pos = num_list;
185 while (pos != NULL)
186 {
187 res = res * 10 + kp_todigit(pos->data);
188 pos = g_slist_next(pos);
189 i++;
190 // some sanity check
191 if (res > 1000000)
192 break;
193 }
194
195 return res;
196 }
197