Input.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. using Microsoft.Xna.Framework;
  2. using Microsoft.Xna.Framework.Input;
  3. using System;
  4. using System.Collections.Generic;
  5. namespace FF8
  6. {
  7. public enum Buttons
  8. {
  9. None, Up, Down, Left, Right, Okay, Cancel, Exit, Switch, Menu, Back, Start, X, Y, B, A, L1, L2, L3, R1, R2, R3, Select, LeftStickX, LeftStickY, RightStickX, RightStickY, MouseX, MouseY, MouseXjoy, MouseYjoy, MouseLeft, MouseMiddle, MouseRight, Mouse4, Mouse5, MouseWheelup, MouseWheeldown,
  10. Triangle = Y, Square = X, Circle = B, Cross = A
  11. }
  12. [Flags]
  13. public enum Button_Flags : ushort
  14. {
  15. Up = 0x10,
  16. Right = 0x20,
  17. Down = 0x40,
  18. Left = 0x80,
  19. L2 = 0x100,
  20. R2 = 0x200,
  21. L1 = 0x400,
  22. R1 = 0x800,
  23. Triangle = 0x1000,
  24. Circle = 0x2000,
  25. Cross = 0x4000,
  26. Square = 0x8000
  27. }
  28. public class Input
  29. {
  30. public static Dictionary<Button_Flags, Buttons> Convert_Button { get; private set; }
  31. //store current input states;
  32. private static GamePadState m_gp_state = new GamePadState();
  33. private static KeyboardState m_kb_state = new KeyboardState();
  34. private static MouseState m_m_state = new MouseState();
  35. //properties to assign current input states and back up last input states on the fly.
  36. protected static GamePadState CurrentGPState { get => m_gp_state; set { LastGPState = m_gp_state; m_gp_state = value; } }
  37. protected static KeyboardState CurrentKBState { get => m_kb_state; set { LastKBState = m_kb_state; m_kb_state = value; } }
  38. protected static MouseState CurrentMState { get => m_m_state; set { LastMState = m_m_state; m_m_state = value; } }
  39. //last states
  40. protected static GamePadState LastGPState { get; private set; } = new GamePadState();
  41. protected static KeyboardState LastKBState { get; private set; } = new KeyboardState();
  42. protected static MouseState LastMState { get; private set; }
  43. private static bool bLimitInput;
  44. private static int msDelay = 0;
  45. private static readonly int msDelayLimit = 100;
  46. public static bool GetInputDelayed(Keys key)
  47. {
  48. //if (bLimitInput)
  49. // bLimitInput = (msDelay += Memory.gameTime.ElapsedGameTime.Milliseconds) < msDelayLimit;
  50. if (Keyboard.GetState().IsKeyDown(key) && !bLimitInput)
  51. {
  52. ResetInputLimit();
  53. return true;
  54. }
  55. return false;
  56. }
  57. public static void Init()
  58. {
  59. Convert_Button = new Dictionary<Button_Flags, Buttons>()
  60. {
  61. //Buttons is
  62. //finisher = 0x0001
  63. //up = 0x0010
  64. //-> = 0x0020
  65. //do = 0x0040
  66. //< - = 0x0080
  67. //L2 = 0x0100
  68. //R2 = 0x0200
  69. //L1 = 0x0400
  70. //R1 = 0x0800
  71. // /\ = 0x1000
  72. //O = 0x2000
  73. //X = 0x4000
  74. //| _ |= 0x8000
  75. //None = 0xFFFF
  76. {Button_Flags.Up,Buttons.Up},
  77. {Button_Flags.Right,Buttons.Right },
  78. {Button_Flags.Down,Buttons.Down },
  79. {Button_Flags.Left,Buttons.Left },
  80. {Button_Flags.L2,Buttons.L2 },
  81. {Button_Flags.R2,Buttons.R2 },
  82. {Button_Flags.L1,Buttons.L1 },
  83. {Button_Flags.R1,Buttons.R1 },
  84. {Button_Flags.Triangle,Buttons.Triangle},
  85. {Button_Flags.Circle,Buttons.Circle },
  86. {Button_Flags.Cross,Buttons.Cross },
  87. {Button_Flags.Square,Buttons.Square }
  88. };
  89. Update();
  90. }
  91. public static void Update()
  92. {
  93. CurrentGPState = GamePad.GetState(PlayerIndex.One, GamePadDeadZone.Circular);
  94. CurrentKBState = Keyboard.GetState();
  95. CurrentMState = Mouse.GetState();
  96. LockMouse();
  97. CheckInputLimit();
  98. }
  99. private static void CheckInputLimit()
  100. {
  101. if (bLimitInput)
  102. {
  103. bLimitInput = (msDelay += Memory.gameTime.ElapsedGameTime.Milliseconds) < msDelayLimit;
  104. }
  105. }
  106. public static void ResetInputLimit()
  107. {
  108. msDelay = 0;
  109. bLimitInput = true;
  110. }
  111. private static bool IsPressed(Keys k, bool dblinput = false)
  112. {
  113. //This function checks if the key on KB is pressed
  114. //if dblinput is false it makes sure the key wasn't pressed last time.
  115. bool boolRT = CurrentKBState.IsKeyDown(k);
  116. boolRT = !dblinput ? boolRT && LastKBState.IsKeyUp(k) : boolRT && !bLimitInput;
  117. return boolRT;
  118. }
  119. private static bool IsPressed(Buttons b, bool dblinput = false)
  120. {
  121. //This function checks if the button on controller is pressed
  122. //if dblinput is false it makes sure the button wasn't pressed last time.
  123. bool boolRT = false;
  124. if (CurrentGPState.IsConnected)
  125. {
  126. switch (b)
  127. {
  128. case Buttons.Up:
  129. boolRT = CurrentGPState.DPad.Up == ButtonState.Pressed;
  130. break;
  131. case Buttons.Down:
  132. boolRT = CurrentGPState.DPad.Down == ButtonState.Pressed;
  133. break;
  134. case Buttons.Left:
  135. boolRT = CurrentGPState.DPad.Left == ButtonState.Pressed;
  136. break;
  137. case Buttons.Right:
  138. boolRT = CurrentGPState.DPad.Right == ButtonState.Pressed;
  139. break;
  140. case Buttons.B:
  141. boolRT = CurrentGPState.Buttons.B == ButtonState.Pressed;
  142. break;
  143. case Buttons.A:
  144. boolRT = CurrentGPState.Buttons.A == ButtonState.Pressed;
  145. break;
  146. case Buttons.Y:
  147. boolRT = CurrentGPState.Buttons.Y == ButtonState.Pressed;
  148. break;
  149. case Buttons.X:
  150. boolRT = CurrentGPState.Buttons.X == ButtonState.Pressed;
  151. break;
  152. case Buttons.L1:
  153. boolRT = CurrentGPState.Buttons.LeftShoulder == ButtonState.Pressed;
  154. break;
  155. case Buttons.L2:
  156. case Buttons.R2:
  157. boolRT = Analog(b) >= 0.25f; // treating the trigger like a button ignoring .25
  158. break;
  159. case Buttons.L3:
  160. boolRT = CurrentGPState.Buttons.LeftStick == ButtonState.Pressed;
  161. break;
  162. case Buttons.R1:
  163. boolRT = CurrentGPState.Buttons.RightShoulder == ButtonState.Pressed;
  164. break;
  165. case Buttons.R3:
  166. boolRT = CurrentGPState.Buttons.RightStick == ButtonState.Pressed;
  167. break;
  168. case Buttons.Start:
  169. boolRT = CurrentGPState.Buttons.Start == ButtonState.Pressed;
  170. break;
  171. case Buttons.Back:
  172. boolRT = CurrentGPState.Buttons.Back == ButtonState.Pressed;
  173. break;
  174. // this would be used as a test to see if stick is currently used. not ment to
  175. // control anything.
  176. case Buttons.LeftStickX:
  177. case Buttons.LeftStickY:
  178. case Buttons.RightStickX:
  179. case Buttons.RightStickY:
  180. boolRT = Analog(b) != 0.0f;
  181. break;
  182. }
  183. if (Memory.IsActive)
  184. {
  185. switch (b)
  186. {
  187. case Buttons.MouseXjoy:
  188. case Buttons.MouseYjoy:
  189. boolRT = Analog(b) != 0.0f;
  190. break;
  191. case Buttons.MouseX:
  192. case Buttons.MouseY:
  193. boolRT = Analog(b) != Analog(b, true);
  194. break;
  195. case Buttons.MouseLeft:
  196. boolRT = CurrentMState.LeftButton == ButtonState.Pressed;
  197. break;
  198. case Buttons.MouseMiddle:
  199. boolRT = CurrentMState.MiddleButton == ButtonState.Pressed;
  200. break;
  201. case Buttons.MouseRight:
  202. boolRT = CurrentMState.RightButton == ButtonState.Pressed;
  203. break;
  204. case Buttons.Mouse4:
  205. boolRT = CurrentMState.XButton1 == ButtonState.Pressed;
  206. break;
  207. case Buttons.Mouse5:
  208. boolRT = CurrentMState.XButton2 == ButtonState.Pressed;
  209. break;
  210. case Buttons.MouseWheelup:
  211. boolRT = CurrentMState.ScrollWheelValue > LastMState.ScrollWheelValue;
  212. break;
  213. case Buttons.MouseWheeldown:
  214. boolRT = CurrentMState.ScrollWheelValue < LastMState.ScrollWheelValue;
  215. break;
  216. }
  217. }
  218. if (!dblinput && boolRT)
  219. {
  220. switch (b)
  221. {
  222. case Buttons.Up:
  223. boolRT = LastGPState.DPad.Up == ButtonState.Released;
  224. break;
  225. case Buttons.Down:
  226. boolRT = LastGPState.DPad.Down == ButtonState.Released;
  227. break;
  228. case Buttons.Left:
  229. boolRT = LastGPState.DPad.Left == ButtonState.Released;
  230. break;
  231. case Buttons.Right:
  232. boolRT = LastGPState.DPad.Right == ButtonState.Released;
  233. break;
  234. case Buttons.B:
  235. boolRT = LastGPState.Buttons.B == ButtonState.Released;
  236. break;
  237. case Buttons.A:
  238. boolRT = LastGPState.Buttons.A == ButtonState.Released;
  239. break;
  240. case Buttons.Y:
  241. boolRT = LastGPState.Buttons.Y == ButtonState.Released;
  242. break;
  243. case Buttons.X:
  244. boolRT = LastGPState.Buttons.X == ButtonState.Released;
  245. break;
  246. case Buttons.L1:
  247. boolRT = LastGPState.Buttons.LeftShoulder == ButtonState.Released;
  248. break;
  249. case Buttons.L2:
  250. case Buttons.R2:
  251. boolRT = Analog(b, true) < 0.25f; // treating the trigger like a button ignoring .25
  252. break;
  253. case Buttons.L3:
  254. boolRT = LastGPState.Buttons.LeftStick == ButtonState.Released;
  255. break;
  256. case Buttons.R1:
  257. boolRT = LastGPState.Buttons.RightShoulder == ButtonState.Released;
  258. break;
  259. case Buttons.R3:
  260. boolRT = LastGPState.Buttons.RightStick == ButtonState.Released;
  261. break;
  262. case Buttons.Start:
  263. boolRT = LastGPState.Buttons.Start == ButtonState.Released;
  264. break;
  265. case Buttons.Back:
  266. boolRT = LastGPState.Buttons.Back == ButtonState.Released;
  267. break;
  268. // this would be used as a test to see if stick was released previously not
  269. // ment to control anything.
  270. case Buttons.LeftStickX:
  271. case Buttons.LeftStickY:
  272. case Buttons.RightStickX:
  273. case Buttons.RightStickY:
  274. boolRT = Analog(b, true) == 0.0f;
  275. break;
  276. }
  277. if (Memory.IsActive)
  278. {
  279. switch (b)
  280. {
  281. case Buttons.MouseXjoy:
  282. case Buttons.MouseYjoy:
  283. boolRT = Analog(b, true) == 0.0f;
  284. break;
  285. case Buttons.MouseLeft:
  286. boolRT = LastMState.LeftButton == ButtonState.Released;
  287. break;
  288. case Buttons.MouseMiddle:
  289. boolRT = LastMState.MiddleButton == ButtonState.Released;
  290. break;
  291. case Buttons.MouseRight:
  292. boolRT = LastMState.RightButton == ButtonState.Released;
  293. break;
  294. case Buttons.Mouse4:
  295. boolRT = LastMState.XButton1 == ButtonState.Released;
  296. break;
  297. case Buttons.Mouse5:
  298. boolRT = LastMState.XButton2 == ButtonState.Released;
  299. break;
  300. }
  301. }
  302. }
  303. else
  304. {
  305. boolRT = boolRT && !bLimitInput;
  306. }
  307. }
  308. if (boolRT)
  309. {
  310. }
  311. return boolRT;
  312. }
  313. public static float Distance(float speed) =>
  314. // no input throttle but still take the max speed * time; for non analog controls
  315. speed * Memory.gameTime.ElapsedGameTime.Milliseconds;
  316. public static float Distance(Buttons b, float speed, bool last = false) =>
  317. // (speed * stickvalue) * time = distance idea is you get the distance traveled per ms
  318. // value the speed being the max speed. your sticks value being the throttle.
  319. (speed * Analog(b, last)) * Memory.gameTime.ElapsedGameTime.Milliseconds;
  320. public static float Analog(Buttons b, bool last = false)
  321. {
  322. //get output from analog controls
  323. //mousexjoy and mouseyjoy attempt to convert mouse input to a joystick like input 1.0f to -1.0f
  324. float tmp = 0f;
  325. if (last)
  326. {
  327. switch (b)
  328. {
  329. case Buttons.LeftStickX:
  330. return LastGPState.ThumbSticks.Left.X;
  331. case Buttons.LeftStickY:
  332. return LastGPState.ThumbSticks.Left.Y;
  333. case Buttons.RightStickX:
  334. return LastGPState.ThumbSticks.Right.X;
  335. case Buttons.RightStickY:
  336. return LastGPState.ThumbSticks.Right.Y;
  337. case Buttons.L2:
  338. return LastGPState.Triggers.Left;
  339. case Buttons.R2:
  340. return LastGPState.Triggers.Right;
  341. }
  342. if (Memory.IsActive)
  343. {
  344. switch (b)
  345. {
  346. case Buttons.MouseX:
  347. return LastMState.X;
  348. case Buttons.MouseY:
  349. return LastMState.Y;
  350. case Buttons.MouseXjoy:
  351. tmp = (LastMState.X - Memory.graphics.GraphicsDevice.Viewport.Bounds.Width / 2) / (50f);
  352. return MathHelper.Clamp(tmp, -1f, 1f);
  353. case Buttons.MouseYjoy:
  354. tmp = (Memory.graphics.GraphicsDevice.Viewport.Bounds.Height / 2 - LastMState.Y) / (50f);
  355. return MathHelper.Clamp(tmp, -1f, 1f);
  356. }
  357. }
  358. }
  359. else
  360. {
  361. switch (b)
  362. {
  363. case Buttons.LeftStickX:
  364. return CurrentGPState.ThumbSticks.Left.X;
  365. case Buttons.LeftStickY:
  366. return CurrentGPState.ThumbSticks.Left.Y;
  367. case Buttons.RightStickX:
  368. return CurrentGPState.ThumbSticks.Right.X;
  369. case Buttons.RightStickY:
  370. return CurrentGPState.ThumbSticks.Right.Y;
  371. case Buttons.L2:
  372. return CurrentGPState.Triggers.Left;
  373. case Buttons.R2:
  374. return CurrentGPState.Triggers.Right;
  375. }
  376. if (Memory.IsActive)
  377. {
  378. switch (b)
  379. {
  380. case Buttons.MouseX:
  381. return LastMState.X;
  382. case Buttons.MouseY:
  383. return LastMState.Y;
  384. case Buttons.MouseXjoy:
  385. tmp = (CurrentMState.X - Memory.graphics.GraphicsDevice.Viewport.Bounds.Width / 2) / (50f);
  386. return MathHelper.Clamp(tmp, -1f, 1f);
  387. case Buttons.MouseYjoy:
  388. tmp = (Memory.graphics.GraphicsDevice.Viewport.Bounds.Height / 2 - CurrentMState.Y) / (50f);
  389. return MathHelper.Clamp(tmp, -1f, 1f);
  390. }
  391. }
  392. }
  393. return 0.0f;
  394. }
  395. public static MouseLockMode CurrentMode;
  396. public static bool OverrideLockMouse { get; set; } = false;
  397. public enum MouseLockMode
  398. {
  399. Center,
  400. Screen
  401. }
  402. public static void LockMouse()
  403. {
  404. if (Memory.IsActive && OverrideLockMouse) // check for focus to allow for tabbing out with out taking over mouse.
  405. {
  406. if (CurrentMode == MouseLockMode.Center) //center mouse in screen after grabbing state, release mouse if alt tabbed out.
  407. {
  408. Mouse.SetPosition(Memory.graphics.GraphicsDevice.Viewport.Bounds.Width / 2, Memory.graphics.GraphicsDevice.Viewport.Bounds.Height / 2);
  409. }
  410. else if (CurrentMode == MouseLockMode.Screen) //alt lock that clamps to viewport every frame. would be useful if using mouse to navigate menus and stuff.
  411. {
  412. //there is a better way to clamp as if you move mouse fast enough it will escape for a short time.
  413. Mouse.SetPosition(
  414. MathHelper.Clamp(CurrentMState.X, 0, Memory.graphics.GraphicsDevice.Viewport.Bounds.Width),
  415. MathHelper.Clamp(CurrentMState.Y, 0, Memory.graphics.GraphicsDevice.Viewport.Bounds.Height));
  416. }
  417. }
  418. }
  419. public static Point MouseLocation => new Point(CurrentMState.X, CurrentMState.Y);
  420. public static bool Button(Keys k, bool dblinput = false) => IsPressed(k, dblinput); // fail over to IsPressed
  421. public static bool Button(Buttons b, bool dblinput = false)
  422. {
  423. // To add support for controller I was extracting the boolean bits from the if
  424. // statements. Maybe it could be a scheme in future. When these are configureable. This
  425. // function mostly translates the function to the button(s) or key(s).
  426. switch (b)
  427. {
  428. case Buttons.Up:
  429. return (IsPressed(Keys.Up, true) || IsPressed(Buttons.MouseWheelup) || IsPressed(Keys.W, true) || (CurrentGPState.IsConnected && (IsPressed(b, true) || Analog(Buttons.LeftStickY) > 0.0f))) && !bLimitInput;
  430. case Buttons.Down:
  431. return (IsPressed(Keys.Down, true) || IsPressed(Buttons.MouseWheeldown) || IsPressed(Keys.S, true) || (CurrentGPState.IsConnected && (IsPressed(b, true) || Analog(Buttons.LeftStickY) < 0.0f))) && !bLimitInput;
  432. case Buttons.Left:
  433. return (IsPressed(Keys.Left, true) || IsPressed(Keys.A, true) || (CurrentGPState.IsConnected && (IsPressed(b, true) || Analog(Buttons.LeftStickX) < 0.0f))) && !bLimitInput;
  434. case Buttons.Right:
  435. return (IsPressed(Keys.Right, true) || IsPressed(Keys.D, true) || (CurrentGPState.IsConnected && (IsPressed(b, true) || Analog(Buttons.LeftStickX) > 0.0f))) && !bLimitInput;
  436. case Buttons.Okay:
  437. return IsPressed(Keys.Enter, dblinput) || IsPressed(Buttons.B, dblinput) || IsPressed(Buttons.MouseLeft);
  438. case Buttons.Cancel:
  439. return IsPressed(Keys.Back, dblinput) || IsPressed(Buttons.A, dblinput) || IsPressed(Buttons.MouseRight);
  440. case Buttons.Menu:
  441. return IsPressed(Keys.PageUp, dblinput) || IsPressed(Buttons.Y, dblinput);
  442. case Buttons.Switch:
  443. return IsPressed(Keys.PageDown, dblinput) || IsPressed(Buttons.X, dblinput);
  444. case Buttons.Start:
  445. return IsPressed(Keys.Home, dblinput) || IsPressed(Buttons.Start, dblinput);
  446. case Buttons.Select:
  447. return IsPressed(Keys.End, dblinput) || IsPressed(Buttons.Back, dblinput);
  448. case Buttons.Exit:
  449. return IsPressed(Keys.Escape, dblinput);
  450. default:
  451. return IsPressed(b, dblinput); // fail over to IsPressed if no custom input is avalible above
  452. }
  453. }
  454. }
  455. }