from github

This commit is contained in:
jonas
2024-10-29 17:16:17 +01:00
commit 537f1d77fb
1074 changed files with 303521 additions and 0 deletions
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2023 Black Whale Studio. All rights reserved.
*
* This software is the intellectual property of Black Whale Studio. Direct use, copying, or distribution of this code in its original or only slightly modified form is strictly prohibited. Significant modifications or derivations are required for any use.
*
* If this code is intended to be used in a commercial setting, you must contact Black Whale Studio for explicit permission.
*
* For the full licensing terms and conditions, visit:
* https://blackwhale.dev/
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTIES OR CONDITIONS.
*
* For questions or to join our community, please visit our Discord: https://discord.gg/55gtTryfWw
*/
using UnityEngine;
using UnityEngine.UI;
namespace Keyboard
{
public class Key : MonoBehaviour
{
[SerializeField] protected KeyChannel keyChannel;
[SerializeField] protected KeyboardManager keyboard;
protected Button button;
protected virtual void Awake()
{
button = GetComponent<Button>();
button.onClick.AddListener(OnPress);
keyboard.onKeyboardModeChanged.AddListener(UpdateKey);
keyChannel.onFirstKeyPress.AddListener(UpdateKey);
keyChannel.OnKeyColorsChanged += ChangeKeyColors;
keyChannel.OnKeysStateChange += ChangeKeyState;
}
protected virtual void OnDestroy()
{
button.onClick.RemoveListener(OnPress);
keyboard.onKeyboardModeChanged.RemoveListener(UpdateKey);
keyChannel.onFirstKeyPress.RemoveListener(UpdateKey);
keyChannel.OnKeyColorsChanged -= ChangeKeyColors;
keyChannel.OnKeysStateChange -= ChangeKeyState;
}
protected virtual void OnPress()
{
keyboard.DeactivateShift();
}
protected virtual void UpdateKey()
{
// empty method for override in child classes
}
protected void ChangeKeyColors(Color normalColor, Color highlightedColor, Color pressedColor, Color selectedColor)
{
ColorBlock cb = button.colors;
cb.normalColor = normalColor;
cb.highlightedColor = highlightedColor;
cb.pressedColor = pressedColor;
cb.selectedColor = selectedColor;
button.colors = cb;
}
protected void ChangeKeyState(bool enabled)
{
button.interactable = enabled;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 47d613a961a2d824ab81491977261b3f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- keyChannel: {fileID: 11400000, guid: 707903675feb07f42bda5f7de5dbe878, type: 2}
- keyboard: {instanceID: 0}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2023 Black Whale Studio. All rights reserved.
*
* This software is the intellectual property of Black Whale Studio. Direct use, copying, or distribution of this code in its original or only slightly modified form is strictly prohibited. Significant modifications or derivations are required for any use.
*
* If this code is intended to be used in a commercial setting, you must contact Black Whale Studio for explicit permission.
*
* For the full licensing terms and conditions, visit:
* https://blackwhale.dev/
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTIES OR CONDITIONS.
*
* For questions or to join our community, please visit our Discord: https://discord.gg/55gtTryfWw
*/
using UnityEngine;
using UnityEngine.Events;
// [CreateAssetMenu(fileName = "KeyChannel", menuName = "Channels/KeyChannel")]
namespace Keyboard
{
public class KeyChannel : ScriptableObject
{
public UnityAction<string> OnKeyPressed;
public UnityAction<Color, Color, Color, Color> OnKeyColorsChanged;
public UnityAction<bool> OnKeysStateChange;
public UnityEvent onFirstKeyPress;
public void RaiseKeyPressedEvent(string key) =>
OnKeyPressed?.Invoke(key);
public void RaiseKeyColorsChangedEvent(Color normalColor, Color highlightedColor, Color pressedColor,
Color selectedColor) =>
OnKeyColorsChanged?.Invoke(normalColor, highlightedColor, pressedColor, selectedColor);
public void RaiseKeysStateChangeEvent(bool enabled) =>
OnKeysStateChange?.Invoke(enabled);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fc9cadaa03c9af64ebfb56b1e467a080
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,326 @@
/*
* Copyright (c) 2023 Black Whale Studio. All rights reserved.
*
* This software is the intellectual property of Black Whale Studio. Direct use, copying, or distribution of this code in its original or only slightly modified form is strictly prohibited. Significant modifications or derivations are required for any use.
*
* If this code is intended to be used in a commercial setting, you must contact Black Whale Studio for explicit permission.
*
* For the full licensing terms and conditions, visit:
* https://blackwhale.dev/
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTIES OR CONDITIONS.
*
* For questions or to join our community, please visit our Discord: https://discord.gg/55gtTryfWw
*/
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace Keyboard
{
public class KeyboardManager : MonoBehaviour
{
[Header("Keyboard Setup")]
[SerializeField] private KeyChannel keyChannel;
[SerializeField] private Button spacebarButton;
[SerializeField] private Button speechButton;
[SerializeField] private Button deleteButton;
[SerializeField] private Button switchButton;
[SerializeField] private string switchToNumbers = "Numbers";
[SerializeField] private string switchToLetter = "Letters";
private TextMeshProUGUI switchButtonText;
[Header("Keyboards")]
[SerializeField] private GameObject lettersKeyboard;
[SerializeField] private GameObject numbersKeyboard;
[SerializeField] private GameObject specialCharactersKeyboard;
[Header("Shift/Caps Lock Button")]
[SerializeField] internal bool autoCapsAtStart = true;
[SerializeField] private Button shiftButton;
[SerializeField] private Image buttonImage;
[SerializeField] private Sprite defaultSprite;
[SerializeField] private Sprite activeSprite;
[Header("Switch Number/Special Button")]
[SerializeField] private Button switchNumberSpecialButton;
[SerializeField] private string numbersString = "Numbers";
[SerializeField] private string specialString = "Special";
private TextMeshProUGUI switchNumSpecButtonText;
[Header("Keyboard Button Colors")]
[SerializeField] private Color normalColor = Color.black;
[SerializeField] private Color highlightedColor = Color.yellow;
[SerializeField] private Color pressedColor = Color.red;
[SerializeField] private Color selectedColor = Color.blue;
[Header("Output Field Settings")]
[SerializeField] private TMP_InputField outputField;
[SerializeField] private Button enterButton;
[SerializeField] private int maxCharacters = 15;
[SerializeField] private int minCharacters = 3;
private ColorBlock shiftButtonColors;
private bool isFirstKeyPress = true;
private bool keyHasBeenPressed;
private bool shiftActive;
private bool capsLockActive;
private bool specialCharactersActive;
private float lastShiftClickTime;
private float shiftDoubleClickDelay = 0.5f;
public UnityEvent onKeyboardModeChanged;
private void Awake()
{
shiftButtonColors = shiftButton.colors;
CheckTextLength();
speechButton.interactable = false;
numbersKeyboard.SetActive(false);
specialCharactersKeyboard.SetActive(false);
lettersKeyboard.SetActive(true);
spacebarButton.onClick.AddListener(OnSpacePress);
deleteButton.onClick.AddListener(OnDeletePress);
switchButton.onClick.AddListener(OnSwitchPress);
shiftButton.onClick.AddListener(OnShiftPress);
switchNumberSpecialButton.onClick.AddListener(SwitchBetweenNumbersAndSpecialCharacters);
switchButtonText = switchButton.GetComponentInChildren<TextMeshProUGUI>();
switchNumSpecButtonText = switchNumberSpecialButton.GetComponentInChildren<TextMeshProUGUI>();
keyChannel.RaiseKeyColorsChangedEvent(normalColor, highlightedColor, pressedColor, selectedColor);
switchNumberSpecialButton.gameObject.SetActive(false);
numbersKeyboard.SetActive(false);
specialCharactersKeyboard.SetActive(false);
if (!autoCapsAtStart) return;
ActivateShift();
UpdateShiftButtonAppearance();
}
private void OnDestroy()
{
spacebarButton.onClick.RemoveListener(OnSpacePress);
deleteButton.onClick.RemoveListener(OnDeletePress);
switchButton.onClick.RemoveListener(OnSwitchPress);
shiftButton.onClick.RemoveListener(OnShiftPress);
switchNumberSpecialButton.onClick.RemoveListener(SwitchBetweenNumbersAndSpecialCharacters);
}
private void OnEnable() => keyChannel.OnKeyPressed += KeyPress;
private void OnDisable() => keyChannel.OnKeyPressed -= KeyPress;
private void KeyPress(string key)
{
keyHasBeenPressed = true;
bool wasShiftActive = shiftActive;
DeactivateShift();
string textToInsert;
if (wasShiftActive || capsLockActive)
{
textToInsert = key.ToUpper();
}
else
{
textToInsert = key.ToLower();
}
int startPos = Mathf.Min(outputField.selectionAnchorPosition, outputField.selectionFocusPosition);
int endPos = Mathf.Max(outputField.selectionAnchorPosition, outputField.selectionFocusPosition);
outputField.text = outputField.text.Remove(startPos, endPos - startPos);
outputField.text = outputField.text.Insert(startPos, textToInsert);
outputField.selectionAnchorPosition = outputField.selectionFocusPosition = startPos + textToInsert.Length;
if (isFirstKeyPress)
{
isFirstKeyPress = false;
keyChannel.onFirstKeyPress.Invoke();
}
CheckTextLength();
}
private void OnSpacePress()
{
int startPos = Mathf.Min(outputField.selectionAnchorPosition, outputField.selectionFocusPosition);
int endPos = Mathf.Max(outputField.selectionAnchorPosition, outputField.selectionFocusPosition);
outputField.text = outputField.text.Remove(startPos, endPos - startPos);
outputField.text = outputField.text.Insert(startPos, " ");
outputField.selectionAnchorPosition = outputField.selectionFocusPosition = startPos + 1;
CheckTextLength();
}
private void OnDeletePress()
{
if (string.IsNullOrEmpty(outputField.text)) return;
int startPos = Mathf.Min(outputField.selectionAnchorPosition, outputField.selectionFocusPosition);
int endPos = Mathf.Max(outputField.selectionAnchorPosition, outputField.selectionFocusPosition);
if (endPos > startPos)
{
outputField.text = outputField.text.Remove(startPos, endPos - startPos);
outputField.selectionAnchorPosition = outputField.selectionFocusPosition = startPos;
}
else if (startPos > 0)
{
outputField.text = outputField.text.Remove(startPos - 1, 1);
outputField.selectionAnchorPosition = outputField.selectionFocusPosition = startPos - 1;
}
CheckTextLength();
}
private void CheckTextLength()
{
int currentLength = outputField.text.Length;
// Raise event to enable or disable keys based on the text length
bool keysEnabled = currentLength < maxCharacters;
keyChannel.RaiseKeysStateChangeEvent(keysEnabled);
// Disables or enables the enter button based on the text length
enterButton.interactable = currentLength >= minCharacters;
// Always enable the delete button, regardless of the text length
deleteButton.interactable = true;
// Disable shift/caps lock if maximum text length is reached
if (currentLength != maxCharacters) return;
DeactivateShift();
capsLockActive = false;
UpdateShiftButtonAppearance();
}
private void OnSwitchPress()
{
if (lettersKeyboard.activeSelf)
{
lettersKeyboard.SetActive(false);
numbersKeyboard.SetActive(true);
specialCharactersKeyboard.SetActive(false);
switchNumberSpecialButton.gameObject.SetActive(true);
// Set buttons' text
switchButtonText.text = switchToNumbers;
switchNumSpecButtonText.text = specialString;
}
else
{
lettersKeyboard.SetActive(true);
numbersKeyboard.SetActive(false);
specialCharactersKeyboard.SetActive(false);
switchNumberSpecialButton.gameObject.SetActive(false);
// Set buttons' text
switchButtonText.text = switchToLetter;
switchNumSpecButtonText.text = specialString;
}
DeactivateShift();
onKeyboardModeChanged?.Invoke();
}
private void OnShiftPress()
{
if (capsLockActive)
{
// If Caps Lock is active, deactivate it
capsLockActive = false;
shiftActive = false;
}
else switch (shiftActive)
{
case true when !keyHasBeenPressed && Time.time - lastShiftClickTime < shiftDoubleClickDelay:
// If Shift is active, a key has not been pressed, and Shift button was double clicked, activate Caps Lock
capsLockActive = true;
shiftActive = false;
break;
case true when !keyHasBeenPressed:
// If Shift is active, a key has not been pressed, deactivate Shift
shiftActive = false;
break;
case false:
// If Shift is not active and Shift button was clicked once, activate Shift
shiftActive = true;
break;
}
lastShiftClickTime = Time.time;
UpdateShiftButtonAppearance();
onKeyboardModeChanged?.Invoke();
}
private void ActivateShift()
{
if (!capsLockActive) shiftActive = true;
UpdateShiftButtonAppearance();
onKeyboardModeChanged?.Invoke();
}
public void DeactivateShift()
{
if (shiftActive && !capsLockActive && keyHasBeenPressed)
{
shiftActive = false;
UpdateShiftButtonAppearance();
onKeyboardModeChanged?.Invoke();
}
keyHasBeenPressed = false;
}
public bool IsShiftActive() => shiftActive;
public bool IsCapsLockActive() => capsLockActive;
private void SwitchBetweenNumbersAndSpecialCharacters()
{
if (lettersKeyboard.activeSelf) return;
// Switch between numbers and special characters keyboard
bool isNumbersKeyboardActive = numbersKeyboard.activeSelf;
numbersKeyboard.SetActive(!isNumbersKeyboardActive);
specialCharactersKeyboard.SetActive(isNumbersKeyboardActive);
switchNumSpecButtonText.text = switchNumSpecButtonText.text == specialString ? numbersString : specialString;
onKeyboardModeChanged?.Invoke();
}
private void UpdateShiftButtonAppearance()
{
if (capsLockActive)
{
shiftButtonColors.normalColor = highlightedColor;
buttonImage.sprite = activeSprite;
}
else if(shiftActive)
{
shiftButtonColors.normalColor = highlightedColor;
buttonImage.sprite = defaultSprite;
}
else
{
shiftButtonColors.normalColor = normalColor;
buttonImage.sprite = defaultSprite;
}
shiftButton.colors = shiftButtonColors;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: d1fbe56b68e55344cafc5bc770a0dd79
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- outputField: {instanceID: 0}
- keyChannel: {fileID: 11400000, guid: 707903675feb07f42bda5f7de5dbe878, type: 2}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2023 Black Whale Studio. All rights reserved.
*
* This software is the intellectual property of Black Whale Studio. Direct use, copying, or distribution of this code in its original or only slightly modified form is strictly prohibited. Significant modifications or derivations are required for any use.
*
* If this code is intended to be used in a commercial setting, you must contact Black Whale Studio for explicit permission.
*
* For the full licensing terms and conditions, visit:
* https://blackwhale.dev/
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTIES OR CONDITIONS.
*
* For questions or to join our community, please visit our Discord: https://discord.gg/55gtTryfWw
*/
using TMPro;
using UnityEngine;
namespace Keyboard
{
public class LetterKey : Key
{
[SerializeField] private string character;
private TextMeshProUGUI buttonText;
protected override void Awake()
{
base.Awake();
buttonText = GetComponentInChildren<TextMeshProUGUI>();
InitializeKey();
}
private void InitializeKey() => buttonText.text = keyboard.autoCapsAtStart ? character.ToUpper() : character;
protected override void OnPress()
{
base.OnPress();
keyChannel.RaiseKeyPressedEvent(character);
}
protected override void UpdateKey()
{
if(keyboard.IsShiftActive() || keyboard.IsCapsLockActive())
{
buttonText.text = character.ToUpper();
}
else
{
buttonText.text = character.ToLower();
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 2c854b523eeb36b489c89a40beb6e039
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- keyChannel: {fileID: 11400000, guid: 707903675feb07f42bda5f7de5dbe878, type: 2}
- keyboard: {instanceID: 0}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2f36ddf56451b9041a9080575760ac90
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fc9cadaa03c9af64ebfb56b1e467a080, type: 3}
m_Name: KeyChannel
m_EditorClassIdentifier:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 707903675feb07f42bda5f7de5dbe878
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant: