1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdio.h>
32#include <math.h>
33#include <X11/X.h>
34#include <X11/Xproto.h>
35#include <X11/keysym.h>
36#include "misc.h"
37#include "inputstr.h"
38#include "exevents.h"
39#include "eventstr.h"
40#include <xkbsrv.h>
41#include <ctype.h>
42#include "events.h"
43
44/***====================================================================***/
45
46void
47XkbProcessKeyboardEvent(DeviceEvent *event, DeviceIntPtr keybd)
48{
49    KeyClassPtr keyc = keybd->key;
50    XkbSrvInfoPtr xkbi;
51    int key;
52    XkbBehavior behavior;
53    unsigned ndx;
54
55    xkbi = keyc->xkbInfo;
56    key = event->detail.key;
57    if (xkbDebugFlags & 0x8)
58        DebugF("[xkb] XkbPKE: Key %d %s\n", key,
59               (event->type == ET_KeyPress ? "down" : "up"));
60
61    if (xkbi->repeatKey == key && event->type == ET_KeyRelease &&
62        !(xkbi->desc->ctrls->enabled_ctrls & XkbRepeatKeysMask))
63        AccessXCancelRepeatKey(xkbi, key);
64
65    behavior = xkbi->desc->server->behaviors[key];
66    /* The "permanent" flag indicates a hard-wired behavior that occurs */
67    /* below XKB, such as a key that physically locks.   XKB does not   */
68    /* do anything to implement the behavior, but it *does* report that */
69    /* key is hardwired */
70
71    if (!(behavior.type & XkbKB_Permanent)) {
72        switch (behavior.type) {
73        case XkbKB_Default:
74            /* Neither of these should happen in practice, but ignore them
75               anyway. */
76            if (event->type == ET_KeyPress && !event->key_repeat &&
77                key_is_down(keybd, key, KEY_PROCESSED))
78                return;
79            else if (event->type == ET_KeyRelease &&
80                     !key_is_down(keybd, key, KEY_PROCESSED))
81                return;
82            break;
83        case XkbKB_Lock:
84            if (event->type == ET_KeyRelease)
85                return;
86            else if (key_is_down(keybd, key, KEY_PROCESSED))
87                event->type = ET_KeyRelease;
88            break;
89        case XkbKB_RadioGroup:
90            ndx = (behavior.data & (~XkbKB_RGAllowNone));
91            if (ndx < xkbi->nRadioGroups) {
92                XkbRadioGroupPtr rg;
93
94                if (event->type == ET_KeyRelease)
95                    return;
96
97                rg = &xkbi->radioGroups[ndx];
98                if (rg->currentDown == event->detail.key) {
99                    if (behavior.data & XkbKB_RGAllowNone) {
100                        event->type = ET_KeyRelease;
101                        XkbHandleActions(keybd, keybd, event);
102                        rg->currentDown = 0;
103                    }
104                    return;
105                }
106                if (rg->currentDown != 0) {
107                    int tmpkey = event->detail.key;
108
109                    event->type = ET_KeyRelease;
110                    event->detail.key = rg->currentDown;
111                    XkbHandleActions(keybd, keybd, event);
112                    event->type = ET_KeyPress;
113                    event->detail.key = tmpkey;
114                }
115                rg->currentDown = key;
116            }
117            else
118                ErrorF("[xkb] InternalError! Illegal radio group %d\n", ndx);
119            break;
120        case XkbKB_Overlay1:
121        case XkbKB_Overlay2:
122        {
123            unsigned which;
124            unsigned overlay_active_now;
125            unsigned is_keyrelease = (event->type == ET_KeyRelease) ? 1 : 0;
126            /* Remembers whether the key was pressed while overlay was down,
127             * for when overlay is already released, but the key is not. */
128            unsigned key_was_overlaid = 0;
129
130            if (behavior.type == XkbKB_Overlay1)
131                which = XkbOverlay1Mask;
132            else
133                which = XkbOverlay2Mask;
134            overlay_active_now = (xkbi->desc->ctrls->enabled_ctrls & which) ? 1 : 0;
135
136            if ((unsigned char)key == key) {
137                key_was_overlaid = BitIsOn(xkbi->overlay_perkey_state, key);
138                if (!is_keyrelease) {
139                    if (overlay_active_now)
140                        SetBit(xkbi->overlay_perkey_state, key);
141                } else {
142                    if (key_was_overlaid)
143                        ClearBit(xkbi->overlay_perkey_state, key);
144                }
145            }
146
147            if ((overlay_active_now || key_was_overlaid) &&
148                    (behavior.data >= xkbi->desc->min_key_code) &&
149                    (behavior.data <= xkbi->desc->max_key_code)) {
150                event->detail.key = behavior.data;
151            }
152        }
153            break;
154        default:
155            ErrorF("[xkb] unknown key behavior 0x%04x\n", behavior.type);
156            break;
157        }
158    }
159    XkbHandleActions(keybd, keybd, event);
160    return;
161}
162
163void
164ProcessKeyboardEvent(InternalEvent *ev, DeviceIntPtr keybd)
165{
166
167    KeyClassPtr keyc = keybd->key;
168    XkbSrvInfoPtr xkbi = NULL;
169    ProcessInputProc backup_proc;
170    xkbDeviceInfoPtr xkb_priv = XKBDEVICEINFO(keybd);
171    DeviceEvent *event = &ev->device_event;
172    int is_press = (event->type == ET_KeyPress);
173    int is_release = (event->type == ET_KeyRelease);
174
175    /* We're only interested in key events. */
176    if (!is_press && !is_release) {
177        UNWRAP_PROCESS_INPUT_PROC(keybd, xkb_priv, backup_proc);
178        keybd->public.processInputProc(ev, keybd);
179        COND_WRAP_PROCESS_INPUT_PROC(keybd, xkb_priv, backup_proc,
180                                     xkbUnwrapProc);
181        return;
182    }
183
184    xkbi = keyc->xkbInfo;
185
186    /* If AccessX filters are active, then pass it through to
187     * AccessXFilter{Press,Release}Event; else, punt to
188     * XkbProcessKeyboardEvent.
189     *
190     * If AXF[PK]E don't intercept anything (which they probably won't),
191     * they'll punt through XPKE anyway. */
192    if ((xkbi->desc->ctrls->enabled_ctrls & XkbAllFilteredEventsMask)) {
193        if (is_press)
194            AccessXFilterPressEvent(event, keybd);
195        else if (is_release)
196            AccessXFilterReleaseEvent(event, keybd);
197        return;
198    }
199    else {
200        XkbProcessKeyboardEvent(event, keybd);
201    }
202
203    return;
204}
205