| 1 | /************************************************************ |
| 2 | Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. |
| 3 | |
| 4 | Permission to use, copy, modify, and distribute this |
| 5 | software and its documentation for any purpose and without |
| 6 | fee is hereby granted, provided that the above copyright |
| 7 | notice appear in all copies and that both that copyright |
| 8 | notice and this permission notice appear in supporting |
| 9 | documentation, and that the name of Silicon Graphics not be |
| 10 | used in advertising or publicity pertaining to distribution |
| 11 | of the software without specific prior written permission. |
| 12 | Silicon Graphics makes no representation about the suitability |
| 13 | of this software for any purpose. It is provided "as is" |
| 14 | without any express or implied warranty. |
| 15 | |
| 16 | SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS |
| 17 | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
| 18 | AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON |
| 19 | GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL |
| 20 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| 21 | DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE |
| 22 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH |
| 23 | THE 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 | |
| 46 | void |
| 47 | XkbProcessKeyboardEvent(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 | |
| 125 | if (behavior.type == XkbKB_Overlay1) |
| 126 | which = XkbOverlay1Mask; |
| 127 | else |
| 128 | which = XkbOverlay2Mask; |
| 129 | if ((xkbi->desc->ctrls->enabled_ctrls & which) == 0) |
| 130 | break; |
| 131 | if ((behavior.data >= xkbi->desc->min_key_code) && |
| 132 | (behavior.data <= xkbi->desc->max_key_code)) { |
| 133 | event->detail.key = behavior.data; |
| 134 | /* 9/11/94 (ef) -- XXX! need to match release with */ |
| 135 | /* press even if the state of the */ |
| 136 | /* corresponding overlay control */ |
| 137 | /* changes while the key is down */ |
| 138 | } |
| 139 | } |
| 140 | break; |
| 141 | default: |
| 142 | ErrorF("[xkb] unknown key behavior 0x%04x\n", behavior.type); |
| 143 | break; |
| 144 | } |
| 145 | } |
| 146 | XkbHandleActions(keybd, keybd, event); |
| 147 | return; |
| 148 | } |
| 149 | |
| 150 | void |
| 151 | ProcessKeyboardEvent(InternalEvent *ev, DeviceIntPtr keybd) |
| 152 | { |
| 153 | |
| 154 | KeyClassPtr keyc = keybd->key; |
| 155 | XkbSrvInfoPtr xkbi = NULL; |
| 156 | ProcessInputProc backup_proc; |
| 157 | xkbDeviceInfoPtr xkb_priv = XKBDEVICEINFO(keybd); |
| 158 | DeviceEvent *event = &ev->device_event; |
| 159 | int is_press = (event->type == ET_KeyPress); |
| 160 | int is_release = (event->type == ET_KeyRelease); |
| 161 | |
| 162 | /* We're only interested in key events. */ |
| 163 | if (!is_press && !is_release) { |
| 164 | UNWRAP_PROCESS_INPUT_PROC(keybd, xkb_priv, backup_proc); |
| 165 | keybd->public.processInputProc(ev, keybd); |
| 166 | COND_WRAP_PROCESS_INPUT_PROC(keybd, xkb_priv, backup_proc, |
| 167 | xkbUnwrapProc); |
| 168 | return; |
| 169 | } |
| 170 | |
| 171 | xkbi = keyc->xkbInfo; |
| 172 | |
| 173 | /* If AccessX filters are active, then pass it through to |
| 174 | * AccessXFilter{Press,Release}Event; else, punt to |
| 175 | * XkbProcessKeyboardEvent. |
| 176 | * |
| 177 | * If AXF[PK]E don't intercept anything (which they probably won't), |
| 178 | * they'll punt through XPKE anyway. */ |
| 179 | if ((xkbi->desc->ctrls->enabled_ctrls & XkbAllFilteredEventsMask)) { |
| 180 | if (is_press) |
| 181 | AccessXFilterPressEvent(event, keybd); |
| 182 | else if (is_release) |
| 183 | AccessXFilterReleaseEvent(event, keybd); |
| 184 | return; |
| 185 | } |
| 186 | else { |
| 187 | XkbProcessKeyboardEvent(event, keybd); |
| 188 | } |
| 189 | |
| 190 | return; |
| 191 | } |