I can explain it if people want.
Go on.
Cool. Wasn't sure if anyone would care or not, ha.
Mostly, the functionality is similar to AutoHotKey. What we are doing is detecting keyboard presses from the X-Arcade (same as a keyboard key press) and re-mapping the keys to other Keyboard Inputs along with mouse inputs as well.
I create a global keyboard hook that listens for any key events, and I manually map my keys to the keys that Gauntlet expects. A few limitations though, I don't think you could map 'W' to 'S' and then 'S' to 'D'. W would then fire S->D. So you'll have to watch out for that.
If you scroll through the code with me we can discuss what is happening.
[DllImport("user32.dll")]
static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData,
int dwExtraInfo);
http://www.pinvoke.net/default.aspx/user32.mouse_eventpInvoke is a cool resource for pretty much everything used here. First up mouse_event.
When I use this, I fire off the right and left clicks, which mouse_events takes as its dwFlag value. I also give the mouses current X and Y value for its x and y.
const uint RIGHTDOWN = 0x0008;
const uint RIGHTUP = 0x0010;
const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
const uint MOUSEEVENTF_LEFTUP = 0x0004;
mouse_event(MOUSEEVENTF_LEFTDOWN, (uint)Cursor.Position.X, (uint)Cursor.Position.Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, (uint)Cursor.Position.X, (uint)Cursor.Position.Y, 0, 0);
In the code snippet above, you have the events that happen with each button (up,down). Then you call mouse_event. This basically left/right clicks.
Next up is the keyhook
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
Used along with this code
private static LowLevelKeyboardProc hookProc2 = HookCallback2;
private static IntPtr hookId = IntPtr.Zero;
public IntPtr moduleHandle;
private static IntPtr SetHook(LowLevelKeyboardProc hookProc, IntPtr moduleHandle)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, moduleHandle, 0);
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
And then we use the code
moduleHandle = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
hookId = SetHook(hookProc2, moduleHandle);
So we have a hook for our key presses, the code that launches is the function hookProc2
So in the hookProc2 function we either have a keyUp or keyDown event
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
...
}
//ALSO
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
..
}
This is how you send a KeyDown. First you detect the keystroke you want to alter, in this case an F key
if (((System.Windows.Forms.Keys)vkCode).ToString() == "F5") //F
{
INPUT[] inputs = new INPUT[] {
INPUT.VirtualKeyDown((ushort)0x21),
};
returnMe = 1;
SendInput(inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
}
You have an array of inputs you can technically send off more than 1 keystroke, I only do 1 for 1. I have a flag returnMe so that later I can tell it to not fire the original key event of F5, because it launched my keyEvent of 0x21.
0x21 is a keycode, theres a list of all the keycodes here:
http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.htmlTo do a keyUp event, you want to do VirtualKeyUp(0x21) instead of virtualKeyDown above.
In my down events, I fire off right and left downclicks
if (((System.Windows.Forms.Keys)vkCode).ToString() == "F12") //spell
{
const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
const uint MOUSEEVENTF_LEFTUP = 0x0004;
mouse_event(MOUSEEVENTF_LEFTDOWN, (uint)Cursor.Position.X, (uint)Cursor.Position.Y, 0, 0);
//mouse_event(MOUSEEVENTF_LEFTUP, (uint)Cursor.Position.X, (uint)Cursor.Position.Y, 0, 0);
}
if (((System.Windows.Forms.Keys)vkCode).ToString() == "F8") //ligghtning
{
const uint RIGHTDOWN = 0x0008;
const uint RIGHTUP = 0x0010;
mouse_event(RIGHTDOWN, (uint)Cursor.Position.X, (uint)Cursor.Position.Y, 0, 0);
// mouse_event(RIGHTUP, (uint)Cursor.Position.X, (uint)Cursor.Position.Y, 0, 0);
}
You can see in the code the variation the Up code has, its virtually the same, just a different event flag.
Other than that its all just map key1->key2 or key1->mouse1
Here I detect if a key press is already in place
It's the left mouse button
Keys myKey3 = new Keys();
myKey3 = Keys.LButton;
if (!IsKeyDown(myKey3))
{
...
}
Where it takes your key you made, and runs it through this
private static KeyStates GetKeyState(Keys key)
{
KeyStates state = KeyStates.None;
short retVal = GetKeyState((int)key);
//If the high-order bit is 1, the key is down
//otherwise, it is up.
if ((retVal & 0x8000) == 0x8000)
state |= KeyStates.Down;
//If the low-order bit is 1, the key is toggled.
if ((retVal & 1) == 1)
state |= KeyStates.Toggled;
return state;
}
public static bool IsKeyDown(Keys key)
{
return KeyStates.Down == (GetKeyState(key) & KeyStates.Down);
}
true if its down, false if it isn't. So if your not firing a spell its ok to change your position.
When you press one of the 4 directionals, and it checks if its diagnol too, you move the mouse position to move your characters pointing direction.
My mouse coordinates are manually added, you could do a variable so that all you have to do is type your resolution once
int screenWidth = 1440;
int screenHeight = 0;// 900;
Win32.POINT p = new Win32.POINT();
p.x = Convert.ToInt16(screenWidth);
p.y = Convert.ToInt16(screenHeight);
//Win32.ClientToScreen(moduleHandle, ref p);
Win32.SetCursorPos(p.x, p.y);
Basically moves the mouse position to 0 (out of 900) for the height, and 1440 for the width (my monitor was 1440x900 resolution). Which is top right corner of the screen if I remember correctly.
I think thats the gist of it. On key press, don't fire original key press and send a different keystroke instead. Sometimes you move the mouse too. Sometimes you determine the keystate of other keys while firing off other key events.