Hi; I recently bought one of the Nokia BT keyboards for my 770. Tomas's btkeyboard-plugin rocks but I soon got pretty frustrated at the 770 not registering keypresses as activity to stop the display from blanking.
Attached is a patch to btkeyboard-plugin which attempts to remedy this. It works rather brutally via sniffing out x keyevents on currently active windows and calling the equivilent of osso_display_blanking_pause() for each key press, keeping the display lit for another 60 seconds. There is no doubt more efficient ways to do the same thing lower down the stack. But this was quickest way for me todo and suit my needs. Also attached is a matchbox keyboard shortcut config file. Put this file in /home/user/.matchbox/kbdconfig, then run matchbox-remote -k. This sets up keyshortcuts for 'tabbing' between windows, fullscreening, closing apps and a couple of other things ( check kbdconfig for details ). YMMV with these shortcuts as matchbox key shortcuts arn't totally integrated into maemo. Finally attached is an xmodmap file. This is relevant at least for the Nokia BT keyboard and may need editing for other makes. It basically switches the caps and ctrl keys, makes 'del' a backspace and maps the non functional 'blue' keys to page up, page down and home. Put this file in /home/user/.xmodmap. Remap keyboard via 'xmodmap ~/.xmodmap' ( patched btkeyboard-plugin runs this command on new keyboard connection ). I've put an ARM binary ( from Debian ) of xmodmap here; http://butterfeet.org/maemo/keyboard/ ( Also togeather with a patched built binary of bt-plugin.so etc. ) All this is very much hacker orientated and really aimed at those who know what there doing. Try at your own risk. At least for me it makes the keyboard a little more useable. Regards; -- Matthew
--- btkeyboard-plugin-0.2.2.orig/bt-plugin.c 2005-09-21 08:59:50.000000000 +0100 +++ btkeyboard-plugin-0.2.2/bt-plugin.c 2005-11-28 19:30:33.000000000 +0000 @@ -28,6 +28,13 @@ #include <glib.h> #include <gdk/gdkkeysyms.h> +#include <gdk/gdkx.h> +#include <gdk/gdkevents.h> + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xatom.h> + #include <libintl.h> #include <locale.h> #include <unistd.h> @@ -74,6 +81,11 @@ NUM_PIXBUFS }; +enum { + CATCH, + RELEASE +}; + typedef struct { HildonStatusBarItem *item; @@ -89,6 +101,8 @@ gboolean button_released; gboolean connected; gboolean searching; + Atom atom_net_active_win; + Window last_active_win; } PluginInfo; /* Hildon Status Bar plugin API prototypes */ @@ -99,6 +113,184 @@ gint bt_get_priority(void *data); void bt_update(void *data, gint value1, gint value2, const gchar *str); +void set_key_events (Window win, int mode); + +static GdkFilterReturn +x_key_event_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + DBusConnection *conn; + DBusMessage *msg = NULL; + DBusError dbus_error; + dbus_bool_t dresult; + + if (((XEvent*)xevent)->type == PropertyNotify) + return GDK_FILTER_CONTINUE; + + /* + * This is basically osso_display_blanking_pause(), execpt + * we have no osso_context_t... but we do have the source + * for osso_display_blanking_pause() :) + */ + +#define MCE_SERVICE "com.nokia.mce" +#define MCE_REQUEST_PATH "/com/nokia/mce/request" +#define MCE_REQUEST_IF "com.nokia.mce.request" +#define MCE_PREVENT_BLANK_REQ "req_display_blanking_pause" + + dbus_error_init(&dbus_error); + + conn = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error); + + msg = dbus_message_new_method_call(MCE_SERVICE, + MCE_REQUEST_PATH, + MCE_REQUEST_IF, + MCE_PREVENT_BLANK_REQ); + if (msg == NULL) + return GDK_FILTER_CONTINUE; + + dresult = dbus_connection_send (conn, msg, NULL); + + if (!dresult) + { + dbus_message_unref(msg); + return GDK_FILTER_CONTINUE; + } + + dbus_connection_flush(conn); + dbus_message_unref(msg); + + + return GDK_FILTER_CONTINUE; +} + +void +set_key_events (Window win, int mode) +{ + Window root_win, parent_win; + unsigned int num_children; + Window *child_list; + Status status; + GdkWindow *gdk_wrapper_win = NULL; + int i; + + if (win == None) + return; + + gdk_error_trap_push(); + + status = XQueryTree(GDK_DISPLAY(), + win, + &root_win, + &parent_win, + &child_list, + &num_children); + + if (gdk_error_trap_pop() || status == 0 + || num_children == 0 || child_list == NULL) + return; + + for (i = num_children - 1; i >= 0; i--) + { + gdk_error_trap_push(); + + gdk_wrapper_win = gdk_window_foreign_new (child_list[i]); + + if (gdk_wrapper_win != NULL) + { + /* Monitor the window for prop changes */ + if (mode == CATCH) + { + gdk_window_set_events(gdk_wrapper_win, + gdk_window_get_events(gdk_wrapper_win) + |GDK_KEY_RELEASE_MASK); + gdk_window_add_filter(gdk_wrapper_win, x_key_event_filter, NULL); + } + else + { + /* Potentially dangerous on desktop to unset events here. + * most of work is saved in removing at least the filter. + */ + /* gdk_window_set_events(gdk_wrapper_win, 0); */ + gdk_window_remove_filter(gdk_wrapper_win, + x_key_event_filter, NULL); + } + + g_object_unref(gdk_wrapper_win); + } + + gdk_error_trap_pop(); + + /* Urg need to recurse as it seems GTK at least does not like + * propogating key events for its sub wins. + */ + set_key_events (child_list[i], mode); + } +} + + +static GdkFilterReturn +x_event_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + Window *active_win = NULL; + Atom type_ret; + int format_ret; + unsigned long items_ret; + unsigned long after_ret; + int status; + + PluginInfo *info; + + if (((XEvent*)xevent)->type != PropertyNotify) + return GDK_FILTER_CONTINUE; + + info = (PluginInfo*)data; + + gdk_error_trap_push(); + + /* Grab the current active window */ + status = XGetWindowProperty (GDK_DISPLAY(), + GDK_ROOT_WINDOW(), + info->atom_net_active_win, + 0, G_MAXLONG, + False, + XA_WINDOW, + &type_ret, + &format_ret, + &items_ret, + &after_ret, + (unsigned char**)&active_win); + + if (gdk_error_trap_pop() || status != Success || active_win == NULL) + goto cleanup; + + if (type_ret != XA_WINDOW || format_ret != 32 || items_ret == 0) + goto cleanup; + + if (info->last_active_win == *active_win) + goto cleanup; + + /* Recursive monitor key events for this win and sub wins */ + set_key_events (*active_win, CATCH); + + /* Free up event for any old wins */ + if (info->last_active_win && info->last_active_win != GDK_ROOT_WINDOW()) + set_key_events (info->last_active_win, RELEASE); + + /* Remember this value so we can know when a window is new */ + info->last_active_win = *active_win; + + cleanup: + + if (active_win) + XFree(active_win); + + return GDK_FILTER_CONTINUE; +} + static void close_window(void *data) { PluginInfo *info = (PluginInfo*)data; @@ -397,6 +589,25 @@ gtk_infoprintf(NULL, "Bluetooth device connected"); gtk_image_set_from_pixbuf(GTK_IMAGE(info->icon), info->pixbuf[PIXBUF_ACTIVE]); connected_event_queue = g_strdup(path); + + gdk_error_trap_push(); + + /* Check for prop changes on root window to track active window + * so we know what to select for keyevents on + */ + gdk_window_set_events(gdk_get_default_root_window(), + gdk_window_get_events(gdk_get_default_root_window()) + | GDK_PROPERTY_CHANGE_MASK ); + + gdk_window_add_filter(gdk_get_default_root_window(), + x_event_filter, + info); + + gdk_error_trap_pop(); + + /* *really* hackerly run xmodmap to set up any key mappings */ + /* FIXME: do via g_spawn_async () */ + system("xmodmap /home/user/.xmodmap"); } } else if (info->connected && dbus_message_is_signal(m, IF_NAME, REMOVE_SIG)) { if (strncmp(path, connected_event_queue, strlen(connected_event_queue)) == 0) { @@ -404,6 +615,13 @@ gtk_infoprintf(NULL, "Bluetooth device disconnected"); gtk_image_set_from_pixbuf(GTK_IMAGE(info->icon), info->pixbuf[PIXBUF_INACTIVE]); g_free(connected_event_queue); + + /* No need to track X events anymore */ + gdk_window_remove_filter(gdk_get_default_root_window(), + x_event_filter, + NULL); + /* just to be safe */ + set_key_events (info->last_active_win, RELEASE); } } @@ -451,6 +669,11 @@ gtk_image_set_from_pixbuf(GTK_IMAGE(info->icon), info->pixbuf[PIXBUF_INACTIVE]); gtk_widget_show_all(GTK_WIDGET(info->button)); + /* Atom for Key monitoring */ + info->atom_net_active_win = XInternAtom (GDK_DISPLAY(), + "_NET_ACTIVE_WINDOW", + False); + dbus_error_init(&dbus_error); conn = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error); if (conn == NULL) {
kbdconfig
Description: Binary data
.xmodmap
Description: Binary data
_______________________________________________ maemo-developers mailing list maemo-developers@maemo.org https://maemo.org/mailman/listinfo/maemo-developers