#include <X11/XKBlib.h>
#define XK_MISCELLANY
#include <X11/keysymdef.h>
+
+#ifdef HAVE_XEVIE
+#include <X11/Xproto.h>
+#include <X11/X.h>
+#include <X11/extensions/Xevie.h>
+#endif /* HAVE_XEVIE */
+
#include <gdk/gdk.h>
#include <gdk/gdkx.h> /* TODO: hide dependency (wrap in single porting file) */
#include <gdk/gdkkeysyms.h>
#include "../libspi/spi-private.h"
#include "deviceeventcontroller.h"
+KeySym ucs2keysym (long ucs);
+
+#define CHECK_RELEASE_DELAY 20
+#define BIT(c, x) (c[x/8]&(1<<(x%8)))
+static guint check_release_handler = 0;
+static Accessibility_DeviceEvent pressed_event;
+static SpiDEController *saved_controller;
+static void wait_for_release_event (GdkEvent *event, SpiDEController *controller);
+
/* Our parent Gtk object type */
#define PARENT_TYPE BONOBO_TYPE_OBJECT
static gboolean spi_controller_register_device_listener (SpiDEController *controller,
DEControllerListener *l,
CORBA_Environment *ev);
-static void spi_device_event_controller_forward_key_event (SpiDEController *controller,
+static gboolean spi_device_event_controller_forward_key_event (SpiDEController *controller,
const XEvent *event);
static void spi_deregister_controller_device_listener (SpiDEController *controller,
DEControllerListener *listener,
#endif
snprintf (event_name, 22, "mouse:button:%d%c", button_number,
(is_down) ? 'p' : 'r');
- /* TODO: distinguish between physical and
+ /* TODO: FIXME distinguish between physical and
* logical buttons
*/
mouse_e.type = (is_down) ?
if (display)
{
if (XGrabButton (display, AnyButton, AnyModifier,
- gdk_x11_get_default_root_xwindow (),
- True, ButtonPressMask | ButtonReleaseMask,
- GrabModeSync, GrabModeAsync, None, None) != Success)
+ gdk_x11_get_default_root_xwindow (),
+ True, ButtonPressMask | ButtonReleaseMask,
+ GrabModeSync, GrabModeAsync, None, None) != Success) {
+#ifdef SPI_DEBUG
fprintf (stderr, "WARNING: could not grab mouse buttons!\n");
+#endif
+ ;
+ }
XSync (display, False);
#ifdef SPI_DEBUG
fprintf (stderr, "mouse buttons grabbed\n");
static Accessibility_ControllerEventMask
spi_dec_translate_mask (Accessibility_ControllerEventMask mask)
{
- DEControllerPrivateData *priv;
-
if (mask == SPI_KEYMASK_NUMLOCK) {
mask = _numlock_physical_mask;
}
DEControllerKeyListener *key_listener)
{
handle_keygrab (controller, key_listener, _register_keygrab);
- return spi_controller_update_key_grabs (controller, NULL);
+ if (controller->xevie_display == NULL)
+ return spi_controller_update_key_grabs (controller, NULL);
+ else
+ return TRUE;
}
static void
DEControllerKeyListener *key_listener)
{
handle_keygrab (controller, key_listener, _deregister_keygrab);
- spi_controller_update_key_grabs (controller, NULL);
+ if (controller->xevie_display == NULL)
+ spi_controller_update_key_grabs (controller, NULL);
}
static gboolean
GSList *notify = NULL, *l2;
GList **listeners = &controller->mouse_listeners;
gboolean is_consumed;
+ gboolean found = FALSE;
if (!listeners)
{
/* we clone (don't dup) the listener, to avoid refcount inc. */
notify = g_slist_prepend (notify,
spi_listener_clone (listener, ev));
+ found = TRUE;
}
}
}
#ifdef SPI_KEYEVENT_DEBUG
- if (!notify)
+ if (!found)
{
g_print ("no match for event\n");
}
snprintf (event_name, 22, "mouse:button:%d%c", button,
(xevent->type == ButtonPress) ? 'p' : 'r');
- /* TODO: distinguish between physical and logical buttons */
+ /* TODO: FIXME distinguish between physical and logical buttons */
mouse_e.type = (xevent->type == ButtonPress) ?
Accessibility_BUTTON_PRESSED_EVENT :
Accessibility_BUTTON_RELEASED_EVENT;
if (xevent->type == KeyPress || xevent->type == KeyRelease)
{
- spi_device_event_controller_forward_key_event (controller, xevent);
+ if (controller->xevie_display == NULL)
+ {
+ gboolean is_consumed =
+ spi_device_event_controller_forward_key_event (controller, xevent);
+
+ if (is_consumed)
+ XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
+ else
+ {
+ wait_for_release_event (event, controller);
+ XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
+ }
+ }
+
return GDK_FILTER_CONTINUE;
}
if (xevent->type == ButtonPress || xevent->type == ButtonRelease)
for (i = 0; i < len; ++i)
{
#ifdef SPI_KEYEVENT_DEBUG
- g_print ("key_set[%d] = %d; key_event %d, code %d, string %s\n",
- i, (int) key_set->_buffer[i].keycode,
- (int) key_event->id, (int) key_event->hw_code,
- key_event->event_string);
+ g_print ("key_set[%d] event = %d, code = %d; key_event %d, code %d, string %s\n",
+ i,
+ (int)key_set->_buffer[i].keysym,
+ (int) key_set->_buffer[i].keycode,
+ (int) key_event->id,
+ (int) key_event->hw_code,
+ key_event->event_string);
#endif
if (key_set->_buffer[i].keysym == (CORBA_long) key_event->id)
{
return TRUE;
}
}
-
+
return FALSE;
}
key_event.timestamp = (CORBA_unsigned_long) x_key_event->time;
#ifdef SPI_KEYEVENT_DEBUG
- fprintf (stderr,
- "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)");
+ {
+ char *pressed_str = "pressed";
+ char *released_str = "released";
+ char *state_ptr;
+
+ if (key_event.type == Accessibility_KEY_PRESSED_EVENT)
+ state_ptr = pressed_str;
+ else
+ state_ptr = released_str;
+
+ fprintf (stderr,
+ "Key %lu %s (%c), modifiers %d; string=%s [%x] %s\n",
+ (unsigned long) keysym,
+ state_ptr,
+ 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",
+ fprintf (stderr, "%s%c\n",
(x_key_event->state & Mod1Mask)?"Alt-":"",
((x_key_event->state & ShiftMask)^(x_key_event->state & LockMask))?
g_ascii_toupper (keysym) : g_ascii_tolower (keysym));
/* disconnect any special listeners, get rid of outstanding keygrabs */
XUngrabKey (spi_get_display (), AnyKey, AnyModifier, DefaultRootWindow (spi_get_display ()));
+#ifdef HAVE_XEVIE
+ if (controller->xevie_display != NULL)
+ {
+ XevieEnd(controller->xevie_display);
+#ifdef SPI_KEYEVENT_DEBUG
+ printf("XevieEnd(dpy) finished \n");
+#endif
+ }
+#endif
+
private = g_object_get_data (G_OBJECT (controller), "spi-dec-private");
if (private->xkb_desc)
XkbFreeKeyboard (private->xkb_desc, 0, True);
modifiers, 0);
}
+static KeySym
dec_keysym_for_unichar (SpiDEController *controller, gunichar unichar)
{
- /* TODO: table lookups within a range, for various code pages! */
- KeySym keysym = NoSymbol;
-
- if (unichar >= 0x20 && unichar < 0x7f) { /* Basic Latin/ASCII */
- keysym = (KeySym) unichar;
- }
- else if (unichar >= 0xa0 && unichar <= 0xff) { /* Latin 1 extensions */
- keysym = (KeySym) unichar;
- }
- else if (unichar >= 0x100 && unichar <= 0x233) { /* unfortunately the mapping gets nasty for Latin-2 and 3... help! */
- keysym = NoSymbol;
- }
- else if (unichar >= 0x7c1 && unichar <= 0x3a1) { /* let's try Greek anyway... */
- keysym = (KeySym) (0x391 + (unichar - 0x7c1));
- }
- else if (unichar >= 0x3a3 && unichar <= 0x3a9) { /* let's try Greek anyway... */
- keysym = (KeySym) (0x7d2 + (unichar - 0x3a3));
- }
- else if (unichar >= 0x3b1 && unichar <= 0x3c1) { /* let's try Greek anyway... */
- keysym = (KeySym) (0x7e1 + (unichar - 0x3b1));
- }
- else if (unichar == 0x3c2) {
- keysym = (KeySym) 0x7f3; /* XK_Greek_finalsmallsigma; */
- }
- else if (unichar >= 0x3c3 && unichar <= 0x3c9) { /* let's try Greek anyway... */
- keysym = (KeySym) (0x7f2 + (unichar - 0x3c2));
- }
- else if (unichar >= 0x5d0 && unichar <= 0x5ea) { /* Hebrew basics */
- /* probably broken :-) */
- keysym = (KeySym) (0xce0 + (unichar - 0x5d0));
- }
- else if (unichar >= 0x30a1 && unichar <= 0x30ab) { /* partial katakana support */
- /* TODO: complete! */
- keysym = (KeySym) (0x4b1 + (unichar - 0x30a1)/2);
- }
- else if (unichar >= 0x20a0 && unichar <= 0x20ac) { /* currency */
- keysym = (KeySym) unichar; /* how convenient ;-) */
- }
- return keysym;
+ return ucs2keysym ((long) unichar);
}
static gboolean
modifiers = dec_get_modifier_state (controller);
/* side-effect; we may unset mousebutton modifiers here! */
+ lock_mods = 0;
if (synth_mods != modifiers) {
lock_mods = synth_mods & ~modifiers;
dec_lock_modifiers (controller, lock_mods);
* and fall back to XSendEvent() if XTest is not available.
*/
- /* TODO: implement keystring mode also */
gdk_error_trap_push ();
key_synth_code = keycode;
spi_dec_private_quark = g_quark_from_static_string ("spi-dec-private");
}
+#ifdef HAVE_XEVIE
+Bool isEvent(dpy,event,arg)
+ Display *dpy;
+ XEvent *event;
+ char *arg;
+{
+ return TRUE;
+}
+
+gboolean
+handle_io (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ SpiDEController *controller = (SpiDEController *) data;
+ gboolean is_consumed = FALSE;
+ XEvent ev;
+
+ while (XCheckIfEvent(controller->xevie_display, &ev, isEvent, NULL))
+ {
+ if (ev.type == KeyPress || ev.type == KeyRelease)
+ is_consumed = spi_device_event_controller_forward_key_event (controller, &ev);
+
+ if (! is_consumed)
+ XevieSendEvent(controller->xevie_display, &ev, XEVIE_UNMODIFIED);
+ }
+
+ return TRUE;
+}
+#endif /* HAVE_XEVIE */
+
static void
spi_device_event_controller_init (SpiDEController *device_event_controller)
{
+#ifdef HAVE_XEVIE
+ GIOChannel *ioc;
+ int fd;
+#endif /* HAVE_XEVIE */
+
DEControllerPrivateData *private;
device_event_controller->key_listeners = NULL;
device_event_controller->mouse_listeners = NULL;
device_event_controller->keygrabs_list = NULL;
+ device_event_controller->xevie_display = NULL;
+
+#ifdef HAVE_XEVIE
+ device_event_controller->xevie_display = XOpenDisplay(NULL);
+
+ if (XevieStart(device_event_controller->xevie_display) == TRUE)
+ {
+#ifdef SPI_KEYEVENT_DEBUG
+ fprintf (stderr, "XevieStart() success \n");
+#endif
+ XevieSelectInput(device_event_controller->xevie_display, KeyPressMask | KeyReleaseMask);
+
+ fd = ConnectionNumber(device_event_controller->xevie_display);
+ ioc = g_io_channel_unix_new (fd);
+ g_io_add_watch (ioc, G_IO_IN | G_IO_HUP, handle_io, device_event_controller);
+ g_io_channel_unref (ioc);
+ }
+ else
+ {
+ device_event_controller->xevie_display = NULL;
+#ifdef SPI_KEYEVENT_DEBUG
+ fprintf (stderr, "XevieStart() failed, only one client is allowed to do event int exception\n");
+#endif
+ }
+#endif /* HAVE_XEVIE */
private = g_new0 (DEControllerPrivateData, 1);
gettimeofday (&private->last_press_time, NULL);
spi_controller_register_with_devices (device_event_controller);
}
-static void
+static gboolean
spi_device_event_controller_forward_key_event (SpiDEController *controller,
const XEvent *event)
{
- gboolean is_consumed = FALSE;
CORBA_Environment ev;
Accessibility_DeviceEvent key_event;
key_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
- spi_controller_update_key_grabs (controller, &key_event);
+ if (controller->xevie_display == NULL)
+ spi_controller_update_key_grabs (controller, &key_event);
/* relay to listeners, and decide whether to consume it or not */
- is_consumed = spi_controller_notify_keylisteners (
- controller, &key_event, CORBA_TRUE, &ev);
-
- if (is_consumed)
- {
- XAllowEvents (spi_get_display (), AsyncKeyboard, CurrentTime);
- }
- else
- {
- XAllowEvents (spi_get_display (), ReplayKeyboard, CurrentTime);
- }
+ return spi_controller_notify_keylisteners (controller, &key_event, CORBA_TRUE, &ev);
}
SpiDEController *
return retval;
}
+static gboolean
+is_key_released (KeyCode code)
+{
+ char keys[32];
+ int down;
+ int i;
+
+ XQueryKeymap (spi_get_display (), keys);
+ down = BIT (keys, code);
+ return (down == 0);
+}
+
+static gboolean
+check_release (gpointer data)
+{
+ gboolean released;
+ Accessibility_DeviceEvent *event = (Accessibility_DeviceEvent *)data;
+ KeyCode code = event->hw_code;
+ CORBA_Environment ev;
+
+ released = is_key_released (code);
+
+ if (released)
+ {
+ check_release_handler = 0;
+ event->type = Accessibility_KEY_RELEASED_EVENT;
+ ev._major = CORBA_NO_EXCEPTION;
+ spi_controller_notify_keylisteners (saved_controller, event, CORBA_TRUE, &ev);
+ }
+ return (released == 0);
+}
+
+static void wait_for_release_event (GdkEvent *event,
+ SpiDEController *controller)
+{
+ pressed_event = spi_keystroke_from_x_key_event ((XKeyEvent *) event);
+ saved_controller = controller;
+ check_release_handler = g_timeout_add (CHECK_RELEASE_DELAY, check_release, &pressed_event);
+}
+
BONOBO_TYPE_FUNC_FULL (SpiDEController,
Accessibility_DeviceEventController,
PARENT_TYPE,