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
[] = {
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
;
83 for( i
= 0; i
< 8; i
++ )
84 if( modifier_map
[ i
] ) {
87 for( j
= 0; modifier_map
[ i
][ j
]; j
++ )
88 if( keyboard_map
[ modifier_map
[ i
][ j
] ][ 0 ] ==
90 keyboard_map
[ modifier_map
[ i
][ j
] ][ 0 ] ==
93 else if( keyboard_map
[ modifier_map
[ i
][ j
] ][ 0 ] ==
99 /* The modifier map is unpopulated: there's nothing we can do yet,
100 and we'll be invoked again later once there is. */
103 for( screen
= 0; screen
< num_screens
; screen
++ ) {
104 /* Undo any previous grabs. */
105 xcb_ungrab_key( c
, XCB_GRAB_ANY
, screens
[ screen
]->root
,
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
++ )
114 /* No key is currently bound to keysym; omit this action. */
117 xcb_grab_key( c
, FALSE
, screens
[ screen
]->root
,
118 key_actions
[ i
].modifiers
, j
, XCB_GRAB_MODE_ASYNC
,
119 XCB_GRAB_MODE_ASYNC
);
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
);
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
) {
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
++ )
165 if( r
->keysyms_per_keycode
> 4 )
166 in
+= r
->keysyms_per_keycode
- 4;
175 extern void get_keyboard_mapping( int first
, int count
) {
177 union callback_param cp
;
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 */
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
++ )
210 modifier_map
[ i
] = out
= xmalloc( ( codes_used
+ 1 ) *
213 for( j
= 0; j
< r
->keycodes_per_modifier
; j
++ )
219 modifier_map
[ i
] = NULL
;
227 extern void get_modifier_mapping( void ) {
229 union callback_param cp
;
232 handle_async_reply( xcb_get_modifier_mapping( c
).sequence
,
233 handle_get_modifier_mapping
, cp
);
237 extern void cleanup_keyboard( void ) {
241 for( i
= 0; i
< 8; i
++ )
242 if( modifier_map
[ i
] )
243 free( modifier_map
[ i
] );