using System;
using System.Collections;
using UnityEngine;
namespace NovaSamples.UIControls
{
///
/// Provides text input via keyboard to a .
///
public class TextFieldKeyboardInput : TextFieldInputProvider
{
public event Action OnSubmit = null;
[SerializeField]
[Tooltip("If true, will fire submit events whenever the return key is pressed.")]
private bool fireSubmitEvents = false;
private Coroutine inputRoutine = null;
private bool requestedIme = false;
///
/// Starts the input loop when the text field gains focus.
///
protected override void HandleFocused()
{
EnableIme();
requestedIme = true;
inputRoutine = StartCoroutine(InputLoop());
}
///
/// Stops the input loop when the text field loses focus.
///
protected override void HandleFocusLost()
{
if (requestedIme)
{
DisableIme();
requestedIme = false;
}
if (inputRoutine != null)
{
StopCoroutine(inputRoutine);
inputRoutine = null;
}
}
protected override void OnDisable()
{
base.OnDisable();
if (requestedIme)
{
DisableIme();
requestedIme = false;
}
}
private IEnumerator InputLoop()
{
// Don't process the input on the frame that we gain focus
yield return null;
Event cachedEvent = new Event();
// Loop indefinitely, the loop will stop when the coroutine is stopped.
while (true)
{
while (Event.PopEvent(cachedEvent))
{
if (cachedEvent.type != EventType.KeyDown)
{
continue;
}
if (!ProcessKeyPress(cachedEvent))
{
break;
}
}
// Wait for the next frame
yield return null;
}
}
///
/// Returns true if should continue
///
private bool ProcessKeyPress(Event evt)
{
var currentEventModifiers = evt.modifiers;
// Get the modifiers for the event
bool ctrl = SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX ? (currentEventModifiers & EventModifiers.Command) != 0 : (currentEventModifiers & EventModifiers.Control) != 0;
bool shift = (currentEventModifiers & EventModifiers.Shift) != 0;
bool alt = (currentEventModifiers & EventModifiers.Alt) != 0;
bool ctrlOnly = ctrl && !alt && !shift;
// Process the "special" keys
switch (evt.keyCode)
{
case KeyCode.Return:
{
if (!fireSubmitEvents || shift)
{
break;
}
OnSubmit?.Invoke();
return false;
}
case KeyCode.Backspace:
{
inputField.DeleteLeft();
return true;
}
case KeyCode.Delete:
{
inputField.DeleteRight();
return true;
}
case KeyCode.Home:
{
inputField.MoveCursor(inputField.CursorPosition.MoveToStartOfLine(), shift);
return true;
}
case KeyCode.End:
{
inputField.MoveCursor(inputField.CursorPosition.MoveToEndOfLine(), shift);
return true;
}
case KeyCode.LeftArrow:
{
if (ctrl)
{
inputField.MoveCursor(inputField.CursorPosition.MoveLeft().MoveToStartOfWord(), shift);
}
else
{
inputField.MoveCursor(inputField.CursorPosition.MoveLeft(), shift);
}
return true;
}
case KeyCode.RightArrow:
{
if (ctrl)
{
inputField.MoveCursor(inputField.CursorPosition.MoveToEndOfWord().MoveRight(), shift);
}
else
{
inputField.MoveCursor(inputField.CursorPosition.MoveRight(), shift);
}
return true;
}
case KeyCode.UpArrow:
{
inputField.MoveCursor(inputField.CursorPosition.MoveUp(), shift);
return true;
}
case KeyCode.DownArrow:
{
inputField.MoveCursor(inputField.CursorPosition.MoveDown(), shift);
return true;
}
case KeyCode.A:
{
if (ctrlOnly)
{
inputField.SetCursorPosition(inputField.CursorPosition.MoveToEnd(), inputField.CursorPosition.MoveToStart());
return true;
}
break;
}
case KeyCode.C:
{
if (ctrlOnly)
{
GUIUtility.systemCopyBuffer = inputField.GetSelectedString();
return true;
}
break;
}
case KeyCode.V:
{
if (ctrlOnly)
{
inputField.Insert(GUIUtility.systemCopyBuffer);
return true;
}
break;
}
case KeyCode.X:
{
if (ctrlOnly)
{
GUIUtility.systemCopyBuffer = inputField.GetSelectedString();
inputField.DeleteSelection();
return true;
}
break;
}
case KeyCode.Escape:
{
inputField.ClearTextSelection();
return false;
}
}
// If we got to here, it wasn't a special character, so try to insert
// it into the input field
char c = evt.character;
if (c == '\r' || (int)c == 3)
{
// Convert carriage return and end-of-text characters to newline.
c = '\n';
}
if (!IsValidChar(c))
{
return true;
}
// Insert the text into the input field
inputField.Insert(c);
return true;
}
#region IME Support
private static int imeEnableRequests = 0;
///
/// Ensures IME input events are enabled
///
private static void EnableIme()
{
imeEnableRequests += 1;
if (imeEnableRequests == 1)
{
// Only need to do this if this is the first request
Input.imeCompositionMode = IMECompositionMode.On;
}
}
private static void DisableIme()
{
imeEnableRequests -= 1;
if (imeEnableRequests == 0)
{
Input.imeCompositionMode = IMECompositionMode.Auto;
}
}
#endregion
}
}