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) {
























Attachment: kbdconfig
Description: Binary data

Attachment: .xmodmap
Description: Binary data

_______________________________________________
maemo-developers mailing list
maemo-developers@maemo.org
https://maemo.org/mailman/listinfo/maemo-developers

Reply via email to