SORU
28 EKİM 2009, ÇARŞAMBA


Klavye kanca (WH_KEYBOARD_LL) WPF / global C#kullanarak

Internet kendimi WH_KEYBOARD_LL Yardımcı Sınıf kodundan birlikte buldum diktim:

Senin araçlarının bazıları aşağıdaki kodu koymak libs, öyle olsunYourUtils.cs:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace MYCOMPANYHERE.WPF.KeyboardHelper
{
    public class KeyboardListener : IDisposable
    {
        private static IntPtr hookId = IntPtr.Zero;

        [MethodImpl(MethodImplOptions.NoInlining)]
        private IntPtr HookCallback(
            int nCode, IntPtr wParam, IntPtr lParam)
        {
            try
            {
                return HookCallbackInner(nCode, wParam, lParam);
            }
            catch
            {
                Console.WriteLine("There was some error somewhere...");
            }
            return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
        }

        private IntPtr HookCallbackInner(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                if (wParam == (IntPtr)InterceptKeys.WM_KEYDOWN)
                {
                    int vkCode = Marshal.ReadInt32(lParam);

                    if (KeyDown != null)
                        KeyDown(this, new RawKeyEventArgs(vkCode, false));
                }
            }
            return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
        }

        public event RawKeyEventHandler KeyDown;
        public event RawKeyEventHandler KeyUp;

        public KeyboardListener()
        {
            hookId = InterceptKeys.SetHook((InterceptKeys.LowLevelKeyboardProc)HookCallback);
        }

        ~KeyboardListener()
        {
            Dispose();
        }

        #region IDisposable Members

        public void Dispose()
        {
            InterceptKeys.UnhookWindowsHookEx(hookId);
        }

        #endregion
    }

    internal static class InterceptKeys
    {
        public delegate IntPtr LowLevelKeyboardProc(
            int nCode, IntPtr wParam, IntPtr lParam);

        public static int WH_KEYBOARD_LL = 13;
        public static int WM_KEYDOWN = 0x0100;

        public static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr SetWindowsHookEx(int idHook,
            LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
            IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);
    }

    public class RawKeyEventArgs : EventArgs
    {
        public int VKCode;
        public Key Key;
        public bool IsSysKey;

        public RawKeyEventArgs(int VKCode, bool isSysKey)
        {
            this.VKCode = VKCode;
            this.IsSysKey = isSysKey;
            this.Key = System.Windows.Input.KeyInterop.KeyFromVirtualKey(VKCode);
        }
    }

    public delegate void RawKeyEventHandler(object sender, RawKeyEventArgs args);
}

Bu gibi kullanabilirsiniz:

App.xaml:

<Application ...
    Startup="Application_Startup"
    Exit="Application_Exit">
    ...

App.xaml.cs:

public partial class App : Application
{
    KeyboardListener KListener = new KeyboardListener();

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        KListener.KeyDown  = new RawKeyEventHandler(KListener_KeyDown);
    }

    void KListener_KeyDown(object sender, RawKeyEventArgs args)
    {
        Console.WriteLine(args.Key.ToString());
        // I tried writing the data in file here also, to make sure the problem is not in Console.WriteLine
    }

    private void Application_Exit(object sender, ExitEventArgs e)
    {
        KListener.Dispose();
    }
}

Sorun budurur bir süre sonra anahtarları vurmaya çalışıyor. Hata bu yüzden hiç, ben sadece bir süre sonra Çıkış için bir şey anlamadım ne kaldırdı. Çalışma durduğunda sağlam bir desen bulamadım.

Bu sorunu yeniden oluşturma oldukça basit, genellikle pencereden deli gibi, bazı anahtarları vurdu.

Bazı kötü olduğundan şüpheleniyorumdiş çekme sorunuarkasında, herkes bu çalışmaya devam etmek nasıl bir fikir var mı?


Ben zaten ne çalıştı:

  1. Basit bir şey ile return HookCallbackInner(nCode, wParam, lParam); değiştirme.
  2. Asenkron yerine, Uyku 5000ms (vs) koymak için çalışırken arayın.

Ara daha iyi bir iş yapmadı asenkron, kullanıcı tek bir harf, bir süre tutar aşağı her zaman durdurmak gibi görünüyor.

CEVAP
30 EKİM 2009, Cuma


SetHook yöntem çağrısı içinde geri temsilci senin içi yaratıyorsun. Bu temsilci eninde sonunda bir referans her yerde saklamadığını beri çöp toplama alacak. Ve temsilci çöp toplanan bir kez, bir daha geri alamazsınız.

Bunu önlemek için, temsilci başvuru canlı tutmak için kanca yerinde olduğu sürece ihtiyacınız UnhookWindowsHookEx dediğiniz kadar).

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • InfoPuppet

    InfoPuppet

    15 Kasım 2011
  • Jeb Corliss

    Jeb Corliss

    17 Kasım 2006
  • Jonathan Leack

    Jonathan Lea

    26 ŞUBAT 2007