Add notes and placeholders for future modifications.
[gwm.git] / keyboard.c
blobf9193dedac5a5b2fd75f5d7e175dca9f9d40f243
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[ NUM_KEY_ACTIONS ] = {
70 /* FIXME This table should be configurable, of course. */
71 { KEYSYM_TAB, XCB_MOD_MASK_1, action_raise_lowest },
72 { KEYSYM_F5, XCB_MOD_MASK_1, action_stack_opposite }
75 static void establish_grabs( void ) {
77 int populated, i, j, screen, lock, num_lock;
79 populated = FALSE;
80 lock = num_lock = -1;
81 for( i = 0; i < 8; i++ )
82 if( modifier_map[ i ] ) {
83 populated = TRUE;
85 for( j = 0; modifier_map[ i ][ j ]; j++ )
86 if( keyboard_map[ modifier_map[ i ][ j ] ][ 0 ] ==
87 KEYSYM_CAPS_LOCK ||
88 keyboard_map[ modifier_map[ i ][ j ] ][ 0 ] ==
89 KEYSYM_SHIFT_LOCK )
90 lock = i;
91 else if( keyboard_map[ modifier_map[ i ][ j ] ][ 0 ] ==
92 KEYSYM_NUM_LOCK )
93 num_lock = i;
96 if( !populated )
97 /* The modifier map is unpopulated: there's nothing we can do yet,
98 and we'll be invoked again later once there is. */
99 return;
101 for( screen = 0; screen < num_screens; screen++ ) {
102 /* Undo any previous grabs. */
103 xcb_ungrab_key( c, XCB_GRAB_ANY, screens[ screen ]->root,
104 XCB_GRAB_ANY );
106 for( i = 0; i < NUM_KEY_ACTIONS; i++ ) {
107 for( j = 0; j < 0x100 &&
108 keyboard_map[ j ][ 0 ] != key_actions[ i ].keysym; j++ )
111 if( j >= 0x100 )
112 /* No key is currently bound to keysym; omit this action. */
113 continue;
115 xcb_grab_key( c, FALSE, screens[ screen ]->root,
116 key_actions[ i ].modifiers, j, XCB_GRAB_MODE_ASYNC,
117 XCB_GRAB_MODE_ASYNC );
119 if( lock >= 0 )
120 xcb_grab_key( c, FALSE, screens[ screen ]->root,
121 key_actions[ i ].modifiers | ( 1 << lock ),
122 j, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC );
124 if( num_lock >= 0 )
125 xcb_grab_key( c, FALSE, screens[ screen ]->root,
126 key_actions[ i ].modifiers | ( 1 << num_lock ),
127 j, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC );
129 if( lock >= 0 && num_lock >= 0 )
130 xcb_grab_key( c, FALSE, screens[ screen ]->root,
131 key_actions[ i ].modifiers | ( 1 << lock ) |
132 ( 1 << num_lock ), j, XCB_GRAB_MODE_ASYNC,
133 XCB_GRAB_MODE_ASYNC );
138 static void handle_get_keyboard_mapping( unsigned int sequence, void *reply,
139 xcb_generic_error_t *error,
140 union callback_param cp ) {
142 if( error ) {
143 show_error( error );
145 free( error );
148 if( reply ) {
149 xcb_get_keyboard_mapping_reply_t *r = reply;
150 xcb_keysym_t *in, *out;
151 int i, j, syms_used, count = r->length / r->keysyms_per_keycode;
153 syms_used = r->keysyms_per_keycode < 4 ? r->keysyms_per_keycode : 4;
155 in = xcb_get_keyboard_mapping_keysyms( r );
156 out = keyboard_map[ cp.l ];
158 for( i = 0; i < count; i++ ) {
159 for( j = 0; j < syms_used; j++ )
160 *out++ = *in++;
161 for( ; j < 4; j++ )
162 *out++ = XCB_NONE;
163 if( r->keysyms_per_keycode > 4 )
164 in += r->keysyms_per_keycode - 4;
167 free( reply );
169 establish_grabs();
173 extern void get_keyboard_mapping( int first, int count ) {
175 union callback_param cp;
177 cp.l = first;
178 handle_async_reply( xcb_get_keyboard_mapping( c, first, count ).sequence,
179 handle_get_keyboard_mapping, cp );
182 static void handle_get_modifier_mapping( unsigned int sequence, void *reply,
183 xcb_generic_error_t *error,
184 union callback_param cp ) {
186 xcb_keycode_t *in, *out;
187 xcb_get_modifier_mapping_reply_t *r;
188 int i, j, codes_used;
190 assert( !error ); /* the protocol defines no error conditions... */
191 assert( reply ); /* ...so we should always get a valid response */
193 r = reply;
195 codes_used = r->keycodes_per_modifier < 8 ? r->keycodes_per_modifier : 8;
197 in = xcb_get_modifier_mapping_keycodes( r );
199 for( i = 0; i < 8; i++, in += r->keycodes_per_modifier ) {
200 if( modifier_map[ i ] )
201 free( modifier_map[ i ] );
203 for( codes_used = 0, j = 0; j < r->keycodes_per_modifier; j++ )
204 if( in[ j ] )
205 codes_used++;
207 if( codes_used ) {
208 modifier_map[ i ] = out = xmalloc( ( codes_used + 1 ) *
209 sizeof *out );
211 for( j = 0; j < r->keycodes_per_modifier; j++ )
212 if( in[ j ] )
213 *out++ = in[ j ];
215 *out = 0;
216 } else
217 modifier_map[ i ] = NULL;
220 free( reply );
222 establish_grabs();
225 extern void get_modifier_mapping( void ) {
227 union callback_param cp;
229 cp.l = 0;
230 handle_async_reply( xcb_get_modifier_mapping( c ).sequence,
231 handle_get_modifier_mapping, cp );
234 #if DEBUG
235 extern void cleanup_keyboard( void ) {
237 int i;
239 for( i = 0; i < 8; i++ )
240 if( modifier_map[ i ] )
241 free( modifier_map[ i ] );
243 #endif