Avatar billede semiprofkode Nybegynder
21. januar 2006 - 12:56 Der er 18 kommentarer

ændre tasten som sendes videre i en keyboard hook

return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);

På msdn står der at wParam indeholder keycode, men det passer ikke. Nu er jeg ikke skarp til pointere osv. i c++, men for mig ser det ud til at lParam indeholder keycoden, da det er det eneste tal som ændrer sig når jeg trykker på forskellige taster.

Hvad er sandheden? Hvordan sender jeg en anden tast videre en den der blev trykket på?
Avatar billede bertelbrander Novice
21. januar 2006 - 13:01 #1
Det kommer an på om det er WH_KEYBOARD eller WH_KEYBOARD_LL du bruger.

For den første bør det være wParam der er key-kode for den anden er lParam en struct, se f.ex:
http://home20.inet.tele.dk/midgaard/snip/rmkey.html
Avatar billede semiprofkode Nybegynder
21. januar 2006 - 13:13 #2
jeg søgte min hook klasse igennem efter _KEYBOARD og fandt to forekomster, begge med WH_KEYBOARD_LL. Her er den ene:

public const int WH_KEYBOARD_LL = 13;

Jeg har ikke selv lavet klassen, men den virker perfekt til at lave læse keyboard tryk globalt. Mit problem er, at jeg også vil ændre nogle af dem. wParam er altid 256 ved pressed og 257 ved released, ligegyldig hvilken tst jeg trykker på.
Avatar billede bertelbrander Novice
21. januar 2006 - 16:43 #3
For WH_KEYBOARD_LL er lParam en pointer til en KBDLLHOOKSTRUCT, du kan caste lParam:
KBDLLHOOKSTRUCT *HookStruct = (KBDLLHOOKSTRUCT *)lParam;

Og finde ud af hvilken tast det er med:
HookStruct->vkCode
Avatar billede semiprofkode Nybegynder
21. januar 2006 - 17:40 #4
Total frustration her hos mig. Noget som ser utrolig let ud viser sig at være nærmest umuligt.

Jeg kan allerede læse hvilken tast det er, det klarer koden således:

KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct) Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;

1. Det er ikke det samme som du skriver.
2. Det er ikke det jeg har brug for, jeg har brug for at sende en anden tast.
3. Har på fornemmelsen, at min klasse er en blanding af c# og c++. Her kommer hele klassen, som iøvrigt virker fantastisk:

using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;

using System.Collections;




namespace GLOBALHOOK
{
   

    public class UserActivityHook : object
    {
       
        public bool mousekillerActive=false;
        public bool disableKeyboard=true;
        /// <summary>
        /// Default constructor - starts hooks automatically
        /// </summary>
        public ArrayList blockedKeys;

        public UserActivityHook(ArrayList blockedKeys)
        {
            this.blockedKeys=blockedKeys;
            Start();
       
        }
       
        ~UserActivityHook()
        {
            Stop();
        }
       

        public event MouseEventHandler OnMouseActivity;
        public event KeyEventHandler KeyDown;
        public event KeyPressEventHandler KeyPress;
        public event KeyEventHandler KeyUp;

        public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

        static int hMouseHook = 0; //Declare mouse hook handle as int.
        public static int hKeyboardHook = 0; //Declare keyboard hook handle as int.

        //values from Winuser.h in Microsoft SDK.
        public const int WH_MOUSE_LL    = 14;    //mouse hook constant
        public const int WH_KEYBOARD_LL = 13;    //keyboard hook constant   

        HookProc MouseHookProcedure; //Declare MouseHookProcedure as HookProc type.
        HookProc KeyboardHookProcedure; //Declare KeyboardHookProcedure as HookProc type.
           

        //Declare wrapper managed POINT class.
        [StructLayout(LayoutKind.Sequential)]
            public class POINT
        {
            public int x;
            public int y;
        }

        //Declare wrapper managed MouseHookStruct class.
        [StructLayout(LayoutKind.Sequential)]
            public class MouseHookStruct
        {
            public POINT pt;
            public int hwnd;
            public int wHitTestCode;
            public int dwExtraInfo;
        }

        //Declare wrapper managed KeyboardHookStruct class.
        [StructLayout(LayoutKind.Sequential)]
            public class KeyboardHookStruct
        {
            public int vkCode;    //Specifies a virtual-key code. The code must be a value in the range 1 to 254.
            public int scanCode; // Specifies a hardware scan code for the key.
            public int flags;  // Specifies the extended-key flag, event-injected flag, context code, and transition-state flag.
            public int time; // Specifies the time stamp for this message.
            public int dwExtraInfo; // Specifies extra information associated with the message.
        }


        //Import for SetWindowsHookEx function.
        //Use this function to install a hook.
        [DllImport("user32.dll",CharSet=CharSet.Auto,
            CallingConvention=CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn,
            IntPtr hInstance, int threadId);

        //Import for UnhookWindowsHookEx.
        //Call this function to uninstall the hook.
        [DllImport("user32.dll",CharSet=CharSet.Auto,
            CallingConvention=CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);
       
        //Import for CallNextHookEx.
        //Use this function to pass the hook information to next hook procedure in chain.
        [DllImport("user32.dll",CharSet=CharSet.Auto,
            CallingConvention=CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode,
            Int32 wParam, IntPtr lParam); 

        public void Start()
        {
            // install Mouse hook
            if(hMouseHook == 0)
            {
                // Create an instance of HookProc.
                MouseHookProcedure = new HookProc(MouseHookProc);

                hMouseHook = SetWindowsHookEx( WH_MOUSE_LL,
                    MouseHookProcedure,
                    Marshal.GetHINSTANCE(
                    Assembly.GetExecutingAssembly().GetModules()[0]),
                    0);

                //If SetWindowsHookEx fails.
                if(hMouseHook == 0 )   
                {
                    Stop();
                    throw new Exception("SetWindowsHookEx failed.");
                }
            }
           
            // install Keyboard hook
            if(hKeyboardHook == 0)
            {
                KeyboardHookProcedure = new HookProc(KeyboardHookProc);
                hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL,
                    KeyboardHookProcedure,
                    Marshal.GetHINSTANCE(
                    Assembly.GetExecutingAssembly().GetModules()[0]),
                    0);

                //If SetWindowsHookEx fails.
                if(hKeyboardHook == 0 )   
                {
                    Stop();
                    throw new Exception("SetWindowsHookEx ist failed.");
                }
            }
        }

        public void Stop()
        {
            bool retMouse =true;
            bool retKeyboard = true;
            if(hMouseHook != 0)
            {
                retMouse = UnhookWindowsHookEx(hMouseHook);
                hMouseHook = 0;
            }
           
            if(hKeyboardHook != 0)
            {
                retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
                hKeyboardHook = 0;
            }
           
            //If UnhookWindowsHookEx fails.
            if (!(retMouse && retKeyboard)) throw new Exception("UnhookWindowsHookEx failed.");
        }



        private const int WM_MOUSEMOVE = 0x200;
        private const int WM_LBUTTONDOWN = 0x201;
        private const int WM_RBUTTONDOWN = 0x204;
        private const int WM_MBUTTONDOWN = 0x207;
        private const int WM_LBUTTONUP = 0x202;
        private const int WM_RBUTTONUP = 0x205;
        private const int WM_MBUTTONUP = 0x208;
        private const int WM_LBUTTONDBLCLK = 0x203;
        private const int WM_RBUTTONDBLCLK = 0x206;
        private const int WM_MBUTTONDBLCLK = 0x209;

        private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            // if ok and someone listens to our events
            if ((nCode >= 0) && (OnMouseActivity!=null))
            {
               
                MouseButtons button=MouseButtons.None;

                switch (wParam)
                {
                    case WM_LBUTTONDOWN:
                        //case WM_LBUTTONUP:
                        //case WM_LBUTTONDBLCLK:
                        button=MouseButtons.Left;
                        break;
                    case WM_RBUTTONDOWN:
                        //case WM_RBUTTONUP:
                        //case WM_RBUTTONDBLCLK:
                        button=MouseButtons.Right;
                        break;
                    case WM_MBUTTONDOWN:
                        //case WM_RBUTTONUP:
                        //case WM_RBUTTONDBLCLK:
                        button=MouseButtons.Middle;
                        break;
                    default :
                        //case WM_RBUTTONUP:
                        //case WM_RBUTTONDBLCLK:
                        //button=MouseButtons.XButton1;
                        if (wParam != WM_MOUSEMOVE && wParam != WM_LBUTTONUP && wParam != WM_RBUTTONUP && wParam !=WM_MBUTTONUP && wParam != WM_LBUTTONDBLCLK && wParam !=WM_RBUTTONDBLCLK && wParam != WM_MBUTTONDBLCLK)
                        {
                            MessageBox.Show(wParam.ToString());
                        }
                        break;
                       
                }
                int clickCount=0;
                if (button!=MouseButtons.None)
                    if (wParam==WM_LBUTTONDBLCLK || wParam==WM_RBUTTONDBLCLK)
                    {
                        clickCount=2;
                    }
                    else
                    {
                        clickCount=1;
                    }
               
                //Marshall the data from callback.
                MouseHookStruct MyMouseHookStruct = (MouseHookStruct) Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
                MouseEventArgs e=new MouseEventArgs(
                    button,
                    clickCount,
                    MyMouseHookStruct.pt.x,
                    MyMouseHookStruct.pt.y,
                    0 );
                OnMouseActivity(this, e);
            }
            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
        }


        //The ToAscii function translates the specified virtual-key code and keyboard state to the corresponding character or characters. The function translates the code using the input language and physical keyboard layout identified by the keyboard layout handle.
        [DllImport("user32")]
        public static extern int ToAscii(int uVirtKey, //[in] Specifies the virtual-key code to be translated.
            int uScanCode, // [in] Specifies the hardware scan code of the key to be translated. The high-order bit of this value is set if the key is up (not pressed).
            byte[] lpbKeyState, // [in] Pointer to a 256-byte array that contains the current keyboard state. Each element (byte) in the array contains the state of one key. If the high-order bit of a byte is set, the key is down (pressed). The low bit, if set, indicates that the key is toggled on. In this function, only the toggle bit of the CAPS LOCK key is relevant. The toggle state of the NUM LOCK and SCROLL LOCK keys is ignored.
            byte[] lpwTransKey, // [out] Pointer to the buffer that receives the translated character or characters.
            int fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise.

        //The GetKeyboardState function copies the status of the 256 virtual keys to the specified buffer.
        [DllImport("user32")]
        public static extern int GetKeyboardState(byte[] pbKeyState);

        private const int WM_KEYDOWN        = 0x100;
        private const int WM_KEYUP            = 0x101;
        private const int WM_SYSKEYDOWN    = 0x104;
        private const int WM_SYSKEYUP        = 0x105;

        private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            bool blockedKey=false;

           
            // it was ok and someone listens to events
            if ((nCode >= 0) && (KeyDown!=null || KeyUp!=null || KeyPress!=null))
            {
               
                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct) Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                // raise KeyDown
                if ( KeyDown!=null && ( wParam ==WM_KEYDOWN || wParam==WM_SYSKEYDOWN ))
                {
                    Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;
                    KeyEventArgs e = new KeyEventArgs(keyData);
                    KeyDown(this, e);

                   
                }

               

               
                // raise KeyPress
                if ( KeyPress!=null &&  wParam ==WM_KEYDOWN )
                {
                    byte[] keyState = new byte[256];
                    GetKeyboardState(keyState);

                    byte[] inBuffer= new byte[2];
                    if (ToAscii(MyKeyboardHookStruct.vkCode,
                        MyKeyboardHookStruct.scanCode,
                        keyState,
                        inBuffer,
                        MyKeyboardHookStruct.flags)==1)
                    {
                        KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);
                        KeyPress(this, e);
                    }
                }
               
                // raise KeyUp
                if ( KeyUp!=null && ( wParam ==WM_KEYUP || wParam==WM_SYSKEYUP ))
                {
                    Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;
                    KeyEventArgs e = new KeyEventArgs(keyData);
                    KeyUp(this, e);
                }

            }
           
           

            return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
           
        }
    }
}
Avatar billede bertelbrander Novice
21. januar 2006 - 18:19 #5
Jeg ved ikke hvad din kode er, det er er ikke C++, måske er det .net/manager/cli?
Bruger du MS VisualC++?
For mig at se er det meget kode for så lidt.

Anyway har du prøvet at sætte MyKeyboardHookStruct.vkCode til noget andet?

Så vidt jeg ved kan denne metode ikke bruges til at snyde alle programmer.
Avatar billede semiprofkode Nybegynder
21. januar 2006 - 18:23 #6
ja, det har jeg prøvet. Jeg bruger Visual studio 2003, normalt c#.

Hjæææælp
Avatar billede semiprofkode Nybegynder
21. januar 2006 - 18:30 #7
Jeg tror altså det er c#, for jeg kan sætte almindelig c# kode ind imellem, f.eks. MessageBox.show(....);

Koden er god fordi man let kan oprette keyboard og mouse events i andre klasser med den.

Men det med pointere og IntPtr er ikke noget jeg er vant til. Har du andre forslag? Det hjalp ikke at ændre MyKeyboardHookStruct.vkCode
Avatar billede bertelbrander Novice
21. januar 2006 - 18:38 #8
Jeg har prøvet lidt af hvert, men jeg kan ikke få det til at virke.

Måske er man nødt til at fjerne den oprindelige tast og sende den man vil have i stedet.
Man fjerner en tast ved at returnere TRUE fra hook funktionen i stedet for at kalde CallNextHookEx, og man kan sende en tast med SendInput:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/sendinput.asp
Avatar billede semiprofkode Nybegynder
21. januar 2006 - 18:50 #9
Okay, det er noget med nogle pointere(ved ikke hvad det går ud på), kan jeg se, og jeg kan ikke se om den både sender keyUp og keyDown. Jeg har brug for begge dele. Jeg forstår ikke hvorfor det er så svært at fixe den metode jeg allerede har.

Hvad med

Marshal.StructureToPtr(MyKeyboardHookStruct,lParam,true/false);

når nu

Marshal.PtrToStructure

bruges til at finde keycoden ?

Der må da være nogen som ved hvad denne kode gør. Det er det tredje spørgsmål jeg har ude på eksperten, er ved at være ret desparat.
Avatar billede bertelbrander Novice
21. januar 2006 - 20:04 #10
Jeg har prøvet at ændre Hook Struct'en med rigtig C++ kode, det virker ikke :-(

Jeg prøver at strikke en løsning sammen med SendInput, så håber jeg at du kan oversætte det til C# eller hvad du nu foretrækker.
Avatar billede semiprofkode Nybegynder
21. januar 2006 - 20:06 #11
Det glæder jeg mig til at prøve
Avatar billede bertelbrander Novice
21. januar 2006 - 20:21 #12
Denne kode bytter om på PAGE_UP og PAGE_DOWN:

#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

HHOOK MouseHook;

LRESULT LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
  if(nCode == HC_ACTION)
  {
      KBDLLHOOKSTRUCT *HookStruct = (KBDLLHOOKSTRUCT *)lParam;
      if(!(HookStruct->flags & LLKHF_INJECTED))
      {
        if(HookStruct->vkCode == VK_NEXT)
        {
            INPUT Input[2];
            Input[0].type = INPUT_KEYBOARD;
            Input[0].ki.wVk = VK_PRIOR;
            Input[0].ki.dwFlags = 0;
            Input[0].ki.time = HookStruct->time;
            Input[0].ki.wScan = 0;
            Input[0].ki.dwExtraInfo = 0;
            Input[1].type = INPUT_KEYBOARD;
            Input[1].ki.wVk = VK_PRIOR;
            Input[1].ki.dwFlags = KEYEVENTF_KEYUP;
            Input[1].ki.time = HookStruct->time;
            Input[1].ki.wScan = 0;
            Input[1].ki.dwExtraInfo = 0;
            SendInput(2, Input, sizeof(INPUT));
            return TRUE;
        }
        else if(HookStruct->vkCode == VK_PRIOR)
        {
            INPUT Input[2];
            Input[0].type = INPUT_KEYBOARD;
            Input[0].ki.wVk = VK_NEXT;
            Input[0].ki.dwFlags = 0;
            Input[0].ki.time = HookStruct->time;
            Input[0].ki.wScan = 0;
            Input[0].ki.dwExtraInfo = 0;
            Input[1].type = INPUT_KEYBOARD;
            Input[1].ki.wVk = VK_NEXT;
            Input[1].ki.dwFlags = KEYEVENTF_KEYUP;
            Input[1].ki.time = HookStruct->time;
            Input[1].ki.wScan = 0;
            Input[1].ki.dwExtraInfo = 0;
            SendInput(2, Input, sizeof(INPUT));
            return TRUE;
        }
      }
  }

  return CallNextHookEx(MouseHook, nCode, wParam, lParam);
}

void InstallHook(void)
{
  if(MouseHook)
      return;

  MouseHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC  )LowLevelKeyboardProc, GetModuleHandle(0), 0);
  if(!MouseHook)
  {
      MessageBox(0, "Failed to install Hook", "PageDown Remover", MB_OK);
  }
}

void UnInstallHook(void)
{
  if(MouseHook)
      UnhookWindowsHookEx(MouseHook);
  MouseHook = 0;
}

int main()
{
  InstallHook();
  MessageBox(0, "Hit Ok to close", "PageDown Remover", MB_OK);
  UnInstallHook();
  return EXIT_SUCCESS;
}
Avatar billede semiprofkode Nybegynder
23. januar 2006 - 14:44 #13
Jeg forstår ikke koden, jeg kan ikke se page_up eller page_down nogen steder.

Det ligner en hel hook, jeg har kun brug for at sende en tast efter eget valg. Både pressed og released.

Jeg sætter pris på at du prøver at hjælpe.
Avatar billede bertelbrander Novice
23. januar 2006 - 19:56 #14
page_up hedder VK_PRIOR og page_down hedder VK_NEXT

Dette er koden til at sende page-up, både pressed og released:
            INPUT Input[2];
            Input[0].type = INPUT_KEYBOARD;
            Input[0].ki.wVk = VK_PRIOR;
            Input[0].ki.dwFlags = 0;
            Input[0].ki.time = HookStruct->time;
            Input[0].ki.wScan = 0;
            Input[0].ki.dwExtraInfo = 0;
            Input[1].type = INPUT_KEYBOARD;
            Input[1].ki.wVk = VK_PRIOR;
            Input[1].ki.dwFlags = KEYEVENTF_KEYUP;
            Input[1].ki.time = HookStruct->time;
            Input[1].ki.wScan = 0;
            Input[1].ki.dwExtraInfo = 0;
            SendInput(2, Input, sizeof(INPUT));
            return TRUE;

Denne linie:
if(!(HookStruct->flags & LLKHF_INJECTED))
Sikrer at man ikke ændrer de taster man selv har indsat, ellers vil man ende i en uendelig loop.
Avatar billede semiprofkode Nybegynder
23. januar 2006 - 21:25 #15
Okay, jeg forklarede mig ikke tydeligt nok. Jeg har brug for at kunne sende keypressed og released, men ikke samtidig. Er det muligt med denne her kode?
Avatar billede bertelbrander Novice
23. januar 2006 - 21:56 #16
Input[0] er key-pressed, Input[1] er key-released
Så du kan lave et delay mellem den første og den anden.
Det første argument til SendInput er antal events, det skal så sættes til 1.
Avatar billede semiprofkode Nybegynder
24. januar 2006 - 21:25 #17
ok. Du skal have pointene for det rigtige svar. Mit problem er bare lige nu at det ikke kan oversættes til c#, metoden findes ikke i c#, så jeg ved ikke hvordan jeg skal bruge koden. Jeg synes på et tidspunkt jeg så at man kunne blande c# og c++ i et projekt. Ellers kan jeg vel lave noget i c++ jeg kan kalde fra mit c# projekt.
Avatar billede bertelbrander Novice
24. januar 2006 - 21:50 #18
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester