xkb: implementation of keyboard layout switched

This patch provides functions to get/set current keyboard layout.

Current implementation doesn't support any configuration of layout,
it's a merely a layout indicator and switcher, however layout
configuration can be set by tools like setxkbmap or by any third-party
tools.
This commit is contained in:
Aleksey Fedotov 2015-02-23 19:08:24 +03:00 committed by Aleksei
parent dde5b1b4d1
commit 996f6785a8
8 changed files with 260 additions and 0 deletions

View File

@ -56,6 +56,7 @@ set(AWE_SRCS
${SOURCE_DIR}/strut.c
${SOURCE_DIR}/systray.c
${SOURCE_DIR}/xwindow.c
${SOURCE_DIR}/xkb.c
${SOURCE_DIR}/common/atoms.c
${SOURCE_DIR}/common/backtrace.c
${SOURCE_DIR}/common/buffer.c

View File

@ -26,6 +26,7 @@
#include "common/backtrace.h"
#include "common/version.h"
#include "common/xutil.h"
#include "xkb.h"
#include "dbus.h"
#include "event.h"
#include "ewmh.h"
@ -499,6 +500,9 @@ main(int argc, char **argv)
/* init spawn (sn) */
spawn_init();
/* init xkb */
xkb_init();
/* The default GC is just a newly created associated with a window with
* depth globalconf.default_depth */
xcb_window_t tmp_win = xcb_generate_id(globalconf.connection);

View File

@ -140,6 +140,7 @@ pkg_check_modules(AWESOME_REQUIRED REQUIRED
xcb-util>=0.3.8
xcb-keysyms>=0.3.4
xcb-icccm>=0.3.8
xcb-xkb>=1.11
cairo-xcb
libstartup-notification-1.0>=0.10
xproto>=7.0.15

View File

@ -75,3 +75,16 @@
-- @param name A string with the event name.
-- @param ... Signal arguments.
-- @function emit_signal
--- Switch keyboard layout group.
-- @param num keyboard layout number, integer from 0 to 3
-- @function xkb_set_layout_group
--- Get current keyboard layout group.
-- @return current keyboard layout number
-- @function xkb_get_layout_group
--- Get description of configured layouts
-- @return String with description of configured layouts
-- @function xkb_get_group_names

14
event.c
View File

@ -32,6 +32,7 @@
#include "mousegrabber.h"
#include "luaa.h"
#include "systray.h"
#include "xkb.h"
#include "objects/screen.h"
#include "common/atoms.h"
#include "common/xutil.h"
@ -42,6 +43,7 @@
#include <xcb/xcb_atom.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_event.h>
#include <xcb/xkb.h>
#define DO_EVENT_HOOK_CALLBACK(type, xcbtype, xcbeventprefix, arraytype, match) \
static void \
@ -880,6 +882,7 @@ void event_handle(xcb_generic_event_t *event)
static uint8_t randr_screen_change_notify = 0;
static uint8_t shape_notify = 0;
static uint8_t xkb_notify = 0;
if(randr_screen_change_notify == 0)
{
@ -898,10 +901,21 @@ void event_handle(xcb_generic_event_t *event)
shape_notify = shape_query->first_event + XCB_SHAPE_NOTIFY;
}
if(xkb_notify == 0)
{
/* check for xkb extension */
const xcb_query_extension_reply_t *xkb_query;
xkb_query = xcb_get_extension_data(globalconf.connection, &xcb_xkb_id);
if(xkb_query->present)
xkb_notify = xkb_query->first_event;
}
if (response_type == randr_screen_change_notify)
event_handle_randr_screen_change_notify((void *) event);
if (response_type == shape_notify)
event_handle_shape_notify((void *) event);
if (response_type == xkb_notify)
event_handle_xkb_notify((void *) event);
}
// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

6
luaa.c
View File

@ -37,6 +37,7 @@
#include "selection.h"
#include "spawn.h"
#include "systray.h"
#include "xkb.h"
#include <lua.h>
#include <lauxlib.h>
@ -359,6 +360,9 @@ luaA_init(xdgHandle* xdg)
{ "get_xproperty", luaA_get_xproperty },
{ "__index", luaA_awesome_index },
{ "__newindex", luaA_default_newindex },
{ "xkb_set_layout_group", luaA_xkb_set_layout_group},
{ "xkb_get_layout_group", luaA_xkb_get_layout_group},
{ "xkb_get_group_names", luaA_xkb_get_group_names},
{ NULL, NULL }
};
@ -473,6 +477,8 @@ luaA_init(xdgHandle* xdg)
signal_add(&global_signals, "debug::newindex::miss");
signal_add(&global_signals, "systray::update");
signal_add(&global_signals, "wallpaper_changed");
signal_add(&global_signals, "xkb::map_changed");
signal_add(&global_signals, "xkb::group_changed");
signal_add(&global_signals, "refresh");
signal_add(&global_signals, "startup");
signal_add(&global_signals, "exit");

185
xkb.c Normal file
View File

@ -0,0 +1,185 @@
/*
* xkb.c - keyboard layout control functions
*
* Copyright © 2015 Aleksey Fedotov <lexa@cfotr.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "xkb.h"
#include "globalconf.h"
#include <xcb/xkb.h>
/* \brief switch keyboard layout
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
* \luastack
* \lparam layout number, integer from 0 to 3
*/
int
luaA_xkb_set_layout_group(lua_State *L)
{
unsigned group = luaL_checkinteger(L, 1);
xcb_xkb_latch_lock_state (globalconf.connection, XCB_XKB_ID_USE_CORE_KBD,
0, 0, true, group, 0, 0, 0);
return 0;
}
/* \brief get current layout number
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
* \luastack
* \lreturn current layout number, integer from 0 to 3
*/
int
luaA_xkb_get_layout_group(lua_State *L)
{
xcb_xkb_get_state_cookie_t state_c;
state_c = xcb_xkb_get_state_unchecked (globalconf.connection,
XCB_XKB_ID_USE_CORE_KBD);
xcb_xkb_get_state_reply_t* state_r;
state_r = xcb_xkb_get_state_reply (globalconf.connection,
state_c, NULL);
if (!state_r)
{
free(state_r);
return 0;
}
lua_pushinteger(L, state_r->group);
free(state_r);
return 1;
}
/* \brief get layout short names
* \param L The Lua VM state.
* \return The number of elements pushed on stack.
* \luastack
* \lreturn string describing current layout settings, \
* example: 'pc+us+de:2+inet(evdev)+group(alt_shift_toggle)+ctrl(nocaps)'
*/
int
luaA_xkb_get_group_names(lua_State *L)
{
xcb_xkb_get_names_cookie_t name_c;
name_c = xcb_xkb_get_names_unchecked (globalconf.connection,
XCB_XKB_ID_USE_CORE_KBD,
XCB_XKB_NAME_DETAIL_SYMBOLS);
xcb_xkb_get_names_reply_t* name_r;
name_r = xcb_xkb_get_names_reply (globalconf.connection, name_c, NULL);
if (!name_r)
{
luaA_warn(L, "Failed to get xkb symbols name");
return 0;
}
xcb_xkb_get_names_value_list_t name_list;
void *buffer = xcb_xkb_get_names_value_list(name_r);
xcb_xkb_get_names_value_list_unpack (
buffer, name_r->nTypes, name_r->indicators,
name_r->virtualMods, name_r->groupNames, name_r->nKeys,
name_r->nKeyAliases, name_r->nRadioGroups, name_r->which,
&name_list);
xcb_get_atom_name_cookie_t atom_name_c;
atom_name_c = xcb_get_atom_name_unchecked(globalconf.connection, name_list.symbolsName);
xcb_get_atom_name_reply_t *atom_name_r;
atom_name_r = xcb_get_atom_name_reply(globalconf.connection, atom_name_c, NULL);
if (!atom_name_r) {
luaA_warn(L, "Failed to get atom symbols name");
free(name_r);
return 0;
}
const char *name = xcb_get_atom_name_name(atom_name_r);
size_t name_len = xcb_get_atom_name_name_length(atom_name_r);
lua_pushlstring(L, name, name_len);
free(atom_name_r);
free(name_r);
return 1;
}
/** The xkb notify event handler.
* \param event The event.
*/
void event_handle_xkb_notify(xcb_generic_event_t* event)
{
lua_State *L = globalconf_get_lua_State();
/* The pad0 field of xcb_generic_event_t contains the event sub-type,
* unfortunately xkb doesn't provide a usable struct for getting this in a
* nicer way*/
switch (event->pad0)
{
case XCB_XKB_NEW_KEYBOARD_NOTIFY:
{
xcb_xkb_new_keyboard_notify_event_t *new_keyboard_event = (void*)event;
if (new_keyboard_event->changed & XCB_XKB_NKN_DETAIL_KEYCODES)
{
signal_object_emit(L, &global_signals, "xkb::map_changed", 0);
}
break;
}
case XCB_XKB_NAMES_NOTIFY:
{
signal_object_emit(L, &global_signals, "xkb::map_changed", 0);
break;
}
case XCB_XKB_STATE_NOTIFY:
{
xcb_xkb_state_notify_event_t *state_notify_event = (void*)event;
if (state_notify_event->changed & XCB_XKB_STATE_PART_GROUP_STATE)
{
lua_pushnumber(L, state_notify_event->group);
signal_object_emit(L, &global_signals, "xkb::group_changed", 1);
}
break;
}
}
}
/** Initialize XKB support
*/
void xkb_init(void)
{
/* check that XKB extension present in this X server */
const xcb_query_extension_reply_t *xkb_r;
xkb_r = xcb_get_extension_data(globalconf.connection, &xcb_xkb_id);
if (!xkb_r || !xkb_r->present)
{
fatal("Xkb extension not present");
}
/* check xkb version */
xcb_xkb_use_extension_cookie_t ext_cookie = xcb_xkb_use_extension(globalconf.connection, 1, 0);
xcb_xkb_use_extension_reply_t *ext_reply = xcb_xkb_use_extension_reply (globalconf.connection, ext_cookie, NULL);
if (!ext_reply || !ext_reply->supported)
{
fatal("Required xkb extension is not supported");
}
unsigned int map = XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY | XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY;
xcb_xkb_select_events_checked(globalconf.connection,
XCB_XKB_ID_USE_CORE_KBD,
map,
0,
map,
0,
0,
0);
}

36
xkb.h Normal file
View File

@ -0,0 +1,36 @@
/*
* xkb.h - Keyboard layout manager header
*
* Copyright © 2015 Aleksey Fedotov <lexa@cfotr.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef AWESOME_XKB_H
#define AWESOME_XKB_H
#include <xcb/xcb.h>
#include <lua.h>
void event_handle_xkb_notify(xcb_generic_event_t* event);
void xkb_init(void);
int luaA_xkb_set_layout_group(lua_State *L);
int luaA_xkb_get_layout_group(lua_State *L);
int luaA_xkb_get_group_names(lua_State *L);
#endif