NomeSkavinski Posted March 5, 2013 Share Posted March 5, 2013 Hi guys, I'm trying to send keyboard button events from a script using PostMessage(). The idea is to allow a game pad to simulate a keypress, so mods that have only been made for keyboard controls can be also used with a pad. So far, GTA acknowledges the Post event and recognizes the key, scancode, and whether or not it is up or down. But it doesn't seem to get processed. All of this has been confirmed using Spy++. Every way of sending a virtual key (SendMessge, PostMessage, SendKey, even third party API's) is acknowledged by GTA/Spy++ but it still doesn't process the event. So is there another way of accessing GTA keyboard sending features? Or is all that handled by GTA it self, and then is it passed down to the scripthook? Any help is appriciated, i think i am going to have to abandone this idea. Nome. Link to comment Share on other sites More sharing options...
pedro2555 Posted March 6, 2013 Share Posted March 6, 2013 That is a bit weird. Have you tried SendInput, from the same library? check this, make sure to check the response on the bottom of the page. Also, have you ever tried something like xpadder or joy2key ? It looks like, they do what you want. Link to comment Share on other sites More sharing options...
NomeSkavinski Posted March 6, 2013 Author Share Posted March 6, 2013 I havn't tried xpadder or joy2Key, i forgot about them, thanks. That post seems extremely handy, i will go through it in a bit more depth. The answer with the most votes is exactly what i was thinking, about checking the scancodes etc. Which I have triple checked that the lparam/wparam are all correct telling which bits are the scancode, whether its up or down or an additional key. The guy also mentions about using the InputSimulator and i tried it and the scripthook cant load it it for some reason or rather my .net.dll cant find it, nevertheless so i got the source code and put that in my project and got it working but still yielding the same result. But ill definitely look into those two areas, thanks for helping your time and information is very much appreciated! Link to comment Share on other sites More sharing options...
nixolas1 Posted March 7, 2013 Share Posted March 7, 2013 Hey, i was doin something similar a few weeks ago, but i was searching for a way of sending emulated mouse events, which you can do like this btw, in C++/scripthook: mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);Wait(0);mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); while trying to find it, i found some stuff which interacted with my mods running in the game, the only thing is that i dont know how the key enums were defined, seemed semi-random. and i dont have the code anymore, cause it didnt work for mouse clicks, but it was using SendInput or SendKey (think it was sendkey). are you sure you did it right? what i did was to loop through all keys as ints from 0 to 500 with some wait time between, all kinds of crazy things happened, from in-game movement, to mod enabling/interaction, to opening explorer windows. hope this helps a bit Link to comment Share on other sites More sharing options...
pedro2555 Posted March 7, 2013 Share Posted March 7, 2013 C++ will be a better approach than any C# or VB.NET. Global events are technically not accessible from C# or VB.NET, they sort of work. But I was thinking about this, and the problem may be in the way your dll is loaded. Try to create a standart console app to send keyinput, and see if GTA processes them. Link to comment Share on other sites More sharing options...
NomeSkavinski Posted March 8, 2013 Author Share Posted March 8, 2013 Thanks for all the replies, really appreciate everyone's input. @nixolas1, that's interesting to hear as i tried different timing (however not 0) and various methods including sendKey and no response but Spy++ registers that the messages are getting through. Im still unsure at the structure of my lparam and every person seems to create it differently, so to check if mine is fully correct is difficult so, so my money is on that personally. @pedro2555, C++ would be a better option as it does operate at a lower level than c#, ive never tried the script hook with c++. I'm guessing its all the same but just include the script hook headers from its dll. So far i have this for my virtual key method: public void SendVKey(System.Windows.Forms.Keys key, bool extended = false) { // Get key scancode in hex int scanCode = MapVirtualKey((int)key, MAPVK_VK_TO_VSC); int wParam = (int)key; int lParam = (0x00000001 | (scanCode << 16)); if (extended) { lParam = lParam | 0x01000000; } if (PostMessage(proc.MainWindowHandle, WM_KEYDOWN, (IntPtr)wParam, (IntPtr)lParam)) Game.Console.Print("Posted WM_KEYDOWN"); Wait(1); lParam = lParam | 1 << 30 | 1 << 31; if (PostMessage(proc.MainWindowHandle, WM_KEYUP, (IntPtr)wParam, (IntPtr)lParam)) Game.Console.Print("Posted WM_KEYUP"); //System.Windows.Forms.SendKeys.SendWait("b"); } I'l try changing wait(1) to wait(0), and double check my bit shifting. Im also trying SendInput, as mentioned by pedro2555, as that actually put the data into teh keyboard stream rather than the msg stream. Nevertheless il shall try all these idea, will take me some time as ive just been offered some work so ill have to do that first lol. Thanks again guys! Link to comment Share on other sites More sharing options...
NomeSkavinski Posted March 10, 2013 Author Share Posted March 10, 2013 So far ive put all of my test code into a console app to test the input with Notepad. System.Windows.Forms.SendKeys works fine, so does the SendInput method. However my SendVKey doesnt put any input in. Nevertheless, when i tried SendInput with GTA 4 i sill got no response except when i used: SendKeyDown(KeyCode.ALT);SendKeyPress(KeyCode.F4);SendKeyUp(KeyCode.ALT); And it quit the game, so its receiving and processing the commands. Joy2Key on the other hand yields the same results, so there may be something within GTA that handles input in a differnet manor. Never mind ill just keep dabbling. Link to comment Share on other sites More sharing options...
NomeSkavinski Posted March 10, 2013 Author Share Posted March 10, 2013 (edited) SUCCESS!!! Dumbass here forgot two things: 1) The hardware scan code, i wasnt mapping form V key properly 2) I needed to Send the key down press, loop, then send the key up press in order for the message to actually be processed by GTA Thanks for all your help guys! Now i can get mods made for the keyboard working on the pad now, *sigh of releif*. Edited March 10, 2013 by NomeSkavinski Link to comment Share on other sites More sharing options...
pedro2555 Posted March 10, 2013 Share Posted March 10, 2013 SUCCESS!!! Dumbass here forgot two things: 1) The hardware scan code, i wasnt mapping form V key properly 2) I needed to Send the key down press, loop, then send the key up press in order for the message to actually be processed by GTA Thanks for all your help guys! Now i can get mods made for the keyboard working on the pad now, *sigh of releif*. Can you post the source code ? It sounds very useful. I'm going to update this post, I have test it out and removed some of the many bugs. It is possible to assign XBox 360 Controller button presses to void methods just like this in C#: using System;using System.Windows.Forms;using XInputDotNet;namespace XInputDotNetTest{ public partial class mainForm : Form { public mainForm() { InitializeComponent(); XboxController.LoadController(); XboxController.BindButton(XboxController.Buttons.buttonX, Print); } private void Print() { Console.WriteLine("Button X pressed"); } }} Hope it helps you guys. Link to comment Share on other sites More sharing options...
NomeSkavinski Posted March 10, 2013 Author Share Posted March 10, 2013 SUCCESS!!! Dumbass here forgot two things: 1) The hardware scan code, i wasnt mapping form V key properly 2) I needed to Send the key down press, loop, then send the key up press in order for the message to actually be processed by GTA Thanks for all your help guys! Now i can get mods made for the keyboard working on the pad now, *sigh of releif*. Can you post the source code ? It sounds very useful. I'm going to update this post, I have test it out and removed some of the many bugs. It is possible to assign XBox 360 Controller button presses to void methods just like this in C#: using System;using System.Windows.Forms;using XInputDotNet;namespace XInputDotNetTest{ public partial class mainForm : Form { public mainForm() { InitializeComponent(); XboxController.LoadController(); XboxController.BindButton(XboxController.Buttons.buttonX, Print); } private void Print() { Console.WriteLine("Button X pressed"); } }} Hope it helps you guys. Yeah ill post the source up soon, and yes you can bind XBox360 buttons to methods. I use a Dictionary with an array of buttons as the key and a delegate as the value. Then all you have to do is loop each Key in the dictionary and confirm all buttons are pressed then call the appropriate delegate. This also allows you to switch between Keyboard control and Pad control without the need to additional methods, that's how i do most of my mods (my RampSpawner v0.9 does this very well). I will post the source of this up with (hopefully) an understandable example. My classes are still unfinished but they do the job. Link to comment Share on other sites More sharing options...
NomeSkavinski Posted March 10, 2013 Author Share Posted March 10, 2013 (edited) @pedro2555 XBox Pad Demo. I'm not 100% this is what you are looking for but i hope it helps you. http://www.filehosting.org/file/details/42.../Pad%20Demo.zip Copy the contents of 'scripts' over to the scripts folder of GTA4 or EFLC. Make sure your pad is connected to Port One. (PS3 pad emulated to xbox360 works fine to) Press A to print text to console. Press B, Y, LB, LS (LeftStickButton) to altered text to to console. These buttons can be changed in XBOXPadDemo.ini - Look in 'ControllerParser.cs' at the 'StringToXboxButton' method, in there you will find the valid strings to use. Compiling the source: Ensure you have XNA 4.0 to build the source code. Ensure the Folder 'XBOXPad is in the directory where the 'bin' folder is with the scripthookdll You will notice in the source that there is a USING_XBOX_PAD symbol, this can be removed in the project properties under build. This allows an xboxpad/keyboard version or just a keyboard version, Just remember to remove the reference to XNA if you do build a keyboard only version. Let me know if there are any issues. As for the Virtual keyPress: namespace NomeScripts{ public class SimulateKeyPress : Script { X360Pad gamePad; [DllImport("user32.dll")] internal static extern uint MapVirtualKey(int uCode, int uMapType); [DllImport("user32.dll", SetLastError = true)] private static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputStructure); const int KEYEVENTF_EXTENDEDKEY = 0x0001; const int KEYEVENTF_KEYUP = 0x0002; const int KEYEVENTF_SCANCODE = 0x0008; const int KEYEVENTF_UNICODE = 0x0004; const int MAPVK_VK_TO_VSC = 0; enum keyStateTest { keyNothing, KeyDown, KeyUp } keyStateTest keyDown = keyStateTest.keyNothing; public SimulateKeyPress() { Interval = 100; gamePad = new X360Pad(1); this.Tick += new EventHandler(this.Input_Tick); } private void Input_Tick(object sender, EventArgs e) { gamePad.UpdateInput(); if (gamePad.CurrentState.IsButtonDown(Buttons.A)) { keyDown = keyStateTest.KeyDown; } else if (keyDown == keyStateTest.KeyDown) { keyDown = keyStateTest.KeyUp; } if (keyDown == keyStateTest.KeyDown) { SendKeyDown(KeyCode.KEY_W); } else if (keyDown == keyStateTest.KeyUp) { SendKeyUp(KeyCode.KEY_W); keyDown = keyStateTest.keyNothing; } } public static void SendKeyUp(KeyCode keyCode) { uint scanCode = MapVirtualKey((int)keyCode, MAPVK_VK_TO_VSC); INPUT input = new INPUT { Type = 1 }; input.Data.Keyboard = new KEYBDINPUT(); input.Data.Keyboard.Vk = (ushort)keyCode; input.Data.Keyboard.Scan = (ushort)scanCode; input.Data.Keyboard.Flags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP; input.Data.Keyboard.Time = 0; input.Data.Keyboard.ExtraInfo = IntPtr.Zero; INPUT[] inputs = new INPUT[] { input }; if (SendInput(1, inputs, Marshal.SizeOf(typeof(INPUT))) == 0) throw new Exception(); } /// <summary> /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx /// </summary> [structLayout(LayoutKind.Sequential)] internal struct INPUT { public uint Type; public MOUSEKEYBDHARDWAREINPUT Data; } /// <summary> /// http://social.msdn.microsoft.com/Forums/en/csharplanguage/thread/f0e82d6e-4999-4d22-b3d3-32b25f61fb2a /// </summary> [structLayout(LayoutKind.Explicit)] internal struct MOUSEKEYBDHARDWAREINPUT { [FieldOffset(0)] public HARDWAREINPUT Hardware; [FieldOffset(0)] public KEYBDINPUT Keyboard; [FieldOffset(0)] public MOUSEINPUT Mouse; } /// <summary> /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx /// </summary> [structLayout(LayoutKind.Sequential)] internal struct HARDWAREINPUT { public uint Msg; public ushort ParamL; public ushort ParamH; } /// <summary> /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx /// </summary> [structLayout(LayoutKind.Sequential)] internal struct KEYBDINPUT { public ushort Vk; public ushort Scan; public uint Flags; public uint Time; public IntPtr ExtraInfo; } /// <summary> /// http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/2abc6be8-c593-4686-93d2-89785232dacd /// </summary> [structLayout(LayoutKind.Sequential)] internal struct MOUSEINPUT { public int X; public int Y; public uint MouseData; public uint Flags; public uint Time; public IntPtr ExtraInfo; } }} Get the VK_keys from the link you gave me before: http://stackoverflow.com/questions/1276116...t-in-user32-dll I still have abit to finish on that code before i release the script, but i hope you can see how im using it. I hope it is useful for you. If anyone else is helped or find this useful, let me know. Or if you have any ideas for this. Edited March 10, 2013 by NomeSkavinski Link to comment Share on other sites More sharing options...
nixolas1 Posted March 10, 2013 Share Posted March 10, 2013 (edited) hey ho, a quick help on xbox/controller keys for GTA IV: to get button pressed, do if (IsButtonPressed(0, 7)){} //accelerate button else if if (IsButtonPressed(0, 5){} //deaccelerate button etc, i dunno what numbers to use to get the key pressed, but you can loop through many keys, and print one if it pressed, like: while(i<100){ if(isbuttonpressed(0,i){ printf(i); Wait(500); } i++; } i=0 Edited March 10, 2013 by nixolas1 Link to comment Share on other sites More sharing options...
NomeSkavinski Posted March 11, 2013 Author Share Posted March 11, 2013 hey ho, a quick help on xbox/controller keys for GTA IV:to get button pressed, do if (IsButtonPressed(0, 7)){} //accelerate button else if if (IsButtonPressed(0, 5){} //deaccelerate button etc, i dunno what numbers to use to get the key pressed, but you can loop through many keys, and print one if it pressed, like: while(i<100){ if(isbuttonpressed(0,i){ printf(i); Wait(500); } i++; } i=0 Thanks for your help, but i have the virtual keys working now. And the XBox stuff is easy to set up had that sorted a long time ago. Much appreciated though. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now