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/>.
36 /* See X Window System Protocol (version 11, release 6.7), Appendix A. */
39 KEYSYM_NUM_LOCK
= 0xFF7F,
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,
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
;
81 for( i
= 0; i
< 8; i
++ )
82 if( modifier_map
[ i
] ) {
85 for( j
= 0; modifier_map
[ i
][ j
]; j
++ )
86 if( keyboard_map
[ modifier_map
[ i
][ j
] ][ 0 ] ==
88 keyboard_map
[ modifier_map
[ i
][ j
] ][ 0 ] ==
91 else if( keyboard_map
[ modifier_map
[ i
][ j
] ][ 0 ] ==
97 /* The modifier map is unpopulated: there's nothing we can do yet,
98 and we'll be invoked again later once there is. */
101 for( screen
= 0; screen
< num_screens
; screen
++ ) {
102 /* Undo any previous grabs. */
103 xcb_ungrab_key( c
, XCB_GRAB_ANY
, screens
[ screen
]->root
,
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
++ )
112 /* No key is currently bound to keysym; omit this action. */
115 xcb_grab_key( c
, FALSE
, screens
[ screen
]->root
,
116 key_actions
[ i
].modifiers
, j
, XCB_GRAB_MODE_ASYNC
,
117 XCB_GRAB_MODE_ASYNC
);
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
);
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
) {
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
++ )
163 if( r
->keysyms_per_keycode
> 4 )
164 in
+= r
->keysyms_per_keycode
- 4;
173 extern void get_keyboard_mapping( int first
, int count
) {
175 union callback_param cp
;
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 */
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
++ )
208 modifier_map
[ i
] = out
= xmalloc( ( codes_used
+ 1 ) *
211 for( j
= 0; j
< r
->keycodes_per_modifier
; j
++ )
217 modifier_map
[ i
] = NULL
;
225 extern void get_modifier_mapping( void ) {
227 union callback_param cp
;
230 handle_async_reply( xcb_get_modifier_mapping( c
).sequence
,
231 handle_get_modifier_mapping
, cp
);
235 extern void cleanup_keyboard( void ) {
239 for( i
= 0; i
< 8; i
++ )
240 if( modifier_map
[ i
] )
241 free( modifier_map
[ i
] );