Fix missing pointer dereference and missing assignment.
[gwm.git] / keyboard.c
blob0532c6ee7355bc25387a579a9cd56ab2ed67d6d6
1 /*
2 * keyboard.c
4 * Part of gwm, the Gratuitous Window Manager,
5 * by Gary Wong, <gtw@gnu.org>.
7 * Copyright (C) 2009 Gary Wong
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of version 3 of the GNU General Public License as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * $Id$
24 #include <config.h>
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <xcb/xcb.h>
30 #include "gwm.h"
32 #include "actions.h"
33 #include "keyboard.h"
35 enum _keysym {
36 /* See X Window System Protocol (version 11, release 6.7), Appendix A. */
37 KEYSYM_TAB = 0xFF09,
38 KEYSYM_MENU = 0xFF67,
39 KEYSYM_NUM_LOCK = 0xFF7F,
40 KEYSYM_F1 = 0xFFBE,
41 KEYSYM_F2 = 0xFFBF,
42 KEYSYM_F3 = 0xFFC0,
43 KEYSYM_F4 = 0xFFC1,
44 KEYSYM_F5 = 0xFFC2,
45 KEYSYM_F6 = 0xFFC3,
46 KEYSYM_F7 = 0xFFC4,
47 KEYSYM_F8 = 0xFFC5,
48 KEYSYM_F9 = 0xFFC6,
49 KEYSYM_F10 = 0xFFC7,
50 KEYSYM_F11 = 0xFFC8,
51 KEYSYM_F12 = 0xFFC9,
52 KEYSYM_SHIFT_L = 0xFFE1,
53 KEYSYM_SHIFT_R = 0xFFE2,
54 KEYSYM_CONTROL_L = 0xFFE3,
55 KEYSYM_CONTROL_R = 0xFFE4,
56 KEYSYM_CAPS_LOCK = 0xFFE5,
57 KEYSYM_SHIFT_LOCK = 0xFFE6,
58 KEYSYM_META_L = 0xFFE7,
59 KEYSYM_META_R = 0xFFE8,
60 KEYSYM_ALT_L = 0xFFE9,
61 KEYSYM_ALT_R = 0xFFEA
64 /* Map of keysyms: first index is keycode, second index is group/modifier. */
65 xcb_keysym_t keyboard_map[ 0x100 ][ 4 ];
66 /* Map of modifiers, indexed by xcb_map_index_t. */
67 xcb_keycode_t *modifier_map[ 8 ];
69 const struct key_action key_actions[] = {
70 /* FIXME This table should be configurable, of course. */
71 { KEYSYM_TAB, XCB_MOD_MASK_1, action_raise_lowest },
72 { KEYSYM_F1, XCB_MOD_MASK_1, action_iconify_window },
73 { KEYSYM_F5, XCB_MOD_MASK_1, action_stack_opposite }
75 const int num_key_actions = sizeof key_actions / sizeof *key_actions;
77 static void establish_grabs( void ) {
79 int populated, i, j, screen, lock, num_lock;
81 populated = FALSE;
82 lock = num_lock = -1;
83 for( i = 0; i < 8; i++ )
84 if( modifier_map[ i ] ) {
85 populated = TRUE;
87 for( j = 0; modifier_map[ i ][ j ]; j++ )
88 if( keyboard_map[ modifier_map[ i ][ j ] ][ 0 ] ==
89 KEYSYM_CAPS_LOCK ||
90 keyboard_map[ modifier_map[ i ][ j ] ][ 0 ] ==
91 KEYSYM_SHIFT_LOCK )
92 lock = i;
93 else if( keyboard_map[ modifier_map[ i ][ j ] ][ 0 ] ==
94 KEYSYM_NUM_LOCK )
95 num_lock = i;
98 if( !populated )
99 /* The modifier map is unpopulated: there's nothing we can do yet,
100 and we'll be invoked again later once there is. */
101 return;
103 for( screen = 0; screen < num_screens; screen++ ) {
104 /* Undo any previous grabs. */
105 xcb_ungrab_key( c, XCB_GRAB_ANY, screens[ screen ]->root,
106 XCB_GRAB_ANY );
108 for( i = 0; i < num_key_actions; i++ ) {
109 for( j = 0; j < 0x100 &&
110 keyboard_map[ j ][ 0 ] != key_actions[ i ].keysym; j++ )
113 if( j >= 0x100 )
114 /* No key is currently bound to keysym; omit this action. */
115 continue;
117 xcb_grab_key( c, FALSE, screens[ screen ]->root,
118 key_actions[ i ].modifiers, j, XCB_GRAB_MODE_ASYNC,
119 XCB_GRAB_MODE_ASYNC );
121 if( lock >= 0 )
122 xcb_grab_key( c, FALSE, screens[ screen ]->root,
123 key_actions[ i ].modifiers | ( 1 << lock ),
124 j, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC );
126 if( num_lock >= 0 )
127 xcb_grab_key( c, FALSE, screens[ screen ]->root,
128 key_actions[ i ].modifiers | ( 1 << num_lock ),
129 j, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC );
131 if( lock >= 0 && num_lock >= 0 )
132 xcb_grab_key( c, FALSE, screens[ screen ]->root,
133 key_actions[ i ].modifiers | ( 1 << lock ) |
134 ( 1 << num_lock ), j, XCB_GRAB_MODE_ASYNC,
135 XCB_GRAB_MODE_ASYNC );
140 static void handle_get_keyboard_mapping( unsigned int sequence, void *reply,
141 xcb_generic_error_t *error,
142 union callback_param cp ) {
144 if( error ) {
145 show_error( error );
147 free( error );
150 if( reply ) {
151 xcb_get_keyboard_mapping_reply_t *r = reply;
152 xcb_keysym_t *in, *out;
153 int i, j, syms_used, count = r->length / r->keysyms_per_keycode;
155 syms_used = r->keysyms_per_keycode < 4 ? r->keysyms_per_keycode : 4;
157 in = xcb_get_keyboard_mapping_keysyms( r );
158 out = keyboard_map[ cp.l ];
160 for( i = 0; i < count; i++ ) {
161 for( j = 0; j < syms_used; j++ )
162 *out++ = *in++;
163 for( ; j < 4; j++ )
164 *out++ = XCB_NONE;
165 if( r->keysyms_per_keycode > 4 )
166 in += r->keysyms_per_keycode - 4;
169 free( reply );
171 establish_grabs();
175 extern void get_keyboard_mapping( int first, int count ) {
177 union callback_param cp;
179 cp.l = first;
180 handle_async_reply( xcb_get_keyboard_mapping( c, first, count ).sequence,
181 handle_get_keyboard_mapping, cp );
184 static void handle_get_modifier_mapping( unsigned int sequence, void *reply,
185 xcb_generic_error_t *error,
186 union callback_param cp ) {
188 xcb_keycode_t *in, *out;
189 xcb_get_modifier_mapping_reply_t *r;
190 int i, j, codes_used;
192 assert( !error ); /* the protocol defines no error conditions... */
193 assert( reply ); /* ...so we should always get a valid response */
195 r = reply;
197 codes_used = r->keycodes_per_modifier < 8 ? r->keycodes_per_modifier : 8;
199 in = xcb_get_modifier_mapping_keycodes( r );
201 for( i = 0; i < 8; i++, in += r->keycodes_per_modifier ) {
202 if( modifier_map[ i ] )
203 free( modifier_map[ i ] );
205 for( codes_used = 0, j = 0; j < r->keycodes_per_modifier; j++ )
206 if( in[ j ] )
207 codes_used++;
209 if( codes_used ) {
210 modifier_map[ i ] = out = xmalloc( ( codes_used + 1 ) *
211 sizeof *out );
213 for( j = 0; j < r->keycodes_per_modifier; j++ )
214 if( in[ j ] )
215 *out++ = in[ j ];
217 *out = 0;
218 } else
219 modifier_map[ i ] = NULL;
222 free( reply );
224 establish_grabs();
227 extern void get_modifier_mapping( void ) {
229 union callback_param cp;
231 cp.l = 0;
232 handle_async_reply( xcb_get_modifier_mapping( c ).sequence,
233 handle_get_modifier_mapping, cp );
236 #if DEBUG
237 extern void cleanup_keyboard( void ) {
239 int i;
241 for( i = 0; i < 8; i++ )
242 if( modifier_map[ i ] )
243 free( modifier_map[ i ] );
245 #endif