kkbswitch
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.

xkeyboard.cpp 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /***************************************************************************
  2. xkeyboard.cpp - description
  3. -------------------
  4. begin : Sun Jul 8 2001
  5. copyright : (C) 2001 by Leonid Zeitlin
  6. email : lz@europe.com
  7. ***************************************************************************/
  8. /***************************************************************************
  9. * *
  10. * This program is free software; you can redistribute it and/or modify *
  11. * it under the terms of the GNU General Public License as published by *
  12. * the Free Software Foundation; either version 2 of the License, or *
  13. * (at your option) any later version. *
  14. * *
  15. ***************************************************************************/
  16. #include "xkeyboard.h"
  17. #include <ntqwindowdefs.h>
  18. #include <ntqstringlist.h>
  19. #include <kdebug.h>
  20. #include <tdelocale.h>
  21. XKeyboard *XKeyboard::m_self = 0;
  22. XKeyboard::XKeyboard()
  23. {
  24. Display *display = tqt_xdisplay();
  25. #ifdef HAVE_LIBXKLAVIER
  26. // XklSetDebugLevel(0);
  27. XklSetLogAppender(XklLogAppender);
  28. XklInit(display);
  29. XklRegisterStateCallback(XklStateCallback, this);
  30. XklRegisterConfigCallback(XklConfigCallback, this);
  31. #else
  32. int opcode, errorBase, major = XkbMajorVersion, minor = XkbMinorVersion;
  33. // check the library version
  34. if (!XkbLibraryVersion(&major, &minor)) {
  35. kdWarning() << i18n("This program was built against XKB extension library\n"
  36. "version %1.%2, but is run with the library version %3.%4.\n"
  37. "This may cause various problems and even result in a complete\n"
  38. "failure to function\n").arg(XkbMajorVersion).arg(XkbMinorVersion).arg(major).arg(minor);
  39. }
  40. // initialize the extension
  41. m_xkb_available = XkbQueryExtension(display, &opcode, &m_event_code, &errorBase, &major, &minor);
  42. if (!m_xkb_available) {
  43. kdError() << i18n("The X Server does not support a compatible XKB extension.\n"
  44. "Either the server is not XKB-capable or the extension was disabled.\n"
  45. "This program would not work with this server, so it will exit now\n");
  46. }
  47. else {
  48. // register for XKB events
  49. //// group state change, i.e. the current group changed:
  50. XkbSelectEventDetails(display, XkbUseCoreKbd, XkbStateNotify,
  51. XkbAllStateComponentsMask, XkbGroupStateMask);
  52. //// keyboard mapping change:
  53. XkbSelectEventDetails(display, XkbUseCoreKbd, XkbMapNotify,
  54. XkbAllMapComponentsMask, XkbKeySymsMask);
  55. //// group names change:
  56. XkbSelectEventDetails(display, XkbUseCoreKbd, XkbNamesNotify,
  57. XkbAllNamesMask, XkbGroupNamesMask);
  58. //// new keyboard:
  59. XkbSelectEventDetails(display, XkbUseCoreKbd, XkbNewKeyboardNotify,
  60. XkbAllNewKeyboardEventsMask, XkbAllNewKeyboardEventsMask);
  61. // retrieve the number of keyboard groups
  62. retrieveNumKbdGroups();
  63. }
  64. #endif
  65. m_self = this;
  66. }
  67. XKeyboard::~XKeyboard(){
  68. #ifdef HAVE_LIBXKLAVIER
  69. XklStopListen();
  70. XklTerm();
  71. #endif
  72. }
  73. /** Determine if the given XEvent e is an XKB event with type XkbStateNotify.
  74. * If so, newgroupno will return the new keyboard group #.
  75. * In other words, return value of true means that this XEvent tells us
  76. * that the user just switched the keyboard group to the new value
  77. * newgroupno */
  78. /*bool XKeyboard::isXkbStateNotifyEvent(XEvent *e, int *newgroupno){
  79. bool ret = false;
  80. if (e->type == m_event_code) {
  81. XkbEvent *kb_ev = (XkbEvent *) e;
  82. if (kb_ev->any.xkb_type == XkbStateNotify) {
  83. ret = true;
  84. *newgroupno = kb_ev->state.group;
  85. }
  86. }
  87. return ret;
  88. }*/
  89. /** Set the current keyboard group to the given groupno */
  90. void XKeyboard::setGroupNo(int groupno){
  91. #ifdef HAVE_LIBXKLAVIER
  92. XklLockGroup(groupno);
  93. #else
  94. XkbLockGroup(tqt_xdisplay(), XkbUseCoreKbd, groupno);
  95. #endif
  96. }
  97. #ifndef HAVE_LIBXKLAVIER
  98. extern "C" {
  99. static int IgnoreXError(Display *, XErrorEvent *) {
  100. return 0;
  101. }
  102. }
  103. #endif
  104. /** Get the names of the currently configured keyboard groups */
  105. void XKeyboard::getGroupNames(TQStringList &list){
  106. #ifdef HAVE_LIBXKLAVIER
  107. const char** groupnames = XklGetGroupNames();
  108. int numgroups = XklGetNumGroups();
  109. for (int i = 0; i < numgroups; i++)
  110. list.append(groupnames[i]);
  111. #else
  112. XkbDescRec xkb;
  113. Display *display = tqt_xdisplay();
  114. char *names[XkbNumKbdGroups];
  115. memset(&xkb, 0, sizeof(xkb));
  116. xkb.device_spec = XkbUseCoreKbd;
  117. XkbGetNames(display, XkbGroupNamesMask, &xkb);
  118. memset(names, 0, sizeof(char *) * XkbNumKbdGroups);
  119. // XGetAtomNames below may generate BadAtom error, which is not a problem.
  120. // (it may happen if the name for a group was not defined)
  121. // Thus we temporarily ignore X errors
  122. XErrorHandler old_handler = XSetErrorHandler(IgnoreXError);
  123. XGetAtomNames(display, xkb.names->groups, m_numgroups, names);
  124. // resume normal X error processing
  125. XSetErrorHandler(old_handler);
  126. for (int i = 0; i < m_numgroups; i++) {
  127. if (names[i]) {
  128. list.append(names[i]);
  129. XFree(names[i]);
  130. }
  131. else list.append(TQString::null);
  132. }
  133. XkbFreeNames(&xkb, XkbGroupNamesMask, 1);
  134. #endif
  135. }
  136. XKeyboard * XKeyboard::self()
  137. {
  138. return m_self;
  139. }
  140. /** return the current keyboard group index */
  141. int XKeyboard::getGroupNo(){
  142. #ifdef HAVE_LIBXKLAVIER
  143. return XklGetCurrentState()->group;
  144. #else
  145. XkbStateRec rec;
  146. XkbGetState(tqt_xdisplay(), XkbUseCoreKbd, &rec);
  147. return (int) rec.group;
  148. #endif
  149. }
  150. /** Returns if the given event notifies us of a keyboard layout change that requires a
  151. * reconfiguration
  152. * (e.g. new group added, group names changed, etc.) */
  153. /*bool XKeyboard::isLayoutChangeEvent(XEvent *e){
  154. if (e->type == m_event_code) {
  155. XkbEvent *xkb_ev = (XkbEvent *) e;
  156. if ((xkb_ev->any.xkb_type == XkbMapNotify) && (xkb_ev->map.changed & XkbKeySymsMask)
  157. || (xkb_ev->any.xkb_type == XkbNamesNotify) && (xkb_ev->names.changed & XkbGroupNamesMask)
  158. || (xkb_ev->any.xkb_type == XkbNewKeyboardNotify)) {
  159. retrieveNumKbdGroups();
  160. return true;
  161. }
  162. }
  163. return false;
  164. }*/
  165. #ifndef HAVE_LIBXKLAVIER
  166. /** No descriptions */
  167. void XKeyboard::retrieveNumKbdGroups(){
  168. XkbDescRec xkb;
  169. memset(&xkb, 0, sizeof(xkb));
  170. /* Interestingly, in RedHat 6.0 (XFree86 3.3.3.1) the XkbGetControls call
  171. below works even if xkb.device_spec is not set. But in RedHat 7.1 (XFree86 4.0.3)
  172. it returns BadImplementation status code, and you have to specify
  173. xkb.device_spec = XkbUseCoreKbd. */
  174. xkb.device_spec = XkbUseCoreKbd;
  175. XkbGetControls(tqt_xdisplay(), XkbGroupsWrapMask, &xkb);
  176. m_numgroups = xkb.ctrls->num_groups;
  177. XkbFreeControls(&xkb, XkbGroupsWrapMask, 1);
  178. }
  179. #endif
  180. /** Examines an X Event passed to it and takes actions if the event is of
  181. * interest to XKeyboard */
  182. void XKeyboard::processEvent(XEvent *ev) {
  183. #ifdef HAVE_LIBXKLAVIER
  184. XklFilterEvents(ev);
  185. #else
  186. if (ev->type == m_event_code) {
  187. // This an XKB event
  188. XkbEvent *xkb_ev = (XkbEvent *) ev;
  189. if (xkb_ev->any.xkb_type == XkbStateNotify) {
  190. // state notify event, the current group has changed
  191. emit groupChanged(xkb_ev->state.group);
  192. }
  193. else if ((xkb_ev->any.xkb_type == XkbMapNotify) && (xkb_ev->map.changed & XkbKeySymsMask)
  194. || (xkb_ev->any.xkb_type == XkbNamesNotify) && (xkb_ev->names.changed & XkbGroupNamesMask)
  195. || (xkb_ev->any.xkb_type == XkbNewKeyboardNotify)) {
  196. // keyboard layout has changed
  197. retrieveNumKbdGroups();
  198. emit layoutChanged();
  199. }
  200. }
  201. #endif
  202. }
  203. #ifdef HAVE_LIBXKLAVIER
  204. void XKeyboard::XklStateCallback(XklStateChange changeType, int group,
  205. Bool /*restore*/, void */*userData*/)
  206. {
  207. if (changeType == GROUP_CHANGED)
  208. emit XKeyboard::self()->groupChanged(group);
  209. }
  210. void XKeyboard::XklConfigCallback(void */*userData*/)
  211. {
  212. emit XKeyboard::self()->layoutChanged();
  213. }
  214. void XKeyboard::XklLogAppender(const char file[], const char function[],
  215. int level, const char format[], va_list args)
  216. {
  217. int size = vsnprintf(NULL, 0, format, args);
  218. char *str = new char[size + 1];
  219. vsnprintf(str, size, format, args);
  220. kdDebug() << file << "/" << function << ": " << str << endl;
  221. delete[] str;
  222. }
  223. #endif
  224. #include "xkeyboard.moc"