AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
AxisController.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using UnityEngine;
5 using System;
6 
7 namespace HoloToolkit.Unity.InputModule
8 {
15  public class AxisController : MonoBehaviour
16  {
20  public enum AxisType
21  {
22  // Axis are double axis (XY) unless indicated as single axis (X only)
23  InputManagerAxis,
24 
25  KeyboardArrows,
26  KeyboardWASD,
27  KeyboardQE, // single axis
28  KeyboardIJKL,
29  KeyboardUO, // single axis
30  Keyboard8426,
31  Keyboard7193,
32  KeyboardPeriodComma, // single axis
33  KeyboardBrackets,
34  KeyBoardHomeEndPgUpPgDown,
35 
36  Mouse,
37  MouseScroll, // single axis
38 
39  None
40  }
41 
45  public enum AxisDestination
46  {
47  PositiveX,
48  NegativeX,
49  PositiveY,
50  NegativeY,
51  PositiveZ,
52  NegativeZ,
53  None
54  }
55 
56  public float SensitivityScale = 3.0f;
57 
58  [Tooltip("Use unscaled time. This is useful for games that have a pause mechanism or otherwise adjust the game timescale.")]
59  public bool UseUnscaledTime = true;
60 
61  public AxisType axisType = AxisType.Mouse;
63 
66 
67  public AxisDestination Axis0Destination = AxisDestination.PositiveX;
68  public AxisDestination Axis1Destination = AxisDestination.PositiveY;
69  public AxisDestination Axis2Destination = AxisDestination.None;
70 
71  private Vector3 lastMousePosition = Vector3.zero;
72 
73  private const float MouseSensitivity = 0.015f; // always affects the mouse sensitivity
74  private const float MouseUnlockedSensitivity = 0.1f; // affects the sensitivity when using the mouse buttons
75  private const float KeyboardSensitivity = 10.0f;
76  private const float InputManagerAxisSensitivity = 0.05f;
77 
78  private bool isMouseJumping = false;
79  private bool appHasFocus = true;
80  private bool usingMouse = false;
81 
82  private bool inputManagerAxesNeedApproval = true;
83  private bool inputManagerHorizontalAxisApproved = false;
84  private bool inputManagerVerticalAxisApproved = false;
85 
86  public bool AxisTypeIsKeyboard
87  {
88  get { return AxisType.KeyboardArrows <= axisType && axisType <= AxisType.KeyBoardHomeEndPgUpPgDown; }
89  }
90  public bool AxisTypeIsInputManagerAxis
91  {
92  get { return axisType == AxisType.InputManagerAxis; }
93  }
94  public bool AxisTypeIsMouse
95  {
96  get { return axisType == AxisType.Mouse; }
97  }
98  public bool AxisTypeIsMouseScroll
99  {
100  get { return axisType == AxisType.MouseScroll; }
101  }
102 
103  public void EnableAndCheck(bool value)
104  {
105  this.enabled = value;
106  if (value)
107  {
108  InputManagerAxisCheck();
109  }
110  }
111 
112  private void Awake()
113  {
114  // AxisController is for development only and should not exist--and certainly not be used--in
115  // any non-Editor scenario.
116 #if !UNITY_EDITOR
117  Destroy(this);
118 #else
119  // Workaround for Remote Desktop. Ctrl-mouse, Shift-mouse, and Alt-mouse don't work, so they should be avoided.
120  if (IsRunningUnderRemoteDesktop())
121  {
122  if (this.buttonType == ButtonController.ButtonType.Control)
123  {
124  this.buttonType = ButtonController.ButtonType.Left;
125  Debug.LogWarning("Running under Remote Desktop, so changed AxisContol method to Left mouse button");
126  }
127  if (this.buttonType == ButtonController.ButtonType.Alt)
128  {
129  this.buttonType = ButtonController.ButtonType.Right;
130  Debug.LogWarning("Running under Remote Desktop, so changed AxisContol method to Right mouse button");
131  }
132  if (this.buttonType == ButtonController.ButtonType.Shift)
133  {
134  this.buttonType = ButtonController.ButtonType.Middle;
135  Debug.LogWarning("Running under Remote Desktop, so changed AxisContol method to Middle mouse button");
136  }
137  }
138 
139  UnityEngine.Cursor.lockState = CursorLockMode.None;
140  UnityEngine.Cursor.visible = true;
141 #endif
142  }
143 
144  private static float InputCurve(float x)
145  {
146  // smoothing input curve, converts from [-1,1] to [-2,2]
147  return (Mathf.Sign(x) * (1.0f - Mathf.Cos(.5f * Mathf.PI * Mathf.Clamp(x, -1.0f, 1.0f))));
148  }
149 
153  public Vector3 GetDisplacementVector3()
154  {
155  Vector3 source = GetDisplacement();
156  Vector3 dest = Vector3.zero;
157  RemapAdditive(source, 0, ref dest, Axis0Destination);
158  RemapAdditive(source, 1, ref dest, Axis1Destination);
159  RemapAdditive(source, 2, ref dest, Axis2Destination);
160  return dest;
161  }
162 
166  public Vector2 GetDisplacementVector2()
167  {
168  Vector3 source = GetDisplacement();
169  Vector3 middle = Vector3.zero;
170  Vector2 dest = Vector2.zero;
171  RemapAdditive(source, 0, ref middle, Axis0Destination);
172  RemapAdditive(source, 1, ref middle, Axis1Destination);
173  dest[0] = middle[0];
174  dest[1] = middle[1];
175  return dest;
176  }
177 
181  public float GetDisplacementFloat()
182  {
183  Vector3 source = GetDisplacement();
184  Vector3 middle = Vector2.zero;
185  RemapAdditive(source, 0, ref middle, Axis0Destination);
186  return middle[0];
187  }
188 
189  private void RemapAdditive(Vector3 source, int sourceDim, ref Vector3 dest, AxisDestination destDim)
190  {
191  float inp = source[sourceDim];
192  if (destDim == AxisDestination.NegativeX || destDim == AxisDestination.NegativeY || destDim == AxisDestination.NegativeZ)
193  {
194  inp = -inp;
195  }
196  if (destDim == AxisDestination.PositiveX || destDim == AxisDestination.NegativeX)
197  {
198  dest[0] += inp;
199  }
200  else if (destDim == AxisDestination.PositiveY || destDim == AxisDestination.NegativeY)
201  {
202  dest[1] += inp;
203  }
204  else if (destDim == AxisDestination.PositiveZ || destDim == AxisDestination.NegativeZ)
205  {
206  dest[2] += inp;
207  }
208  }
209 
210  private Vector3 GetDisplacement()
211  {
212  Vector3 rot = Vector3.zero;
213 
214  // this check enables us to check the InputManagerAxes names when we are switching on the fly
215  if (!AxisTypeIsInputManagerAxis)
216  {
217  inputManagerAxesNeedApproval = true;
218  }
219 
220  // Now check to see what sort of input we have, and dispatch the appropriate LookTick routine
221  if (AxisTypeIsInputManagerAxis)
222  {
223  if (inputManagerAxesNeedApproval)
224  {
225  InputManagerAxisCheck();
226  }
227  if (ShouldControl())
228  {
229  rot = InputManagerAxisLookTick();
230  }
231  }
232  else if (AxisTypeIsKeyboard)
233  {
234  if (ShouldControl())
235  rot = KeyboardLookTick();
236  }
237  else if (AxisTypeIsMouseScroll)
238  {
239  if (ShouldControl())
240  rot.x += Input.GetAxis("Mouse ScrollWheel");
241  }
242  else if (AxisTypeIsMouse)
243  {
244  if (ShouldControl())
245  {
246  if (!this.usingMouse)
247  {
248  OnStartMouseLook();
249  this.usingMouse = true;
250  }
251  rot = MouseLookTick();
252  }
253  else
254  {
255  if (this.usingMouse)
256  {
257  OnEndMouseLook();
258  this.usingMouse = false;
259  }
260  }
261  }
262 
263  rot *= this.SensitivityScale;
264  return rot;
265  }
266 
267  private void OnStartMouseLook()
268  {
269  if (this.buttonType <= ButtonController.ButtonType.Middle)
270  {
271  // if mouse button is either left, right or middle
272  SetWantsMouseJumping(true);
273  }
274  else if (this.buttonType <= ButtonController.ButtonType.Focused)
275  {
276  // if mouse button is either control, shift or focused
277  UnityEngine.Cursor.lockState = CursorLockMode.Locked;
278  UnityEngine.Cursor.visible = false;
279  }
280 
281  // do nothing if (this.MouseLookButton == MouseButton.None)
282  }
283 
284  private void OnEndMouseLook()
285  {
286  if (this.buttonType <= ButtonController.ButtonType.Middle)
287  {
288  // if mouse button is either left, right or middle
289  SetWantsMouseJumping(false);
290  }
291  else if (this.buttonType <= ButtonController.ButtonType.Focused)
292  {
293  // if mouse button is either control, shift or focused
294  UnityEngine.Cursor.lockState = CursorLockMode.None;
295  UnityEngine.Cursor.visible = true;
296  }
297 
298  // do nothing if (this.MouseLookButton == MouseButton.None)
299  }
300 
301  private Vector3 MouseLookTick()
302  {
303  Vector3 rot = Vector3.zero;
304 
305  // Use frame-to-frame mouse delta in pixels to determine mouse rotation. The traditional
306  // GetAxis("Mouse X") method doesn't work under Remote Desktop.
307  Vector3 mousePositionDelta = Input.mousePosition - this.lastMousePosition;
308  this.lastMousePosition = Input.mousePosition;
309 
310  if (UnityEngine.Cursor.lockState == CursorLockMode.Locked)
311  {
312  mousePositionDelta.x = Input.GetAxis("Mouse X");
313  mousePositionDelta.y = Input.GetAxis("Mouse Y");
314  }
315  else
316  {
317  mousePositionDelta.x *= MouseUnlockedSensitivity;
318  mousePositionDelta.y *= MouseUnlockedSensitivity;
319  }
320 
321  rot.x += -InputCurve(mousePositionDelta.y) * MouseSensitivity;
322  rot.y += InputCurve(mousePositionDelta.x) * MouseSensitivity;
323  return rot;
324  }
325 
326  private float GetKeyDir(KeyCode neg, KeyCode pos)
327  {
328  return Input.GetKey(neg) ? -1.0f : Input.GetKey(pos) ? 1.0f : 0.0f;
329  }
330 
331  private float GetKeyDir(string neg, string pos)
332  {
333  return Input.GetKey(neg) ? -1.0f : Input.GetKey(pos) ? 1.0f : 0.0f;
334  }
335 
336  private void InputManagerAxisCheck()
337  {
338  inputManagerHorizontalAxisApproved = false;
339  inputManagerVerticalAxisApproved = false;
340 
341  {
342  inputManagerHorizontalAxisApproved = true;
343  try
344  {
345  Input.GetAxis(InputManagerHorizontalAxisName);
346  }
347  catch (Exception)
348  {
349  Debug.LogWarningFormat("Input Axis {0} is not setup. Use Edit -> Project Settings -> Input", InputManagerHorizontalAxisName);
350  inputManagerHorizontalAxisApproved = false;
351  }
352  }
353 
354  {
355  inputManagerVerticalAxisApproved = true;
356  try
357  {
358  Input.GetAxis(InputManagerVerticalAxisName);
359  }
360  catch (Exception)
361  {
362  Debug.LogWarningFormat("Input Axis {0} is not setup. Use Edit -> Project Settings -> Input", InputManagerVerticalAxisName);
363  inputManagerVerticalAxisApproved = false;
364  }
365  }
366  inputManagerAxesNeedApproval = false;
367  }
368 
369  private Vector3 InputManagerAxisLookTick()
370  {
371  Vector3 rot = Vector3.zero;
372  if (inputManagerHorizontalAxisApproved)
373  {
374  rot.x += InputManagerAxisSensitivity * InputCurve(Input.GetAxis(InputManagerHorizontalAxisName));
375  }
376  if (inputManagerVerticalAxisApproved)
377  {
378  rot.y += InputManagerAxisSensitivity * InputCurve(Input.GetAxis(InputManagerVerticalAxisName));
379  }
380  return rot;
381  }
382 
383  private Vector3 KeyboardLookTick()
384  {
385  float deltaTime = UseUnscaledTime
386  ? Time.unscaledDeltaTime
387  : Time.deltaTime;
388 
389  Vector3 rot = Vector3.zero;
390  if (axisType == AxisType.KeyboardArrows)
391  {
392  rot.x += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.LeftArrow, KeyCode.RightArrow));
393  rot.y += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.DownArrow, KeyCode.UpArrow));
394  }
395  else if (axisType == AxisType.KeyboardWASD)
396  {
397  rot.x += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.A, KeyCode.D));
398  rot.y += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.S, KeyCode.W));
399  }
400  else if (axisType == AxisType.KeyboardQE)
401  {
402  rot.x += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.Q, KeyCode.E));
403  }
404  else if (axisType == AxisType.KeyboardIJKL)
405  {
406  rot.x += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.J, KeyCode.L));
407  rot.y += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.K, KeyCode.I));
408  }
409  else if (axisType == AxisType.KeyboardUO)
410  {
411  rot.x += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.U, KeyCode.O));
412  }
413  else if (axisType == AxisType.Keyboard8426)
414  {
415  rot.x += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.Keypad4, KeyCode.Keypad6));
416  rot.y += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.Keypad2, KeyCode.Keypad8));
417  }
418  else if (axisType == AxisType.Keyboard7193)
419  {
420  rot.x += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.Keypad1, KeyCode.Keypad7));
421  rot.y += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.Keypad3, KeyCode.Keypad9));
422  }
423  else if (axisType == AxisType.KeyboardPeriodComma)
424  {
425  rot.x += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.Comma, KeyCode.Period));
426  }
427  else if (axisType == AxisType.KeyboardBrackets)
428  {
429  rot.x += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.LeftBracket, KeyCode.RightBracket));
430  }
431  else if (axisType == AxisType.KeyBoardHomeEndPgUpPgDown)
432  {
433  rot.x += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.End, KeyCode.Home));
434  rot.y += InputCurve(deltaTime * KeyboardSensitivity * GetKeyDir(KeyCode.PageDown, KeyCode.PageUp));
435  }
436  return rot;
437  }
438 
445  public bool ShouldControl()
446  {
447  if (!this.appHasFocus)
448  {
449  return false;
450  }
451  else if (this.buttonType == ButtonController.ButtonType.None)
452  {
453  return true;
454  }
455  else if (this.buttonType <= ButtonController.ButtonType.Middle)
456  {
457  return Input.GetMouseButton((int)this.buttonType);
458  }
459  else if (this.buttonType == ButtonController.ButtonType.Control)
460  {
461  return Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
462  }
463  else if (this.buttonType == ButtonController.ButtonType.Shift)
464  {
465  return Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
466  }
467  else if (this.buttonType == ButtonController.ButtonType.Alt)
468  {
469  return Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt);
470  }
471  else if (this.buttonType == ButtonController.ButtonType.Space)
472  {
473  return Input.GetKey(KeyCode.Space);
474  }
475  else if (this.buttonType == ButtonController.ButtonType.Return)
476  {
477  return Input.GetKey(KeyCode.Return);
478  }
479  else if (this.buttonType == ButtonController.ButtonType.Focused)
480  {
481  if (!this.usingMouse)
482  {
483  // any kind of click will capture focus
484  return Input.GetMouseButtonDown((int)ButtonController.ButtonType.Left)
485  || Input.GetMouseButtonDown((int)ButtonController.ButtonType.Right)
486  || Input.GetMouseButtonDown((int)ButtonController.ButtonType.Middle);
487  }
488  else
489  {
490  // pressing escape will stop capture
491  return !Input.GetKeyDown(KeyCode.Escape);
492  }
493  }
494 
495  return false;
496  }
497 
498  private void OnApplicationFocus(bool focusStatus)
499  {
500  this.appHasFocus = focusStatus;
501  }
502 
509  private void SetWantsMouseJumping(bool wantsJumping)
510  {
511  if (wantsJumping != this.isMouseJumping)
512  {
513  this.isMouseJumping = wantsJumping;
514 
515  if (wantsJumping)
516  {
517  // unlock the cursor if it was locked
518  UnityEngine.Cursor.lockState = CursorLockMode.None;
519 
520  // hide the cursor
521  UnityEngine.Cursor.visible = false;
522 
523  this.lastMousePosition = Input.mousePosition;
524  }
525  else
526  {
527  // recenter the cursor (setting lockCursor has side-effects under the hood)
528  UnityEngine.Cursor.lockState = CursorLockMode.Locked;
529  UnityEngine.Cursor.lockState = CursorLockMode.None;
530 
531  // show the cursor
532  UnityEngine.Cursor.visible = true;
533  }
534 
535 #if UNITY_EDITOR
536  UnityEditor.EditorGUIUtility.SetWantsMouseJumping(wantsJumping ? 1 : 0);
537 #endif
538  }
539  }
540 
541 #if UNITY_EDITOR
542  [System.Runtime.InteropServices.DllImport("kernel32.dll")]
543  private static extern uint GetCurrentProcessId();
544 
545  [System.Runtime.InteropServices.DllImport("kernel32.dll")]
546  private static extern bool ProcessIdToSessionId(uint dwProcessId, out uint pSessionId);
547 
548  [System.Runtime.InteropServices.DllImport("kernel32.dll")]
549  private static extern uint WTSGetActiveConsoleSessionId();
550 
551  private bool IsRunningUnderRemoteDesktop()
552  {
553  uint processId = GetCurrentProcessId();
554  uint sessionId;
555  return ProcessIdToSessionId(processId, out sessionId) && (sessionId != WTSGetActiveConsoleSessionId());
556  }
557 #else
558  private bool IsRunningUnderRemoteDesktop()
559  {
560  return false;
561  }
562 #endif
563  }
564 
565 }
AxisDestination
Each input axis, x, y, or z, will get mapped to an output axis, with potential inversion ...
Vector2 GetDisplacementVector2()
Get a Vector2 populated with axis mapped displacements.
ButtonController provides a per key or button component for the Manual input Controls in the Unity Ed...
bool ShouldControl()
Only allow the mouse to control rotation when Unity has focus. This enables the player to temporarily...
AxisType
Type of input axis, based on device.
Vector3 GetDisplacementVector3()
Get a Vector3 populated with axis mapped displacements.
ButtonType
These enums allow us to activate an axis only by a key press, such as CTRL mouse or ALT mouse ...
float GetDisplacementFloat()
Get a float populated with axis mapped displacements.
Useful for releasing external override. See CursorStateEnum.Contextual
AxisController uses the keyboard, mouse, or joystick and allows you to map a 1 axis controller to 1 a...