more mpv hacks
[jrugr.git] / src / xkeyboard.cpp
blobbe9283e154c8cf7d63dfa3f4cc95e33969da8771
1 /*************************************************************************
2 * based on xkeyboard.h by Leonid Zeitlin (lz@europe.com) *
3 * heavily modified by Ketmar // Vampire Avalon *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 *************************************************************************/
11 #include "xkeyboard.h"
13 //XkbNumKbdGroups -- maximum number of groups (currently 4)
16 XKeyboard::XKeyboard () {
17 Display *dpy = QX11Info::display();
18 int opcode, errorBase, major = XkbMajorVersion, minor = XkbMinorVersion;
20 // check the library version
21 if (!XkbLibraryVersion(&major, &minor)) {
22 qWarning() << QString(
23 "This program was built against XKB extension library\n"
24 "version %1.%2, but is run with the library version %3.%4.\n"
25 "This may cause various problems and even result in a complete\n"
26 "failure to function\n").arg(XkbMajorVersion).arg(XkbMinorVersion).arg(major).arg(minor);
29 // initialize the extension
30 mXKbAvailable = XkbQueryExtension(dpy, &opcode, &mEventCode, &errorBase, &major, &minor);
31 if (!mXKbAvailable) {
32 qCritical() <<
33 "The X Server does not support a compatible XKB extension.\n"
34 "Either the server is not XKB-capable or the extension was disabled.\n"
35 "This program would not work with this server, so it will exit now\n";
36 } else {
37 // register for XKB events
38 // group state change, i.e. the current group changed:
39 XkbSelectEventDetails(dpy, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask);
40 // keyboard mapping change:
41 XkbSelectEventDetails(dpy, XkbUseCoreKbd, XkbMapNotify, XkbAllMapComponentsMask, XkbKeySymsMask);
42 // group names change:
43 XkbSelectEventDetails(dpy, XkbUseCoreKbd, XkbNamesNotify, XkbAllNamesMask, XkbGroupNamesMask);
44 // new keyboard:
45 XkbSelectEventDetails(dpy, XkbUseCoreKbd, XkbNewKeyboardNotify, XkbAllNewKeyboardEventsMask, XkbAllNewKeyboardEventsMask);
50 XKeyboard::~XKeyboard () {
54 void XKeyboard::setActiveGroup (int groupno) {
55 XkbStateRec state;
57 XkbLockGroup(QX11Info::display(), XkbUseCoreKbd, groupno);
58 // the following call is necessary
59 memset(&state, 0, sizeof(state));
60 XkbGetState(QX11Info::display(), XkbUseCoreKbd, &state);
64 int XKeyboard::activeGroup () {
65 XkbStateRec state;
67 memset(&state, 0, sizeof(state));
68 XkbGetState(QX11Info::display(), XkbUseCoreKbd, &state);
69 return (int)state.group;
73 int XKeyboard::groupCount () {
74 XkbDescRec kbd;
75 int res;
77 memset(&kbd, 0, sizeof(kbd));
78 kbd.device_spec = XkbUseCoreKbd;
79 XkbGetControls(QX11Info::display(), XkbGroupsWrapMask, &kbd);
80 res = (int)kbd.ctrls->num_groups;
81 XkbFreeControls(&kbd, XkbGroupsWrapMask, 1);
82 return res;
86 extern "C" {
87 static int IgnoreXError(Display *, XErrorEvent *) { return 0; }
91 void XKeyboard::groupNames (QStringList &list) {
92 XErrorHandler oh;
93 XkbDescRec kbd;
94 char **names;
95 int count;
96 Display *dpy = QX11Info::display();
98 memset(&kbd, 0, sizeof(kbd));
99 kbd.device_spec = XkbUseCoreKbd;
101 XkbGetControls(dpy, XkbGroupsWrapMask, &kbd);
102 count = (int)kbd.ctrls->num_groups;
103 XkbFreeControls(&kbd, XkbGroupsWrapMask, True);
105 names = (char **)calloc(count+1, sizeof(char *));
106 XkbGetNames(dpy, XkbGroupNamesMask, &kbd);
107 // XGetAtomNames below may generate BadAtom error, which is not a problem.
108 // (it may happen if the name for a group was not defined)
109 // Thus we temporarily ignore X errors
110 oh = XSetErrorHandler(IgnoreXError);
112 XGetAtomNames(dpy, kbd.names->groups, count, names);
113 // resume normal X error processing
114 XSetErrorHandler(oh);
115 for (int f = 0; f < count; ++f) {
116 if (names[f]) {
117 list.append(names[f]);
118 XFree(names[f]);
119 } else {
120 list.append(QString::null);
123 free(names);
124 XkbFreeNames(&kbd, XkbGroupNamesMask, 1);
128 // pc+us+ru(winkey):2+inet(evdev)+group(menu_toggle)
129 void XKeyboard::symbolNames (QStringList &list) {
130 XErrorHandler oh;
131 XkbDescRec kbd;
132 Atom symNameA;
133 Display *dpy = QX11Info::display();
135 memset(&kbd, 0, sizeof(kbd));
136 kbd.device_spec = XkbUseCoreKbd;
138 XkbGetNames(dpy, XkbSymbolsNameMask, &kbd);
140 symNameA = kbd.names->symbols;
141 if (symNameA != None) {
142 char *symName;
144 oh = XSetErrorHandler(IgnoreXError);
145 symName = XGetAtomName(dpy, symNameA);
146 // resume normal X error processing
147 XSetErrorHandler(oh);
149 if (symName) {
150 char *s;
152 //qDebug() << "symName:" << symName;
153 // parse it
154 s = strdup(symName);
155 XFree(symName);
156 symName = s;
158 s = symName;
159 qDebug("symName: [%s]", s);
160 while (*s) {
161 char *e = strchr(s, '+'), ch, *t;
163 if (e == NULL) e = s+strlen(s);
164 ch = *e; *e = '\0';
165 if ((t = strchr(s, '(')) != NULL) *t = '\0';
166 if ((t = strchr(s, ':')) != NULL) *t = '\0';
167 if (strcasecmp(s, "pc") != 0 && strlen(s) == 2) {
168 qDebug(" found: [%s]", s);
169 list << s;
171 if (ch) *e++ = ch;
172 s = e;
174 free(symName);
180 void XKeyboard::groupInfo (QXkbLayoutList &list) {
181 QStringList gn, sn;
183 list.clear();
184 groupNames(gn);
185 symbolNames(sn);
186 if (gn.size() < 1) {
187 gn << "USA";
188 if (sn.size() < 1) sn << "us";
190 for (int f = 0; f < gn.size(); ++f) {
191 XkbLayoutInfo i;
193 i.name = gn[f];
194 if (f < sn.size()) i.sym = sn[f]; else i.sym = "us";
195 list << i;
200 void XKeyboard::processEvent (XEvent *ev) {
201 // XKB event?
202 if (ev->type == mEventCode) {
203 XkbEvent *xkbEv = (XkbEvent *)ev;
205 if (xkbEv->any.xkb_type == XkbStateNotify) {
206 // state notify event, the current group has changed
207 emit groupChanged(xkbEv->state.group);
208 } else if ((xkbEv->any.xkb_type == XkbMapNotify && (xkbEv->map.changed & XkbKeySymsMask)) ||
209 (xkbEv->any.xkb_type == XkbNamesNotify && (xkbEv->names.changed & XkbGroupNamesMask)) ||
210 (xkbEv->any.xkb_type == XkbNewKeyboardNotify)) {
211 // keyboard layout has changed
212 emit layoutChanged();
218 int XKeyboard::findBySym (const QXkbLayoutList &lst, const QString &sym) {
219 for (int f = 0; f < lst.size(); ++f) if (sym.compare(lst[f].sym, Qt::CaseInsensitive) == 0) return (int)f;
220 return -1;