2012-11-30 6 views
5

Ich versuche, zwei "Mäuse" zu steuern. Die primäre Maus (Maus) wird zur Steuerung des Cursors für normale UI-Steuerung (die ich nicht abfangen möchte) und eine sekundäre "Maus" verwendet, die nur als Eingabe in die Anwendung verwendet werden sollte, die ich schreibe und sonst ignoriert würde.So verhindern Sie rohe Mausklicks außerhalb einer Anwendung mit C#

Ich bin erfolgreich erfassen die Maus Nachrichten und Filterung wie gewünscht. Ich kann die Mauseingaben auch dann erfolgreich erfassen, wenn meine App nicht scharf ist (wie gewünscht).

Das einzige verbleibende Problem ist, dass ich nicht scheinen kann, die Maus von der Interaktion mit anderen Anwendungen zu halten. So kann ich im Wesentlichen die Maus ausspionieren, aber die Nachricht nicht vollständig konsumieren.

Ich "glaube" Ich verhindere, dass die "base.WndProc (ref message)" aufgerufen wird, wenn ich die gefilterten Mausnachrichten verarbeite, aber das System scheint immer noch die Mausklicks zu bekommen.

Kann C# (Visual Studio Express 2010) dies tun?

Vielen Dank für jegliche Unterstützung, die Sie möglicherweise geben können.

+1

heq's Antwort scheint am richtigsten. Überschreiben von Basis.WndProc steuert nur die Windows-Nachrichten * Ihre * Anwendung empfängt, aber es hat nichts damit zu tun, die Windows-Nachrichten anderer Anwendungen zu steuern. Ein globaler Maushaken ist der Weg zu gehen. Es ist wirklich sehr beliebt. – Jason

+0

Ein Maushaken ist nur die halbe Miete. Ich brauche beide. Der Haken wird verwendet, um zu verhindern, dass das Klickformular zu anderen Apps geht, aber ich brauche eine rohe Maus, damit ich das tatsächliche Gerät das Klicken tat. Die wirkliche Antwort ist, dass C# (.net) leider nicht das richtige Werkzeug ist. – ChronoFish

+0

Was meinen Sie mit roher Maus, damit Sie [wissen], welches Gerät das Klicken tat? Wenn Sie einen Mausklick ausführen, können Sie das aktive Fenster (GetActiveWindow()) und den Speicherort des Klicks bestimmen und dann bestimmen, ob dieser Klick in Ihrem Formular erfolgt ist oder nicht. – Jason

Antwort

3

Raw-Eingabe könnte was Sie suchen. Here ist eine MSDN-Diskussion mit einer ähnlichen Frage, die mit einem Codeprojektartikel zum Behandeln von mehreren Tastaturen in C# verknüpft ist.

+0

Dies ist die primäre Referenz, die mich so weit wie ich gemacht habe. Es "funktioniert" mit Ausnahme der Begrenzung der Eingabe in anderen Anwendungen. Trotzdem danke. – ChronoFish

+0

Ich glaube nicht, dass es möglich ist, Input global zu filtern, nach [this] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms645543 (v = vs.85) .aspx) Artikel. Der Satz, der mich dazu bringt, ist: "Beachten Sie, dass die Maus und die Tastatur ebenfalls HIDs sind, sodass Daten von ihnen sowohl die HID-Nachricht WM_INPUT als auch traditionelle Nachrichten enthalten können. Eine Anwendung kann eine Methode durch die richtige Auswahl von Flags auswählen in RAWINPUTDEVICE. " – Bikonja

+0

Ich gebe Ihnen die Antwort, weil es in C# oder .net "nicht möglich" ist. Obwohl es möglich ist - aber Sie müssen mit einer nicht. NET-DLL gehen, die im Grunde bedeutet Programmierung in C/C++ – ChronoFish

1

Sie können globalen Maushaken verwenden. Ich erinnere mich nicht, wo ich es gefunden habe, aber here ist das Beispiel

+0

Ich habe versucht, den globalen Maus-Hook zu verwenden - das ist wahrscheinlich, was ich verwenden muss ... aber bisher kann ich nur für WH_MOUSE arbeiten, die nur Nachrichten für meine App erfasst, wo-wie WH_MOUSE_LL ist soll alle Nachrichten erfassen - aber ich kann den Code nicht dazu bringen, die Erfassung zu initiieren (es ist fehlerhaft). (Es scheint, ich bin im Niemandsland und in ein bisschen nicht unterstützte Funktionalität für C#). Danke – ChronoFish

+0

Auch spreche ich oder lese nicht Russisch, also hilft mir der Forumlink nicht. – ChronoFish

+0

Es gibt keine Notwendigkeit, Russisch zu lesen, das ist ein Link auf Maus-Hook-Beispiel mit Kommentaren alle auf Englisch. Und es enthält einige Dinge, die Sie brauchen, zum Beispiel:. 'Privat const int WH_KEYBOARD_LL = 13;' und 'hMouseHook = SetWindowsHookEx ( WH_MOUSE_LL, MouseHookProcedure, Marshal.GetHINSTANCE ( Assembly.GetExecutingAssembly() GetModules() [0]), 0); ' – heq

0

Ich glaube nicht, dass es möglich ist, einen Mausklick über C# .Net zu verhindern. Möglicherweise können Sie den Mauszeiger jedoch über ClipCursor in einer Position sperren. Der folgende Link kann Ihnen dabei helfen.

Wenn Sie im Wesentlichen verhindern wollen, dass eine Maus verwendet wird, deaktivieren Sie einfach die Maus, als ob Sie zum Gerätemanager gehen und auf "disable" klicken würden. Dies kann programmgesteuert wie gelöst here erfolgen.

Hier ist der Code aus dem obigen Link kopiert:

public static class DisableHardware 
{ 
    const uint DIF_PROPERTYCHANGE = 0x12; 
    const uint DICS_ENABLE = 1; 
    const uint DICS_DISABLE = 2; // disable device 
    const uint DICS_FLAG_GLOBAL = 1; // not profile-specific 
    const uint DIGCF_ALLCLASSES = 4; 
    const uint DIGCF_PRESENT = 2; 
    const uint ERROR_INVALID_DATA = 13; 
    const uint ERROR_NO_MORE_ITEMS = 259; 
    const uint ERROR_ELEMENT_NOT_FOUND = 1168; 

    static DEVPROPKEY DEVPKEY_Device_DeviceDesc; 
    static DEVPROPKEY DEVPKEY_Device_HardwareIds; 

    [StructLayout(LayoutKind.Sequential)] 
    struct SP_CLASSINSTALL_HEADER 
    { 
     public UInt32 cbSize; 
     public UInt32 InstallFunction; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    struct SP_PROPCHANGE_PARAMS 
    { 
     public SP_CLASSINSTALL_HEADER ClassInstallHeader; 
     public UInt32 StateChange; 
     public UInt32 Scope; 
     public UInt32 HwProfile; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    struct SP_DEVINFO_DATA 
    { 
     public UInt32 cbSize; 
     public Guid classGuid; 
     public UInt32 devInst; 
     public IntPtr reserved;  // CHANGE #1 - was UInt32 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    struct DEVPROPKEY 
    { 
     public Guid fmtid; 
     public UInt32 pid; 
    } 

    [DllImport("setupapi.dll", SetLastError = true)] 
    static extern IntPtr SetupDiGetClassDevsW(
     [In] ref Guid ClassGuid, 
     [MarshalAs(UnmanagedType.LPWStr)] 
string Enumerator, 
     IntPtr parent, 
     UInt32 flags); 

    [DllImport("setupapi.dll", SetLastError = true)] 
    static extern bool SetupDiDestroyDeviceInfoList(IntPtr handle); 

    [DllImport("setupapi.dll", SetLastError = true)] 
    static extern bool SetupDiEnumDeviceInfo(IntPtr deviceInfoSet, 
     UInt32 memberIndex, 
     [Out] out SP_DEVINFO_DATA deviceInfoData); 

    [DllImport("setupapi.dll", SetLastError = true)] 
    static extern bool SetupDiSetClassInstallParams(
     IntPtr deviceInfoSet, 
     [In] ref SP_DEVINFO_DATA deviceInfoData, 
     [In] ref SP_PROPCHANGE_PARAMS classInstallParams, 
     UInt32 ClassInstallParamsSize); 

    [DllImport("setupapi.dll", SetLastError = true)] 
    static extern bool SetupDiChangeState(
     IntPtr deviceInfoSet, 
     [In] ref SP_DEVINFO_DATA deviceInfoData); 

    [DllImport("setupapi.dll", SetLastError = true)] 
    static extern bool SetupDiGetDevicePropertyW(
      IntPtr deviceInfoSet, 
      [In] ref SP_DEVINFO_DATA DeviceInfoData, 
      [In] ref DEVPROPKEY propertyKey, 
      [Out] out UInt32 propertyType, 
      IntPtr propertyBuffer, 
      UInt32 propertyBufferSize, 
      out UInt32 requiredSize, 
      UInt32 flags); 

    [DllImport("setupapi.dll", SetLastError = true)] 
    static extern bool SetupDiGetDeviceRegistryPropertyW(
     IntPtr DeviceInfoSet, 
     [In] ref SP_DEVINFO_DATA DeviceInfoData, 
     UInt32 Property, 
     [Out] out UInt32 PropertyRegDataType, 
     IntPtr PropertyBuffer, 
     UInt32 PropertyBufferSize, 
     [In,Out] ref UInt32 RequiredSize 
    ); 

    static DisableHardware() 
    { 
     DisableHardware.DEVPKEY_Device_DeviceDesc = new DEVPROPKEY(); 
     DEVPKEY_Device_DeviceDesc.fmtid = new Guid(
       0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 
       0xd1, 0x46, 0xa8, 0x50, 0xe0); 
     DEVPKEY_Device_DeviceDesc.pid = 2; 

     DEVPKEY_Device_HardwareIds = new DEVPROPKEY(); 
     DEVPKEY_Device_HardwareIds.fmtid = new Guid(
      0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 
      0xd1, 0x46, 0xa8, 0x50, 0xe0); 
     DEVPKEY_Device_HardwareIds.pid = 3; 
    } 




    public static void DisableDevice(Func<string, bool> filter, bool disable = true) 
    { 
     IntPtr info = IntPtr.Zero; 
     Guid NullGuid = Guid.Empty; 
     try 
     { 
      info = SetupDiGetClassDevsW(
       ref NullGuid, 
       null, 
       IntPtr.Zero, 
       DIGCF_ALLCLASSES); 
      CheckError("SetupDiGetClassDevs"); 

      SP_DEVINFO_DATA devdata = new SP_DEVINFO_DATA(); 
      devdata.cbSize = (UInt32)Marshal.SizeOf(devdata); 

      // Get first device matching device criterion. 
      for (uint i = 0; ; i++) 
      { 
       SetupDiEnumDeviceInfo(info, 
        i, 
        out devdata); 
       // if no items match filter, throw 
       if (Marshal.GetLastWin32Error() == ERROR_NO_MORE_ITEMS) 
        CheckError("No device found matching filter.", 0xcffff); 
       CheckError("SetupDiEnumDeviceInfo"); 

       string devicepath = GetStringPropertyForDevice(info, 
              devdata, 1); // SPDRP_HARDWAREID 

       // Uncomment to print name/path 
       //Console.WriteLine(GetStringPropertyForDevice(info, 
       //       devdata, DEVPKEY_Device_DeviceDesc)); 
       //Console.WriteLine(" {0}", devicepath); 
       if (devicepath != null && filter(devicepath)) break; 

      } 

      SP_CLASSINSTALL_HEADER header = new SP_CLASSINSTALL_HEADER(); 
      header.cbSize = (UInt32)Marshal.SizeOf(header); 
      header.InstallFunction = DIF_PROPERTYCHANGE; 

      SP_PROPCHANGE_PARAMS propchangeparams = new SP_PROPCHANGE_PARAMS(); 
      propchangeparams.ClassInstallHeader = header; 
      propchangeparams.StateChange = disable ? DICS_DISABLE : DICS_ENABLE; 
      propchangeparams.Scope = DICS_FLAG_GLOBAL; 
      propchangeparams.HwProfile = 0; 

      SetupDiSetClassInstallParams(info, 
       ref devdata, 
       ref propchangeparams, 
       (UInt32)Marshal.SizeOf(propchangeparams)); 
      CheckError("SetupDiSetClassInstallParams"); 

      SetupDiChangeState(
       info, 
       ref devdata); 
      CheckError("SetupDiChangeState"); 
     } 
     finally 
     { 
      if (info != IntPtr.Zero) 
       SetupDiDestroyDeviceInfoList(info); 
     } 
    } 
    private static void CheckError(string message, int lasterror = -1) 
    { 

     int code = lasterror == -1 ? Marshal.GetLastWin32Error() : lasterror; 
     if (code != 0) 
      throw new ApplicationException(
       String.Format("Error disabling hardware device (Code {0}): {1}", 
        code, message)); 
    } 

    private static string GetStringPropertyForDevice(IntPtr info, SP_DEVINFO_DATA devdata, 
     uint propId) 
    { 
     uint proptype, outsize; 
     IntPtr buffer = IntPtr.Zero; 
     try 
     { 
      uint buflen = 512; 
      buffer = Marshal.AllocHGlobal((int)buflen); 
      outsize=0; 
      // CHANGE #2 - Use this instead of SetupDiGetDeviceProperty 
      SetupDiGetDeviceRegistryPropertyW(
       info, 
       ref devdata, 
       propId, 
       out proptype, 
       buffer, 
       buflen, 
       ref outsize); 
      byte[] lbuffer = new byte[outsize]; 
      Marshal.Copy(buffer, lbuffer, 0, (int)outsize); 
      int errcode = Marshal.GetLastWin32Error(); 
      if (errcode == ERROR_INVALID_DATA) return null; 
      CheckError("SetupDiGetDeviceProperty", errcode); 
      return Encoding.Unicode.GetString(lbuffer); 
     } 
     finally 
     { 
      if (buffer != IntPtr.Zero) 
       Marshal.FreeHGlobal(buffer); 
     } 
    } 

} 

http://msdn.microsoft.com/en-us/library/windows/desktop/ms648383%28v=vs.85%29.aspx http://www.pinvoke.net/default.aspx/user32/ClipCursor.html

+0

Danke für den Vorschlag, aber Clipping ist etwas, das ich vermeiden möchte. Vielen Dank. – ChronoFish

+0

@ChronoFish was ist mit meinem anderen Vorschlag: Einfach das Gerät programmatisch deaktivieren? – FrostyFire

+0

Ich möchte nicht die zweite Maus deaktiviert. Meine Anwendung muss wissen, wann die zweite Maus "geklickt" wird - aber ich möchte nicht, dass andere Anwendungen wissen, wann die zweite Maus geklickt wird. – ChronoFish

1

Wie andere dies angegeben haben zumindest mühsam in dot net ist. Ich würde Ihnen wärmstens empfehlen, zu C++/Win32 zu wechseln, um dies zu erreichen. Ich denke, auf lange Sicht werden Sie sich viele Kopfschmerzen ersparen.

+0

Ja, du hast Recht. Dies ist die Route, die ich gehe ... aber MS, meiner Meinung nach, hat eine so schlechte Arbeit der API gemacht, dass es die Programmierung in C++ in die Irre führt. Ich werde es schaffen, trete und schreie den ganzen Weg bis zum Ende. In der heutigen Zeit sollte es trivial sein, einen String aus der Registry zu nehmen und ihn in ein Control zu posten - aber du musst durch die Ringe springen, um einen "LPCTSTR" zu erhalten, der auf "cout" gedruckt werden kann .... – ChronoFish

+0

Wenn Sie wirklich C++ vermeiden wollen, können Sie VB6 ausprobieren. Ich schneide meine Zähne auf VB6 und Win32 :) Soweit ich mich erinnere, ist es sehr effektiv bei der Arbeit mit der win32 apis (Aber etwas als Sprache begrenzt). Die andere große Sache ist, wie es schon eine Weile her ist, und wird immer noch viel benutzt, es gibt auch eine Menge guter Dokumentation da draußen. –

Verwandte Themen