You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
8.1 KiB
249 lines
8.1 KiB
/***************************************************************************
|
|
xkeyboard.cpp - description
|
|
-------------------
|
|
begin : Sun Jul 8 2001
|
|
copyright : (C) 2001 by Leonid Zeitlin
|
|
email : lz@europe.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. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "xkeyboard.h"
|
|
|
|
#include <ntqwindowdefs.h>
|
|
#include <ntqstringlist.h>
|
|
|
|
#include <kdebug.h>
|
|
#include <tdelocale.h>
|
|
|
|
XKeyboard *XKeyboard::m_self = 0;
|
|
|
|
XKeyboard::XKeyboard()
|
|
{
|
|
Display *display = tqt_xdisplay();
|
|
#ifdef HAVE_LIBXKLAVIER
|
|
// XklSetDebugLevel(0);
|
|
XklSetLogAppender(XklLogAppender);
|
|
XklInit(display);
|
|
XklRegisterStateCallback(XklStateCallback, this);
|
|
XklRegisterConfigCallback(XklConfigCallback, this);
|
|
#else
|
|
int opcode, errorBase, major = XkbMajorVersion, minor = XkbMinorVersion;
|
|
|
|
// check the library version
|
|
if (!XkbLibraryVersion(&major, &minor)) {
|
|
kdWarning() << i18n("This program was built against XKB extension library\n"
|
|
"version %1.%2, but is run with the library version %3.%4.\n"
|
|
"This may cause various problems and even result in a complete\n"
|
|
"failure to function\n").arg(XkbMajorVersion).arg(XkbMinorVersion).arg(major).arg(minor);
|
|
}
|
|
|
|
// initialize the extension
|
|
m_xkb_available = XkbQueryExtension(display, &opcode, &m_event_code, &errorBase, &major, &minor);
|
|
if (!m_xkb_available) {
|
|
kdError() << i18n("The X Server does not support a compatible XKB extension.\n"
|
|
"Either the server is not XKB-capable or the extension was disabled.\n"
|
|
"This program would not work with this server, so it will exit now\n");
|
|
}
|
|
else {
|
|
// register for XKB events
|
|
//// group state change, i.e. the current group changed:
|
|
XkbSelectEventDetails(display, XkbUseCoreKbd, XkbStateNotify,
|
|
XkbAllStateComponentsMask, XkbGroupStateMask);
|
|
//// keyboard mapping change:
|
|
XkbSelectEventDetails(display, XkbUseCoreKbd, XkbMapNotify,
|
|
XkbAllMapComponentsMask, XkbKeySymsMask);
|
|
//// group names change:
|
|
XkbSelectEventDetails(display, XkbUseCoreKbd, XkbNamesNotify,
|
|
XkbAllNamesMask, XkbGroupNamesMask);
|
|
//// new keyboard:
|
|
XkbSelectEventDetails(display, XkbUseCoreKbd, XkbNewKeyboardNotify,
|
|
XkbAllNewKeyboardEventsMask, XkbAllNewKeyboardEventsMask);
|
|
// retrieve the number of keyboard groups
|
|
retrieveNumKbdGroups();
|
|
}
|
|
#endif
|
|
m_self = this;
|
|
}
|
|
|
|
XKeyboard::~XKeyboard(){
|
|
#ifdef HAVE_LIBXKLAVIER
|
|
XklStopListen();
|
|
XklTerm();
|
|
#endif
|
|
}
|
|
|
|
/** Determine if the given XEvent e is an XKB event with type XkbStateNotify.
|
|
* If so, newgroupno will return the new keyboard group #.
|
|
* In other words, return value of true means that this XEvent tells us
|
|
* that the user just switched the keyboard group to the new value
|
|
* newgroupno */
|
|
/*bool XKeyboard::isXkbStateNotifyEvent(XEvent *e, int *newgroupno){
|
|
bool ret = false;
|
|
if (e->type == m_event_code) {
|
|
XkbEvent *kb_ev = (XkbEvent *) e;
|
|
if (kb_ev->any.xkb_type == XkbStateNotify) {
|
|
ret = true;
|
|
*newgroupno = kb_ev->state.group;
|
|
}
|
|
}
|
|
return ret;
|
|
}*/
|
|
|
|
/** Set the current keyboard group to the given groupno */
|
|
void XKeyboard::setGroupNo(int groupno){
|
|
#ifdef HAVE_LIBXKLAVIER
|
|
XklLockGroup(groupno);
|
|
#else
|
|
XkbLockGroup(tqt_xdisplay(), XkbUseCoreKbd, groupno);
|
|
#endif
|
|
}
|
|
|
|
#ifndef HAVE_LIBXKLAVIER
|
|
extern "C" {
|
|
static int IgnoreXError(Display *, XErrorEvent *) {
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/** Get the names of the currently configured keyboard groups */
|
|
void XKeyboard::getGroupNames(TQStringList &list){
|
|
#ifdef HAVE_LIBXKLAVIER
|
|
const char** groupnames = XklGetGroupNames();
|
|
int numgroups = XklGetNumGroups();
|
|
for (int i = 0; i < numgroups; i++)
|
|
list.append(groupnames[i]);
|
|
#else
|
|
XkbDescRec xkb;
|
|
Display *display = tqt_xdisplay();
|
|
char *names[XkbNumKbdGroups];
|
|
|
|
memset(&xkb, 0, sizeof(xkb));
|
|
xkb.device_spec = XkbUseCoreKbd;
|
|
XkbGetNames(display, XkbGroupNamesMask, &xkb);
|
|
memset(names, 0, sizeof(char *) * XkbNumKbdGroups);
|
|
// XGetAtomNames below may generate BadAtom error, which is not a problem.
|
|
// (it may happen if the name for a group was not defined)
|
|
// Thus we temporarily ignore X errors
|
|
XErrorHandler old_handler = XSetErrorHandler(IgnoreXError);
|
|
XGetAtomNames(display, xkb.names->groups, m_numgroups, names);
|
|
// resume normal X error processing
|
|
XSetErrorHandler(old_handler);
|
|
for (int i = 0; i < m_numgroups; i++) {
|
|
if (names[i]) {
|
|
list.append(names[i]);
|
|
XFree(names[i]);
|
|
}
|
|
else list.append(TQString::null);
|
|
}
|
|
XkbFreeNames(&xkb, XkbGroupNamesMask, 1);
|
|
#endif
|
|
}
|
|
|
|
XKeyboard * XKeyboard::self()
|
|
{
|
|
return m_self;
|
|
}
|
|
|
|
/** return the current keyboard group index */
|
|
int XKeyboard::getGroupNo(){
|
|
#ifdef HAVE_LIBXKLAVIER
|
|
return XklGetCurrentState()->group;
|
|
#else
|
|
XkbStateRec rec;
|
|
XkbGetState(tqt_xdisplay(), XkbUseCoreKbd, &rec);
|
|
return (int) rec.group;
|
|
#endif
|
|
}
|
|
|
|
/** Returns if the given event notifies us of a keyboard layout change that requires a
|
|
* reconfiguration
|
|
* (e.g. new group added, group names changed, etc.) */
|
|
/*bool XKeyboard::isLayoutChangeEvent(XEvent *e){
|
|
if (e->type == m_event_code) {
|
|
XkbEvent *xkb_ev = (XkbEvent *) e;
|
|
if ((xkb_ev->any.xkb_type == XkbMapNotify) && (xkb_ev->map.changed & XkbKeySymsMask)
|
|
|| (xkb_ev->any.xkb_type == XkbNamesNotify) && (xkb_ev->names.changed & XkbGroupNamesMask)
|
|
|| (xkb_ev->any.xkb_type == XkbNewKeyboardNotify)) {
|
|
retrieveNumKbdGroups();
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}*/
|
|
|
|
#ifndef HAVE_LIBXKLAVIER
|
|
/** No descriptions */
|
|
void XKeyboard::retrieveNumKbdGroups(){
|
|
XkbDescRec xkb;
|
|
|
|
memset(&xkb, 0, sizeof(xkb));
|
|
/* Interestingly, in RedHat 6.0 (XFree86 3.3.3.1) the XkbGetControls call
|
|
below works even if xkb.device_spec is not set. But in RedHat 7.1 (XFree86 4.0.3)
|
|
it returns BadImplementation status code, and you have to specify
|
|
xkb.device_spec = XkbUseCoreKbd. */
|
|
xkb.device_spec = XkbUseCoreKbd;
|
|
XkbGetControls(tqt_xdisplay(), XkbGroupsWrapMask, &xkb);
|
|
m_numgroups = xkb.ctrls->num_groups;
|
|
XkbFreeControls(&xkb, XkbGroupsWrapMask, 1);
|
|
}
|
|
#endif
|
|
|
|
/** Examines an X Event passed to it and takes actions if the event is of
|
|
* interest to XKeyboard */
|
|
void XKeyboard::processEvent(XEvent *ev) {
|
|
#ifdef HAVE_LIBXKLAVIER
|
|
XklFilterEvents(ev);
|
|
#else
|
|
if (ev->type == m_event_code) {
|
|
// This an XKB event
|
|
XkbEvent *xkb_ev = (XkbEvent *) ev;
|
|
if (xkb_ev->any.xkb_type == XkbStateNotify) {
|
|
// state notify event, the current group has changed
|
|
emit groupChanged(xkb_ev->state.group);
|
|
}
|
|
else if ((xkb_ev->any.xkb_type == XkbMapNotify) && (xkb_ev->map.changed & XkbKeySymsMask)
|
|
|| (xkb_ev->any.xkb_type == XkbNamesNotify) && (xkb_ev->names.changed & XkbGroupNamesMask)
|
|
|| (xkb_ev->any.xkb_type == XkbNewKeyboardNotify)) {
|
|
// keyboard layout has changed
|
|
retrieveNumKbdGroups();
|
|
emit layoutChanged();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef HAVE_LIBXKLAVIER
|
|
void XKeyboard::XklStateCallback(XklStateChange changeType, int group,
|
|
Bool /*restore*/, void */*userData*/)
|
|
{
|
|
if (changeType == GROUP_CHANGED)
|
|
emit XKeyboard::self()->groupChanged(group);
|
|
}
|
|
|
|
void XKeyboard::XklConfigCallback(void */*userData*/)
|
|
{
|
|
emit XKeyboard::self()->layoutChanged();
|
|
}
|
|
|
|
void XKeyboard::XklLogAppender(const char file[], const char function[],
|
|
int level, const char format[], va_list args)
|
|
{
|
|
int size = vsnprintf(NULL, 0, format, args);
|
|
char *str = new char[size + 1];
|
|
vsnprintf(str, size, format, args);
|
|
kdDebug() << file << "/" << function << ": " << str << endl;
|
|
delete[] str;
|
|
}
|
|
#endif
|
|
|
|
#include "xkeyboard.moc"
|