软件编程
位置:首页>> 软件编程>> C#编程>> Unity实现虚拟键盘

Unity实现虚拟键盘

作者:小小小小羽丶  发布时间:2022-05-24 11:25:38 

标签:Unity,虚拟键盘

本文实例为大家分享了Unity实现虚拟键盘的具体代码,供大家参考,具体内容如下

这是一个网上找的插件,自己改了点东西,方便使用在项目中。暂时不适用中文输入,中文输入可能得调出系统输入法,项目不需要就没去研究了,大伙有兴趣可以研究研究。

包含两个类,一个是虚拟键盘类,还一个是文本框输入类。下面直接上代码:


using UnityEngine;
using System.Collections.Generic;

/*
* On Screen Keyboard
* By Richard Taylor, Holopoint Interactive Pty. Ltd.
*
* FEATURES:
* - Fully configurable layout
* - Fully skinnable
* - Key select and press audio
* - Configurable caps functionality
* - Configurable key repeat settings
* - Works with both joystick/gamepad and mouse/touchscreen input
* - Simple integration
* - Tested using Xbox 360 controller and iPad
*/

/*
* Time list:
* June于2020.04.17改
*
*/

public enum ShiftState { Off, Shift, CapsLock }

public class OnScreenKeyboard : MonoBehaviour {

// INSPECTOR VISIBLE PROPERTIES -------------------------------------------

// Skinning
public GUIStyle boardStyle;
public GUIStyle keyStyle;
public Texture2D selectionImage;

// Board and button sizes
public Rect screenRect = new Rect(0, 0, 0, 0);
public Vector2 stdKeySize = new Vector2(32, 32);
public Vector2 lgeKeySize = new Vector2(64, 32);

// Key audio
public AudioClip keySelectSound = null;
public AudioClip keyPressSound = null;

// Shift settings
public bool shiftStateSwitchEnabled = true;
public ShiftState shiftStateDefault = ShiftState.Off;

// Joystick settings
public bool joystickEnabled = true;
public string joyPressButton = "Fire1";
public string joyCapsButton = "Fire2";

// Our keys. By default we'll include a simplified QWERTY keyboard handy
// for name entry, but this can literally be anything you want. Either the
// two arrays must be of matching length, or lowerKeys must be of size 0.
public string[] upperKeys = { "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "<<", "<row>",
    "A", "S", "D", "F", "G", "H", "J", "K", "L", "Done", "<row>",
    "Z", "X", "C", "V", "B", "N", "M", "Caps", "Space" };

public string[] lowerKeys = { "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "<<", "<row>",
    "a", "s", "d", "f", "g", "h", "j", "k", "l", "Done", "<row>",
    "z", "x", "c", "v", "b", "n", "m", "Caps", "Space" };

// The size must match the number of rows, or be 0
public float[] rowIndents = { 0.0f, 0.2f, 0.5f };

// Delays for repeated events
public float initialRepeatDelay = 0.8f;
public float continuedRepeatDelay = 0.2f;
public float moveRepeatDelay = 0.3f;

// INTERNAL DATA MEMBERS --------------------------------------------------
private string keyPressed = "";
private int pSelectedButton;

private GUIStyle pressedStyle = null;

private float keyRepeatTimer = 0;
private bool keyDownPrevFrame = false;
private bool keyReleased = false;
private bool lastKeyWasShift = false;

private float moveTimer = 0;

private ShiftState shiftState;

private bool[] keySizes;
private Rect[] keyRects;
private int[] rowMarkers;

private int selectedButton;

private AudioSource keySelectSource = null;
private AudioSource keyPressSource = null;

// Change this if it's conflicting with your own GUI's windows
private int windowId = 0;

/// <summary>
/// 新增属性,控制虚拟键盘在屏幕中的位置
/// </summary>
[Header("June_Add_Attribute_Control_keyBoardTF---------------------------------------")]
public float _keyBoardTF_X;
public float _keyBoardTF_Y;

// INITIALISATION ---------------------------------------------------------
void Awake()
{
// Check that our key array sizes match
if (upperKeys.Length != lowerKeys.Length && !(lowerKeys.Length == 0 && !shiftStateSwitchEnabled))
{
print("Error: OnScreenKeyboard needs the same number of upper and lower case keys, or there must be no lower keys and caps switch must be disabled");
Destroy(this);
}

// Check for row markers and count row lengths
List<int> rowMarkersTemp = new List<int>();
for (int i = 0; i < upperKeys.Length; i++)
if (upperKeys[i] == "<row>") rowMarkersTemp.Add(i);
rowMarkers = rowMarkersTemp.ToArray();

// Check row indents
if (rowIndents.Length < rowMarkers.Length + 1)
{
 float[] rowIndentsTemp = new float[rowMarkers.Length + 1];
 for (int i = 0; i < rowIndentsTemp.Length; i++)
 {
 if (i < rowIndents.Length) rowIndentsTemp[i] = rowIndents[i];
 else rowIndentsTemp[i] = 0;
 }
}

// Check button sizes - anything that's not a single character is a "large" key
keySizes = new bool[upperKeys.Length];
for (int i = 0; i < upperKeys.Length; i++) keySizes[i] = upperKeys[i].Length > 1;

// Populate the array of key rectangles
keyRects = new Rect[upperKeys.Length];
int currentRow = 0;
float xPos = (rowIndents.Length > 0 ? rowIndents[currentRow] : 0) + stdKeySize.x*0.33f;
float yPos = stdKeySize.y*1.33f*currentRow + stdKeySize.y*0.33f;
for (int i = 0; i < upperKeys.Length; i++)
{
// On the start of a new line, position the new key accordingly
 if (IsRowMarker(i))
 {
 if (i != 0) currentRow++;
 xPos = (rowIndents.Length > 0 ? rowIndents[currentRow] : 0) + stdKeySize.x * 0.33f;
 yPos = stdKeySize.y*1.33f*currentRow + stdKeySize.y * 0.33f;
 }
 else
 {
 // Draw the key, and set keyPressed accordingly
 keyRects[i] = new Rect(screenRect.x + xPos, screenRect.y + yPos, keySizes[i] ? lgeKeySize.x : stdKeySize.x, keySizes[i] ? lgeKeySize.y : stdKeySize.y);

// Move over to the next key's position on this line
 xPos += keySizes[i] ? lgeKeySize.x + stdKeySize.x*0.33f : stdKeySize.x*1.33f;
 }
}

// Put ourselves in a default screen position if we haven't been explicitly placed yet
if (screenRect.x == 0 && screenRect.y == 0 && screenRect.width == 0 && screenRect.height == 0)
{
 // Figure out how big we need to be
 float maxWidth = 0;
float maxHeight = 0;
for (int i = 0; i < keyRects.Length; i++)
{
if (keyRects[i].xMax > maxWidth) maxWidth = keyRects[i].xMax;
if (keyRects[i].yMax > maxHeight) maxHeight = keyRects[i].yMax;
}
maxWidth += stdKeySize.x*0.33f;
maxHeight += stdKeySize.y*0.33f;

screenRect = new Rect(_keyBoardTF_X, _keyBoardTF_Y, maxWidth, maxHeight);
}

// If we've got audio, create sources so we can play it
if (keySelectSound != null)
{
keySelectSource = gameObject.AddComponent<AudioSource>() as AudioSource;
keySelectSource.spatialBlend = 0;
keySelectSource.clip = keySelectSound;
}
if (keyPressSound != null)
{
keyPressSource = gameObject.AddComponent<AudioSource>() as AudioSource;
keyPressSource.spatialBlend = 0;
keyPressSource.clip = keyPressSound;
}

// Set the initial shift state
if (shiftStateSwitchEnabled) SetShiftState(shiftStateDefault);

// Create a pressed button skin for joysticks
pressedStyle = new GUIStyle();
pressedStyle.normal.background = keyStyle.active.background;
pressedStyle.border = keyStyle.border;
pressedStyle.normal.textColor = keyStyle.active.textColor;
pressedStyle.alignment = keyStyle.alignment;
//新增字体样式------->按钮按下的时候调用
pressedStyle.font = keyStyle.font;

}

// GAME LOOP --------------------------------------------------------------

void Update()
{
// Handle keys being released
if (!keyDownPrevFrame)
{
keyRepeatTimer = 0;
if (!keyReleased) KeyReleased();
}
keyDownPrevFrame = false;

// Check mouse input
Vector3 guiMousePos = Input.mousePosition;
guiMousePos.y = Screen.height - guiMousePos.y;
for (int i = 0; i < keyRects.Length; i++)
{
Rect clickRect = keyRects[i];
clickRect.x += screenRect.x; clickRect.y += screenRect.y;
// Check for the click ourself, because we want to do it differently to usual
if (clickRect.Contains(guiMousePos))
{
selectedButton = i;
if (Input.GetMouseButtonDown(0)) KeyPressed();
else if (Input.GetMouseButton(0)) KeyHeld();
else if (Input.GetMouseButtonUp(0)) KeyReleased();
}
}

// If the joystick is in use, update accordingly
if (joystickEnabled) CheckJoystickInput();
}

private void CheckJoystickInput()
{
// KEY SELECTION
float horiz = Input.GetAxis("Horizontal");
float vert = Input.GetAxis("Vertical");

moveTimer -= Time.deltaTime;
if (moveTimer < 0) moveTimer = 0;

bool hadInput = false;
bool moved = false;
if (horiz > 0.5f)
{
if (moveTimer <= 0)
{
SelectRight();
moved = true;
}
hadInput = true;
}
else if (horiz < -0.5f)
{
if (moveTimer <= 0)
{
SelectLeft();
moved = true;
}
hadInput = true;
}
if (vert < -0.5f)
{
if (moveTimer <= 0)
{
SelectDown();
moved = true;
}
hadInput = true;
}
else if (vert > 0.5f)
{
if (moveTimer <= 0)
{
SelectUp();
moved = true;
}
hadInput = true;
}
if (!hadInput) moveTimer = 0;
if (moved)
{
moveTimer += moveRepeatDelay;
if (keySelectSource != null) keySelectSource.Play();
}
selectedButton = Mathf.Clamp(selectedButton, 0, upperKeys.Length - 1);

// CAPITALS
if (shiftStateSwitchEnabled &&
 (Input.GetKeyDown(KeyCode.LeftShift) ||
 Input.GetButtonDown(joyCapsButton)))
 shiftState = (shiftState == ShiftState.CapsLock ? ShiftState.Off : ShiftState.CapsLock);

// TYPING
if (Input.GetButtonDown(joyPressButton)) KeyPressed();
else if (Input.GetButton(joyPressButton)) KeyHeld();
}

// Called on the first frame where a new key is pressed
private void KeyPressed()
{
keyPressed = (shiftState != ShiftState.Off) ? upperKeys[selectedButton] : lowerKeys[selectedButton];
pSelectedButton = selectedButton;
keyRepeatTimer = initialRepeatDelay;

keyDownPrevFrame = true;
keyReleased = false;
lastKeyWasShift = false;

if (keyPressSource != null) keyPressSource.Play();
}

// Called for every frame AFTER the first while a key is being held
private void KeyHeld()
{
// If the key being pressed has changed, revert to an initial press
if (selectedButton != pSelectedButton)
{
KeyReleased();
KeyPressed();
return;
}

// Check if we're ready to report another press yet
keyRepeatTimer -= Time.deltaTime;
if (keyRepeatTimer < 0)
{
keyPressed = (shiftState != ShiftState.Off) ? upperKeys[selectedButton] : lowerKeys[selectedButton];
keyRepeatTimer += continuedRepeatDelay;

if (keyPressSource != null) keyPressSource.Play();
}

keyDownPrevFrame = true;
keyReleased = false;
}

// Called the frame after a key is released
private void KeyReleased()
{
keyDownPrevFrame = false;
keyReleased = true;

if (shiftState == ShiftState.Shift && !lastKeyWasShift)
SetShiftState(ShiftState.Off);
}

// Selects the key to the left of the currently selected key
private void SelectLeft()
{
selectedButton--;

// If we've hit the start of a row, wrap to the end of it instead
if (IsRowMarker(selectedButton) || selectedButton < 0)
{
 selectedButton++;
 while (!IsRowMarker(selectedButton+1) && selectedButton+1 < upperKeys.Length) selectedButton++;
}
}

// Selects the key to the right of the currently selected key
private void SelectRight()
{
selectedButton++;

// If we've hit the end of a row, wrap to the start of it instead
if (IsRowMarker(selectedButton) || selectedButton >= upperKeys.Length)
{
 selectedButton--;
 while (!IsRowMarker(selectedButton-1) && selectedButton-1 >= 0) selectedButton--;
}
}

// Selects the key above the currently selected key
private void SelectUp()
{
// Find the center of the currently selected button
float selCenter = keyRects[selectedButton].x + keyRects[selectedButton].width/2;

// Find the start of the next button;
int tgtButton = selectedButton;
while (!IsRowMarker(tgtButton) && tgtButton >= 0) tgtButton--;
if (IsRowMarker(tgtButton)) tgtButton--;
if (tgtButton < 0) tgtButton = upperKeys.Length-1;

// Find the button with the closest center on that line
float nDist = float.MaxValue;
while (!IsRowMarker(tgtButton) && tgtButton >= 0)
{
float tgtCenter = keyRects[tgtButton].x + keyRects[tgtButton].width/2;
float tDist = Mathf.Abs(tgtCenter - selCenter);
if (tDist < nDist)
{
nDist = tDist;
}
else
{
selectedButton = tgtButton+1;
return;
}
tgtButton--;
}
selectedButton = tgtButton+1;
}

// Selects the key below the currently selected key
private void SelectDown()
{
// Find the center of the currently selected button
float selCenter = keyRects[selectedButton].x + keyRects[selectedButton].width/2;

// Find the start of the next button;
int tgtButton = selectedButton;
while (!IsRowMarker(tgtButton) && tgtButton < upperKeys.Length) tgtButton++;
if (IsRowMarker(tgtButton)) tgtButton++;
if (tgtButton >= upperKeys.Length) tgtButton = 0;

// Find the button with the closest center on that line
float nDist = float.MaxValue;
while (!IsRowMarker(tgtButton) && tgtButton < upperKeys.Length)
{
float tgtCenter = keyRects[tgtButton].x + keyRects[tgtButton].width/2;
float tDist = Mathf.Abs(tgtCenter - selCenter);
if (tDist < nDist)
{
nDist = tDist;
}
else
{
selectedButton = tgtButton-1;
return;
}
tgtButton++;
}
selectedButton = tgtButton-1;
}

// Returns the row number of a specified button
private int ButtonRow(int buttonIndex)
{
for (int i = 0; i < rowMarkers.Length; i++)
 if (buttonIndex < rowMarkers[i]) return i;

return rowMarkers.Length;
}

// GUI FUNCTIONALITY ------------------------------------------------------

void OnGUI()
{
GUI.Window(windowId, screenRect, WindowFunc, "", boardStyle);
}

private void WindowFunc(int id)
{
for (int i = 0; i < upperKeys.Length; i++)
{
 if (!IsRowMarker(i))
 {
 // Draw a glow behind the selected button
 if (i == selectedButton)
  GUI.DrawTexture(new Rect(keyRects[i].x-5, keyRects[i].y-5, keyRects[i].width+10, keyRects[i].height+10), selectionImage);
 // Draw the key
// Note that we don't do click detection here, we do it in update
GUI.Button(keyRects[i], (shiftState != ShiftState.Off) ? upperKeys[i] : lowerKeys[i],
 (joystickEnabled && selectedButton == i && Input.GetButton(joyPressButton) ? pressedStyle : keyStyle));
 }
}
}

// Returns true if they item at a specified index is a row end marker
private bool IsRowMarker(int currentKeyIndex)
{
for (int i = 0; i < rowMarkers.Length; i++) if (rowMarkers[i] == currentKeyIndex) return true;
return false;
}

// CONTROL INTERFACE ------------------------------------------------------

// Returns the latest key to be pressed, or null if no new key was pressed
// since last time you checked. This means that you can only grab a single
// keypress once, as it's cleared once you've read it. It also means that
// if you let the user press multiple keys between checks only the most
// recent one will be picked up each time.
public string GetKeyPressed()
{
if (keyPressed == null) keyPressed = "";

string key = keyPressed;
keyPressed = "";
return key;
}

// Toggle the caps state from elsewhere
public void SetShiftState(ShiftState newShiftState)
{
if (!shiftStateSwitchEnabled) return;

shiftState = newShiftState;
if (shiftState == ShiftState.Shift) lastKeyWasShift = true;
}

public ShiftState GetShiftState() { return shiftState; }
}

using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// 这是虚拟键盘插件脚本,June于2020.4.16改
/// </summary>

public class OnScreenKeyboardExample : MonoBehaviour
{
public OnScreenKeyboard osk;
/// <summary>
 /// 输入文字
 /// </summary>
private string _inputString;
 /// <summary>
 /// 输入文本框
 /// </summary>
 public InputField _inputField;

//每次激活清空文本框内容
 private void OnEnable()
 {
   _inputString = "";
 }

void Update ()
 {

// You can use input from the OSK just by asking for the most recent
// pressed key, which will be returned to you as a string, or null if
// no key has been pressed since you last checked. Note that if more
// than one key has been pressed you will only be given the most recent.
string keyPressed = osk.GetKeyPressed();
if (keyPressed != "")
{

// Take different action depending on what key was pressed
 if (keyPressed == "Backspace" || keyPressed == "<<")
 {
 // Remove a character
 if (_inputString.Length > 0)
         _inputString = _inputString.Substring(0, _inputString.Length-1);
 }
 else if (keyPressed == "Space")
 {
       // Add a space
       _inputString += " ";
     }
 else if (keyPressed == "Enter" || keyPressed == "Done")
 {
       // Change screens, or do whatever you want to
       // do when your user has finished typing :-)
     }
 else if (keyPressed == "Caps")
 {
 // Toggle the capslock state yourself
 osk.SetShiftState(osk.GetShiftState() == ShiftState.CapsLock ? ShiftState.Off : ShiftState.CapsLock);
     }
 else if (keyPressed == "Shift")
 {
 // Toggle shift state ourselves
 osk.SetShiftState(osk.GetShiftState() == ShiftState.Shift ? ShiftState.Off : ShiftState.Shift);
     }
 else
 {
       //限制输入
       if (_inputField.text.Length >= _inputField.characterLimit) return;
       // Add a letter to the existing string
       _inputString += keyPressed;
 }
     //将文字赋值给文本框中的文本属性
     _inputField.text = _inputString;

}
}
}

在场景中新建个空物体,用来放虚拟键盘脚本,再新建个输入文本框,脚本可以挂在画布上或者新建个空物体都行。把输入文本框赋上去就可以了。运行效果是这样的

Unity实现虚拟键盘

当然,你想要各种风格之类的,换底图之类的,以及按键数量,都可以自行设置。

来源:https://blog.csdn.net/qq_36374904/article/details/105576270

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com