Laden...

Hotkey-Klasse

Erstellt von Floste vor 15 Jahren Letzter Beitrag vor 12 Jahren 16.334 Views
Floste Themenstarter:in
1.130 Beiträge seit 2007
vor 15 Jahren
Hotkey-Klasse

Beschreibung:

Mit der Klasse kann man einfach Systemweite Hotkeys installieren.

So benutzt man die Klasse:


Hotkey h=Hotkey.Register(Keys.A|Keys.Control|Keys.Alt);
h.HotkeyPressed+=...
....
h.Dispose();

Der Hotkey wird unregistriert, sobald der Garbagecollector das Hotkeyobjekt einsammelt. Deshalb muss man eine Referenz halten.


public class Hotkey:IDisposable
    {
        protected Hotkey()
        { }

        /// <summary>
        /// Registers the hotkey. You have to keep a reference to the returned object.
        /// </summary>
        /// <param name="keys"></param>
        /// <returns></returns>
        public static Hotkey Register(Keys keys)
        {
            Hotkey ret = new Hotkey();
            ret.keys = keys;
            wnd.Register(ret);
            return ret;
        }

        /// <summary>
        /// Calls Dispose: Unregisters the hotkey
        /// </summary>
        /// <param name="h">The Hotkey</param>
        public static void UnRegister(Hotkey h)
        { h.Dispose(); }

        /// <summary>
        /// Rises when the hotkey is pressed
        /// </summary>
        public event EventHandler HotkeyPressed;

        public object Tag;
        private Keys keys;
        private int id;

        /// <summary>
        /// The keycombination
        /// </summary>
        public Keys Keys
        {
            get { return keys; }
        }

        #region IDisposable Member

        ~Hotkey()
        {
            Dispose();
        }

        bool disposed=false;

        /// <summary>
        /// Unregisters the Hotkey
        /// </summary>
        public void Dispose()
        {
            if (disposed) return;
            disposed=true;
            wnd.UnRegister(this);
        }


        #endregion

        private class wnd : Control
        {
            public wnd()
            {
                Visible=false;
            }

            public static wnd Default
            {
                get
                {
                    if (def == null)
                    {
                        def = new wnd();
                        def.CreateHandle();
                    }
                    return def;
                }
            }

            List<IntPtr> hotkeys=new List<IntPtr>();
            int getNewId(IntPtr item)
            {
                int i = 0;
                foreach(IntPtr r in hotkeys)
                {
                    if ((long)r == 0)
                    {
                        hotkeys[i] = item;
                        return i;
                    }
                    i++;
                }
                hotkeys.Add(item);
                return i;
            }

            IntPtr getObject(int id)
            {
                return hotkeys[id];
            }

            void removeId(int id)
            {
                hotkeys[id] = (IntPtr)0;
            }

            static wnd def;
            public short LOWORD(int l)
            { return ((short)(l & 0xffff));}
            
            public short HIWORD(int l)
            { return ((short)(l >> 16)); }

            public const int MOD_ALT = 0x1;
            public const int MOD_CONTROL = 0x2;
            public const int MOD_SHIFT = 0x4;
            public const int MOD_WIN = 0x8;
            public const int WM_HOTKEY = 0x312;

            [DllImport("user32.dll")]
            private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);

            [DllImport("user32.dll")]
            private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

            protected override void WndProc(ref Message m)
            {
                if (m.Msg == WM_HOTKEY)
                {
                    Hotkey h = (Hotkey)GCHandle.FromIntPtr(getObject((int)m.WParam)).Target;
                    if (h.HotkeyPressed != null)
                    { h.HotkeyPressed(h, null); }
                }
                else
                    base.WndProc(ref m);
            }

            internal static void Register(Hotkey h)
            {
                h.id=Default.getNewId (GCHandle.ToIntPtr (GCHandle.Alloc (h,GCHandleType.WeakTrackResurrection)));
                int modifiers = 0;
                if ((h.keys & Keys.Alt) == Keys.Alt)
                    modifiers = modifiers | MOD_ALT;
                if ((h.keys & Keys.Control) == Keys.Control)
                    modifiers = modifiers | MOD_CONTROL;
                if ((h.keys & Keys.Shift) == Keys.Shift)
                    modifiers = modifiers | MOD_SHIFT;
                Keys k = h.keys & ~Keys.Control & ~Keys.Shift & ~Keys.Alt;
                RegisterHotKey((IntPtr)Default.Handle, h.id, modifiers, (int)k);
            }

            internal static void UnRegister(Hotkey h)
            {
                try
                {
                    UnregisterHotKey(Default.Handle, h.id);
                }
                catch { }
                GCHandle.FromIntPtr(Default.getObject(h.id)).Free();
                Default.removeId(h.id);
            }
        }
    }

(Die interne Liste führe ich, da ein IntPtr größer als ein int sein kann.)

Schlagwörter: Hotkey systemweit registrieren System global Tastenkombination

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

C
14 Beiträge seit 2008
vor 15 Jahren

Wenn ich deinen Code verwende und standardmässig STRG+ALT+A drücke, dann kriege ich eine InvalidOperationException mit dem Hinweis "Das Handle wurde nicht initialisiert." auf folgende, fettmarkierte Zeile:

protected override void WndProc(ref Message m)  
            {  
                if (m.Msg == WM_HOTKEY)  
                {  
                    Hotkey h = (Hotkey)GCHandle.FromIntPtr(getObject((int)m.WParam)).Target; // hier  
                    if (h.HotkeyPressed != null)  
                    { h.HotkeyPressed(h, null); }  
                }  
                else  
                    base.WndProc(ref m);  
            }  
Floste Themenstarter:in
1.130 Beiträge seit 2007
vor 15 Jahren

Kann es sein, dass dein Code keine Referenz auf das Objekt hält?

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

3.971 Beiträge seit 2006
vor 15 Jahren

Hallo floste,


public void Dispose()
        {
            if (disposed) return;
            disposed=true;
            wnd.UnRegister(this);
        }

da ich das erst jetzt sehe, schau dir mal Dispose implementieren und verwenden an und ergänze dein Dispose noch um


GC.SuppressFinalize (this);

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

344 Beiträge seit 2007
vor 15 Jahren

Hallo, existiert ein Testprojekt?

Grüße und danke

👶-> :]-> 8o-> 🙂

J
1.114 Beiträge seit 2007
vor 15 Jahren

Hey, die Klasse kommt mir wie gerufen... Werd in den nächsten Tagen genau so etwas brauchen... Ganz herzlichen Dank.

abs übrigens in einem Testprojekt ausprobiert, und es klappt einwandfrei!

Floste Themenstarter:in
1.130 Beiträge seit 2007
vor 15 Jahren

Hallo, existiert ein Testprojekt?

Die klasse ist (fast) exakt so in cmdFloste enthaqlten.

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

R
17 Beiträge seit 2011
vor 13 Jahren

Gibt es zu diesem Quelltext eventuell auch eine Kommentar version?

Weil ich genau diesen Text in einem Projekt habe.

Falls nicht, ist auch nicht so wild. 😃

Gelöschter Account
vor 12 Jahren

Ich hab einfach mal versucht F12 zu registrieren das klappte aber nicht.
A hingegen ging super. Gibts ne Chance die F Tasten auch zu unterstützen?

771 Beiträge seit 2009
vor 12 Jahren

Hallo Sebastian,

die "F12"-Taste ist für den System-Debugger reserviert.
Auf die Schnelle habe ich folgende Links dazu gefunden:
Programm reagiert nach einer Zeit nicht mehr auf Tastatureingaben (wird hier erwähnt)
Das C# 2010 Codebook (S. 594)
http://stackoverflow.com/questions/408744/how-do-i-get-f12-to-break-into-the-debugger-on-vista-x64-with-vs-2008

F
174 Beiträge seit 2007
vor 12 Jahren

Hallo Floste,

ich habe versucht, wie in deinem Beispiel Strg + Alt + A zu registrieren. [Ich habe eine Konsolenanwendung.] Leider tut sich da bei mir gar nichts. Muss ich noch irgendetwas beachten?
Hier mein Code:


static void Main(string[] args)
{
    Hotkey h = Hotkey.Register(Keys.A | Keys.Control | Keys.Alt);
    h.HotkeyPressed += new EventHandler(hotkeyPressed);
    Console.ReadLine();

    h.Dispose();
}

static void hotkeyPressed(object sender, EventArgs e)
{
    System.Windows.Forms.MessageBox.Show("hotkey pressed");
}

Betriebssystem: Windows 7 64 Bit (falls das irgendeine Rolle spielt)

Floste Themenstarter:in
1.130 Beiträge seit 2007
vor 12 Jahren

😁 Du brauchst zwingend eine nachrichtenschleife. Die klasse darf nur innerhalb eines gui-threads verwendet werden, nicht in der console: Ersetz mal Console.ReadLine(); Durch System.Windows.Forms.Application.Run(); dann hast du quasi nen guithread^^

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

F
174 Beiträge seit 2007
vor 12 Jahren

Hallo Floste,

juhu ... das hat funktioniert. Vielen Dank. 😉