Try a keyboard hook.
https://www.codeprojec*****m/Articles/...-Keyboard-Hook
Hey Guys,
I've recently purchased an Xbox360 Gamepad controller and I feel the need to create a little external toolbar to add more functionality to my hotkeys since a Gamepad is so limited compared to a keyboard..
My only problem is the sending Keys part.
Basically, I do know how to do it but for some reason the Game I am trying to send the Keystrokes to (through VB.NET) doesn't recognize the pressed Keys.
I've used both ways, the normal VB.NET SendKeys.Send() function and the API function "keybd_event"
SendKeys.Send("{6}")
SendKeys.Send("6")
keybd_event(&H97, 0, 0, 0)
keybd_event(&H97, 0, KEYEVENTF_KEYUP, 0)
All of these instructions send the digit "6" (tested on Notepad), but InGame nothing happens.
I've tried to see what gets send to the Game by having the chat open, and it works just the same way as with Notepad.. Although, the hotkeys are simply not working and I don't understand why. The Keystrokes are sent successfully so it doesn't make sense to me..
I've also tried to run the implemented Windows' Screen Keyboard to see if it'd be some kind of Hackshield block for certain keys pressed from external programs.. but I was wrong since everything works fine just like when I press a key on my Computer's keyboard.
Does anyone have an Idea how to work it around? The game I am trying to get this to work on is Vindictus.
It's simply odd that simple Characters and Digits are sent.. but not pre-set Hotkeys (Only if pressed with my Keyboard)..
Thanks in advance for any kind of help.
Legend
Try a keyboard hook.
https://www.codeprojec*****m/Articles/...-Keyboard-Hook
Light travels faster than sound. That's why most people seem bright until you hear them speak.
Thanks for your input, Brinuz, but I don't think I can achieve my goal with Keyboard hooks as they are used to listen to keyboard inputs in a global level and not to send keys to a specific application..
Atleast that's what I've read in several posts on Google..
I guess, It might be an Hackshield issue to prevent bots from using hotkeys :/
I was wondering if there would be a way to emulate the windows' on-screen keyboard as it seems to work perfectly the same way as a normal hardware keyboard does.. Any idea?
You are right, kinda read through your post in a quick way.
Im not seeing that working either. Since you already tried "keybd_event" aswell. Someone might have an answer to you tho.
does the onscreen keyboard work ingame?
Last edited by 'Bruno; 09-04-2012 at 06:34 PM.
Light travels faster than sound. That's why most people seem bright until you hear them speak.
Yes it does. Which makes my theory of the hackshield being faulty fail since the on-screen keyboard is an external program aswell..
I'm pretty much lost right now since I can't find a sense in this..
This class will allow you to capture hotkeys even when your program doesn't have focus.
Usage example:
The first parameter is the modifier, all the modifiers can be accessed using the HotkeyModifierFlags enumeration, which is included in the class.Code:Dim HelloSystemHotkey As New SystemHotkey(HotkeyModifierFlags.Control, Keys.A, New EventHandler(AddressOf Hello_Pressed)) If HelloSystemHotkey.Register() Then MsgBox("Registered") Else MsgBox("Not Registered") End If
The second parameter is the key to press with the modifier, identify one by simply using the Keys enumeration.
The third parameter is the eventhandler which will be raised once the key is pressed -> obviously we need the Hello_Pressed sub
The class has a property IsRegistered, this returns whether the hotkey is registered or not.Code:Private Sub Hello_Pressed(ByVal sender As Object, ByVal e As EventArgs) MsgBox("Pressed") End Sub
To unregister a hotkey, simply call the Unregister() function.
The Register() & Unregister() function return a boolean whether the operation has succeeded or not.
A hotkey registration will always fail if it is already in use by another program (or another instance of your program).
To use multiple modifiers, use the logical or operator (please not that some bindings are not allowed by the system).
Binding multiple keys is not allowed by the system.
So, create a new class
Hope this helps.Code:Imports System.Runtime.InteropServices Imports System.Threading Imports System.ComponentModel Public Class User32 <DllImport("user32", EntryPoint:="RegisterHotKey", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _ Public Shared Function RegisterHotkey(ByVal hwnd As IntPtr, ByVal Id As Int32, <MarshalAs(UnmanagedType.U4)> ByVal fsModifiers As Int32, <MarshalAs(UnmanagedType.U4)> ByVal vkey As Int32) As Boolean End Function <DllImport("user32", EntryPoint:="UnregisterHotKey", SetLastError:=True, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _ Public Shared Function UnregisterHotkey(ByVal hwnd As Int32, ByVal Id As Int32) As Boolean End Function End Class Public Class Kernel32 <DllImport("kernel32", EntryPoint:="GlobalAddAtom", SetLastError:=True, ExactSpelling:=False)> Public Shared Function GlobalAddAtom(<MarshalAs(UnmanagedType.LPTStr)> ByVal lpString As String) As Int32 End Function End Class Public Class SystemHotkey Public Property Modifiers As Int32 Public Property Key As Integer Public Property Pressed As eventhandler Private Id As String = "" Private Hwnd As IntPtr = IntPtr.Zero Public Sub New(ByVal pModifiers As Int32, ByVal pKey As Integer, ByVal pPressed As eventhandler) Modifiers = pModifiers Key = pKey Pressed = pPressed End Sub Public Function Register() As Boolean If IsRegistered Then Return False Else Id = Kernel32.GlobalAddAtom(GetHashCode) Dim Listener As New GlobalHotkeyListener(Id, Modifiers, Key, New EventHandler(AddressOf Hotkey_Pressed), IsRegistered) Hwnd = Listener.Handle Return IsRegistered End If End Function Public Function Unregister() As Boolean If IsRegistered Then If User32.UnregisterHotkey(Hwnd, Id) Then IsRegistered = False Return True Else Return False End If Else Return False End If End Function Private Sub Hotkey_Pressed(ByVal sender As Object, ByVal e As EventArgs) Pressed.Invoke(sender, e) End Sub Public Property IsRegistered As Boolean End Class Public Enum HotkeyModifierFlags None = 0 Alt = &H1 Control = &H2 Shift = &H4 Win = &H8 End Enum Public Class GlobalHotkeyListener Inherits NativeWindow #Region "Enums" <Flags()> _ Public Enum WindowStylesEx As UInteger WS_EX_ACCEPTFILES = &H10 WS_EX_APPWINDOW = &H40000 WS_EX_CLIENTEDGE = &H200 WS_EX_COMPOSITED = &H2000000 WS_EX_CONTEXTHELP = &H400 WS_EX_CONTROLPARENT = &H10000 WS_EX_DLGMODALFRAME = &H1 WS_EX_LAYERED = &H80000 WS_EX_LAYOUTRTL = &H400000 WS_EX_LEFT = &H0 WS_EX_LEFTSCROLLBAR = &H4000 WS_EX_LTRREADING = &H0 WS_EX_MDICHILD = &H40 WS_EX_NOACTIVATE = &H8000000 WS_EX_NOINHERITLAYOUT = &H100000 WS_EX_NOPARENTNOTIFY = &H4 WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE Or WS_EX_CLIENTEDGE WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE Or WS_EX_TOOLWINDOW Or WS_EX_TOPMOST WS_EX_RIGHT = &H1000 WS_EX_RIGHTSCROLLBAR = &H0 WS_EX_RTLREADING = &H2000 WS_EX_STATICEDGE = &H20000 WS_EX_TOOLWINDOW = &H80 WS_EX_TOPMOST = &H8 WS_EX_TRANSPARENT = &H20 WS_EX_WINDOWEDGE = &H100 End Enum <Flags()> Public Enum WindowStyles As UInteger WS_BORDER = &H800000 WS_CAPTION = &HC00000 WS_CHILD = &H40000000 WS_CLIPCHILDREN = &H2000000 WS_CLIPSIBLINGS = &H4000000 WS_DISABLED = &H8000000 WS_DLGFRAME = &H400000 WS_GROUP = &H20000 WS_HSCROLL = &H100000 WS_MAXIMIZE = &H1000000 WS_MAXIMIZEBOX = &H10000 WS_MINIMIZE = &H20000000 WS_MINIMIZEBOX = &H20000 WS_OVERLAPPED = &H0 WS_OVERLAPPEDWINDOW = WS_OVERLAPPED Or WS_CAPTION Or WS_SYSMENU Or WS_SIZEFRAME Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX WS_POPUP = &H80000000UI WS_POPUPWINDOW = WS_POPUP Or WS_BORDER Or WS_SYSMENU WS_SIZEFRAME = &H40000 WS_SYSMENU = &H80000 WS_TABSTOP = &H10000 WS_VISIBLE = &H10000000 WS_VSCROLL = &H200000 End Enum #End Region Private Pressed As EventHandler Public Sub New(ByVal Id As Int32, ByVal fsModifiers As Int32, ByVal vkey As Int32, ByVal PressedHandler As EventHandler, ByRef IsRegistered As Boolean) Pressed = PressedHandler Dim cp As CreateParams = New CreateParams() cp.Caption = "" cp.ClassName = "STATIC" cp.X = 0 cp.Y = 0 cp.Height = 0 cp.Width = 0 cp.Style = WindowStyles.WS_MINIMIZE cp.ExStyle = WindowStylesEx.WS_EX_NOACTIVATE Me.CreateHandle(cp) IsRegistered = User32.RegisterHotkey(MyBase.Handle, Id, fsModifiers, vkey) End Sub Private WM_HOTKEY As Integer = &H312 <System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _ Protected Overrides Sub WndProc(ByRef m As Message) Select Case (m.Msg) Case WM_HOTKEY If Pressed IsNot Nothing Then Pressed.Invoke(Me, New EventArgs()) End If End Select MyBase.WndProc(m) End Sub End Class
I'm sorry, I believe I should have found a better title for my Topic as I do not want to capture keystrokes.. I want to SEND KEYSTROKES to Vindictus from my VB.NET Program. The hotkeys I am talking about are the InGame ones to execute emotes, open UI Windows, etc etc and my scope is to send a key from my VB.NET Tool to Vindictus without me needing to touch my Keyboard.
Basically, the Tool is supposed to work like this:
1. Select an Option with my Gamepad
2. Press a Button of my choice to "execute" the Function
3. Invoked Function shall Send the Keycode that matches the Option I want to the extern Program, a.k.a. Vindictus.
#1 to #2 are working fine.. but #3 fails sending Keycodes that are set as Hotkeys Ingame like F1-F12 or anythig else that is being used as an hotkey in the game. Note that I am NOT assigning custom Hotkeys myself.. I'm relying on the ones InGame thus why I want to send the Hotkey keycodes to the Game..
When using Microsoft's On-Screen Keyboard (Start -> osk.exe), I can execute anything within the game just like when I press a key on my keyboard.
I want to achieve the same effect since the SendKeys.Send/SendWait class of VB.NET and the API function keybd_event don't want to work (They do work.. They do send ASCII Codes to the Ingame chat.. but Hotkeys are not working)..
Good, but code in VB must contain only what belongs to the VB interface any more.
My Creation------------------------------------------------------------------
I didn't really understand what you are trying to say but since API Functions can be imported into VB.NET aswell, I don't see why You shouldn't use them :P
However, I have tried to send keystrokes with C++ and it doesn't work either.
The odd thing is that it works just fine on any other Program.. except Vindictus..
Edit: I was trying to find a way to send inputs through the Device itself with the following code:
All I managed to achieve so far with this is, like with my gamepad, to capture what key's were pressed.. But I'd like to know if I could send keyboard inputs through the device itself.. Any hints?Code:Dim keyboardDevice As Device Dim keyboardDeviceList As DeviceList = Manager.GetDevices(DeviceClass.Keyboard, EnumDevicesFlags.AttachedOnly) If (keyboardDeviceLis*****unt > 0) Then keyboardDeviceList.MoveNext() Dim kbDeviceInstance As DeviceInstance = keyboardDeviceList.Current keyboardDevice = New Device(kbDeviceInstance.InstanceGuid) keyboardDevice.SetCooperativeLevel(Me, CooperativeLevelFlags.Background Or CooperativeLevelFlags.NonExclusive) keyboardDevice.SetDataFormat(DeviceDataFormat.Keyboard) keyboardDevice.Acquire() End If
Last edited by Legend2007; 09-05-2012 at 01:11 PM.
Problem solved.
I managed to get PostMessage simulate mouse clicks on OSK's Control buttons so that It'd input the pressed keys directly to Vindictus and it's working perfectly.
For those interested ones:
Note: CoordX/Y are the X & Y Mouse Position Coordinates relative to the Control! Not global coordinates!Code:Private MainHandle As Integer = FindWindow(vbNullString, "Window title") Private ControlHandle As Integer = FindWindowEx(MainHandle, IntPtr.Zero, "Class name of the Control", "") PostMessage(ControlHandle, WM_LBUTTONDOWN, 0, MakeDWord(CoordX, CoordY)) PostMessage(ControlHandle, WM_LBUTTONUP, 0, MakeDWord(CoordX, CoordY))
Code:Public Const WM_LBUTTONDOWN As Long = &H201 Public Const WM_LBUTTONUP As Long = &H202Code:Public Function MakeDWord(ByVal LoWord As Integer, ByVal HiWord As Integer) As Long Return CInt(HiWord) << 16 Or LoWord End FunctionI won't reveal how to get to the Class name though otherwise nobody will actually learn anything ;o Atleast those unexperienced ones..Code:Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Integer, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _ Public Function PostMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer End Function
Thanks everyone for helping.
Legend
'Bruno (09-06-2012)
Good luck on your program legend. Sorry that I was no help.
Gj and thanks for sharing. Marked solved
Light travels faster than sound. That's why most people seem bright until you hear them speak.
Last edited by hardenqueen; 11-04-2013 at 03:28 AM.