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实现虚拟键盘 的全部内容, 来源链接: utcz.com/z/349179.html

回到顶部