#include <config.h>
-#undef SPI_DEBUG
+#define SPI_DEBUG
#include <string.h>
#include <ctype.h>
/* A pointer to our parent object class */
static GObjectClass *spi_device_event_controller_parent_class;
+int (*x_default_error_handler) (Display *display, XErrorEvent *error_event);
+
typedef enum {
SPI_DEVICE_TYPE_KBD,
+ SPI_DEVICE_TYPE_MOUSE,
SPI_DEVICE_TYPE_LAST_DEFINED
} SpiDeviceTypeCategory;
static void spi_device_event_controller_forward_key_event (SpiDEController *controller,
const XEvent *event);
+#define spi_get_display() GDK_DISPLAY()
+
/* Private methods */
static KeyCode
keycode_for_keysym (long keysym)
{
- return XKeysymToKeycode (GDK_DISPLAY (), (KeySym) keysym);
+ return XKeysymToKeycode (spi_get_display (), (KeySym) keysym);
}
static DEControllerGrabMask *
DEControllerGrabMask *cur_mask = l->data;
cur_mask->ref_count--;
- cur_mask->pending_remove = TRUE;
+ if (cur_mask->ref_count <= 0)
+ {
+ cur_mask->pending_remove = TRUE;
+ }
}
else
{
/* X Grabs require keycodes, not keysyms */
if (key_val >= 0)
{
- key_val = XKeysymToKeycode (GDK_DISPLAY (), (KeySym) key_val);
+ key_val = XKeysymToKeycode (spi_get_display (), (KeySym) key_val);
}
grab_mask.key_val = key_val;
return GDK_FILTER_CONTINUE;
}
+int
+_spi_controller_device_error_handler (Display *display, XErrorEvent *error)
+{
+ if (error->error_code == BadAccess)
+ {
+ g_message ("Could not complete key grab: grab already in use.\n");
+ return 0;
+ }
+ else
+ {
+ return (*x_default_error_handler) (display, error);
+ }
+}
+
static void
spi_controller_register_with_devices (SpiDEController *controller)
{
gdk_window_set_events (gdk_get_default_root_window (),
GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
- XSelectInput (GDK_DISPLAY (),
- DefaultRootWindow (GDK_DISPLAY ()),
- KeyPressMask | KeyReleaseMask);
+ x_default_error_handler = XSetErrorHandler (_spi_controller_device_error_handler);
}
static gboolean
}
g_slist_free (notify);
-
+
+#ifdef SPI_DEBUG
+ if (is_consumed) g_message ("consumed\n");
+#endif
return is_consumed;
}
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));
}
else if (grab_mask->pending_remove)
{
- XUngrabKey (GDK_DISPLAY (),
+#ifdef SPI_DEBUG
+ fprintf (stderr, "ungrabbing, mask=%x\n", grab_mask->mod_mask);
+#endif
+ XUngrabKey (spi_get_display (),
grab_mask->key_val,
grab_mask->mod_mask,
gdk_x11_get_default_root_xwindow ());
}
else if (grab_mask->pending_add || re_issue_grab)
{
- XGrabKey (GDK_DISPLAY (),
+
+#ifdef SPI_DEBUG
+ fprintf (stderr, "grab with mask %x\n", grab_mask->mod_mask);
+#endif
+ XGrabKey (spi_get_display (),
grab_mask->key_val,
grab_mask->mod_mask,
gdk_x11_get_default_root_xwindow (),
fprintf(stderr, "spi_device_event_controller_object_finalize called\n");
#endif
/* disconnect any special listeners, get rid of outstanding keygrabs */
+ XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
spi_device_event_controller_parent_class->finalize (object);
}
DEControllerKeyListener *key_listener;
} RemoveKeyListenerClosure;
-static SpiReEnterantContinue
+static SpiReEntrantContinue
remove_key_listener_cb (GList * const *list,
gpointer user_data)
{
if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
key_listener->listener.object, ctx->ev))
{
- spi_re_enterant_list_delete_link (list);
+ spi_re_entrant_list_delete_link (list);
spi_dec_key_listener_free (key_listener, ctx->ev);
}
- return SPI_RE_ENTERANT_CONTINUE;
+ return SPI_RE_ENTRANT_CONTINUE;
+}
+
+static SpiReEntrantContinue
+copy_key_listener_cb (GList * const *list,
+ gpointer user_data)
+{
+ DEControllerKeyListener *key_listener = (*list)->data;
+ RemoveKeyListenerClosure *ctx = user_data;
+
+ if (CORBA_Object_is_equivalent (ctx->key_listener->listener.object,
+ key_listener->listener.object, ctx->ev))
+ {
+ /* TODO: FIXME aggregate keys in case the listener is registered twice */
+ CORBA_free (ctx->key_listener->keys);
+ ctx->key_listener->keys = ORBit_copy_value (key_listener->keys, TC_Accessibility_KeySet);
+ }
+
+ return SPI_RE_ENTRANT_CONTINUE;
}
/*
(void *) l, (unsigned long) mask->value);
#endif
- spi_controller_deregister_global_keygrabs (controller, key_listener);
-
ctx.ev = ev;
ctx.key_listener = key_listener;
- spi_re_enterant_list_foreach (&controller->key_listeners,
+ /* special case, copy keyset from existing controller list entry */
+ if (keys->_length == 0)
+ {
+ spi_re_entrant_list_foreach (&controller->key_listeners,
+ copy_key_listener_cb, &ctx);
+ }
+
+ spi_controller_deregister_global_keygrabs (controller, key_listener);
+
+ spi_re_entrant_list_foreach (&controller->key_listeners,
remove_key_listener_cb, &ctx);
spi_dec_key_listener_free (key_listener, ev);
switch (synth_type)
{
case Accessibility_KEY_PRESS:
- XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, True, CurrentTime);
+ XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, True, CurrentTime);
break;
case Accessibility_KEY_PRESSRELEASE:
- XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, True, CurrentTime);
+ XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, True, CurrentTime);
case Accessibility_KEY_RELEASE:
- XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) keycode, False, CurrentTime);
+ XTestFakeKeyEvent (spi_get_display (), (unsigned int) keycode, False, CurrentTime);
break;
case Accessibility_KEY_SYM:
key_synth_code = keycode_for_keysym (keycode);
- XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) key_synth_code, True, CurrentTime);
- XTestFakeKeyEvent (GDK_DISPLAY (), (unsigned int) key_synth_code, False, CurrentTime);
+ XTestFakeKeyEvent (spi_get_display (), (unsigned int) key_synth_code, True, CurrentTime);
+ XTestFakeKeyEvent (spi_get_display (), (unsigned int) key_synth_code, False, CurrentTime);
break;
case Accessibility_KEY_STRING:
fprintf (stderr, "Not yet implemented\n");
const CORBA_char *eventName,
CORBA_Environment *ev)
{
+ int button;
+ gboolean error = FALSE;
+ Display *display = spi_get_display ();
#ifdef SPI_DEBUG
fprintf (stderr, "generating mouse %s event at %ld, %ld\n",
eventName, (long int) x, (long int) y);
#endif
- g_warning ("not yet implemented");
+ g_message ("mouse event synthesis\n");
+ switch (eventName[0])
+ {
+ case 'b':
+ switch (eventName[1])
+ {
+ /* TODO: check number of buttons before parsing */
+ case '1':
+ button = 1;
+ break;
+ case '2':
+ button = 2;
+ break;
+ case '3':
+ button = 3;
+ break;
+ default:
+ error = TRUE;
+ }
+ if (!error)
+ {
+ if (x != -1 && y != -1)
+ {
+ XTestFakeMotionEvent (display, DefaultScreen (display),
+ x, y, 0);
+ }
+ XTestFakeButtonEvent (display, button, !(eventName[2] == 'r'), 0);
+ if (eventName[2] == 'c')
+ XTestFakeButtonEvent (display, button, FALSE, 1);
+ else if (eventName[2] == 'd')
+ {
+ XTestFakeButtonEvent (display, button, FALSE, 1);
+ XTestFakeButtonEvent (display, button, TRUE, 2);
+ XTestFakeButtonEvent (display, button, FALSE, 3);
+ }
+ }
+ break;
+ case 'r': /* relative motion */
+ XTestFakeRelativeMotionEvent (display, x, y, 0);
+ break;
+ case 'a': /* absolute motion */
+ XTestFakeMotionEvent (display, DefaultScreen (display),
+ x, y, 0);
+ break;
+ }
}
/* Accessibility::DEController::notifyListenersSync */
CORBA_exception_init (&ev);
key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
+
+ spi_controller_update_key_grabs (controller, &key_event);
+
/* relay to listeners, and decide whether to consume it or not */
is_consumed = spi_notify_keylisteners (
&controller->key_listeners, &key_event, CORBA_TRUE, &ev);
if (is_consumed)
{
- XAllowEvents (GDK_DISPLAY (), AsyncKeyboard, CurrentTime);
+ XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
}
else
{
- XAllowEvents (GDK_DISPLAY (), ReplayKeyboard, CurrentTime);
+ XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
}
-
- spi_controller_update_key_grabs (controller, &key_event);
}
SpiDEController *