1/*
2
3Copyright 1993 by Davor Matic
4
5Permission to use, copy, modify, distribute, and sell this software
6and its documentation for any purpose is hereby granted without fee,
7provided that the above copyright notice appear in all copies and that
8both that copyright notice and this permission notice appear in
9supporting documentation.  Davor Matic makes no representations about
10the suitability of this software for any purpose.  It is provided "as
11is" without express or implied warranty.
12
13*/
14
15#ifdef HAVE_XNEST_CONFIG_H
16#include <xnest-config.h>
17#endif
18
19#ifdef WIN32
20#include <X11/Xwindows.h>
21#endif
22
23#include <X11/X.h>
24#include <X11/Xproto.h>
25#include <X11/keysym.h>
26#include "screenint.h"
27#include "inputstr.h"
28#include "misc.h"
29#include "scrnintstr.h"
30#include "servermd.h"
31
32#include "Xnest.h"
33
34#include "Display.h"
35#include "Screen.h"
36#include "Keyboard.h"
37#include "Args.h"
38#include "Events.h"
39
40#include <X11/extensions/XKB.h>
41#include "xkbsrv.h"
42#include <X11/extensions/XKBconfig.h>
43
44extern Bool
45 XkbQueryExtension(Display * /* dpy */ ,
46                   int * /* opcodeReturn */ ,
47                   int * /* eventBaseReturn */ ,
48                   int * /* errorBaseReturn */ ,
49                   int * /* majorRtrn */ ,
50                   int *        /* minorRtrn */
51    );
52
53extern XkbDescPtr XkbGetKeyboard(Display * /* dpy */ ,
54                                 unsigned int /* which */ ,
55                                 unsigned int   /* deviceSpec */
56    );
57
58extern Status XkbGetControls(Display * /* dpy */ ,
59                             unsigned long /* which */ ,
60                             XkbDescPtr /* desc */
61    );
62
63DeviceIntPtr xnestKeyboardDevice = NULL;
64
65void
66xnestBell(int volume, DeviceIntPtr pDev, void *ctrl, int cls)
67{
68    XBell(xnestDisplay, volume);
69}
70
71void
72DDXRingBell(int volume, int pitch, int duration)
73{
74    XBell(xnestDisplay, volume);
75}
76
77void
78xnestChangeKeyboardControl(DeviceIntPtr pDev, KeybdCtrl * ctrl)
79{
80#if 0
81    unsigned long value_mask;
82    XKeyboardControl values;
83    int i;
84
85    value_mask = KBKeyClickPercent |
86        KBBellPercent | KBBellPitch | KBBellDuration | KBAutoRepeatMode;
87
88    values.key_click_percent = ctrl->click;
89    values.bell_percent = ctrl->bell;
90    values.bell_pitch = ctrl->bell_pitch;
91    values.bell_duration = ctrl->bell_duration;
92    values.auto_repeat_mode = ctrl->autoRepeat ?
93        AutoRepeatModeOn : AutoRepeatModeOff;
94
95    XChangeKeyboardControl(xnestDisplay, value_mask, &values);
96
97    /*
98       value_mask = KBKey | KBAutoRepeatMode;
99       At this point, we need to walk through the vector and compare it
100       to the current server vector.  If there are differences, report them.
101     */
102
103    value_mask = KBLed | KBLedMode;
104    for (i = 1; i <= 32; i++) {
105        values.led = i;
106        values.led_mode =
107            (ctrl->leds & (1 << (i - 1))) ? LedModeOn : LedModeOff;
108        XChangeKeyboardControl(xnestDisplay, value_mask, &values);
109    }
110#endif
111}
112
113int
114xnestKeyboardProc(DeviceIntPtr pDev, int onoff)
115{
116    XModifierKeymap *modifier_keymap;
117    KeySym *keymap;
118    int mapWidth;
119    int min_keycode, max_keycode;
120    KeySymsRec keySyms;
121    CARD8 modmap[MAP_LENGTH];
122    int i, j;
123    XKeyboardState values;
124    XkbDescPtr xkb;
125    int op, event, error, major, minor;
126
127    switch (onoff) {
128    case DEVICE_INIT:
129        XDisplayKeycodes(xnestDisplay, &min_keycode, &max_keycode);
130#ifdef _XSERVER64
131        {
132            KeySym64 *keymap64;
133            int len;
134
135            keymap64 = XGetKeyboardMapping(xnestDisplay,
136                                           min_keycode,
137                                           max_keycode - min_keycode + 1,
138                                           &mapWidth);
139            len = (max_keycode - min_keycode + 1) * mapWidth;
140            keymap = xallocarray(len, sizeof(KeySym));
141            for (i = 0; i < len; ++i)
142                keymap[i] = keymap64[i];
143            XFree(keymap64);
144        }
145#else
146        keymap = XGetKeyboardMapping(xnestDisplay,
147                                     min_keycode,
148                                     max_keycode - min_keycode + 1, &mapWidth);
149#endif
150
151        memset(modmap, 0, sizeof(modmap));
152        modifier_keymap = XGetModifierMapping(xnestDisplay);
153        for (j = 0; j < 8; j++)
154            for (i = 0; i < modifier_keymap->max_keypermod; i++) {
155                CARD8 keycode;
156
157                if ((keycode =
158                     modifier_keymap->modifiermap[j *
159                                                  modifier_keymap->
160                                                  max_keypermod + i]))
161                    modmap[keycode] |= 1 << j;
162            }
163        XFreeModifiermap(modifier_keymap);
164
165        keySyms.minKeyCode = min_keycode;
166        keySyms.maxKeyCode = max_keycode;
167        keySyms.mapWidth = mapWidth;
168        keySyms.map = keymap;
169
170        if (XkbQueryExtension(xnestDisplay, &op, &event, &error, &major, &minor)
171            == 0) {
172            ErrorF("Unable to initialize XKEYBOARD extension.\n");
173            goto XkbError;
174        }
175        xkb =
176            XkbGetKeyboard(xnestDisplay, XkbGBN_AllComponentsMask,
177                           XkbUseCoreKbd);
178        if (xkb == NULL || xkb->geom == NULL) {
179            ErrorF("Couldn't get keyboard.\n");
180            goto XkbError;
181        }
182        XkbGetControls(xnestDisplay, XkbAllControlsMask, xkb);
183
184        InitKeyboardDeviceStruct(pDev, NULL,
185                                 xnestBell, xnestChangeKeyboardControl);
186
187        XkbApplyMappingChange(pDev, &keySyms, keySyms.minKeyCode,
188                              keySyms.maxKeyCode - keySyms.minKeyCode + 1,
189                              modmap, serverClient);
190
191        XkbDDXChangeControls(pDev, xkb->ctrls, xkb->ctrls);
192        XkbFreeKeyboard(xkb, 0, False);
193        free(keymap);
194        break;
195    case DEVICE_ON:
196        xnestEventMask |= XNEST_KEYBOARD_EVENT_MASK;
197        for (i = 0; i < xnestNumScreens; i++)
198            XSelectInput(xnestDisplay, xnestDefaultWindows[i], xnestEventMask);
199        break;
200    case DEVICE_OFF:
201        xnestEventMask &= ~XNEST_KEYBOARD_EVENT_MASK;
202        for (i = 0; i < xnestNumScreens; i++)
203            XSelectInput(xnestDisplay, xnestDefaultWindows[i], xnestEventMask);
204        break;
205    case DEVICE_CLOSE:
206        break;
207    }
208    return Success;
209
210 XkbError:
211    XGetKeyboardControl(xnestDisplay, &values);
212    memmove((char *) defaultKeyboardControl.autoRepeats,
213            (char *) values.auto_repeats, sizeof(values.auto_repeats));
214
215    InitKeyboardDeviceStruct(pDev, NULL, xnestBell, xnestChangeKeyboardControl);
216    free(keymap);
217    return Success;
218}
219
220void
221xnestUpdateModifierState(unsigned int state)
222{
223    DeviceIntPtr pDev = xnestKeyboardDevice;
224    KeyClassPtr keyc = pDev->key;
225    int i;
226    CARD8 mask;
227    int xkb_state;
228
229    if (!pDev)
230        return;
231
232    xkb_state = XkbStateFieldFromRec(&pDev->key->xkbInfo->state);
233    state = state & 0xff;
234
235    if (xkb_state == state)
236        return;
237
238    for (i = 0, mask = 1; i < 8; i++, mask <<= 1) {
239        int key;
240
241        /* Modifier is down, but shouldn't be */
242        if ((xkb_state & mask) && !(state & mask)) {
243            int count = keyc->modifierKeyCount[i];
244
245            for (key = 0; key < MAP_LENGTH; key++)
246                if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
247                    if (mask == LockMask) {
248                        xnestQueueKeyEvent(KeyPress, key);
249                        xnestQueueKeyEvent(KeyRelease, key);
250                    }
251                    else if (key_is_down(pDev, key, KEY_PROCESSED))
252                        xnestQueueKeyEvent(KeyRelease, key);
253
254                    if (--count == 0)
255                        break;
256                }
257        }
258
259        /* Modifier should be down, but isn't */
260        if (!(xkb_state & mask) && (state & mask))
261            for (key = 0; key < MAP_LENGTH; key++)
262                if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
263                    xnestQueueKeyEvent(KeyPress, key);
264                    if (mask == LockMask)
265                        xnestQueueKeyEvent(KeyRelease, key);
266                    break;
267                }
268    }
269}
270