[Banshee-List] Multimediakeys Plugin
- From: Danilo Reinhardt <danilo reinhardt gmx net>
- To: banshee-list gnome org
- Subject: [Banshee-List] Multimediakeys Plugin
- Date: Thu, 26 Jan 2006 19:15:36 +0100
Hello,
im new to banshee and this list. I like banshee and it fits my needs.
The only thing i missed was the support for x11 multimedia keys. I found
this support in the code, but it is commented out. To readd it again
i've create a small plugin
I have "copied" the commented out code in latest banshee release 0.10.4
for multimedia key handling to a separate plugin. My changes are some
error handling and code for proper ungrabbing the keys.
I dont know why there was a decision to exclude this code from banshee,
but i think to add a plugin would be a good solution for the moment (or
longer) to get back this x11 integration capability. A least i hope
it :) And I hope this plugin will be added to the main plugins.
I doesnt tried to compile using the makefiles, maybe is miss something
to add in it.
Bye Danilo
MCS_FLAGS = -debug -unsafe
ASSEMBLY_NAME = MMKeys
ASSEMBLY = $(ASSEMBLY_NAME).dll
fsmondir = $(pkglibdir)/Banshee.Plugins
fsmon_SCRIPTS = $(ASSEMBLY) $(ASSEMBLY).mdb $(ASSEMBLY).config
ASSEMBLY_SOURCES = \
$(srcdir)/MMKeysPlugin.cs \
$(srcdir)/MMKeysSpecialKeys.cs
PKG_REFERENCES = \
$(GTKSHARP_LIBS) \
-r:System.Data \
-r:Mono.Posix
schema_in_files = MMKeys.schemas.in
schemadir = $(GCONF_SCHEMA_FILE_DIR)
schema_DATA = $(schema_in_files:.schemas.in=.schemas)
@INTLTOOL_SCHEMAS_RULE@
$(ASSEMBLY): $(ASSEMBLY_SOURCES)
$(MCS) $(MCS_FLAGS) -target:library -out:$@ $(ASSEMBLY_SOURCES) -r:$(top_builddir)/src/Banshee.Base/Banshee.Base.dll -r:$(top_builddir)/src/Banshee.Widgets/Banshee.Widgets.dll $(PKG_REFERENCES)
EXTRA_DIST = $(ASSEMBLY_SOURCES) $(ASSEMBLY).config.in $(schema_in_files)
CLEANFILES = $(ASSEMBLY) *.dll *.exe
DISTCLEANFILES = *.mdb Makefile.in $(schema_DATA)
if GCONF_SCHEMAS_INSTALL
install-data-local:
if [ -z "$(DESTDIR)" ]; then \
GCONF_CONFIG_SOURCE="" $(GCONFTOOL) --makefile-install-rule $(builddir)$(schema_DATA); \
fi
endif
<configuration>
<dllmap dll="libglib-2.0.so" target="libglib-2.0.so.0" />
<dllmap dll="libgobject-2.0-0.dll" target="libgobject-2.0.so.0" />
<dllmap dll="libgtk-win32-2.0-0.dll" target="libgtk-x11-2.0.so.0" />
<dllmap dll="libbonobo-2.so" target="libbonobo-2.so.0" />
<dllmap dll="gdk-x11-2.0" target="libgdk-x11-2.0.so.0" />
<dllmap dll="libbanshee" target="@expanded_libdir@/@PACKAGE@/libbanshee.so" />
</configuration>
<?xml version="1.0"?>
<gconfschemafile>
<schemalist>
<schema>
<key>/schemas/apps/Banshee/MMKeysPlugin/Enabled</key>
<applyto>/apps/Banshee/MMKeysPlugin/Enabled</applyto>
<owner>banshee</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Enable the MultimediaKeys plugin</short>
<long></long>
</locale>
</schema>
</schemalist>
</gconfschemafile>
/* -*- Mode: csharp; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: t -*- */
/***************************************************************************
* MMKeysPlugin.cs
*
* Written by Danilo Reinhardt (danilo reinhardt gmx net)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.IO;
using Gtk;
using Gdk;
using Mono.Unix;
using Banshee.Base;
namespace Banshee.Plugins.MMKeysPlugin
{
public class MMKeysPlugin : Banshee.Plugins.Plugin
{
private Action playAction;
private Action nextTrackAction;
private Action prevTrackAction;
private MMKeysSpecialKeys special_keys;
protected override string ConfigurationName { get { return "MMKeysPlugin"; } }
public override string DisplayName { get { return "Multimediakeys"; } }
public override string Description {
get {
return Catalog.GetString(
"Adding support for configured gnome multimedia keys."
);
}
}
public override string [] Authors {
get {
return new string [] {
"Danilo Reinhardt"
};
}
}
protected override void PluginInitialize()
{
playAction = Globals.ActionManager["PlayPauseAction"];
nextTrackAction = Globals.ActionManager["NextAction"];
prevTrackAction = Globals.ActionManager["PreviousAction"];
try {
if((bool)Globals.Configuration.Get(GConfKeys.EnableSpecialKeys)) {
special_keys = new MMKeysSpecialKeys();
special_keys.Delay = new TimeSpan(350 * TimeSpan.TicksPerMillisecond);
special_keys.RegisterHandler(OnSpecialKeysPressed,
MMKeysSpecialKey.AudioPlay,
MMKeysSpecialKey.AudioPrev,
MMKeysSpecialKey.AudioNext
);
}
} catch(GConf.NoSuchKeyException) {
} catch(Exception e) {
special_keys = null;
Console.WriteLine (e.Message);
LogCore.Instance.PushWarning(Catalog.GetString("Could not setup special keys"), e.Message, false);
}
Console.WriteLine ("MMKeys: loaded");
}
private void OnSpecialKeysPressed(object o, MMKeysSpecialKey key)
{
switch(key) {
case MMKeysSpecialKey.AudioPlay:
playAction.Activate();
break;
case MMKeysSpecialKey.AudioNext:
nextTrackAction.Activate();
break;
case MMKeysSpecialKey.AudioPrev:
prevTrackAction.Activate();
break;
}
}
protected override void PluginDispose()
{
special_keys.UnregisterHandler(OnSpecialKeysPressed,
MMKeysSpecialKey.AudioPlay,
MMKeysSpecialKey.AudioPrev,
MMKeysSpecialKey.AudioNext
);
special_keys.UngrabKeys();
special_keys = null;
playAction = null;
nextTrackAction = null;
prevTrackAction = null;
Console.WriteLine ("MMKeys: unloaded");
}
}
}
/* -*- Mode: csharp; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: t -*- */
/***************************************************************************
* MMKeysSpecialKeys.cs
*
* Written by Danilo Reinhardt (danilo reinhardt gmx net)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections;
using System.Runtime.InteropServices;
namespace Banshee.Plugins.MMKeysPlugin
{
public delegate void MMKeysSpecialKeyPressedHandler(object o, MMKeysSpecialKey key);
public enum MMKeysSpecialKey {
None = 0,
AudioLowerVolume = 0x1008FF11,
AudioMute = 0x1008FF12,
AudioRaiseVolume = 0x1008FF13,
AudioPlay = 0x1008FF14,
AudioStop = 0x1008FF15,
AudioPrev = 0x1008FF16,
AudioNext = 0x1008FF17
};
public class MMKeysSpecialKeys
{
private Hashtable key_map = new Hashtable();
private Hashtable key_registrations = new Hashtable();
private TimeSpan raise_delay = new TimeSpan(0);
private DateTime last_raise = DateTime.MinValue;
private bool keysInited;
public MMKeysSpecialKeys()
{
InitializeKeys();
}
~MMKeysSpecialKeys() {
UnitializeKeys();
}
public void RegisterHandler(MMKeysSpecialKeyPressedHandler handler, params MMKeysSpecialKey [] specialKeys)
{
foreach(MMKeysSpecialKey specialKey in specialKeys) {
if (key_map.Contains(specialKey)) {
int key = (int)key_map[specialKey];
key_registrations[key] = Delegate.Combine(key_registrations[key] as Delegate, handler);
}
}
}
public void UnregisterHandler(MMKeysSpecialKeyPressedHandler handler, params MMKeysSpecialKey [] specialKeys)
{
foreach(MMKeysSpecialKey specialKey in specialKeys) {
if (key_map.Contains(specialKey)) {
int key = (int)key_map[specialKey];
key_registrations[key] = Delegate.Remove(key_registrations[key] as Delegate, handler);
}
}
}
public void UngrabKeys() {
UnitializeKeys();
}
private void InitializeKeys()
{
if (!keysInited) {
ArrayList kc_list = new ArrayList();
foreach(MMKeysSpecialKey key in Enum.GetValues(typeof(MMKeysSpecialKey))) {
IntPtr xdisplay = gdk_x11_get_default_xdisplay();
if (!xdisplay.Equals(IntPtr.Zero))
{
int keycode = XKeysymToKeycode(xdisplay, key);
if (keycode != 0)
{
//Console.WriteLine ("MMKeys: Adding key " + key + " with keycode " + keycode);
key_map[keycode] = key;
key_map[key] = keycode;
kc_list.Add(keycode);
}
//else Console.WriteLine ("MMKeys: keycode for key "+ key + " is not defined");
}
//else Console.WriteLine ("MMKeys: xdisplay == null");
}
for(int i = 0; i < Gdk.Display.Default.NScreens; i++) {
Gdk.Screen screen = Gdk.Display.Default.GetScreen(i);
foreach(int keycode in kc_list)
{
//Console.WriteLine ("MMKeys: Grabbing key with keycode " + keycode);
GrabKey(screen.RootWindow, keycode);
}
screen.RootWindow.AddFilter(FilterKey);
}
keysInited = true;
}
}
private void UnitializeKeys() {
//Console.WriteLine ("MMKeys: UnitializeKeys()");
if (keysInited) {
ArrayList kc_list = new ArrayList();
Console.WriteLine ("1");
foreach(MMKeysSpecialKey key in Enum.GetValues(typeof(MMKeysSpecialKey))) {
IntPtr xdisplay = gdk_x11_get_default_xdisplay();
if (!xdisplay.Equals(IntPtr.Zero))
{
int keycode = XKeysymToKeycode(xdisplay, key);
if (keycode != 0)
{
//Console.WriteLine ("MMKeys: Adding key " + key + " with keycode " + keycode);
key_map[keycode] = key;
key_map[key] = keycode;
kc_list.Add(keycode);
Console.WriteLine ("2");
}
//else Console.WriteLine ("MMKeys: keycode for key "+ key + " is not defined");
}
//else Console.WriteLine ("MMKeys: xdisplay == null");
}
Console.WriteLine ("3");
for(int i = 0; i < Gdk.Display.Default.NScreens; i++) {
Gdk.Screen screen = Gdk.Display.Default.GetScreen(i);
foreach(int keycode in kc_list)
{
//Console.WriteLine ("MMKeys: Grabbing key with keycode " + keycode);
UngrabKey(screen.RootWindow, keycode);
}
screen.RootWindow.RemoveFilter(FilterKey);
}
Console.WriteLine ("4");
keysInited = false;
}
}
private void GrabKey(Gdk.Window root, int keycode)
{
IntPtr xid = gdk_x11_drawable_get_xid(root.Handle);
IntPtr xdisplay = gdk_x11_get_default_xdisplay();
gdk_error_trap_push();
XGrabKey(xdisplay, keycode, XModMask.None, xid, true, XGrabMode.Async, XGrabMode.Async);
XGrabKey(xdisplay, keycode, XModMask.Mod2, xid, true, XGrabMode.Async, XGrabMode.Async);
XGrabKey(xdisplay, keycode, XModMask.Mod5, xid, true, XGrabMode.Async, XGrabMode.Async);
XGrabKey(xdisplay, keycode, XModMask.Lock, xid, true, XGrabMode.Async, XGrabMode.Async);
XGrabKey(xdisplay, keycode, XModMask.Mod2 | XModMask.Mod5, xid, true, XGrabMode.Async, XGrabMode.Async);
XGrabKey(xdisplay, keycode, XModMask.Mod2 | XModMask.Lock, xid, true, XGrabMode.Async, XGrabMode.Async);
XGrabKey(xdisplay, keycode, XModMask.Mod5 | XModMask.Lock, xid, true, XGrabMode.Async, XGrabMode.Async);
XGrabKey(xdisplay, keycode, XModMask.Mod2 | XModMask.Mod5 | XModMask.Lock, xid, true,
XGrabMode.Async, XGrabMode.Async);
gdk_flush ();
if(gdk_error_trap_pop() != 0) {
Console.Error.WriteLine("MMKeys: Could not grab key {0} (maybe another application has grabbed this key)", keycode);
}
}
private void UngrabKey(Gdk.Window root, int keycode)
{
IntPtr xid = gdk_x11_drawable_get_xid(root.Handle);
IntPtr xdisplay = gdk_x11_get_default_xdisplay();
gdk_error_trap_push();
XUngrabKey(xdisplay, keycode, XModMask.None, xid);
XUngrabKey(xdisplay, keycode, XModMask.Mod2, xid);
XUngrabKey(xdisplay, keycode, XModMask.Mod5, xid);
XUngrabKey(xdisplay, keycode, XModMask.Lock, xid);
XUngrabKey(xdisplay, keycode, XModMask.Mod2 | XModMask.Mod5, xid);
XUngrabKey(xdisplay, keycode, XModMask.Mod2 | XModMask.Lock, xid);
XUngrabKey(xdisplay, keycode, XModMask.Mod5 | XModMask.Lock, xid);
XUngrabKey(xdisplay, keycode, XModMask.Mod2 | XModMask.Mod5 | XModMask.Lock,xid);
gdk_flush ();
if(gdk_error_trap_pop() != 0) {
Console.Error.WriteLine("MMKeys: Could not ungrab key {0} (maybe another application has grabbed this key)", keycode);
}
}
private Gdk.FilterReturn FilterKey(IntPtr xeventPtr, Gdk.Event gdkEvent)
{
XKeyEvent xevent = (XKeyEvent)Marshal.PtrToStructure(xeventPtr, typeof(XKeyEvent));
if(xevent.type != XEventName.KeyPress) {
return Gdk.FilterReturn.Continue;
}
if(DateTime.Now - last_raise < raise_delay) {
return Gdk.FilterReturn.Continue;
}
last_raise = DateTime.Now;
int keycode = (int)xevent.keycode;
object x = key_map [keycode];
if (x == null)
return Gdk.FilterReturn.Continue;
MMKeysSpecialKey key = (MMKeysSpecialKey)key_map[keycode];
if(key_registrations[keycode] != null) {
x = key_registrations [keycode];
if (x is MMKeysSpecialKeyPressedHandler){
((MMKeysSpecialKeyPressedHandler)x)(this, key);
}
return Gdk.FilterReturn.Remove;
}
return Gdk.FilterReturn.Continue;
}
public TimeSpan Delay {
get {
return raise_delay;
}
set {
raise_delay = value;
}
}
[StructLayout(LayoutKind.Sequential)]
private struct XKeyEvent
{
public XEventName type;
public IntPtr serial;
public bool send_event;
public IntPtr display;
public IntPtr window;
public IntPtr root;
public IntPtr subwindow;
public IntPtr time;
public int x;
public int y;
public int x_root;
public int x_y;
public uint state;
public uint keycode;
public bool same_screen;
}
[DllImport("libX11")]
extern static int XKeysymToKeycode(IntPtr display, MMKeysSpecialKey keysym);
[DllImport("libX11")]
extern static void XGrabKey(IntPtr display, int keycode, XModMask modifiers,
IntPtr window, bool owner_events, XGrabMode pointer_mode, XGrabMode keyboard_mode);
[DllImport("libX11")]
extern static void XUngrabKey(IntPtr display, int keycode, XModMask modifiers,
IntPtr window);
[DllImport("libgdk-x11-2.0")]
extern static IntPtr gdk_x11_drawable_get_xid(IntPtr window);
[DllImport("libgdk-x11-2.0")]
extern static IntPtr gdk_x11_get_default_xdisplay();
[DllImport("libgdk-x11-2.0")]
extern static void gdk_error_trap_push();
[DllImport("libgdk-x11-2.0")]
extern static int gdk_error_trap_pop();
[DllImport("libgdk-x11-2.0")]
extern static void gdk_flush();
[Flags]
private enum XModMask {
None = 0,
Shift = 1 << 0,
Lock = 1 << 1,
Control = 1 << 2,
Mod1 = 1 << 3,
Mod2 = 1 << 4,
Mod3 = 1 << 5,
Mod4 = 1 << 6,
Mod5 = 1 << 7
}
private enum XGrabMode {
Sync = 0,
Async = 1
}
private enum XEventName {
KeyPress = 2,
KeyRelease = 3,
}
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]