Skip to content

Instantly share code, notes, and snippets.

@jstine35
Last active December 3, 2022 08:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jstine35/2a0b491cb1c1822debbc2571b487ad8d to your computer and use it in GitHub Desktop.
Save jstine35/2a0b491cb1c1822debbc2571b487ad8d to your computer and use it in GitHub Desktop.
Resolves Editor Keyboard Behavior in Unity Player, so your game can handle CTRL and hotkeys without corrupting your scene
// Summary
// Disables Editor Keyboard Behavior when Unity Player has focus, so your game can handle CTRL and
// without corrupting your scene.
//
// Usage
// * Download or copy/paste and attach this component to a scene management object in your scene.
// * Create a new shortcut profile using Edit->Shortcuts (tedious, you need to pretty much click every
// button and remove every keystroke, one by one).
//
// Remarks
// Editor preferences are stored in the Registry so there's no lightweight way to transfer them to
// other members on your team. Pretty much, everyone needs to perform the tedious step of creating a
// Player profile manually, and possibly for every install of Unity.
//
// Author: Jake Stine (@MysteriousNixon)
// GIST URL: https://gist.github.com/jstine35/2a0b491cb1c1822debbc2571b487ad8d
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.ShortcutManagement;
#endif
#if UNITY_EDITOR
[InitializeOnLoad]
#endif
public class SwapEditorShortcutsOnPlayerFocus : MonoBehaviour
{
[Tooltip("Create a playing profile using Edit->Shortcuts")]
public string PlayingProfileId = "Playing";
private static string LastEditorProfileId;
#if UNITY_EDITOR
private static void SetActiveProfile(string profileId)
{
Debug.Log($"Activating Shortcut profile '{profileId}'");
ShortcutManager.instance.activeProfileId = profileId;
}
void OnApplicationFocus(bool hasFocus) {
var curProfileId = ShortcutManager.instance.activeProfileId;
var newProfileId = LastEditorProfileId;
if (hasFocus) {
if (EditorApplication.isPaused) {
return;
}
newProfileId = PlayingProfileId;
if (string.IsNullOrEmpty(newProfileId)) {
Debug.Log($"PlayingProfileId is empty. Disable component SwapEditorShortcutsOnPlayerFocus to silence this warning.");
return;
}
if (curProfileId != PlayingProfileId) {
LastEditorProfileId = curProfileId;
}
}
else {
newProfileId = LastEditorProfileId;
LastEditorProfileId = null;
}
if (!string.IsNullOrEmpty(newProfileId)) {
SetActiveProfile(newProfileId);
}
}
void OnApplicationPause(bool pauseStatus) {
}
// statically bind Editor's Play/Pause button callbacks.
// pauseStateChanged binding - this is useful to maintain 'expected behavior'. The dev typically wants all
// regular editor hotkeys to be effective any time the player is paused.
//
// playModeStateChanged binding - this is a safeguard / fallback to handle cases where Unity might
// fail to send in-game OnApplicationFocus() callbacks. I haven't specifically seen a case where it
// happens, but it's not unreasonable to think it could happen during some attached-debugging operations.
static SwapEditorShortcutsOnPlayerFocus() {
EditorApplication.playModeStateChanged += DetectEditorPlayModeState;
EditorApplication.pauseStateChanged += DetectEditorPauseState;
}
private static void DetectEditorPauseState(PauseState state) {
if (state == PauseState.Paused) {
OnExitingPlayMode();
}
}
private static void DetectEditorPlayModeState(PlayModeStateChange state) {
if (state == PlayModeStateChange.ExitingPlayMode) {
OnExitingPlayMode();
}
}
private static void OnExitingPlayMode() {
if (!string.IsNullOrEmpty(LastEditorProfileId)) {
SetActiveProfile(LastEditorProfileId);
LastEditorProfileId = null;
}
}
#endif
}
@hassan404
Copy link

Thank you, it has been very helpful! Asking permission to include this code in commercial products while crediting you in comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment