0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ゲームパッド入力変換用ブリッジ

Last updated at Posted at 2021-04-26
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Runtime.InteropServices;
using System.Text.Json;
using Microsoft.Web.WebView2.WinForms;

//thx
//https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-input
//https://qiita.com/kob58im/items/5a9d909377272d74eefd
//https://www.it-swarm-ja.com/ja/c%23/user32dll%e3%81%aesendinput%e3%82%92%e4%bb%8b%e3%81%97%e3%81%a6%e3%82%ad%e3%83%bc%e3%82%92%e9%80%81%e4%bf%a1%e3%81%99%e3%82%8b/1068919389/

namespace Gamepad
{
	public class InputStructures {

		[DllImport("user32.dll", SetLastError = true)]
		public extern static int
			SendInput(int length, ref InputEvent events, int size);

		[DllImport("user32.dll", EntryPoint = "MapVirtualKeyA")]
		public extern static int MapVirtualKey(int wCode, int wMapType);

		public const int MOUSEEVENTF_MOVE       = 0x01;
		public const int MOUSEEVENTF_LEFTDOWN   = 0x02;
		public const int MOUSEEVENTF_LEFTUP     = 0x04;
		public const int MOUSEEVENTF_RIGHTDOWN  = 0x08;
		public const int MOUSEEVENTF_RIGHTUP    = 0x10;
		public const int MOUSEEVENTF_MIDDLEDOWN = 0x20;
		public const int MOUSEEVENTF_MIDDLEUP   = 0x40;

		public const int KEYEVENTF_KEYUP        = 0x02;
		public const int MAPVK_VK_TO_VSC 		= 0;
		
		[StructLayout(LayoutKind.Sequential)]
		public struct InputEvent{
			public int Type;
			public InputUnion Data;
		}

		[StructLayout(LayoutKind.Explicit)]
		public struct InputUnion{
			[FieldOffset(0)] public MouseInput Mouse;
			[FieldOffset(0)] public KeyboardInput Keyboard;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct MouseInput{
			public int X;
			public int Y;
			public int MouseData;
			public int Flags;
			public int Time;
			public IntPtr ExtraInfo;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct KeyboardInput{
			public short VirtualKey;
			public short ScanCode;
			public int Flags;
			public int Time;
			public IntPtr ExtraInfo;
		}
	}

	[ComVisible(true)]
	public class Bridge : InputStructures {
		
		public class ControllerEvent{
			public string type	{ get; set; }
			public string key	{ get; set; }
			public int button	{ get; set; }
			public float x		{ get; set; }
			public float y		{ get; set; }
		}

		public void dispatch(string s){
			var e = JsonSerializer.Deserialize<ControllerEvent>(s);
			switch(e.type){
				case "mousemove":   SendMouseMove(e);   break;
				case "mousedown":   SendMouse(e);       break;
				case "mouseup":     SendMouse(e);       break;
				case "keydown":     SendKeyboard(e);    break;
				case "keyup":       SendKeyboard(e);    break;
			}
		}
		
		static readonly Dictionary<string,object>
			flag = new Dictionary<string,object>(){
				{"keydown",     0},
				{"keyup",       KEYEVENTF_KEYUP},
				{"mousemove",   MOUSEEVENTF_MOVE},
				{"mousedown",   new []{
					MOUSEEVENTF_LEFTDOWN,
					MOUSEEVENTF_MIDDLEDOWN,
					MOUSEEVENTF_RIGHTDOWN,
				}},
				{"mouseup",     new []{
					MOUSEEVENTF_LEFTUP,
					MOUSEEVENTF_MIDDLEUP,
					MOUSEEVENTF_RIGHTUP,
				}}
			};
		
		static void SendMouseMove(ControllerEvent e){
			var v = new InputEvent(){Type = 0};
			v.Data.Mouse    = new MouseInput(){
				Flags       = (int)flag[e.type],
				X           = (int)Math.Round(e.x),
				Y           = (int)Math.Round(e.y),
			};
			SendInput(1, ref v, Marshal.SizeOf(v));
		}
		
		static void SendMouse(ControllerEvent e){
			var v = new InputEvent(){Type = 0};
			v.Data.Mouse    = new MouseInput(){
				Flags       = (int)(flag[e.type] as int[])[e.button]
			};
			SendInput(1, ref v, Marshal.SizeOf(v));
		}
		
		static void SendKeyboard(ControllerEvent e){
			if (Keys.TryParse(e.key, out Keys k)){
				var v = new InputEvent(){Type = 1};
				v.Data.Keyboard = new KeyboardInput(){
					VirtualKey  = (short)k,
					ScanCode    = (short)MapVirtualKey((int)k,MAPVK_VK_TO_VSC),
					Flags       = (int)flag[e.type],
				};
				SendInput(1, ref v, Marshal.SizeOf(v));
			}
		}
	}
	
	public class Browser : Form {

		public Browser(string html){
			ClientSize = new System.Drawing.Size(600,400);
			Text = "Gamepad";
			var v = new WebView2(){
				Source  = new Uri(GetPath()+"\\"+html),
				Size    = ClientSize,
			};
			v.NavigationCompleted += (s,e) => 
				v.CoreWebView2.AddHostObjectToScript("bridge",new Bridge());
			SizeChanged += (s,e) => v.Size = ClientSize;
			Controls.Add(v);
		}

		private static string GetPath(){
			var p = System.Diagnostics.Process.GetCurrentProcess();
			return System.IO.Path.GetDirectoryName(p.MainModule.FileName);
		}
	}

	static class Program
	{
		[STAThread]
		static void Main()
		{
			Application.SetHighDpiMode(HighDpiMode.SystemAware);
			Application.EnableVisualStyles();
			Application.SetCompatibleTextRenderingDefault(false);
			Application.Run(new Browser("Gamepad.html"));
		}
	}
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?