[PATCH, RFC] Add support for keyboard hotkeys

Matthew Garrett mjg59 at srcf.ucam.org
Mon Jan 30 17:52:23 PST 2006


I've attached two patches. The first adds some code to the acpi addon to
place the type of the button pressed in the details field of the
generated event. This isn't strictly necessary for acpi (since the
button type can be worked out afterwards), but makes sense in the
context of the second patch.

This adds an addon for keyboard devices. It simply attaches to the
keyboard's event device (these allow multiple readers) and monitors
keypresses. When an "interesting" key (currently defined as one which
would correspond to power management events) is pressed, it generates a
ButtonPressed condition and puts the appropriate type in the details
field.

KEY_SLEEP corresponds to the sleep key that appears on Microsoft (and
some laptop) keyboards. KEY_SUSPEND doesn't actually appear to exist on
any PS/2 keyboards (judging by atkbd.c), so it's a handy thing to hijack
for hibernation. KEY_POWER is fairly self-explanatory.

Any comments on this approach? Right now it doesn't provide any
information about these capabilities, on the assumption that all
keyboards may potentially have these keys (we certainly can't tell for
PS/2, I'm not sure about USB)

-- 
Matthew Garrett | mjg59 at srcf.ucam.org
-------------- next part --------------
--- addon-acpi.c	2005-11-14 16:16:04 +0000
+++ hal/hald/linux2/addons/addon-acpi.c	2006-01-29 23:43:55 +0000
@@ -119,8 +121,16 @@
 				/* TODO: only rescan if button got state */
 				libhal_device_rescan (ctx, udi, &error);
 
-				libhal_device_emit_condition (ctx, udi, "ButtonPressed", "", &error);
-
+				char *type = libhal_device_get_property_string(ctx, udi, 
+									       "button.type",
+									       &error);
+				if (type) {
+					libhal_device_emit_condition (ctx, udi, "ButtonPressed",
+								      type, &error);
+					libhal_free_string(type);
+				} else {
+					libhal_device_emit_condition (ctx, udi, "ButtonPressed", "", &error);
+				}
 			} else if (strncmp (acpi_path, "ac_adapter", sizeof ("ac_adapter") - 1) == 0) {
 				dbg ("ac_adapter event");
 				libhal_device_rescan (ctx, udi, &error);

-------------- next part --------------
diff -urN bar/addon-keyboard.c foo/addon-keyboard.c
--- bar/addon-keyboard.c	1970-01-01 01:00:00 +0100
+++ hal/hald/linux2/addons/addon-keyboard.c	2006-01-30 23:45:46 +0000
@@ -0,0 +1,156 @@
+/***************************************************************************
+ * CVSID: $Id: addon-key.c,v 1.13 2005/11/09 21:13:30 dkukawka Exp $
+ *
+ * addon-acpi.c : Listen to key events and modify hal device objects
+ *
+ * Copyright (C) 2005 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2005 Ryan Lortie <desrt at desrt.ca>
+ * Copyright (C) 2006 Matthew Garrett <mjg59 at srcf.ucam.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <grp.h>
+#include <linux/input.h>
+
+#include "libhal/libhal.h"
+
+#include "../probing/shared.h"
+
+/* FIXME - find the keyboard device */
+
+char *udi;
+
+static void
+main_loop (LibHalContext *ctx, FILE* eventfp)
+{
+	DBusError error;
+	struct input_event event;
+
+	dbus_error_init (&error);
+
+	while (fread (&event, sizeof(event), 1, eventfp)) {
+		if (event.code == KEY_SLEEP && event.value == 1) {
+			libhal_device_emit_condition (ctx, udi, 
+						      "ButtonPressed", "sleep",
+						      &error);
+		} else if (event.code == KEY_SUSPEND && event.value == 1) {
+			libhal_device_emit_condition (ctx, udi,
+						      "ButtonPressed",
+						      "hibernate", &error);
+		} else if (event.code == KEY_POWER && event.value == 1) {
+			libhal_device_emit_condition (ctx, udi,
+						      "ButtonPressed", "power",
+						      &error);
+		}
+	}
+
+	dbus_error_free (&error);
+}
+
+/** Drop all but necessary privileges.  Set the running user id to HAL_USER and
+ *  group to HAL_GROUP
+ */
+static void drop_privileges () { 
+    struct passwd *pw = NULL; 
+    struct group *gr = NULL;
+
+    /* determine user id */
+    pw = getpwnam (HAL_USER);
+    if (!pw)  {
+        printf ("drop_privileges: user " HAL_USER " does not exist");
+        exit (-1);
+    }
+
+    /* determine primary group id */
+    gr = getgrnam (HAL_GROUP);
+    if(!gr) {
+        printf("drop_privileges: group " HAL_GROUP " does not exist");
+        exit (-1);
+    }
+
+    if( setgid (gr->gr_gid) ) {
+        printf ("drop_privileges: could not set group id");
+        exit (-1);
+    }
+
+    if( setuid (pw->pw_uid)) {
+        printf ("drop_privileges: could not set user id");
+        exit (-1);
+    }
+}
+
+
+int
+main (int argc, char **argv)
+{
+	LibHalContext *ctx = NULL;
+	DBusError error;
+	char *device_file;
+	FILE *eventfp;
+
+	dbus_error_init (&error);
+
+	if ((udi = getenv ("UDI")) == NULL)
+		goto out;
+	
+	if ((device_file = getenv ("HAL_PROP_INPUT_DEVICE")) == NULL)
+		goto out;
+
+	if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
+                goto out;
+
+	eventfp = fopen(device_file, "r");	
+
+	drop_privileges();
+
+	while (1)
+	{
+		main_loop (ctx, eventfp);
+		
+		/* If main_loop exits sleep for 5s and try to reconnect (
+		   again). */
+		sleep (5);
+	}
+
+	return 0;
+
+ out:
+	if (ctx != NULL) {
+                dbus_error_init (&error);
+                libhal_ctx_shutdown (ctx, &error);
+                libhal_ctx_free (ctx);
+        }
+	
+	return 0;
+}
+
+/* vim:set sw=8 noet: */


More information about the hal mailing list