*
* (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
*
- * Copyright 2001, 2002 Sun Microsystems Inc.,
+ * Copyright 2001, 2003 Sun Microsystems Inc.,
* Copyright 2001, 2002 Ximian, Inc.
*
* This library is free software; you can redistribute it and/or
#include <string.h>
#include <ctype.h>
#include <stdio.h>
+#include <sys/time.h>
#include <bonobo/bonobo-exception.h>
#include <X11/Xlib.h>
static unsigned int mouse_button_mask =
Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask;
static unsigned int key_modifier_mask =
- Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask;
+ Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | LockMask | ControlMask | SPI_KEYMASK_NUMLOCK;
+static unsigned int _numlock_physical_mask = Mod2Mask; /* a guess, will be reset */
static GQuark spi_dec_private_quark = 0;
int xkb_base_error_code;
unsigned int xkb_latch_mask;
unsigned int pending_xkb_mod_relatch_mask;
- KeyCode *shift_keycodes;
XkbDescPtr xkb_desc;
} DEControllerPrivateData;
return XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
}
-#define SPI_DEC_MAX_SHIFT_KEYSYMS 15
-static long _shift_keysyms[SPI_DEC_MAX_SHIFT_KEYSYMS] =
- {XK_Shift_L, XK_Shift_R,
- XK_Control_L, XK_Control_R,
- XK_Caps_Lock, XK_Shift_Lock,
- XK_Alt_L, XK_Alt_R,
- XK_Meta_L, XK_Meta_R,
- XK_Super_L, XK_Super_R,
- XK_Hyper_L, XK_Hyper_R,
- 0};
-
-static gboolean
-spi_keycodes_contain (KeyCode keycodes[], KeyCode keycode)
-{
- int i = 0;
-
- if (keycode)
- {
- while (i < SPI_DEC_MAX_SHIFT_KEYSYMS)
- {
- if (keycodes[i] == keycode)
- return TRUE;
- ++i;
- }
- }
- return FALSE;
-}
-
-static void
-spi_dec_init_keycode_list (SpiDEController *controller)
-{
- DEControllerPrivateData *priv =
- g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
- KeyCode keycode;
- int i;
- priv->shift_keycodes = g_malloc (sizeof (KeyCode) *
- SPI_DEC_MAX_SHIFT_KEYSYMS);
- for (i = 0; _shift_keysyms[i] != 0; ++i)
- {
- keycode = keycode_for_keysym (_shift_keysyms [i]);
- priv->shift_keycodes [i] = keycode;
- }
- priv->shift_keycodes [i] = 0; /* terminate the list */
-}
-
static DEControllerGrabMask *
spi_grab_mask_clone (DEControllerGrabMask *grab_mask)
{
DEControllerPrivateData *priv =
g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
#ifdef SPI_XKB_DEBUG
- if (priv->xkb_latch_mask) fprintf (stderr, "unlatch pending! %x\n", mask);
+ if (priv->xkb_latch_mask) fprintf (stderr, "unlatch pending! %x\n",
+ priv->xkb_latch_mask);
#endif
priv->pending_xkb_mod_relatch_mask |= priv->xkb_latch_mask;
}
-static gint poll_count = 0;
-
+static void
+spi_dec_clear_unlatch_pending (SpiDEController *controller)
+{
+ DEControllerPrivateData *priv =
+ g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
+ priv->xkb_latch_mask = 0;
+}
+
static gboolean
spi_dec_button_update_and_emit (SpiDEController *controller,
guint mask_return)
is_down = True;
}
else if (!(mask_return & Button4Mask) &&
- (mouse_mask_state & Button1Mask))
+ (mouse_mask_state & Button4Mask))
{
mouse_mask_state &= ~Button4Mask;
button_number = 4;
}
else if ((mask_return & Button4Mask) &&
- !(mouse_mask_state & Button1Mask))
+ !(mouse_mask_state & Button4Mask))
{
mouse_mask_state |= Button4Mask;
button_number = 4;
Accessibility_Event e;
CORBA_Environment ev;
int win_x_return,win_y_return;
- int poll_count_modulus = 10;
unsigned int mask_return;
Window root_return, child_return;
Display *display = spi_get_display ();
while (spi_dec_button_update_and_emit (controller, mask_return));
}
- if (poll_count++ == poll_count_modulus) {
- poll_count = 0;
- e.type = "mouse:abs";
- e.source = BONOBO_OBJREF (controller->registry->desktop);
- e.detail1 = *x;
- e.detail2 = *y;
- spi_init_any_nil (&e.any_data);
- CORBA_exception_init (&ev);
- Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
- &e,
- &ev);
- }
if (*x != last_mouse_pos->x || *y != last_mouse_pos->y)
{
+ e.type = "mouse:abs";
+ e.source = BONOBO_OBJREF (controller->registry->desktop);
+ e.detail1 = *x;
+ e.detail2 = *y;
+ spi_init_any_nil (&e.any_data);
+ CORBA_exception_init (&ev);
+ Accessibility_Registry_notifyEvent (BONOBO_OBJREF (controller->registry),
+ &e,
+ &ev);
e.type = "mouse:rel";
e.source = BONOBO_OBJREF (controller->registry->desktop);
e.detail1 = *x - last_mouse_pos->x;
fprintf (stderr, "MODIFIER CHANGE EVENT! %x to %x\n",
prev_mask, current_mask);
#endif
+
+ /* set bits for the virtual modifiers like NUMLOCK */
+ if (prev_mask & _numlock_physical_mask)
+ prev_mask |= SPI_KEYMASK_NUMLOCK;
+ if (current_mask & _numlock_physical_mask)
+ current_mask |= SPI_KEYMASK_NUMLOCK;
+
e.type = "keyboard:modifiers";
e.source = BONOBO_OBJREF (controller->registry->desktop);
e.detail1 = prev_mask & key_modifier_mask;
}
}
+#ifdef WE_NEED_UGRAB_MOUSE
static int
spi_dec_ungrab_mouse (gpointer data)
{
}
return FALSE;
}
+#endif
static void
spi_dec_init_mouse_listener (SpiRegistry *registry)
if (display)
{
- XGrabButton (display, AnyButton, AnyModifier,
+ if (XGrabButton (display, AnyButton, AnyModifier,
gdk_x11_get_default_root_xwindow (),
True, ButtonPressMask | ButtonReleaseMask,
- GrabModeSync, GrabModeAsync, None, None);
+ GrabModeSync, GrabModeAsync, None, None) != Success)
+ fprintf (stderr, "WARNING: could not grab mouse buttons!\n");
XSync (display, False);
#ifdef SPI_DEBUG
fprintf (stderr, "mouse buttons grabbed\n");
}
}
+/**
+ * Eventually we can use this to make the marshalling of mask types
+ * more sane, but for now we just use this to detect
+ * the use of 'virtual' masks such as Mumlock and convert them to
+ * system-specific mask values (i.e. ModMask).
+ *
+ **/
+static Accessibility_ControllerEventMask
+spi_dec_translate_mask (Accessibility_ControllerEventMask mask)
+{
+ DEControllerPrivateData *priv;
+
+ if (mask == SPI_KEYMASK_NUMLOCK) {
+ mask = _numlock_physical_mask;
+ }
+ return mask;
+}
+
static DEControllerKeyListener *
spi_dec_key_listener_new (CORBA_Object l,
const Accessibility_KeySet *keys,
key_listener->listener.object = bonobo_object_dup_ref (l, ev);
key_listener->listener.type = SPI_DEVICE_TYPE_KBD;
key_listener->keys = ORBit_copy_value (keys, TC_Accessibility_KeySet);
- key_listener->mask = mask;
+ key_listener->mask = spi_dec_translate_mask (mask);
key_listener->listener.typeseq = ORBit_copy_value (typeseq, TC_Accessibility_EventTypeSeq);
if (mode)
key_listener->mode = ORBit_copy_value (mode, TC_Accessibility_EventListenerMode);
int button = xbutton_event->button;
unsigned int mouse_button_state = xbutton_event->state;
-
+
switch (button)
{
case 1:
/* if client wants to consume this event, and XKB latch state was
* unset by this button event, we reset it
*/
- if (is_consumed && (xkb_mod_unlatch_occurred))
+ if (is_consumed && xkb_mod_unlatch_occurred)
spi_dec_set_unlatch_pending (controller, mouse_mask_state);
XAllowEvents (spi_get_display (),
&= ~(XkbAX_StickyKeysFBMask);
XkbChangeControls (display, priv->xkb_desc, &changes);
}
+ /* TODO: account for lock as well as latch */
XkbLatchModifiers (display,
XkbUseCoreKbd,
priv->pending_xkb_mod_relatch_mask,
g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
/* FIXME: should check for extension first! */
XTestGrabControl (spi_get_display (), True);
- priv->xkb_desc = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
/* calls to device-specific implementations and routines go here */
/* register with: keyboard hardware code handler */
&priv->xkb_base_error_code, NULL, NULL);
if (priv->have_xkb)
{
+ priv->xkb_desc = XkbGetMap (spi_get_display (), 0, XkbUseCoreKbd);
XkbSelectEvents (spi_get_display (),
XkbUseCoreKbd,
XkbStateNotifyMask, XkbStateNotifyMask);
+ _numlock_physical_mask = XkbKeysymToModifiers (spi_get_display (),
+ XK_Num_Lock);
}
+
gdk_window_add_filter (NULL, global_filter_fn, controller);
gdk_window_set_events (gdk_get_default_root_window (),
DEControllerKeyListener *listener,
CORBA_boolean is_system_global)
{
- if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFFFF)) &&
+ if ((key_event->modifiers == (CORBA_unsigned_short) (listener->mask & 0xFF)) &&
spi_key_set_contains_key (listener->keys, key_event) &&
spi_eventtype_seq_contains_event (listener->listener.typeseq, key_event) &&
(is_system_global == listener->mode->global))
Accessibility_DeviceEvent key_event;
KeySym keysym;
const int cbuf_bytes = 20;
- char cbuf [cbuf_bytes];
-
- keysym = XLookupKeysym (x_key_event, 0);
+ char cbuf [cbuf_bytes+1];
+ int nbytes;
+
+ nbytes = XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL);
key_event.id = (CORBA_long)(keysym);
key_event.hw_code = (CORBA_short) x_key_event->keycode;
if (((XEvent *) x_key_event)->type == KeyPress)
{
- key_event.type = Accessibility_KEY_PRESSED;
+ key_event.type = Accessibility_KEY_PRESSED_EVENT;
}
else
{
- key_event.type = Accessibility_KEY_RELEASED;
+ key_event.type = Accessibility_KEY_RELEASED_EVENT;
}
key_event.modifiers = (CORBA_unsigned_short)(x_key_event->state);
key_event.is_text = CORBA_FALSE;
key_event.event_string = CORBA_string_dup ("space");
break;
case XK_Tab:
-#ifdef SPI_KEYEVENT_DEBUG
- fprintf(stderr, "Tab\n");
-#endif
key_event.event_string = CORBA_string_dup ("Tab");
break;
case XK_BackSpace:
key_event.event_string = CORBA_string_dup ("Right");
break;
default:
- if (XLookupString (x_key_event, cbuf, cbuf_bytes, &keysym, NULL) > 0)
+ if (nbytes > 0)
{
+ gunichar c;
+ cbuf[nbytes] = '\0'; /* OK since length is cbuf_bytes+1 */
key_event.event_string = CORBA_string_dup (cbuf);
- if (isgraph (keysym))
+ c = g_utf8_get_char_validated (cbuf, nbytes);
+ if ((c > 0) && g_unichar_isprint (c))
{
- key_event.is_text = CORBA_TRUE; /* FIXME: incorrect for some composed chars? */
+ key_event.is_text = CORBA_TRUE;
+ /* incorrect for some composed chars? */
}
}
else
key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
#ifdef SPI_KEYEVENT_DEBUG
fprintf (stderr,
- "Key %lu pressed (%c), modifiers %d\n",
- (unsigned long) keysym,
- keysym ? (int) keysym : '*',
- (int) x_key_event->state);
+ "Key %lu pressed (%c), modifiers %d; string=%s [%x] %s\n",
+ (unsigned long) keysym,
+ keysym ? (int) keysym : '*',
+ (int) x_key_event->state,
+ key_event.event_string,
+ key_event.event_string[0],
+ (key_event.is_text == CORBA_TRUE) ? "(text)" : "(not text)");
#endif
#ifdef SPI_DEBUG
fprintf (stderr, "%s%c",
next = l->next;
re_issue_grab = recv &&
-/* (recv->type == Accessibility_KEY_RELEASED) && - (?) */
(recv->modifiers & grab_mask->mod_mask) &&
(grab_mask->key_val == keycode_for_keysym (recv->id));
{
SpiDEController *controller =
SPI_DEVICE_EVENT_CONTROLLER (bonobo_object (servant));
- DEControllerPrivateData *priv;
long key_synth_code;
- unsigned int slow_keys_delay;
- unsigned int press_time;
- unsigned int release_time;
+ KeySym keysym;
#ifdef SPI_DEBUG
fprintf (stderr, "synthesizing keystroke %ld, type %d\n",
{
DBG (-1, g_warning ("Error emitting keystroke"));
}
-
- /* now we must determine whether this keystroke is expected
- * to delatch XKB. This is a bit of a hack :-( */
- priv = g_object_get_qdata (G_OBJECT (controller), spi_dec_private_quark);
- if (!priv->shift_keycodes)
- spi_dec_init_keycode_list (controller);
- if (!spi_keycodes_contain (priv->shift_keycodes, key_synth_code))
- {
- priv->pending_xkb_mod_relatch_mask = 0;
- priv->xkb_latch_mask = 0;
- fprintf (stderr, "resetting the relatch masks.\n");
- }
- else
+ if (synth_type == Accessibility_KEY_SYM) {
+ keysym = keycode;
+ }
+ else {
+ keysym = XkbKeycodeToKeysym (spi_get_display (), keycode, 0, 0);
+ }
+ if (XkbKeysymToModifiers (spi_get_display (), keysym) == 0)
{
- int x, y;
- gboolean moved;
- priv->pending_xkb_mod_relatch_mask =
- spi_dec_mouse_check (controller, &x, &y, &moved);
- fprintf (stderr, "preparing to relatch %x\n");
+ spi_dec_clear_unlatch_pending (controller);
}
}
const CORBA_char *eventName,
CORBA_Environment *ev)
{
- int button;
+ int button = 0;
gboolean error = FALSE;
Display *display = spi_get_display ();
#ifdef SPI_DEBUG
case '3':
button = 3;
break;
+ case '4':
+ button = 4;
+ break;
+ case '5':
+ button = 5;
+ break;
default:
error = TRUE;
}
device_event_controller->mouse_listeners = NULL;
device_event_controller->keygrabs_list = NULL;
- /*
- * TODO: fixme, this module makes the foolish assumptions that
- * registryd uses the same display as the apps, and that the
- * DISPLAY environment variable is set.
- */
- gdk_init (NULL, NULL);
-
private = g_new0 (DEControllerPrivateData, 1);
gettimeofday (&private->last_press_time, NULL);
gettimeofday (&private->last_release_time, NULL);
g_object_set_qdata (G_OBJECT (device_event_controller),
spi_dec_private_quark,
private);
- private->shift_keycodes = NULL;
spi_controller_register_with_devices (device_event_controller);
}
{
SpiDEController *retval = g_object_new (
SPI_DEVICE_EVENT_CONTROLLER_TYPE, NULL);
- DEControllerPrivateData *private;
retval->registry = SPI_REGISTRY (bonobo_object_ref (
BONOBO_OBJECT (registry)));
BONOBO_TYPE_FUNC_FULL (SpiDEController,
Accessibility_DeviceEventController,
PARENT_TYPE,
- spi_device_event_controller);
+ spi_device_event_controller)