Skip to content

Commit f369f51

Browse files
authored
Create KeystrokeVisualizer.cs
1 parent b5a9b5d commit f369f51

1 file changed

Lines changed: 306 additions & 0 deletions

File tree

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
// displays the currently held keys in a small window, useful for recording tutorials or presentations.
2+
3+
using System.Collections.Generic;
4+
using UnityEditor;
5+
using UnityEngine;
6+
7+
namespace UnityLibrary.EditorTools
8+
{
9+
public class KeystrokeVisualizer : EditorWindow
10+
{
11+
private readonly List<KeyCode> heldKeys = new List<KeyCode>();
12+
13+
private bool ctrlHeld;
14+
private bool shiftHeld;
15+
private bool altHeld;
16+
private bool cmdHeld;
17+
18+
private string displayedKeys = "";
19+
private double lastReleaseTime;
20+
21+
private float displayDuration = 2.0f;
22+
private int fontSize = 30;
23+
private bool showMouseClicks = true;
24+
private bool showSettings;
25+
26+
private GUIStyle keyStyle;
27+
28+
private bool HasHeldKeys => ctrlHeld || shiftHeld || altHeld || cmdHeld || heldKeys.Count > 0;
29+
30+
[MenuItem("Tools/UnityLibrary/Keystroke Visualizer")]
31+
public static void OpenWindow()
32+
{
33+
KeystrokeVisualizer window = GetWindow<KeystrokeVisualizer>(true, "Keystroke Visualizer", true);
34+
window.minSize = new Vector2(360, 120);
35+
window.ShowUtility();
36+
}
37+
38+
private void OnEnable()
39+
{
40+
SceneView.beforeSceneGui += OnSceneGUI;
41+
EditorApplication.update += OnEditorUpdate;
42+
}
43+
44+
private void OnDisable()
45+
{
46+
SceneView.beforeSceneGui -= OnSceneGUI;
47+
EditorApplication.update -= OnEditorUpdate;
48+
}
49+
50+
private void OnEditorUpdate()
51+
{
52+
if (HasHeldKeys && !(EditorWindow.focusedWindow is SceneView))
53+
{
54+
ClearHeldKeys();
55+
lastReleaseTime = EditorApplication.timeSinceStartup;
56+
}
57+
58+
if (HasHeldKeys || EditorApplication.timeSinceStartup - lastReleaseTime < displayDuration)
59+
Repaint();
60+
}
61+
62+
private void OnSceneGUI(SceneView sceneView)
63+
{
64+
Event e = Event.current;
65+
66+
if (e == null)
67+
return;
68+
69+
if (e.type == EventType.KeyDown)
70+
{
71+
HandleKeyDown(e);
72+
}
73+
else if (e.type == EventType.KeyUp)
74+
{
75+
HandleKeyUp(e);
76+
}
77+
else if (showMouseClicks && e.type == EventType.MouseDown)
78+
{
79+
HandleMouseDown(e);
80+
}
81+
}
82+
83+
private void HandleKeyDown(Event e)
84+
{
85+
KeyCode key = e.keyCode;
86+
87+
if (key == KeyCode.None)
88+
return;
89+
90+
UpdateModifiers(e);
91+
92+
if (!IsModifier(key) && !heldKeys.Contains(key))
93+
heldKeys.Add(key);
94+
95+
UpdateHeldDisplay();
96+
}
97+
98+
private void HandleKeyUp(Event e)
99+
{
100+
KeyCode key = e.keyCode;
101+
102+
if (key == KeyCode.None)
103+
return;
104+
105+
UpdateModifiers(e);
106+
107+
if (IsModifier(key))
108+
{
109+
ReleaseModifier(key);
110+
}
111+
else
112+
{
113+
heldKeys.Remove(key);
114+
}
115+
116+
if (HasHeldKeys)
117+
{
118+
UpdateHeldDisplay();
119+
}
120+
else
121+
{
122+
lastReleaseTime = EditorApplication.timeSinceStartup;
123+
}
124+
125+
Repaint();
126+
}
127+
128+
private void UpdateModifiers(Event e)
129+
{
130+
ctrlHeld = e.control;
131+
shiftHeld = e.shift;
132+
altHeld = e.alt;
133+
cmdHeld = e.command;
134+
}
135+
136+
private void ReleaseModifier(KeyCode key)
137+
{
138+
switch (key)
139+
{
140+
case KeyCode.LeftControl:
141+
case KeyCode.RightControl:
142+
ctrlHeld = false;
143+
break;
144+
145+
case KeyCode.LeftShift:
146+
case KeyCode.RightShift:
147+
shiftHeld = false;
148+
break;
149+
150+
case KeyCode.LeftAlt:
151+
case KeyCode.RightAlt:
152+
altHeld = false;
153+
break;
154+
155+
case KeyCode.LeftCommand:
156+
case KeyCode.RightCommand:
157+
cmdHeld = false;
158+
break;
159+
}
160+
}
161+
162+
private void UpdateHeldDisplay()
163+
{
164+
List<string> parts = new List<string>();
165+
166+
if (ctrlHeld)
167+
parts.Add("Ctrl");
168+
169+
if (cmdHeld)
170+
parts.Add("Cmd");
171+
172+
if (altHeld)
173+
parts.Add("Alt");
174+
175+
if (shiftHeld)
176+
parts.Add("Shift");
177+
178+
foreach (KeyCode key in heldKeys)
179+
parts.Add(FormatKey(key));
180+
181+
if (parts.Count > 0)
182+
displayedKeys = string.Join(" + ", parts);
183+
184+
Repaint();
185+
}
186+
187+
private void HandleMouseDown(Event e)
188+
{
189+
string mouseButton = "";
190+
191+
switch (e.button)
192+
{
193+
case 0: mouseButton = "Left Click"; break;
194+
case 1: mouseButton = "Right Click"; break;
195+
case 2: mouseButton = "Middle Click"; break;
196+
default: return;
197+
}
198+
199+
UpdateModifiers(e);
200+
201+
List<string> parts = new List<string>();
202+
203+
if (ctrlHeld)
204+
parts.Add("Ctrl");
205+
206+
if (cmdHeld)
207+
parts.Add("Cmd");
208+
209+
if (altHeld)
210+
parts.Add("Alt");
211+
212+
if (shiftHeld)
213+
parts.Add("Shift");
214+
215+
parts.Add(mouseButton);
216+
217+
displayedKeys = string.Join(" + ", parts);
218+
lastReleaseTime = EditorApplication.timeSinceStartup;
219+
220+
Repaint();
221+
}
222+
223+
private void ClearHeldKeys()
224+
{
225+
heldKeys.Clear();
226+
ctrlHeld = false;
227+
shiftHeld = false;
228+
altHeld = false;
229+
cmdHeld = false;
230+
}
231+
232+
private static bool IsModifier(KeyCode key)
233+
{
234+
return key == KeyCode.LeftShift || key == KeyCode.RightShift ||
235+
key == KeyCode.LeftControl || key == KeyCode.RightControl ||
236+
key == KeyCode.LeftAlt || key == KeyCode.RightAlt ||
237+
key == KeyCode.LeftCommand || key == KeyCode.RightCommand;
238+
}
239+
240+
private static string FormatKey(KeyCode key)
241+
{
242+
string name = key.ToString();
243+
244+
if (name.StartsWith("Alpha"))
245+
return name.Substring(5);
246+
247+
switch (key)
248+
{
249+
case KeyCode.Return: return "Enter";
250+
case KeyCode.Escape: return "Esc";
251+
case KeyCode.Space: return "Space";
252+
case KeyCode.Backspace: return "Backspace";
253+
case KeyCode.Delete: return "Delete";
254+
case KeyCode.LeftArrow: return "Left";
255+
case KeyCode.RightArrow: return "Right";
256+
case KeyCode.UpArrow: return "Up";
257+
case KeyCode.DownArrow: return "Down";
258+
case KeyCode.KeypadEnter: return "Numpad Enter";
259+
default: return name;
260+
}
261+
}
262+
263+
private void OnGUI()
264+
{
265+
EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), new Color(0.07f, 0.07f, 0.09f, 1f));
266+
267+
if (keyStyle == null)
268+
{
269+
keyStyle = new GUIStyle(EditorStyles.boldLabel);
270+
keyStyle.alignment = TextAnchor.MiddleCenter;
271+
keyStyle.wordWrap = true;
272+
keyStyle.normal.textColor = Color.white;
273+
}
274+
275+
keyStyle.fontSize = fontSize;
276+
277+
double elapsed = EditorApplication.timeSinceStartup - lastReleaseTime;
278+
279+
float alpha = HasHeldKeys ? 1f : Mathf.Clamp01((float)(displayDuration - elapsed) / 0.35f);
280+
281+
float contentHeight = showSettings ? position.height - 115f : position.height - 30f;
282+
contentHeight = Mathf.Max(30f, contentHeight);
283+
284+
if (!string.IsNullOrEmpty(displayedKeys) && alpha > 0f)
285+
{
286+
Color oldColor = GUI.color;
287+
GUI.color = new Color(1f, 1f, 1f, alpha);
288+
GUI.Label(new Rect(12, 8, position.width - 24, contentHeight), displayedKeys, keyStyle);
289+
GUI.color = oldColor;
290+
}
291+
292+
GUILayout.FlexibleSpace();
293+
294+
showSettings = EditorGUILayout.Foldout(showSettings, "Settings", true);
295+
296+
if (showSettings)
297+
{
298+
fontSize = EditorGUILayout.IntSlider("Font Size", fontSize, 16, 60);
299+
displayDuration = EditorGUILayout.Slider("Duration", displayDuration, 0.5f, 5f);
300+
showMouseClicks = EditorGUILayout.Toggle("Mouse Clicks", showMouseClicks);
301+
}
302+
303+
GUILayout.Space(8);
304+
}
305+
}
306+
}

0 commit comments

Comments
 (0)