1943很经典的街机游戏
我突然想用鼠标来控制飞机可以吗?于是网上找了一下,没有找鼠标移动映射键盘的软件。
自己建了一个C#项目,加入别人写好的全局鼠标钩子。
很简单的代码,实现了获取全局鼠标坐标并做相应的操作:
using Gma.System.MouseKeyHook;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace GetMousePoint
{
public partial class Form1 : Form
{
[DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
public static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
private IKeyboardMouseEvents m_GlobalHook;
int x_tmp;
int y_tmp;
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
Subscribe();
}
public void Subscribe()
{
// Note: for the application hook, use the Hook.AppEvents() instead
m_GlobalHook = Hook.GlobalEvents();
m_GlobalHook.MouseMoveExt += M_GlobalHook_MouseMoveExt;
}
private void M_GlobalHook_MouseMoveExt(object sender, MouseEventExtArgs e)
{
label1.Text = e.X.ToString() + "," + e.Y.ToString();
if (e.X > x_tmp) {label2.Text = "→"; keybd_event(Keys.D, 0, 0, 0); }
if (e.X < x_tmp) {label2.Text = "←"; ; keybd_event(Keys.A, 0, 0, 0);}
if (e.Y < y_tmp) {label4.Text = "↑";; keybd_event(Keys.W, 0, 0, 0);}
if (e.Y > y_tmp) {label4.Text = "↓";; keybd_event(Keys.S, 0, 0, 0);}
x_tmp = e.X;
y_tmp = e.Y;
}
}
}
但FBA V2.4.0 版本的游戏模拟器油盐不进,对它发消息,它没有反应,SPY++看不到它的任何消息。今天晚上时间不够了,就研究到这里。
------2022.2.20------
仔细看了一下,是SPY++64位32位的问题,确认可以收到消息后,模拟键盘按键给FBA发了键盘消息。又出现了新问题,SPY++可以看到程序发给FBA的消息和实际的消息完全一样,但是FBA不能识别。
可能是因为FBA使用了DIRECTX INPUT,一般的模拟键盘消息对它无效,程序也尝试了线程挂接,只是没再进一步使用HOOK注入。
找到一个WINIO方法,据说可以对付DIRECTX INPUT不识别消息的顽症。
C#的例子程序写的很完整,但是WINIO32.DLL居然网上下载不到,文章地址:
一个C#写的模拟键盘输入的例子_lucky811的专栏-CSDN博客
那么,后面还需要找一个WIN10,VS2019环境下可以使用WINIO32.DLL的DEMO。
-------2022.2.25-----------
WINIO32.DLL这条路不通,在百度搜索 directx input 模拟键盘,在知乎上有个回答,还有一个是WIN10场景最新的场景。看来可行。
-------2022.2.26-----------
今天终于成功了,用右手控制鼠标控制了一下飞机,但是要达到极致体验,程序还需要调试一下,让鼠标的移动跟上飞机。比如:一个方向一个线程,因为程序只会傻填键盘缓冲区,四个方向都是单独线程控制才比较合理。
全部的C# 代码如下(鼠标中键工作,右键停止):
using Gma.System.MouseKeyHook;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace GetMousePoint
{
public partial class Form1 : Form
{
[DllImport("user32.dll")] static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")] static extern bool SetForegroundWindow(IntPtr hWnd);
//----------------------------------------------------------------------
[DllImport("user32 ")]
private static extern IntPtr EnumChildWindows(int hWndParent, EnumWindowsProc lpEnumFunc, int lParam);
public delegate bool EnumWindowsProc(int hWnd, int lParam);
[DllImport("user32.dll", EntryPoint = "GetClassName")]
public static extern int GetClassName(int hWnd, StringBuilder lpString, int nMaxCont);
[DllImport("User32.dll")]
static extern int GetWindowText(IntPtr handle, StringBuilder text, int MaxLen);
//------------------------------------------------------------------------
[DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
public static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
[DllImport("user32.dll")]
static extern byte MapVirtualKey(byte wCode, int wMap);
public static List<WinObject> ListWin = new List<WinObject>();
private IKeyboardMouseEvents m_GlobalHook;
int x_tmp;
int y_tmp;
int mouse_x = 0;
int mouse_y = 0;
bool IsOpen = false;
MouseEventExtArgs gv_e;
public Form1()
{
InitializeComponent();
//加载全局钩子
Subscribe();
Control.CheckForIllegalCrossThreadCalls = false;
Thread t11 = new Thread(new ThreadStart(Worker11));
t11.Start();
Thread t12 = new Thread(new ThreadStart(Worker12));
t12.Start();
Thread t13 = new Thread(new ThreadStart(Worker13));
t13.Start();
Thread t14 = new Thread(new ThreadStart(Worker14));
t14.Start();
Thread t2 = new Thread(new ThreadStart(Worker2));
t2.Start();
Thread t3 = new Thread(new ThreadStart(Worker3));
t3.Start();
}
public void Worker11()
{
while (true)
{
Thread.Sleep(5);
if (IsOpen)
{
if (mouse_y == -1) { MyKey(Keys.S); }
}
}
}
public void Worker12()
{
while (true)
{
Thread.Sleep(5);
if (IsOpen)
{
if (mouse_y == 1) { MyKey(Keys.W); }
}
}
}
public void Worker13()
{
while (true)
{
Thread.Sleep(5);
if (IsOpen)
{
if (mouse_x == 1) { MyKey(Keys.D); }
}
}
}
public void Worker14()
{
while (true)
{
Thread.Sleep(5);
if (IsOpen)
{
if (mouse_x == -1) { MyKey(Keys.A); }
}
}
}
public void Worker2()
{
while (true)
{
Thread.Sleep(100);
if (gv_e != null)
{
label1.Text = gv_e.X.ToString() + "," + gv_e.Y.ToString();
if (gv_e.X > x_tmp) { label2.Text = "→"; mouse_x = 1; }
if (gv_e.X == x_tmp) { label2.Text = "0"; mouse_x = 0; }
if (gv_e.X < x_tmp) { label2.Text = "←"; mouse_x = -1; }
x_tmp = gv_e.X;
}
}
}
public void Worker3()
{
while (true)
{
Thread.Sleep(100);
if (gv_e != null)
{
if (gv_e.Y < y_tmp) { label4.Text = "↑"; mouse_y = 1; }
if (gv_e.Y == y_tmp) { label4.Text = "0"; mouse_y = 0; }
if (gv_e.Y > y_tmp) { label4.Text = "↓"; mouse_y = -1; }
y_tmp = gv_e.Y;
}
}
}
public void Subscribe()
{
// Note: for the application hook, use the Hook.AppEvents() instead
m_GlobalHook = Hook.GlobalEvents();
m_GlobalHook.MouseMoveExt += M_GlobalHook_MouseMoveExt;
m_GlobalHook.MouseClick += M_GlobalHook_MouseClick;
}
private void M_GlobalHook_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle)
{
EnumChildWindows(0, new EnumWindowsProc(EnumWindowCallBack), 0);
if (ListWin.Count > 0) { label6.Text = "locked windows"; }
SetForegroundWindow(ListWin.FirstOrDefault().hand);
IsOpen = true;
label3.Text = "IsOpen: true";
};
if (e.Button == MouseButtons.Right)
{
IsOpen = false;
label3.Text = "IsOpen: false";
label6.Text = "UnLocked windows";
}
}
private void M_GlobalHook_MouseMoveExt(object sender, MouseEventExtArgs e)
{
gv_e = e;
}
private void MyKey(System.Windows.Forms.Keys x)
{
keybd_event(x, (byte)MapVirtualKey(Convert.ToByte(x), 0), 0, 0);
Thread.Sleep(5);
keybd_event(x, (byte)MapVirtualKey(Convert.ToByte(x), 0), 0x0002, 0);
}
public class WinObject
{
public bool isprocess { get; set; }
public IntPtr hand { get; set; }
public string ClassName { get; set; }
public string text { get; set; }
}
public static bool EnumWindowCallBack(int hWnd, int lParam)
{
try
{
WinObject one = new WinObject();
one.isprocess = false;
one.hand = (IntPtr)hWnd;
StringBuilder name = new StringBuilder(256);
GetClassName(hWnd, name, 256);
one.ClassName = name.ToString();
StringBuilder text = new StringBuilder(100);
GetWindowText((IntPtr)hWnd, text, 100);
one.text = text.ToString();
if (one.ClassName.Equals("FBA shuffle"))
{
ListWin.Add(one);
}
}
catch { }
return true;
}
}
}