├── .vs └── ClickThroughBlocker │ └── v15 │ ├── sqlite3 │ ├── db.lock │ └── storage.ide │ └── Server │ └── sqlite3 │ ├── db.lock │ └── storage.ide ├── .github └── FUNDING.yml ├── GameData └── 000_ClickThroughBlocker │ ├── PluginData │ ├── FFC.png │ ├── FFM.png │ ├── FFC-24.png │ ├── FFC-38.png │ ├── FFM-24.png │ ├── FFM-38.png │ ├── Image5.png │ ├── lock-24.png │ └── lock-38.png │ ├── ClickThroughBlocker.version │ ├── README.md │ ├── changelog.cfg │ └── LICENSE.md ├── ClickThroughBlocker ├── AssemblyVersion.cs ├── CBTGlobalMonitor.cs ├── Properties │ └── AssemblyInfo.cs ├── FocusLock.cs ├── OnGUILoopCount.cs ├── RegisterToolbar.cs ├── SceneChangeCleanup.cs ├── Log.cs ├── Settings.cs ├── AssemblyVersion.tt ├── ClickThroughBlocker.csproj.180 ├── GlobalFlagStorage.cs ├── ClearInputLocks.cs ├── InstallChecker.cs ├── ClickThroughBlocker.csproj.173 ├── ClickThroughBlocker.csproj.orig ├── ClickThroughBlocker.csproj ├── CBTMonitor.cs ├── OneTimePopup.cs └── ClickThroughBlocker.cs ├── ClickThroughBlocker.version ├── deploy.bat ├── jenkins.txt ├── ClickThroughBlocker.sln ├── .gitignore ├── changelog.cfg ├── Changelog.txt ├── README.md └── LICENSE.md /.vs/ClickThroughBlocker/v15/sqlite3/db.lock: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: linuxgurugamer 2 | -------------------------------------------------------------------------------- /.vs/ClickThroughBlocker/v15/Server/sqlite3/db.lock: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vs/ClickThroughBlocker/v15/sqlite3/storage.ide: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/.vs/ClickThroughBlocker/v15/sqlite3/storage.ide -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/PluginData/FFC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/GameData/000_ClickThroughBlocker/PluginData/FFC.png -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/PluginData/FFM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/GameData/000_ClickThroughBlocker/PluginData/FFM.png -------------------------------------------------------------------------------- /.vs/ClickThroughBlocker/v15/Server/sqlite3/storage.ide: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/.vs/ClickThroughBlocker/v15/Server/sqlite3/storage.ide -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/PluginData/FFC-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/GameData/000_ClickThroughBlocker/PluginData/FFC-24.png -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/PluginData/FFC-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/GameData/000_ClickThroughBlocker/PluginData/FFC-38.png -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/PluginData/FFM-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/GameData/000_ClickThroughBlocker/PluginData/FFM-24.png -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/PluginData/FFM-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/GameData/000_ClickThroughBlocker/PluginData/FFM-38.png -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/PluginData/Image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/GameData/000_ClickThroughBlocker/PluginData/Image5.png -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/PluginData/lock-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/GameData/000_ClickThroughBlocker/PluginData/lock-24.png -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/PluginData/lock-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/HEAD/GameData/000_ClickThroughBlocker/PluginData/lock-38.png -------------------------------------------------------------------------------- /ClickThroughBlocker/AssemblyVersion.cs: -------------------------------------------------------------------------------- 1 | 2 | // This code was generated by a tool. Any changes made manually will be lost 3 | // the next time this code is regenerated. 4 | // 5 | 6 | using System.Reflection; 7 | 8 | [assembly: AssemblyVersion("2.1.10.21")] 9 | [assembly: AssemblyFileVersion("2.1.10.21")] 10 | [assembly: KSPAssembly("ClickThroughBlocker", 2, 1, 0)] -------------------------------------------------------------------------------- /ClickThroughBlocker.version: -------------------------------------------------------------------------------- 1 | { 2 | "NAME": "ClickThroughBlocker", 3 | "URL": "https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/refs/heads/master/ClickThroughBlocker.version", 4 | "DOWNLOAD": "https://github.com/linuxgurugamer/ClickThroughBlocker/releases", 5 | "GITHUB": { 6 | "USERNAME": "linuxgurugamer", 7 | "REPOSITORY": "ClickThroughBlocker" 8 | }, 9 | "VERSION": { 10 | "MAJOR": 2, 11 | "MINOR": 1, 12 | "PATCH": 10, 13 | "BUILD": 22 14 | }, 15 | "KSP_VERSION_MIN": { 16 | "MAJOR": 1, 17 | "MINOR": 11, 18 | "PATCH": 0 19 | }, 20 | "KSP_VERSION_MAX": { 21 | "MAJOR": 1, 22 | "MINOR": 12, 23 | "PATCH": 99 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/ClickThroughBlocker.version: -------------------------------------------------------------------------------- 1 | { 2 | "NAME": "ClickThroughBlocker", 3 | "URL": "https://raw.githubusercontent.com/linuxgurugamer/ClickThroughBlocker/refs/heads/master/ClickThroughBlocker.version", 4 | "DOWNLOAD": "https://github.com/linuxgurugamer/ClickThroughBlocker/releases", 5 | "GITHUB": { 6 | "USERNAME": "linuxgurugamer", 7 | "REPOSITORY": "ClickThroughBlocker" 8 | }, 9 | "VERSION": { 10 | "MAJOR": 2, 11 | "MINOR": 1, 12 | "PATCH": 10, 13 | "BUILD": 21 14 | }, 15 | "KSP_VERSION_MIN": { 16 | "MAJOR": 1, 17 | "MINOR": 11, 18 | "PATCH": 0 19 | }, 20 | "KSP_VERSION_MAX": { 21 | "MAJOR": 1, 22 | "MINOR": 11, 23 | "PATCH": 0 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /deploy.bat: -------------------------------------------------------------------------------- 1 | 2 | @echo off 3 | 4 | rem H is the destination game folder 5 | rem GAMEDIR is the name of the mod folder (usually the mod name) 6 | rem GAMEDATA is the name of the local GameData 7 | rem VERSIONFILE is the name of the version file, usually the same as GAMEDATA, 8 | rem but not always 9 | 10 | set H=%KSPDIR% 11 | 12 | rem set H=R:\KSP_1.12.4 13 | 14 | set GAMEDIR=000_ClickThroughBlocker 15 | set GAMEDATA=GameData 16 | set VERSIONFILE=ClickThroughBlocker.version 17 | 18 | set DP0=r:\dp0\kspdev 19 | 20 | copy /Y "%1%2" "%GAMEDATA%\%GAMEDIR%\Plugins" 21 | copy /Y "%1%3".pdb "%GAMEDATA%\%GAMEDIR%\Plugins 22 | 23 | copy /Y %VERSIONFILE% %GAMEDATA%\%GAMEDIR% 24 | copy /y changelog.cfg %GAMEDATA%\%GAMEDIR% 25 | 26 | xcopy /y /s /I %GAMEDATA%\%GAMEDIR% "%H%\GameData\%GAMEDIR%" 27 | xcopy /y /s /I %GAMEDATA%\%GAMEDIR% "%DP0%\GameData\%GAMEDIR%" 28 | -------------------------------------------------------------------------------- /ClickThroughBlocker/CBTGlobalMonitor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | 4 | #if !DUMMY 5 | namespace ClickThroughFix 6 | { 7 | // This monitor deletes closed windows from the internal list 8 | // Needed for FocusFollowsWindow only 9 | 10 | [KSPAddon(KSPAddon.Startup.AllGameScenes, false)] 11 | class CBTGlobalMonitor : MonoBehaviour 12 | { 13 | void Start() 14 | { 15 | //DontDestroyOnLoad(this); 16 | // GameEvents.onGameSceneLoadRequested.Add(onGameSceneLoadRequested); 17 | FocusLock.focusLockDict.Clear(); 18 | } 19 | 20 | void onGameSceneLoadRequested(GameScenes gs) 21 | { 22 | FocusLock.focusLockDict.Clear(); 23 | } 24 | 25 | 26 | 27 | static internal long globalTimeTics = 0; 28 | void FixedUpdate() 29 | { 30 | globalTimeTics++; 31 | 32 | if (ClearInputLocks.focusFollowsclick) 33 | { 34 | foreach (var w in FocusLock.focusLockDict) 35 | { 36 | if (w.Value.win.lastUpdated < globalTimeTics - 4) 37 | { 38 | FocusLock.FreeLock(w.Key, 1); 39 | w.Value.win.OnDestroy(); 40 | break; 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | #endif -------------------------------------------------------------------------------- /ClickThroughBlocker/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ClickThroughBlocker")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ClickThroughBlocker")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("98f60ab0-2d4d-479d-a77d-b2555934d443")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | //[assembly: AssemblyVersion("1.0.0.0")] 36 | //[assembly: AssemblyFileVersion("1.0.0.0")] 37 | //[assembly: AssemblyVersion("0.1.7.0")] 38 | //[assembly: KSPAssembly("ClickThroughBlocker", 1, 8, 0)] 39 | 40 | -------------------------------------------------------------------------------- /ClickThroughBlocker/FocusLock.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ClickThroughFix 4 | { 5 | internal class FocusLock 6 | { 7 | internal static Dictionary focusLockDict = new Dictionary(); 8 | 9 | internal string lockName; 10 | internal long cnt; 11 | internal ClickThruBlocker.CTBWin win; 12 | 13 | internal FocusLock(string lockName, ClickThruBlocker.CTBWin win) 14 | { 15 | this.lockName = lockName; 16 | cnt = CBTGlobalMonitor.globalTimeTics; 17 | this.win = win; 18 | } 19 | 20 | internal static void SetLock(string lockName, ClickThruBlocker.CTBWin win, int i) 21 | { 22 | FocusLock focusLock; 23 | if (HighLogic.LoadedSceneIsEditor) 24 | EditorLogic.fetch.Lock(true, true, true, lockName); 25 | else 26 | InputLockManager.SetControlLock(ControlTypes.ALLBUTCAMERAS, lockName); 27 | 28 | if (focusLockDict.TryGetValue(lockName, out focusLock)) 29 | { 30 | focusLock.cnt = CBTGlobalMonitor.globalTimeTics; 31 | } 32 | else 33 | { 34 | focusLockDict.Add(lockName, new FocusLock(lockName, win)); 35 | } 36 | } 37 | internal static void FreeLock(string lockName, int i) 38 | { 39 | focusLockDict.Remove(lockName); 40 | // flight 41 | if (!HighLogic.LoadedSceneIsEditor) 42 | InputLockManager.RemoveControlLock(lockName); 43 | else 44 | EditorLogic.fetch.Unlock(lockName); 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /jenkins.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file contains several types of information: 3 | # 4 | # 0 KSP version, if not the current 5 | # 1 Mod install directory, version file to use when building zip file 6 | # 2 Project definitions 7 | # 3 Files to copy, source, dest 8 | # 4 Directory to copy, sourcedir, destdir 9 | # 5 Add ModuleManager to GameData 10 | # 6 Spacedock.info mod id 11 | # 7 Additional folders in the GameData to be included in the final zip 12 | # 8 Additional mods to include, will copy into GameData and will be included in zip 13 | 14 | # Special case if files are in the GameData directory itself 15 | # Special Case: 7:GameData 16 | 17 | # 18 | # All paths are relative to the top git folder of the repo 19 | # 20 | # and must use forward slashes 21 | # 22 | 23 | # 0:KSPVersion 24 | # 0:1.3 25 | 26 | # 1:GAMEDIR, VERSIONFILE [, GITHUBREPO ] 27 | 1:000_ClickThroughBlocker, ClickThroughBlocker.version, ClickThroughBlocker 28 | 29 | # 2:PROJNAME, PROJFILE, VERSIONFILE, PLUGINSFOLDER 30 | 2:ClickThroughBlocker,ClickThroughBlocker/ClickThroughBlocker.csproj,ClickThroughBlocker.version,GameData/000_ClickThroughBlocker/Plugins 31 | 32 | # 3:SOURCEFILE, DESTDIR 33 | 3:ClickThroughBlocker.version,GameData/000_ClickThroughBlocker 34 | 3:changelog.cfg,GameData/000_ClickThroughBlocker 35 | 3:LICENSE.md,GameData/000_ClickThroughBlocker 36 | 3:README.md,GameData/000_ClickThroughBlocker 37 | 38 | # 4:SOURCDIR, DESTDIR 39 | #4:Textures,GameData/ManeuverQueue/Textures 40 | 41 | # 5:ModuleManager 42 | # 5:ModuleManager 43 | 44 | # 6:mod_id 45 | #6:1272 46 | 47 | # 7: AdditionalFolders in the GameData, 1 per line 48 | # Special case if files are in the GameData directory itself 49 | # Special Case: 7:GameData 50 | #7:ConnectedLivingSpace 51 | 52 | # 8: AdditionalMods to include 53 | #8:ConnectedLivingSpace 54 | 55 | # 56 | # End of file 57 | # 58 | -------------------------------------------------------------------------------- /ClickThroughBlocker/OnGUILoopCount.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace ClickThroughFix 4 | { 5 | #if !DUMMY 6 | [KSPAddon(KSPAddon.Startup.Flight, true)] 7 | internal class OnGUILoopCount : MonoBehaviour 8 | { 9 | static long onguiCnt = 0; 10 | 11 | 12 | internal static long GetOnGUICnt() 13 | { 14 | return onguiCnt; 15 | } 16 | private void Start() 17 | { 18 | DontDestroyOnLoad(this); 19 | InvokeRepeating("DoGuiCounter", 5.0f, 0.25f); 20 | } 21 | 22 | long lastonGuiCnt; 23 | private void DoGuiCounter() 24 | { 25 | if (HighLogic.CurrentGame == null || ClearInputLocks.focusFollowsclick) 26 | return; 27 | 28 | lastonGuiCnt = (onguiCnt++) - 1; 29 | 30 | foreach (var win in ClickThruBlocker.winList.Values) 31 | { 32 | if (win.lastLockCycle < lastonGuiCnt) 33 | { 34 | //Log.Info("lastonGuiCnt: " + lastonGuiCnt + "lastLockCycle: " + win.lastLockCycle); 35 | { 36 | if (EditorLogic.fetch != null && win.weLockedEditorInputs) 37 | { 38 | EditorLogic.fetch.Unlock(win.lockName); 39 | win.weLockedEditorInputs = false; 40 | ClickThruBlocker.CTBWin.activeBlockerCnt--; 41 | } 42 | if (win.weLockedFlightInputs && win.lockName != null) 43 | { 44 | InputLockManager.RemoveControlLock(win.lockName); 45 | win.weLockedFlightInputs = false; 46 | } 47 | } 48 | } 49 | } 50 | 51 | } 52 | } 53 | #endif 54 | 55 | } 56 | -------------------------------------------------------------------------------- /ClickThroughBlocker/RegisterToolbar.cs: -------------------------------------------------------------------------------- 1 | using ToolbarControl_NS; 2 | using UnityEngine; 3 | 4 | 5 | namespace ClickThroughFix 6 | { 7 | [KSPAddon(KSPAddon.Startup.MainMenu, true)] 8 | public class RegisterToolbar : MonoBehaviour 9 | { 10 | void Start() 11 | { 12 | ToolbarControl.RegisterMod(ClearInputLocks.MODID, ClearInputLocks.MODNAME); 13 | ToolbarControl.RegisterMod(ClearInputLocks.MODID2, ClearInputLocks.MODNAME2); 14 | GameEvents.onGameNewStart.Add(OnGameNewStart); 15 | GameEvents.onGameStateCreated.Add(OnGameStateCreated); 16 | GameEvents.OnGameSettingsWritten.Add(OnGameSettingsWritten); 17 | DontDestroyOnLoad(this); 18 | } 19 | void OnGameSettingsWritten() 20 | { 21 | if (HighLogic.CurrentGame != null && HighLogic.CurrentGame.Parameters.CustomParams().global) 22 | OneTimePopup.SaveGlobalDefault (HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick); 23 | } 24 | 25 | void OnGameNewStart() 26 | { 27 | bool b = false; 28 | if (OneTimePopup.GetGlobalDefault(ref b)) 29 | { 30 | HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick = b; 31 | HighLogic.CurrentGame.Parameters.CustomParams().showPopup = false; 32 | OneTimePopup.CreatePopUpFlagFile(); 33 | } 34 | } 35 | void OnGameStateCreated(Game g) 36 | { 37 | bool b = false; 38 | if (OneTimePopup.GetGlobalDefault(ref b)) 39 | { 40 | g.Parameters.CustomParams().focusFollowsclick = b; 41 | g.Parameters.CustomParams().showPopup = false; 42 | OneTimePopup.CreatePopUpFlagFile(); 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /ClickThroughBlocker.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30204.135 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClickThroughBlocker", "ClickThroughBlocker\ClickThroughBlocker.csproj", "{98F60AB0-2D4D-479D-A77D-B2555934D443}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{087A2B79-84C9-4FE3-8EFD-7767F79F51A0}" 9 | ProjectSection(SolutionItems) = preProject 10 | buildRelease.bat = buildRelease.bat 11 | changelog.cfg = changelog.cfg 12 | Changelog.txt = Changelog.txt 13 | ClickThroughBlocker.version = ClickThroughBlocker.version 14 | deploy.bat = deploy.bat 15 | jenkins.txt = jenkins.txt 16 | LICENSE.md = LICENSE.md 17 | README.md = README.md 18 | EndProjectSection 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Dummy|Any CPU = Dummy|Any CPU 24 | Release|Any CPU = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {98F60AB0-2D4D-479D-A77D-B2555934D443}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {98F60AB0-2D4D-479D-A77D-B2555934D443}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {98F60AB0-2D4D-479D-A77D-B2555934D443}.Dummy|Any CPU.ActiveCfg = Dummy|Any CPU 30 | {98F60AB0-2D4D-479D-A77D-B2555934D443}.Dummy|Any CPU.Build.0 = Dummy|Any CPU 31 | {98F60AB0-2D4D-479D-A77D-B2555934D443}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {98F60AB0-2D4D-479D-A77D-B2555934D443}.Release|Any CPU.Build.0 = Release|Any CPU 33 | EndGlobalSection 34 | GlobalSection(SolutionProperties) = preSolution 35 | HideSolutionNode = FALSE 36 | EndGlobalSection 37 | GlobalSection(ExtensibilityGlobals) = postSolution 38 | SolutionGuid = {3C62B9F1-E63E-4CFF-88A7-60BB1E88B6C1} 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/README.md: -------------------------------------------------------------------------------- 1 | Having clicked one too many times on one window, only to have it click on the parts underneath (in the Editor), 2 | or click on an unwanted item in flight, I decided to solve the problem with yet another mod 3 | 4 | Mods which use the Click Through Blocker would need to be modified, and this would become a hard dependency for that mod. 5 | 6 | The changes are very simple: 7 | 8 | Replace all calls to GUILayout.Window with ClickThruBlocker.GUILayoutWindow, the parameters are identical 9 | Replace all calls to GUI.Window with ClickThruBlocker.GUIWindow, the parameters are identical 10 | 11 | How it works 12 | 13 | Each call first calls the original method (ie: ClickThruBlocker.GUILayoutWindow will call GUILayout.Window). After the call, 14 | the position of the mouse is checked to see if it was on top of the window Rect, if it is, it then locks the controls so that clicks don't 15 | pass through to any other window. 16 | 17 | Usage 18 | 19 | Add the following to the top of the source: 20 | using ClickThroughFix; 21 | Replace calls to GUILayout.Window with ClickThruBlocker.GUILayoutWindow 22 | Replace calls to GUI.Window with ClickThruBlocker.GUIWindow 23 | 24 | Functions - Identical to the GUI and GUILayout versions 25 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, GUIContent content, GUIStyle style, params GUILayoutOption[] options); 26 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, Texture image, GUIStyle style, params GUILayoutOption[] options); 27 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, string text, GUIStyle style, params GUILayoutOption[] options); 28 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, GUIContent content, params GUILayoutOption[] options); 29 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, Texture image, params GUILayoutOption[] options); 30 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, string text, params GUILayoutOption[] options); 31 | 32 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, Texture image, GUIStyle style); 33 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, string text, GUIStyle style); 34 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, GUIContent content); 35 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, Texture image); 36 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, string text); 37 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, GUIContent title, GUIStyle style); 38 | 39 | Additional functions 40 | 41 | bool MouseIsOverWindow(Rect rect) Returns true if the mouse is over the specified rectangle 42 | -------------------------------------------------------------------------------- /ClickThroughBlocker/SceneChangeCleanup.cs: -------------------------------------------------------------------------------- 1 | using ClickThroughFix; 2 | using System; 3 | using System.Collections; 4 | using UnityEngine; 5 | 6 | namespace ClearAllInputLocks 7 | { 8 | [KSPAddon(KSPAddon.Startup.AllGameScenes, false)] 9 | class SceneChangeCleanup : MonoBehaviour 10 | { 11 | void Start() 12 | { 13 | GameEvents.onGameSceneLoadRequested.Add(onGameSceneLoadRequested); 14 | GameEvents.onGUIApplicationLauncherReady.Add(onGUIApplicationLauncherReady); 15 | GameEvents.onLevelWasLoadedGUIReady.Add(onLevelWasLoadedGUIReady); 16 | } 17 | void OnDestroy() 18 | { 19 | GameEvents.onGameSceneLoadRequested.Remove(onGameSceneLoadRequested); 20 | GameEvents.onGUIApplicationLauncherReady.Remove(onGUIApplicationLauncherReady); 21 | GameEvents.onLevelWasLoadedGUIReady.Remove(onLevelWasLoadedGUIReady); 22 | } 23 | 24 | bool ongameSceneLoadRequestedCalled = false; 25 | void onGameSceneLoadRequested(GameScenes gs) 26 | { 27 | if (!ongameSceneLoadRequestedCalled) 28 | { 29 | ongameSceneLoadRequestedCalled = true; 30 | InputLockManager.ClearControlLocks(); 31 | } 32 | } 33 | 34 | bool onGUIApplicationLauncherReadyCalled = false; 35 | void onGUIApplicationLauncherReady() 36 | { 37 | if (!onGUIApplicationLauncherReadyCalled) 38 | { 39 | onGUIApplicationLauncherReadyCalled = true; 40 | if (!isRunning) 41 | StartCoroutine("CleanupInputLocks"); 42 | } 43 | } 44 | 45 | bool onLevelWasLoadedGUIReadycalled = false; 46 | void onLevelWasLoadedGUIReady(GameScenes gs) 47 | { 48 | if (!onLevelWasLoadedGUIReadycalled) 49 | { 50 | onLevelWasLoadedGUIReadycalled = true; 51 | if (!isRunning) 52 | StartCoroutine("CleanupInputLocks"); 53 | } 54 | } 55 | 56 | void StopStartCoroutine() 57 | { 58 | StopCoroutine("CleanupInputLocks"); 59 | StartCoroutine("CleanupInputLocks"); 60 | } 61 | 62 | bool isRunning = false; 63 | IEnumerator CleanupInputLocks() 64 | { 65 | //Log.Info("CleanUpInputLocks entry"); 66 | isRunning = true; 67 | yield return new WaitForSeconds(HighLogic.CurrentGame.Parameters.CustomParams().cleanupDelay); 68 | if (Versioning.version_major == 1 && Versioning.version_minor < 11) 69 | { 70 | InputLockManager.ClearControlLocks(); 71 | yield return null; 72 | } 73 | isRunning = false; 74 | //Log.Info("CleanUpInputLocks exit"); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ClickThroughBlocker/Log.cs: -------------------------------------------------------------------------------- 1 | #if !DUMMY 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Diagnostics; 7 | 8 | namespace ClickThroughFix 9 | { 10 | internal static class Log 11 | { 12 | internal enum LEVEL 13 | { 14 | OFF = 0, 15 | ERROR = 1, 16 | WARNING = 2, 17 | INFO = 3, 18 | DETAIL = 4, 19 | TRACE = 5 20 | }; 21 | static string PREFIX = "ClickThroughBlocker: "; 22 | 23 | internal static void setTitle(string t) 24 | { 25 | PREFIX = t + ": "; 26 | } 27 | 28 | internal static LEVEL level = LEVEL.INFO; 29 | 30 | 31 | 32 | internal static LEVEL GetLevel() 33 | { 34 | return level; 35 | } 36 | 37 | internal static void SetLevel(LEVEL level) 38 | { 39 | UnityEngine.Debug.Log("log level " + level); 40 | Log.level = level; 41 | } 42 | 43 | internal static LEVEL GetLogLevel() 44 | { 45 | return level; 46 | } 47 | 48 | private static bool IsLevel(LEVEL level) 49 | { 50 | return level == Log.level; 51 | } 52 | 53 | internal static bool IsLogable(LEVEL level) 54 | { 55 | return level <= Log.level; 56 | } 57 | 58 | internal static void Trace(String msg) 59 | { 60 | if (IsLogable(LEVEL.TRACE)) 61 | { 62 | UnityEngine.Debug.Log(PREFIX + msg); 63 | } 64 | } 65 | 66 | internal static void Detail(String msg) 67 | { 68 | if (IsLogable(LEVEL.DETAIL)) 69 | { 70 | UnityEngine.Debug.Log(PREFIX + msg); 71 | } 72 | } 73 | 74 | [ConditionalAttribute("DEBUG")] 75 | internal static void Info(String msg) 76 | { 77 | 78 | if (IsLogable(LEVEL.INFO)) 79 | { 80 | UnityEngine.Debug.Log(PREFIX + msg); 81 | } 82 | } 83 | 84 | // [ConditionalAttribute("DEBUG")] 85 | internal static void Test(String msg) 86 | { 87 | //if (IsLogable(LEVEL.INFO)) 88 | { 89 | UnityEngine.Debug.LogWarning(PREFIX + "TEST:" + msg); 90 | } 91 | } 92 | 93 | 94 | internal static void Warning(String msg) 95 | { 96 | if (IsLogable(LEVEL.WARNING)) 97 | { 98 | UnityEngine.Debug.LogWarning(PREFIX + msg); 99 | } 100 | } 101 | 102 | internal static void Error(String msg) 103 | { 104 | if (IsLogable(LEVEL.ERROR)) 105 | { 106 | UnityEngine.Debug.LogError(PREFIX + msg); 107 | } 108 | } 109 | 110 | internal static void Exception(Exception e) 111 | { 112 | Log.Error("exception caught: " + e.GetType() + ": " + e.Message); 113 | } 114 | 115 | } 116 | } 117 | #endif -------------------------------------------------------------------------------- /ClickThroughBlocker/Settings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using UnityEngine; 9 | 10 | 11 | 12 | namespace ClickThroughFix 13 | { 14 | // http://forum.kerbalspaceprogram.com/index.php?/topic/147576-modders-notes-for-ksp-12/#comment-2754813 15 | // search for "Mod integration into Stock Settings 16 | // HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick 17 | 18 | 19 | 20 | public class CTB : GameParameters.CustomParameterNode 21 | { 22 | public override string Title { get { return "Click-Through-Blocker"; } } // Column header 23 | public override GameParameters.GameMode GameMode { get { return GameParameters.GameMode.ANY; } } 24 | public override string Section { get { return "Click-Through-Blocker"; } } 25 | public override string DisplaySection { get { return "Click-Through-Blocker"; } } 26 | public override int SectionOrder { get { return 1; } } 27 | public override bool HasPresets { get { return false; } } 28 | 29 | [GameParameters.CustomParameterUI("Show Popup at next start", 30 | toolTip = "Clearing this will allow the pop-up window to be displayed at the next game start.\nSetting it after clearing will allow the popup-window to be shown at the next start of a different save")] 31 | public bool showPopup = true; 32 | 33 | [GameParameters.CustomParameterUI("Focus follows mouse click", 34 | toolTip = "Click on a window to move the focus to it")] 35 | public bool focusFollowsclick = false; 36 | 37 | 38 | [GameParameters.CustomParameterUI("Focus change is global", 39 | toolTip = "This will make it a global setting for all games")] 40 | public bool global = true; 41 | 42 | 43 | [GameParameters.CustomFloatParameterUI("Cleanup delay", minValue = 0.1f, maxValue = 5f, displayFormat = "F2", 44 | toolTip = "Time to wait after scene change before clearing all the input locks")] 45 | public float cleanupDelay = 0.5f; 46 | 47 | public override bool Enabled(MemberInfo member, GameParameters parameters) 48 | { 49 | if (Versioning.version_major == 1 && Versioning.version_minor >= 11) 50 | { 51 | return member.Name != "cleanupDelay"; 52 | } 53 | return true; 54 | } 55 | 56 | bool? oldFocusFollowsClick; 57 | 58 | public override bool Interactible(MemberInfo member, GameParameters parameters) 59 | { 60 | if (oldFocusFollowsClick == null) 61 | oldFocusFollowsClick = focusFollowsclick; 62 | 63 | if (oldFocusFollowsClick != focusFollowsclick) 64 | { 65 | oldFocusFollowsClick = focusFollowsclick; 66 | showPopup = false; 67 | } 68 | if (showPopup && OneTimePopup.Instance != null) 69 | OneTimePopup.RemovePopUpFlagFile(); 70 | return true; 71 | } 72 | 73 | public override IList ValidValues(MemberInfo member) { return null; } 74 | 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /ClickThroughBlocker/AssemblyVersion.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="true" language="C#" #> 2 | <#@ import namespace="System.IO" #> 3 | <#@ output extension=".cs" #> 4 | 5 | <#@ assembly name="EnvDTE" #><# /* This assembly provides access to Visual Studio project properties. */ #> 6 | <# 7 | 8 | // Instructions 9 | // 1. Add a new Text Template to the project 10 | // 2. Copy this file into the new template 11 | // 3. Update the string: versionfile with the complete path to the .version file 12 | // 4. Remove the following line from the file AssemblyInfo.cs (usually located in the "Property" folder inside your C# project): 13 | // [assembly: AssemblyVersion("1.0.0.0")] 14 | // 5. Add the following to the PreBuild steps: 15 | // 16 | // set textTemplatingPath="%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\IDE\texttransform.exe" 17 | // %textTemplatingPath% "$(ProjectDir)AssemblyVersion.tt" 18 | 19 | 20 | int major = 0; 21 | int minor = 0; 22 | int build = 0; 23 | int patch = 0; 24 | bool versionSection = false; 25 | 26 | int i = 0; 27 | int i2 = 0; 28 | string s; 29 | 30 | 31 | // For Visual Studio / MSBuild Build-Time Template Resolution 32 | string RootDirectory = System.IO.Path.GetDirectoryName(Host.TemplateFile) + @"\..\"; 33 | 34 | // 35 | // Update the following with the name of the .version file which is in the root directory 36 | // 37 | string versionfile = RootDirectory + "ClickThroughBlocker.version"; 38 | 39 | if (!File.Exists(versionfile)) 40 | { 41 | Write("File: " + versionfile + " missing\n"); 42 | } 43 | 44 | try 45 | { 46 | foreach (var line in File.ReadAllLines(versionfile)) 47 | { 48 | if (line != null) 49 | { 50 | if (!versionSection) 51 | { 52 | if (line.Contains("\"VERSION\"")) 53 | versionSection = true; 54 | } 55 | else 56 | { 57 | if (line.Contains("}")) 58 | versionSection = false; 59 | i = line.IndexOf(":"); 60 | i2 = line.IndexOf(","); 61 | if (i2 == -1) 62 | i2 = line.Length; 63 | if (i >= 0 && i2 >= 0) 64 | { 65 | s = line.Substring(i + 1, i2 - i - 1); 66 | 67 | if (line.Contains("MAJOR")) 68 | Int32.TryParse(s, out major); 69 | 70 | if (line.Contains("MINOR")) 71 | Int32.TryParse(s, out minor); 72 | 73 | if (line.Contains("PATCH")) 74 | Int32.TryParse(s, out patch); 75 | 76 | if (line.Contains("BUILD")) 77 | Int32.TryParse(s, out build); 78 | } 79 | } 80 | } 81 | } 82 | 83 | } 84 | catch 85 | { 86 | major = 1; 87 | minor = 0; 88 | patch = 0; 89 | build = 0; 90 | } 91 | //Write("File done"); 92 | 93 | #> 94 | // This code was generated by a tool. Any changes made manually will be lost 95 | // the next time this code is regenerated. 96 | // 97 | 98 | using System.Reflection; 99 | 100 | [assembly: AssemblyVersion("<#= major #>.<#= minor #>.<#= patch #>.<#= build #>")] 101 | [assembly: AssemblyFileVersion("<#= major #>.<#= minor #>.<#= patch #>.<#= build #>")] 102 | [assembly: KSPAssembly("ClickThroughBlocker", <#= major #>, <#= minor #>, 0)] -------------------------------------------------------------------------------- /ClickThroughBlocker/ClickThroughBlocker.csproj.180: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {98F60AB0-2D4D-479D-A77D-B2555934D443} 8 | Library 9 | Properties 10 | ClickThroughBlocker 11 | ClickThroughBlocker 12 | v3.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | 29 | 30 | prompt 31 | 4 32 | 33 | 34 | bin\Release, dummy\ 35 | 36 | 37 | true 38 | pdbonly 39 | AnyCPU 40 | prompt 41 | MinimumRecommendedRules.ruleset 42 | 43 | 44 | bin\Dummy\ 45 | DUMMY 46 | 47 | 48 | 49 | True 50 | True 51 | AssemblyVersion.tt 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | TextTemplatingFileGenerator 61 | AssemblyVersion.cs 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | False 70 | 71 | 72 | False 73 | 74 | 75 | 76 | 77 | 78 | 79 | start /D D:\Users\jbb\github\ClickThroughBlocker /WAIT deploy.bat $(TargetDir) $(TargetFileName) 80 | 81 | 82 | if $(ConfigurationName) == Release ( 83 | 84 | 85 | 86 | start /D D:\Users\jbb\github\ClickThroughBlocker /WAIT buildRelease.bat $(TargetDir) $(TargetFileName) 87 | 88 | ) 89 | 90 | 91 | 92 | set textTemplatingPath="%25ProgramFiles(x86)%25\Microsoft Visual Studio\2017\Community\Common7\IDE\texttransform.exe" 93 | %25textTemplatingPath%25 "$(ProjectDir)AssemblyVersion.tt" 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /ClickThroughBlocker/GlobalFlagStorage.cs: -------------------------------------------------------------------------------- 1 | #if false 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | using UnityEngine; 9 | using System; 10 | 11 | namespace ClickThroughBlocker 12 | { 13 | class GlobalFlagStorage 14 | { 15 | const string NODE = "CLICKTHROUGHBLOCKER"; 16 | string PATH = KSPUtil.ApplicationRootPath + "GameData/000_ClickThroughBlocker/PluginData/CBT.cfg"; 17 | 18 | ConfigNode configFile; 19 | ConfigNode configFileNode; 20 | 21 | public void Create() 22 | { 23 | if (configFileNode == null) 24 | { 25 | configFile = new ConfigNode(); 26 | } 27 | if (!configFile.HasNode(NODE)) 28 | { 29 | configFileNode = new ConfigNode(NODE); 30 | configFile.SetNode(NODE, configFileNode, true); 31 | } 32 | else 33 | { 34 | if (configFileNode == null) 35 | { 36 | configFileNode = configFile.GetNode(NODE); 37 | 38 | } 39 | } 40 | } 41 | 42 | public bool Load() 43 | { 44 | configFile = ConfigNode.Load(PATH); 45 | if (configFile != null) 46 | configFileNode = configFile.GetNode(NODE); 47 | return configFile != null; 48 | } 49 | 50 | public void Save() 51 | { 52 | configFile.Save(PATH); 53 | } 54 | 55 | public void SetValue(string name, string value) 56 | { 57 | configFileNode.SetValue(name, value, true); 58 | } 59 | 60 | #if false 61 | public void SetValue(string name, Rect rect) 62 | { 63 | SetValue(name + ".x", (int)rect.x); 64 | SetValue(name + ".y", (int)rect.y); 65 | SetValue(name + ".width", (int)rect.width); 66 | SetValue(name + ".height", (int)rect.height); 67 | } 68 | public void SetValue(string name, int i) 69 | { 70 | SetValue(name, i.ToString()); 71 | } 72 | #endif 73 | public void SetValue(string name, bool b) 74 | { 75 | SetValue(name, b.ToString()); 76 | } 77 | 78 | public string GetValue(string name, string d = "") 79 | { 80 | string s = d; 81 | if (name == null) 82 | return ""; 83 | 84 | if (configFileNode.HasValue(name)) 85 | s = configFileNode.GetValue(name); 86 | 87 | return s; 88 | } 89 | 90 | #if false 91 | public Rect GetValue(string name, Rect rect) 92 | { 93 | try 94 | { 95 | rect.x = Convert.ToSingle(GetValue(name + ".x", rect.x.ToString())); 96 | rect.y = Convert.ToSingle(GetValue(name + ".y", rect.y.ToString())); 97 | rect.width = Convert.ToSingle(GetValue(name + ".width", rect.width.ToString())); 98 | rect.height = Convert.ToSingle(GetValue(name + ".height", rect.height.ToString())); 99 | } 100 | catch (Exception e) 101 | { 102 | Debug.LogError("Exception converting: " + name + " - " + e.Message); 103 | } 104 | return rect; 105 | } 106 | public int GetValue(string name, int i = 0) 107 | { 108 | int r; 109 | try 110 | { 111 | r = Convert.ToInt32(GetValue(name, i.ToString())); 112 | } 113 | catch (Exception e) 114 | { 115 | r = i; 116 | Debug.LogError("Exception converting: " + name + " - " + e.Message); 117 | } 118 | return r; 119 | } 120 | #endif 121 | public bool GetValue(string name, bool b = false) 122 | { 123 | bool r; 124 | try 125 | { 126 | 127 | r = Convert.ToBoolean(GetValue(name, b.ToString())); 128 | } 129 | catch (Exception e) 130 | { 131 | r = b; 132 | Debug.LogError("Exception converting: " + name + " - " + e.Message); 133 | } 134 | return r; 135 | } 136 | } 137 | } 138 | #endif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # MSTest test Results 20 | [Tt]est[Rr]esult*/ 21 | [Bb]uild[Ll]og.* 22 | 23 | #NUNIT 24 | *.VisualState.xml 25 | TestResult.xml 26 | 27 | # Build Results of an ATL Project 28 | [Dd]ebugPS/ 29 | [Rr]eleasePS/ 30 | dlldata.c 31 | 32 | *_i.c 33 | *_p.c 34 | *_i.h 35 | *.ilk 36 | *.meta 37 | *.obj 38 | *.pch 39 | *.pdb 40 | *.pgc 41 | *.pgd 42 | *.rsp 43 | *.sbr 44 | *.tlb 45 | *.tli 46 | *.tlh 47 | *.tmp 48 | *.tmp_proj 49 | *.log 50 | *.vspscc 51 | *.vssscc 52 | .builds 53 | *.pidb 54 | *.svclog 55 | *.scc 56 | 57 | # Chutzpah Test files 58 | _Chutzpah* 59 | 60 | # Visual C++ cache files 61 | ipch/ 62 | *.aps 63 | *.ncb 64 | *.opensdf 65 | *.sdf 66 | *.cachefile 67 | 68 | # Visual Studio profiler 69 | *.psess 70 | *.vsp 71 | *.vspx 72 | 73 | # TFS 2012 Local Workspace 74 | $tf/ 75 | 76 | # Guidance Automation Toolkit 77 | *.gpState 78 | 79 | # ReSharper is a .NET coding add-in 80 | _ReSharper*/ 81 | *.[Rr]e[Ss]harper 82 | *.DotSettings.user 83 | 84 | # JustCode is a .NET coding addin-in 85 | .JustCode 86 | 87 | # TeamCity is a build add-in 88 | _TeamCity* 89 | 90 | # DotCover is a Code Coverage Tool 91 | *.dotCover 92 | 93 | # NCrunch 94 | *.ncrunch* 95 | _NCrunch_* 96 | .*crunch*.local.xml 97 | 98 | # MightyMoose 99 | *.mm.* 100 | AutoTest.Net/ 101 | 102 | # Web workbench (sass) 103 | .sass-cache/ 104 | 105 | # Installshield output folder 106 | [Ee]xpress/ 107 | 108 | # DocProject is a documentation generator add-in 109 | DocProject/buildhelp/ 110 | DocProject/Help/*.HxT 111 | DocProject/Help/*.HxC 112 | DocProject/Help/*.hhc 113 | DocProject/Help/*.hhk 114 | DocProject/Help/*.hhp 115 | DocProject/Help/Html2 116 | DocProject/Help/html 117 | 118 | # Click-Once directory 119 | publish/ 120 | 121 | # Publish Web Output 122 | *.[Pp]ublish.xml 123 | *.azurePubxml 124 | 125 | # NuGet Packages Directory 126 | packages/ 127 | ## TODO: If the tool you use requires repositories.config uncomment the next line 128 | #!packages/repositories.config 129 | 130 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 131 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) 132 | !packages/build/ 133 | 134 | # Windows Azure Build Output 135 | csx/ 136 | *.build.csdef 137 | 138 | # Windows Store app package directory 139 | AppPackages/ 140 | 141 | # Others 142 | sql/ 143 | *.Cache 144 | ClientBin/ 145 | [Ss]tyle[Cc]op.* 146 | ~$* 147 | *~ 148 | *.dbmdl 149 | *.dbproj.schemaview 150 | *.pfx 151 | *.publishsettings 152 | node_modules/ 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | *.mdf 166 | *.ldf 167 | 168 | # Business Intelligence projects 169 | *.rdl.data 170 | *.bim.layout 171 | *.bim_*.settings 172 | 173 | # Microsoft Fakes 174 | FakesAssemblies/ 175 | 176 | # ========================= 177 | # Operating System Files 178 | # ========================= 179 | 180 | # OSX 181 | # ========================= 182 | 183 | .DS_Store 184 | .AppleDouble 185 | .LSOverride 186 | 187 | # Icon must ends with two \r. 188 | Icon 189 | 190 | # Thumbnails 191 | ._* 192 | 193 | # Files that might appear on external disk 194 | .Spotlight-V100 195 | .Trashes 196 | 197 | # Directories potentially created on remote AFP share 198 | .AppleDB 199 | .AppleDesktop 200 | Network Trash Folder 201 | Temporary Items 202 | .apdisk 203 | 204 | 205 | 206 | # Windows 207 | # ========================= 208 | 209 | # Windows image file caches 210 | Thumbs.db 211 | ehthumbs.db 212 | 213 | # Folder config file 214 | Desktop.ini 215 | 216 | # Recycle Bin used on file shares 217 | $RECYCLE.BIN/ 218 | 219 | # Windows Installer files 220 | *.cab 221 | *.msi 222 | *.msm 223 | *.msp 224 | 225 | # Windows shortcuts 226 | *.lnk 227 | 228 | # 229 | # Vim files 230 | # 231 | *~ 232 | *.swp 233 | *.dll 234 | *.pdb 235 | .vs 236 | .vs/* 237 | -------------------------------------------------------------------------------- /ClickThroughBlocker/ClearInputLocks.cs: -------------------------------------------------------------------------------- 1 | using ToolbarControl_NS; 2 | using KSP.UI.Screens; 3 | using KSP.Localization; 4 | using System; 5 | using System.IO; 6 | 7 | using KSP.IO; 8 | using UnityEngine; 9 | 10 | namespace ClickThroughFix 11 | { 12 | [KSPAddon(KSPAddon.Startup.AllGameScenes, false)] 13 | public class ClearInputLocks : MonoBehaviour 14 | { 15 | internal const string MODID = "CTB_ClearInputLocks_ns"; 16 | internal const string MODID2 = "CTB_Toggle_ns"; 17 | internal const string MODNAME = "ClickThroughBlocker: Clear Input Locks"; 18 | internal const string MODNAME2 = "ClickThroughBlocker: Toggle Mode"; 19 | static internal ToolbarControl toolbarControl = null; 20 | static internal ToolbarControl clickThroughToggleControl = null; 21 | static internal bool focusFollowsclick = false; 22 | 23 | const string FFC_38 = "000_ClickThroughBlocker/PluginData/FFC-38"; 24 | const string FFM_38 = "000_ClickThroughBlocker/PluginData/FFM-38"; 25 | const string FFC_24 = "000_ClickThroughBlocker/PluginData/FFC-24"; 26 | const string FFM_24 = "000_ClickThroughBlocker/PluginData/FFM-24"; 27 | 28 | 29 | void Start() 30 | { 31 | AddToolbarButton(); 32 | } 33 | 34 | void AddToolbarButton() 35 | { 36 | if (toolbarControl == null) 37 | { 38 | toolbarControl = gameObject.AddComponent(); 39 | toolbarControl.AddToAllToolbars(null, null, 40 | ApplicationLauncher.AppScenes.SPACECENTER | 41 | ApplicationLauncher.AppScenes.FLIGHT | 42 | ApplicationLauncher.AppScenes.MAPVIEW | 43 | ApplicationLauncher.AppScenes.VAB | 44 | ApplicationLauncher.AppScenes.SPH | 45 | ApplicationLauncher.AppScenes.TRACKSTATION, 46 | MODID, 47 | "ClearInputLocks", 48 | "000_ClickThroughBlocker/PluginData/lock-38", 49 | "000_ClickThroughBlocker/PluginData/lock-24", 50 | MODNAME 51 | ); 52 | toolbarControl.AddLeftRightClickCallbacks(ClearInputLocksToggle, CallModeWindow); 53 | 54 | 55 | 56 | clickThroughToggleControl = gameObject.AddComponent(); 57 | clickThroughToggleControl.AddToAllToolbars(ToggleFocusSetting, ToggleFocusSetting, 58 | ApplicationLauncher.AppScenes.SPACECENTER | 59 | ApplicationLauncher.AppScenes.FLIGHT | 60 | ApplicationLauncher.AppScenes.MAPVIEW | 61 | ApplicationLauncher.AppScenes.VAB | 62 | ApplicationLauncher.AppScenes.SPH | 63 | ApplicationLauncher.AppScenes.TRACKSTATION, 64 | MODID2, 65 | "CTBToggle", 66 | FFC_38, 67 | FFM_38, 68 | FFC_24, 69 | FFM_24, 70 | MODNAME2 71 | ); 72 | } 73 | } 74 | 75 | void OnDestroy() 76 | { 77 | if (toolbarControl != null) 78 | { 79 | toolbarControl.OnDestroy(); 80 | Destroy(toolbarControl); 81 | } 82 | } 83 | 84 | static internal void ToggleFocusSetting() 85 | { 86 | focusFollowsclick = !focusFollowsclick; 87 | if (focusFollowsclick) 88 | clickThroughToggleControl.SetTexture(FFC_38, FFC_24); 89 | else 90 | clickThroughToggleControl.SetTexture(FFM_38, FFM_24); 91 | } 92 | static internal void ClearInputLocksToggle() 93 | { 94 | InputLockManager.ClearControlLocks(); 95 | ScreenMessages.PostScreenMessage("All Input Locks Cleared", 5); 96 | } 97 | 98 | internal static MonoBehaviour modeWindow = null; 99 | void CallModeWindow() 100 | { 101 | //ClickThroughFix.Log.Info("CallModeWindow, modeWindow: " + (modeWindow != null)); 102 | if (modeWindow == null) 103 | { 104 | HighLogic.CurrentGame.Parameters.CustomParams().showPopup = true; 105 | modeWindow = gameObject.AddComponent(); 106 | } 107 | else 108 | { 109 | Destroy(modeWindow); 110 | InputLockManager.ClearControlLocks(); 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /ClickThroughBlocker/InstallChecker.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Based on the InstallChecker from the Kethane mod for Kerbal Space Program. 3 | * https://github.com/Majiir/Kethane/blob/b93b1171ec42b4be6c44b257ad31c7efd7ea1702/Plugin/InstallChecker.cs 4 | * 5 | * Original is (C) Copyright Majiir. 6 | * CC0 Public Domain (http://creativecommons.org/publicdomain/zero/1.0/) 7 | * http://forum.kerbalspaceprogram.com/threads/65395-CompatibilityChecker-Discussion-Thread?p=899895&viewfull=1#post899895 8 | * 9 | * This file has been modified extensively and is released under the same license. 10 | */ 11 | using System; 12 | using System.IO; 13 | using System.Linq; 14 | using System.Reflection; 15 | using UnityEngine; 16 | 17 | namespace ClickThroughFix 18 | { 19 | [KSPAddon(KSPAddon.Startup.Instantly, true)] 20 | internal class Startup : MonoBehaviour 21 | { 22 | private void Start() 23 | { 24 | string v = "n/a"; 25 | AssemblyTitleAttribute attributes = (AssemblyTitleAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyTitleAttribute), false); 26 | string title = attributes?.Title; 27 | if (title == null) 28 | { 29 | title = "TitleNotAvailable"; 30 | } 31 | v = Assembly.GetExecutingAssembly().FullName; 32 | if (v == null) 33 | { 34 | v = "VersionNotAvailable"; 35 | } 36 | Debug.Log("[" + title + "] Version " + v); 37 | } 38 | } 39 | 40 | [KSPAddon(KSPAddon.Startup.MainMenu, true)] 41 | internal class InstallChecker : MonoBehaviour 42 | { 43 | internal const string MODNAME = "ClickThroughBlocker"; 44 | internal const string FOLDERNAME = "000_ClickThroughBlocker"; 45 | internal const string EXPECTEDPATH = FOLDERNAME + "/Plugins"; 46 | 47 | protected void Start() 48 | { 49 | // Search for this mod's DLL existing in the wrong location. This will also detect duplicate copies because only one can be in the right place. 50 | var assemblies = AssemblyLoader.loadedAssemblies.Where(a => a.assembly.GetName().Name == Assembly.GetExecutingAssembly().GetName().Name).Where(a => a.url != EXPECTEDPATH); 51 | if (assemblies.Any()) 52 | { 53 | var badPaths = assemblies.Select(a => a.path).Select(p => Uri.UnescapeDataString(new Uri(Path.GetFullPath(KSPUtil.ApplicationRootPath)).MakeRelativeUri(new Uri(p)).ToString().Replace('/', Path.DirectorySeparatorChar))); 54 | PopupDialog.SpawnPopupDialog 55 | ( 56 | new Vector2(0.5f, 0.5f), 57 | new Vector2(0.5f, 0.5f), 58 | "test", 59 | "Incorrect " + MODNAME + " Installation", 60 | MODNAME + " has been installed incorrectly and will not function properly. All files should be located in KSP/GameData/" + FOLDERNAME + ". Do not move any files from inside that folder.\n\nIncorrect path(s):\n" + String.Join("\n", badPaths.ToArray()), 61 | "OK", 62 | false, 63 | HighLogic.UISkin 64 | ); 65 | Debug.Log("Incorrect " + MODNAME + " Installation: " + MODNAME + " has been installed incorrectly and will not function properly. All files should be located in KSP/GameData/" + EXPECTEDPATH + ". Do not move any files from inside that folder.\n\nIncorrect path(s):\n" + String.Join("\n", badPaths.ToArray()) 66 | 67 | ); 68 | 69 | } 70 | 71 | //// Check for Module Manager 72 | //if (!AssemblyLoader.loadedAssemblies.Any(a => a.assembly.GetName().Name.StartsWith("ModuleManager") && a.url == "")) 73 | //{ 74 | // PopupDialog.SpawnPopupDialog("Missing Module Manager", 75 | // modName + " requires the Module Manager mod in order to function properly.\n\nPlease download from http://forum.kerbalspaceprogram.com/threads/55219 and copy to the KSP/GameData/ directory.", 76 | // "OK", false, HighLogic.Skin); 77 | //} 78 | 79 | CleanupOldVersions(); 80 | } 81 | 82 | /* 83 | * Tries to fix the install if it was installed over the top of a previous version 84 | */ 85 | void CleanupOldVersions() 86 | { 87 | try 88 | { 89 | } 90 | catch (Exception ex) 91 | { 92 | Debug.LogError("-ERROR- " + this.GetType().FullName + "[" + this.GetInstanceID().ToString("X") + "][" + Time.time.ToString("0.00") + "]: " + 93 | "Exception caught while cleaning up old files.\n" + ex.Message + "\n" + ex.StackTrace); 94 | 95 | } 96 | } 97 | } 98 | } 99 | 100 | -------------------------------------------------------------------------------- /ClickThroughBlocker/ClickThroughBlocker.csproj.173: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {98F60AB0-2D4D-479D-A77D-B2555934D443} 8 | Library 9 | Properties 10 | ClickThroughBlocker 11 | ClickThroughBlocker 12 | v3.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | 29 | 30 | prompt 31 | 4 32 | 33 | 34 | bin\Release, dummy\ 35 | 36 | 37 | true 38 | pdbonly 39 | AnyCPU 40 | prompt 41 | MinimumRecommendedRules.ruleset 42 | 43 | 44 | bin\Dummy\ 45 | DUMMY 46 | 47 | 48 | 49 | True 50 | True 51 | AssemblyVersion.tt 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | TextTemplatingFileGenerator 61 | AssemblyVersion.cs 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | False 70 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\Assembly-CSharp.dll 71 | 72 | 73 | False 74 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\Assembly-CSharp-firstpass.dll 75 | 76 | 77 | 78 | False 79 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\UnityEngine.dll 80 | 81 | 82 | False 83 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\UnityEngine.UI.dll 84 | 85 | 86 | 87 | 88 | 89 | 90 | start /D D:\Users\jbb\github\ClickThroughBlocker /WAIT deploy.bat $(TargetDir) $(TargetFileName) 91 | 92 | 93 | if $(ConfigurationName) == Release ( 94 | 95 | 96 | 97 | start /D D:\Users\jbb\github\ClickThroughBlocker /WAIT buildRelease.bat $(TargetDir) $(TargetFileName) 98 | 99 | ) 100 | 101 | 102 | 103 | set textTemplatingPath="%25ProgramFiles(x86)%25\Microsoft Visual Studio\2017\Community\Common7\IDE\texttransform.exe" 104 | %25textTemplatingPath%25 "$(ProjectDir)AssemblyVersion.tt" 105 | 106 | 107 | -------------------------------------------------------------------------------- /ClickThroughBlocker/ClickThroughBlocker.csproj.orig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {98F60AB0-2D4D-479D-A77D-B2555934D443} 8 | Library 9 | Properties 10 | ClickThroughBlocker 11 | ClickThroughBlocker 12 | v3.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | 29 | 30 | prompt 31 | 4 32 | 33 | 34 | bin\Release, dummy\ 35 | 36 | 37 | true 38 | pdbonly 39 | AnyCPU 40 | prompt 41 | MinimumRecommendedRules.ruleset 42 | 43 | 44 | bin\Dummy\ 45 | DUMMY 46 | 47 | 48 | 49 | True 50 | True 51 | AssemblyVersion.tt 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | TextTemplatingFileGenerator 61 | AssemblyVersion.cs 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | False 70 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\Assembly-CSharp.dll 71 | 72 | 73 | False 74 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\Assembly-CSharp-firstpass.dll 75 | 76 | 77 | 78 | False 79 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\UnityEngine.dll 80 | 81 | 82 | False 83 | R:\KSP_1.7.3_dev\KSP_x64_Data\Managed\UnityEngine.UI.dll 84 | 85 | 86 | 87 | 88 | 89 | 90 | start /D D:\Users\jbb\github\ClickThroughBlocker /WAIT deploy.bat $(TargetDir) $(TargetFileName) 91 | 92 | 93 | if $(ConfigurationName) == Release ( 94 | 95 | 96 | 97 | start /D D:\Users\jbb\github\ClickThroughBlocker /WAIT buildRelease.bat $(TargetDir) $(TargetFileName) 98 | 99 | ) 100 | 101 | 102 | 103 | set textTemplatingPath="%25ProgramFiles(x86)%25\Microsoft Visual Studio\2017\Community\Common7\IDE\texttransform.exe" 104 | %25textTemplatingPath%25 "$(ProjectDir)AssemblyVersion.tt" 105 | 106 | 107 | -------------------------------------------------------------------------------- /ClickThroughBlocker/ClickThroughBlocker.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {98F60AB0-2D4D-479D-A77D-B2555934D443} 8 | Library 9 | Properties 10 | ClickThroughFix 11 | ClickThroughBlocker 12 | v4.7.2 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | false 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | 31 | 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | bin\Release, dummy\ 38 | 39 | 40 | true 41 | pdbonly 42 | AnyCPU 43 | prompt 44 | MinimumRecommendedRules.ruleset 45 | 46 | 47 | bin\Dummy\ 48 | DUMMY 49 | 50 | 51 | 52 | True 53 | True 54 | AssemblyVersion.tt 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | TextTemplatingFileGenerator 74 | AssemblyVersion.cs 75 | 76 | 77 | 78 | 79 | False 80 | 81 | 82 | False 83 | 84 | 85 | 86 | $(KSPDIR)\GameData\001_ToolbarControl\Plugins\ToolbarControl.dll 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | set KSPDIR=$(KSPDIR) 96 | 97 | IF "%25KSPDIR%25"=="" ( 98 | 99 | ECHO Configuration error - KSPDIR not specified in project. 100 | 101 | ECHO Either set KSPDIR environment variable or edit BetterLoadSaveGame.Common.props 102 | 103 | PAUSE 104 | 105 | GOTO DONE 106 | 107 | ) 108 | 109 | start /D $(SolutionDir) /WAIT deploy.bat $(TargetDir) $(TargetFileName) $(TargetName) 110 | 111 | if $(ConfigurationName) == Release ( 112 | 113 | start /D $(SolutionDir) /WAIT buildRelease.bat $(TargetDir) $(TargetFileName) $(TargetName) 114 | 115 | ) 116 | 117 | 118 | 119 | "$(DevEnvDir)\texttransform.exe" "$(ProjectDir)AssemblyVersion.tt" 120 | 121 | -------------------------------------------------------------------------------- /ClickThroughBlocker/CBTMonitor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | using KSP.UI.Screens; 4 | 5 | 6 | #if !DUMMY 7 | namespace ClickThroughFix 8 | { 9 | internal class PartEAPS 10 | { 11 | 12 | internal uint persistentId; 13 | internal Part p; 14 | internal EditorActionPartSelector eaps; 15 | 16 | internal PartEAPS(Part p) 17 | { 18 | this.persistentId = p.persistentId; 19 | this.p = p; 20 | this.eaps = p.GetComponent(); 21 | } 22 | } 23 | 24 | [KSPAddon(KSPAddon.Startup.SpaceCentre, true)] 25 | class CBTMonitor : MonoBehaviour 26 | { 27 | static internal Dictionary partEAPSDict; 28 | 29 | void Start() 30 | { 31 | DontDestroyOnLoad(this); 32 | GameEvents.onGameSceneLoadRequested.Add(onGameSceneLoadRequested); 33 | GameEvents.onEditorShipModified.Add(_onEditorShipModified); 34 | GameEvents.onLevelWasLoadedGUIReady.Add(onLevelWasLoadedGUIReady); 35 | 36 | ClickThruBlocker.CTBWin.activeBlockerCnt = 0; 37 | partEAPSDict = new Dictionary(); 38 | } 39 | 40 | void onGameSceneLoadRequested(GameScenes gs) 41 | { 42 | ClickThruBlocker.CTBWin.activeBlockerCnt = 0; 43 | partEAPSDict.Clear(); 44 | } 45 | 46 | void ScanParts(List parts) 47 | { 48 | for (int i = parts.Count - 1; i >= 0; i--) 49 | { 50 | if (!partEAPSDict.ContainsKey(parts[i].persistentId)) 51 | { 52 | partEAPSDict.Add(parts[i].persistentId, new PartEAPS(parts[i])); 53 | } 54 | } 55 | } 56 | void _onEditorShipModified(ShipConstruct sc) 57 | { 58 | if (sc != null && sc.parts != null) 59 | { 60 | ScanParts(sc.parts); 61 | } 62 | } 63 | 64 | void onLevelWasLoadedGUIReady(GameScenes gs) 65 | { 66 | if (HighLogic.LoadedSceneIsEditor) 67 | { 68 | if (EditorLogic.fetch != null && EditorLogic.fetch.ship != null && EditorLogic.fetch.ship.Parts != null) 69 | ScanParts(EditorLogic.fetch.ship.Parts); 70 | } 71 | } 72 | 73 | // this whole mess below is to work around a stock bug. 74 | // The bug is that the editor ignores the lock when the Action Group pane is shown. 75 | // So we have to each time, clear all locks and then reset those which were active when 76 | // the mouse moved over a protected window 77 | void Update() 78 | { 79 | if (HighLogic.LoadedSceneIsEditor && ClearInputLocks.focusFollowsclick) 80 | return; 81 | if (ClickThruBlocker.CTBWin.activeBlockerCnt > 0) 82 | { 83 | //Log.Info("Setting Mouse.HoveredPart to null & deselecting all parts"); 84 | Mouse.HoveredPart = null; 85 | 86 | if (EditorLogic.fetch == null) 87 | { 88 | return; 89 | } 90 | for (int i = EditorLogic.fetch.ship.Parts.Count - 1; i >= 0; i--) 91 | { 92 | EditorActionPartSelector selector = partEAPSDict[EditorLogic.fetch.ship.Parts[i].persistentId].eaps; // EditorLogic.fetch.ship.Parts[i].GetComponent(); 93 | if (selector != null) 94 | selector.Deselect(); 95 | } 96 | 97 | if (EditorActionGroups.Instance != null) 98 | { 99 | if (EditorActionGroups.Instance.HasSelectedParts()) 100 | EditorActionGroups.Instance.ClearSelection(true); 101 | for (int i = ClickThruBlocker.CTBWin.selectedParts.Count - 1; i >= 0; i--) 102 | //for (int i = 0; i < ClickThruBlocker.CTBWin.selectedParts.Count; i++) 103 | { 104 | EditorActionPartSelector selector = partEAPSDict[ClickThruBlocker.CTBWin.selectedParts[i].persistentId].eaps; // ClickThruBlocker.CTBWin.selectedParts[i].GetComponent(); 105 | if (selector != null) 106 | EditorActionGroups.Instance.AddToSelection(selector); 107 | } 108 | } 109 | } 110 | 111 | } 112 | 113 | //static internal long timeTics = 0; 114 | int d; 115 | void LateUpdate() 116 | { 117 | if (HighLogic.CurrentGame == null || 118 | ClearInputLocks.focusFollowsclick) // || 119 | //(!HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick && !HighLogic.LoadedSceneIsEditor)) 120 | return; 121 | 122 | d = -1; 123 | ClickThruBlocker.CTBWin win = null; 124 | { 125 | foreach (var w in ClickThruBlocker.winList) 126 | { 127 | //Log.Info("LateUpdate, w.Value.lastUpdated: " + w.Value.lastUpdated); 128 | if (w.Value.lastUpdated + 4 < CBTGlobalMonitor.globalTimeTics) //+ 0.05 < Planetarium.GetUniversalTime()) 129 | { 130 | d = w.Key; 131 | win = w.Value; 132 | break; 133 | } 134 | } 135 | if (d != -1) 136 | { 137 | win.OnDestroy(); 138 | } 139 | } 140 | } 141 | } 142 | } 143 | #endif -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/changelog.cfg: -------------------------------------------------------------------------------- 1 | KERBALCHANGELOG 2 | { 3 | showChangelog = True //optional but strongly recommended (will be created if non-existant) 4 | modName = Click Through Blocker //required 5 | license = Lesser GPLv3 6 | author = Linuxgurugamer 7 | 8 | VERSION 9 | { 10 | version = 2.1.10.21 11 | CHANGE 12 | { 13 | change = Fixed another nullref when entering game 14 | 15 | type = update 16 | } 17 | } 18 | VERSION 19 | { 20 | version = 2.1.10.20 21 | CHANGE 22 | { 23 | change = Fixed nullref when entering game 24 | 25 | type = update 26 | } 27 | } 28 | 29 | 30 | VERSION 31 | { 32 | version = 2.1.10.19 33 | CHANGE 34 | { 35 | change = Fixed issue where changing the FocusFollowsClick in the settings wasn't being saved properly 36 | change = Fixed issue where changing the global setting in the settings wasn't being honored 37 | 38 | type = update 39 | } 40 | } 41 | VERSION 42 | { 43 | version = 2.1.10.18 44 | CHANGE 45 | { 46 | change = Fixed a memory leak where two game events were being used, added a DontDestroyOnLoad to RegisterToolbar 47 | change = Updated version number to avoid dependency issues 48 | type = update 49 | } 50 | } 51 | VERSION 52 | { 53 | version = 0.1.10.17 54 | CHANGE 55 | { 56 | change = Added AssemblyFileVersion, needed for new KSP 1.12 dll verification 57 | change = Added InstallChecker to ensure installation into correct directory 58 | type = update 59 | } 60 | } 61 | VERSION 62 | { 63 | version = 0.1.10.16 64 | CHANGE 65 | { 66 | change = Fixed issue on 1.11 where a uncontrolled ship would be controllable when changing scenes to it 67 | type = update 68 | } 69 | } 70 | VERSION 71 | { 72 | version = 0.1.10.15 73 | CHANGE 74 | { 75 | change = Fixed issue in editor where a single open window which was closed was leaving everything 76 | type = update 77 | } 78 | } 79 | 80 | VERSION 81 | { 82 | version = 0.1.10.14 83 | CHANGE 84 | { 85 | change = Fixed performance issue in the editor when FocusFollowsMouse was active 86 | subchange = Two problems: 87 | subchange = GetComponent was being called on every part 88 | subchange = EditorActionGroups.Instance.ClearSelection was being called every time through Update() 89 | change = Added global value for FocusFollowsClick or FocusFollowsMouse for all new saves 90 | type = update 91 | } 92 | } 93 | 94 | VERSION 95 | { 96 | version = 0.1.10.13 97 | CHANGE 98 | { 99 | change = Fixed inputlocks not being cleared when canceling the window 100 | change = Added mode toggle on new button to allow toggling between different modes during the game 101 | change = Updated settings to make it clear if popup will be shown next time in the space center 102 | change = Added code to disable the ShowPopup flag if the focusFollowsClick is changed in the settings 103 | change = Thanks to github user @SteveBenz for this: Make the configuration file not depend on Environment.CurrentDirectory and instead depend on the deployment location of the DLL 104 | type = update 105 | } 106 | } 107 | VERSION 108 | { 109 | version = 0.1.10.12 110 | CHANGE 111 | { 112 | change = Fixed inputlocks not being cleared when setting FocusFollowsMouse 113 | type = update 114 | } 115 | } 116 | VERSION 117 | { 118 | version = 0.1.10.11 119 | CHANGE 120 | { 121 | change = Fixed overly aggressive CBTMonitor which was causing the vessel highlighting to stop in the editor when FocusFollowsMouse was set 122 | type = update 123 | } 124 | } 125 | VERSION 126 | { 127 | version = 0.1.10.10 128 | CHANGE 129 | { 130 | change = Fix nullrefs upong returning to mainmenu by adding check for no game loaded (ie: returning to main menu) in CBTMonitor.Update & CBTMonitor.LateUpdate 131 | type = update 132 | } 133 | } 134 | 135 | VERSION 136 | { 137 | version = 0.1.10.9 138 | CHANGE 139 | { 140 | change = Fixed lock issues 141 | type = update 142 | subchange = Fixed Popupshown.cfg from having endless repeats of the popupshown = true appended 143 | subchange = Fixed error which caused buildings to be non-clickable if clicking on a control in the window closed it (such as an X or a Close button) 144 | subchange = Made all members of Log class to be internal, to avoid conflicts with KSP_Log 145 | subchange = Modified the CBTMonitor to run in all scenes, needed for FocusToClick to work properly 146 | } 147 | } 148 | 149 | VERSION 150 | { 151 | version = 1.0.10.7 152 | CHANGE 153 | { 154 | change = Internal cleanup 155 | type = update 156 | subchange = Made all members of Log class to be internal, to avoid conflicts with KSP_Log 157 | } 158 | } 159 | 160 | VERSION 161 | { 162 | version = 1.0.10.6 163 | CHANGE 164 | { 165 | change = Added missing files 166 | type = update 167 | } 168 | } 169 | 170 | VERSION 171 | { 172 | version = 1.0.10.5 173 | CHANGE 174 | { 175 | change = Cleanup Input Locks 176 | type = update 177 | subchange = Added cleanup class to cleanup all input locks after a delay, immediately upon changing scenes 178 | subchange = Added cleanup delay to settings page 179 | } 180 | } 181 | 182 | VERSION 183 | { 184 | version = 1.0.10.4 185 | CHANGE 186 | { 187 | change = Minimod Input Locks 188 | type = update 189 | subchange = Added MiniMod to clear input locks via toolbar button, right-click brings up window 190 | subchange = Added one-time popup window 191 | subchange = Added ToolbarController as a dependency 192 | } 193 | } 194 | VERSION 195 | { 196 | version = 1.0.10.2 197 | CHANGE 198 | { 199 | change = Initial Focus Follows Click and other optimizations 200 | type = update 201 | subchange = Removed need to save window rect 202 | subchange = Added Focus Follows Click mode 203 | subchange = Reorganized code a bit 204 | subchange = Removed some unnecessary assignments 205 | subchange = Added stock settings page to support the FocusFollowsClick mode 206 | } 207 | } 208 | VERSION 209 | { 210 | version = 1.0.10.1 211 | CHANGE 212 | { 213 | change = Minor optimizations 214 | type = update 215 | subchange = Modified the CBTMonitor to not run in any scene other than the editor 216 | subchange = Fixed window data not getting cleared properly 217 | } 218 | } 219 | VERSION 220 | { 221 | version = 1.0.10 222 | CHANGE 223 | { 224 | change = Initial commit for Focus Follows Click 225 | type = HighPriority 226 | subchange = Added Settings page 227 | subchange = Added new setting to specify Focus follows Click 228 | subchange = Added code to have the focus follow the click instead of the mouse, for both editor and flight modes 229 | subchange = Added initial window to select mode, shows one time only 230 | } 231 | } 232 | } -------------------------------------------------------------------------------- /changelog.cfg: -------------------------------------------------------------------------------- 1 | KERBALCHANGELOG 2 | { 3 | showChangelog = True //optional but strongly recommended (will be created if non-existant) 4 | modName = Click Through Blocker //required 5 | license = Lesser GPLv3 6 | author = Linuxgurugamer 7 | 8 | VERSION 9 | { 10 | version = 2.1.10.22 11 | CHANGE 12 | { 13 | change = Updated version file to use github for version info 14 | change = Copied webpage to README.md 15 | 16 | 17 | type = update 18 | } 19 | } 20 | VERSION 21 | { 22 | version = 2.1.10.21 23 | CHANGE 24 | { 25 | change = Fixed another nullref when entering game 26 | 27 | type = update 28 | } 29 | } 30 | VERSION 31 | { 32 | version = 2.1.10.20 33 | CHANGE 34 | { 35 | change = Fixed nullref when entering game 36 | 37 | type = update 38 | } 39 | } 40 | 41 | 42 | VERSION 43 | { 44 | version = 2.1.10.19 45 | CHANGE 46 | { 47 | change = Fixed issue where changing the FocusFollowsClick in the settings wasn't being saved properly 48 | change = Fixed issue where changing the global setting in the settings wasn't being honored 49 | 50 | type = update 51 | } 52 | } 53 | VERSION 54 | { 55 | version = 2.1.10.18 56 | CHANGE 57 | { 58 | change = Fixed a memory leak where two game events were being used, added a DontDestroyOnLoad to RegisterToolbar 59 | change = Updated version number to avoid dependency issues 60 | type = update 61 | } 62 | } 63 | VERSION 64 | { 65 | version = 0.1.10.17 66 | CHANGE 67 | { 68 | change = Added AssemblyFileVersion, needed for new KSP 1.12 dll verification 69 | change = Added InstallChecker to ensure installation into correct directory 70 | type = update 71 | } 72 | } 73 | VERSION 74 | { 75 | version = 0.1.10.16 76 | CHANGE 77 | { 78 | change = Fixed issue on 1.11 where a uncontrolled ship would be controllable when changing scenes to it 79 | type = update 80 | } 81 | } 82 | VERSION 83 | { 84 | version = 0.1.10.15 85 | CHANGE 86 | { 87 | change = Fixed issue in editor where a single open window which was closed was leaving everything 88 | type = update 89 | } 90 | } 91 | 92 | VERSION 93 | { 94 | version = 0.1.10.14 95 | CHANGE 96 | { 97 | change = Fixed performance issue in the editor when FocusFollowsMouse was active 98 | subchange = Two problems: 99 | subchange = GetComponent was being called on every part 100 | subchange = EditorActionGroups.Instance.ClearSelection was being called every time through Update() 101 | change = Added global value for FocusFollowsClick or FocusFollowsMouse for all new saves 102 | type = update 103 | } 104 | } 105 | 106 | VERSION 107 | { 108 | version = 0.1.10.13 109 | CHANGE 110 | { 111 | change = Fixed inputlocks not being cleared when canceling the window 112 | change = Added mode toggle on new button to allow toggling between different modes during the game 113 | change = Updated settings to make it clear if popup will be shown next time in the space center 114 | change = Added code to disable the ShowPopup flag if the focusFollowsClick is changed in the settings 115 | change = Thanks to github user @SteveBenz for this: Make the configuration file not depend on Environment.CurrentDirectory and instead depend on the deployment location of the DLL 116 | type = update 117 | } 118 | } 119 | VERSION 120 | { 121 | version = 0.1.10.12 122 | CHANGE 123 | { 124 | change = Fixed inputlocks not being cleared when setting FocusFollowsMouse 125 | type = update 126 | } 127 | } 128 | VERSION 129 | { 130 | version = 0.1.10.11 131 | CHANGE 132 | { 133 | change = Fixed overly aggressive CBTMonitor which was causing the vessel highlighting to stop in the editor when FocusFollowsMouse was set 134 | type = update 135 | } 136 | } 137 | VERSION 138 | { 139 | version = 0.1.10.10 140 | CHANGE 141 | { 142 | change = Fix nullrefs upong returning to mainmenu by adding check for no game loaded (ie: returning to main menu) in CBTMonitor.Update & CBTMonitor.LateUpdate 143 | type = update 144 | } 145 | } 146 | 147 | VERSION 148 | { 149 | version = 0.1.10.9 150 | CHANGE 151 | { 152 | change = Fixed lock issues 153 | type = update 154 | subchange = Fixed Popupshown.cfg from having endless repeats of the popupshown = true appended 155 | subchange = Fixed error which caused buildings to be non-clickable if clicking on a control in the window closed it (such as an X or a Close button) 156 | subchange = Made all members of Log class to be internal, to avoid conflicts with KSP_Log 157 | subchange = Modified the CBTMonitor to run in all scenes, needed for FocusToClick to work properly 158 | } 159 | } 160 | 161 | VERSION 162 | { 163 | version = 1.0.10.7 164 | CHANGE 165 | { 166 | change = Internal cleanup 167 | type = update 168 | subchange = Made all members of Log class to be internal, to avoid conflicts with KSP_Log 169 | } 170 | } 171 | 172 | VERSION 173 | { 174 | version = 1.0.10.6 175 | CHANGE 176 | { 177 | change = Added missing files 178 | type = update 179 | } 180 | } 181 | 182 | VERSION 183 | { 184 | version = 1.0.10.5 185 | CHANGE 186 | { 187 | change = Cleanup Input Locks 188 | type = update 189 | subchange = Added cleanup class to cleanup all input locks after a delay, immediately upon changing scenes 190 | subchange = Added cleanup delay to settings page 191 | } 192 | } 193 | 194 | VERSION 195 | { 196 | version = 1.0.10.4 197 | CHANGE 198 | { 199 | change = Minimod Input Locks 200 | type = update 201 | subchange = Added MiniMod to clear input locks via toolbar button, right-click brings up window 202 | subchange = Added one-time popup window 203 | subchange = Added ToolbarController as a dependency 204 | } 205 | } 206 | VERSION 207 | { 208 | version = 1.0.10.2 209 | CHANGE 210 | { 211 | change = Initial Focus Follows Click and other optimizations 212 | type = update 213 | subchange = Removed need to save window rect 214 | subchange = Added Focus Follows Click mode 215 | subchange = Reorganized code a bit 216 | subchange = Removed some unnecessary assignments 217 | subchange = Added stock settings page to support the FocusFollowsClick mode 218 | } 219 | } 220 | VERSION 221 | { 222 | version = 1.0.10.1 223 | CHANGE 224 | { 225 | change = Minor optimizations 226 | type = update 227 | subchange = Modified the CBTMonitor to not run in any scene other than the editor 228 | subchange = Fixed window data not getting cleared properly 229 | } 230 | } 231 | VERSION 232 | { 233 | version = 1.0.10 234 | CHANGE 235 | { 236 | change = Initial commit for Focus Follows Click 237 | type = HighPriority 238 | subchange = Added Settings page 239 | subchange = Added new setting to specify Focus follows Click 240 | subchange = Added code to have the focus follow the click instead of the mouse, for both editor and flight modes 241 | subchange = Added initial window to select mode, shows one time only 242 | } 243 | } 244 | } -------------------------------------------------------------------------------- /Changelog.txt: -------------------------------------------------------------------------------- 1 | ChangeLog 2 | 3 | 2.1.20.22 4 | Updated version file to use github for version info 5 | Copied webpage to README.md 6 | 7 | 2.1.20.21 8 | Fixed another nullref when starting game 9 | 10 | 2.1.10.20 11 | Fixed nullref when entering game 12 | 13 | 2.1.10.19 14 | Fixed issue where changing the FocusFollowsClick in the settings wasn't being saved properly 15 | Fixed issue where changing the global setting in the settings wasn't being honored 16 | 17 | 2.1.10.18 18 | Fixed a memory leak where two game events were beiing used, added a DontDestroyOnLoad to RegisterToolbar 19 | Updated version number to avoid dependency issues 20 | 21 | 0.1.10.17 22 | Added AssemblyFileVersion 23 | Added InstallChecker 24 | 25 | 0.1.10.16 26 | Fixed issue on 1.11 where a uncontrolled ship would be controllable when changing scenes to it 27 | 28 | 0.1.10.15 29 | Fixed issue in editor where a single open window which was closed was leaving everything locked. 30 | 31 | 0.1.10.14 32 | Fixed performance issue in the editor when FocusFollowsMouse was active 33 | Two problems: 34 | GetComponent was being called on every part 35 | EditorActionGroups.Instance.ClearSelection was being called every time through Update() 36 | Added global value for FocusFollowsClick or FocusFollowsMouse for all new saves 37 | 38 | 0.1.10.13 39 | Fixed inputlocks not being cleared when canceling the window 40 | Added mode toggle on new button to allow toggling between different modes during the game 41 | Updated settings to make it clear if popup will be shown next time in the space center 42 | Added code to disable the ShowPopup flag if the focusFollowsClick is changed in the settings 43 | Thanks to github user @SteveBenz for this: 44 | Make the configuration file not depend on Environment.CurrentDirectory and instead depend on the deployment location of the DLL 45 | 46 | 0.1.10.12 47 | Fixed inputlocks not being cleared when setting FocusFollowsMouse 48 | 49 | 0.1.10.11 50 | Fixed overly aggressive CBTMonitor which was causing the vessel highlighting to stop in the editor when FocusFollowsMouse was set 51 | 52 | 0.1.10.10 53 | Fix nullrefs upong returning to mainmenu by adding check for no game loaded (ie: returning to main menu) in CBTMonitor.Update & CBTMonitor.LateUpdate 54 | 55 | 0.1.10.9 56 | Fixed Popupshown.cfg from having endless repeats of the popupshown = true appended 57 | Fixed error which caused buildings to be non-clickable if clicking on a control in the window closed it (such as an X or a Close button) 58 | Made all members of Log class to be internal, to avoid conflicts with KSP_Log 59 | Modified the CBTMonitor to run in all scenes, needed for FocusToClick to work properly 60 | 61 | 0.1.10.6 62 | Added missing files 63 | 64 | 0.1.10.5 65 | Added cleanup class to cleanup all input locks after a delay, immediately upon changing scenes 66 | Added cleanup delay to settings page 67 | 68 | 0.1.10.4 69 | Removed need to save window rect 70 | Reorganized code a bit 71 | Removed some unnecessary assignments 72 | Added stock settings page to support the FocusFollowsClick mode 73 | 74 | 0.1.10.2 75 | Removed need to save window rect 76 | Reorganized code a bit 77 | Removed some unnecessary assignments 78 | Added stock settings page to support the FocusFollowsClick mode 79 | 80 | 81 | 0.1.10.1 82 | Modified the CBTMonitor to not run in any scene other than the editor 83 | Fixed window data not getting cleared properly 84 | 85 | 0.1.10 86 | Added Settings page 87 | Added new setting to specify Focus follows Click 88 | Added code to have the focus follow the click instead of the mouse, for both editor and flight modes 89 | Added initial window to select mode, shows one time only 90 | 91 | 0.1.9.5 92 | Fixed subtle bug where the game scene was being changed due to clicking on a mod window, which 93 | prevented the variable counter: ClickThruBlocker.CTBWin.activeBlockerCnt from being reset to 0 94 | Added check for null EditorLogic.fetch in Update() method, was necessary in KSP 1.8.1 due to change 95 | in initialization methods/timings 96 | 97 | 0.1.9.4 98 | Fixed nullref which occurred with CRASH 99 | Updated AssemblyVersion.tt 100 | 101 | 0.1.9.3 102 | Really did the MiniAVC update 103 | 104 | 0.1.9.2 105 | Updated MiniAVC.dll to 1.4.0.2 to fix a nasty CTD 106 | 107 | 0.1.9.1 108 | Updated MiniAVC to 1.4.0 109 | 110 | 0.1.9.0 111 | Rebuild for 1.8.0 112 | 113 | 0.1.7.2 114 | Added replacements for the following functions: 115 | Unity GUI: 116 | public static Rect ModalWindow (int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, string text); 117 | public static Rect ModalWindow (int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, Texture image); 118 | public static Rect ModalWindow (int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, GUIContent content); 119 | public static Rect ModalWindow (int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, string text, GUIStyle style); 120 | public static Rect ModalWindow (int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, Texture image, GUIStyle style); 121 | public static Rect ModalWindow (int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, GUIContent content, GUIStyle style); 122 | Unity GuiLayout: 123 | public static Rect Window (int id, Rect screenRect, UnityEngine.GUI.WindowFunction func, Texture image, GUIStyle style, params GUILayoutOption[] options); 124 | public static Rect Window (int id, Rect screenRect, UnityEngine.GUI.WindowFunction func, GUIContent content, GUIStyle style, params GUILayoutOption[] options); 125 | 126 | 0.1.7.1 127 | Fixed ArgumentNullException: Argument cannot be null when moving mouse over dropdown menu (in the ksp_toolbar) when in the editor 128 | (previous fix was for all other scenes) 129 | 130 | 0.1.7 131 | Fixed ArgumentNullException: Argument cannot be null when moving mouse over dropdown menu (in the ksp_toolbar) 132 | 133 | 0.1.6.9 134 | Version bump to fix .version file 135 | 136 | 0.1.6.8 137 | Version bump for 1.5 rebuild 138 | 139 | 0.1.6.7 140 | Fixed ArgumentOutOfRangeException in Update 141 | 142 | 0.1.6.6 143 | Did some minor runtime optimizations 144 | 145 | 0.1.6.6 146 | Changed directory name to 000_ClickThroughBlocker 147 | 148 | 0.1.6.3 149 | Added an additional check to the CBTMonitor for null refs 150 | Reversed order of loops in CBTMonitor for efficiency 151 | 152 | 0.1.6.2 153 | Added: [assembly: KSPAssembly("ToolbarController", 1, 0)] to assemblyinfo to allow other mods to check the load order 154 | 155 | 0.1.6.1 156 | Updated version to allow all 1.4.* 157 | 158 | 0.1.6 159 | Fix for lock not being released when going from editor to flight (ie: KRASH) 160 | 161 | 0.1.5 162 | Changed check of UniversalTime to a tick counter in CBTMonitor, since time doesn't flow in the Editors 163 | 164 | 0.1.4 165 | Added fix for nullrefs in CBTMonitor.cs 166 | 167 | 0.1.3 168 | Rebuilt for 1.4.1 169 | 170 | 0.1.2 171 | Added code to work around stock bug where the editor ignores the lock when the ActionGroup pane is shown 172 | 173 | 0.1.1.1 174 | Changed Log class to internal, so it won't interfere with other code compiles 175 | 176 | 0.1.1 177 | Fixed bug where closing a window while the mouse was over the window would lock the UI; for example, if a window has an X button to close. Thanks to forum user @keldion for finding this and pointing it out 178 | 179 | 0.1.0 180 | Initial release -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Having clicked one too many times on one window, only to have it click on the parts underneath (in the Editor), 2 | or click on an unwanted item in flight, I decided to solve the problem with yet another mod 3 | 4 | Mods which use the Click Through Blocker would need to be modified, and this would become a hard dependency for that mod. 5 | 6 | The changes are very simple: 7 | 8 | Replace all calls to GUILayout.Window with ClickThruBlocker.GUILayoutWindow, the parameters are identical 9 | Replace all calls to GUI.Window with ClickThruBlocker.GUIWindow, the parameters are identical 10 | 11 | How it works 12 | 13 | Each call first calls the original method (ie: ClickThruBlocker.GUILayoutWindow will call GUILayout.Window). After the call, 14 | the position of the mouse is checked to see if it was on top of the window Rect, if it is, it then locks the controls so that clicks don't 15 | pass through to any other window. 16 | 17 | Usage 18 | 19 | Add the following to the top of the source: 20 | using ClickThroughFix; 21 | Replace calls to GUILayout.Window with ClickThruBlocker.GUILayoutWindow 22 | Replace calls to GUI.Window with ClickThruBlocker.GUIWindow 23 | 24 | Functions - Identical to the GUI and GUILayout versions 25 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, GUIContent content, GUIStyle style, params GUILayoutOption[] options); 26 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, Texture image, GUIStyle style, params GUILayoutOption[] options); 27 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, string text, GUIStyle style, params GUILayoutOption[] options); 28 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, GUIContent content, params GUILayoutOption[] options); 29 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, Texture image, params GUILayoutOption[] options); 30 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, string text, params GUILayoutOption[] options); 31 | 32 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, Texture image, GUIStyle style); 33 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, string text, GUIStyle style); 34 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, GUIContent content); 35 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, Texture image); 36 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, string text); 37 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, GUIContent title, GUIStyle style); 38 | 39 | Additional functions 40 | 41 | bool MouseIsOverWindow(Rect rect) Returns true if the mouse is over the specified rectangle 42 | 43 | 44 | ========================================================================== 45 | 46 | Having clicked one too many times on one window, only to have it click on the parts underneath (in the Editor), or click on an unwanted item in flight, I decided to solve the problem with yet another mod. 47 | 48 | Major Release Update, 1.10.5 49 | 50 | Added Settings page 51 | Added new setting to specify Focus follows Click 52 | Added code to have the focus follow the click instead of the mouse, for both editor and flight modes 53 | Added initial window to select mode, shows one time only 54 | Modified the CBTMonitor to not run in any scene other than the editor 55 | Fixed window data not getting cleared properly 56 | Removed need to save window rect 57 | Reorganized code a bit 58 | Removed some unnecessary assignments 59 | Added stock settings page to support the FocusFollowsClick mode 60 | Removed need to save window rect 61 | Reorganized code a bit 62 | Removed some unnecessary assignments 63 | Added stock settings page to support the FocusFollowsClick mode 64 | Added cleanup class to cleanup all input locks after a delay, immediately upon changing scenes 65 | Added cleanup delay to settings page 66 | NEW DEPENDENCY 67 | 68 | ToolbarController 69 | This mod will do nothing by itself, it will need to be used by other mods (see Precise Node for an example) 70 | 71 | Mods which use the Click Through Blocker would need to be modified, and this would become a hard dependency for that mod. 72 | 73 | The changes are very simple: 74 | 75 | Replace all calls to GUILayout.Window with ClickThruBlocker.GUILayoutWindow, the parameters are identical 76 | Replace all calls to GUI.Window with ClickThruBlocker.GUIWindow, the parameters are identical 77 | 78 | 79 | 80 | Most important (for mod authors) 81 | All mods using this should add the following line to the AssemblyInfo.cs file: 82 | 83 | [assembly: KSPAssemblyDependency("ClickThroughBlocker", 1, 0)] 84 | This will guarantee the load order. One benefit is that KSP will output a warning and won't load an assembly if it's dependencies aren't met (which may be better than puking out a bunch of exceptions). The only other real problem with the forced to the top of the sort list method is that technically there's a couple characters before zero ('~', '!', '@', etc.) and dlls directly in GameData come first too. Of course someone pretty much has to be trying to break things if you have to worry about this particular case. 85 | 86 | 87 | 88 | How it works 89 | 90 | Each call first calls the original method (ie: ClickThruBlocker.GUILayoutWindow will call GUILayout.Window). After the call, the position of the mouse is checked to see if it was on top of the window Rect, if it is, it then locks the controls so that clicks don't pass through to any other window. 91 | 92 | Usage 93 | 94 | Add the following to the top of the source: 95 | using ClickThroughFix; 96 | Replace calls to GUILayout.Window with ClickThruBlocker.GUILayoutWindow 97 | Replace calls to GUI.Window with ClickThruBlocker.GUIWindow 98 | Functions - Identical to the GUI and GUILayout versions 99 | 100 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, GUIContent content, GUIStyle style, params GUILayoutOption[] options); 101 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, Texture image, GUIStyle style, params GUILayoutOption[] options); 102 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, string text, GUIStyle style, params GUILayoutOption[] options); 103 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, GUIContent content, params GUILayoutOption[] options); 104 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, Texture image, params GUILayoutOption[] options); 105 | Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, string text, params GUILayoutOption[] options); 106 | 107 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, Texture image, GUIStyle style); 108 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, string text, GUIStyle style); 109 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, GUIContent content); 110 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, Texture image); 111 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, string text); 112 | Rect GUIWindow(int id, Rect clientRect, WindowFunction func, GUIContent title, GUIStyle style); 113 | Additional functions 114 | 115 | bool MouseIsOverWindow(Rect rect) Returns true if the mouse is over the specified rectangle 116 | 117 | Download 118 | 119 | Source: https://github.com/linuxgurugamer/ClickThroughBlocker 120 | Spacedock: https://spacedock.info/mod/1689 121 | Github: https://github.com/linuxgurugamer/ClickThroughBlocker/releases 122 | License: GPLv3 123 | Available via CKAN 124 | 125 | -------------------------------------------------------------------------------- /ClickThroughBlocker/OneTimePopup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | using KSP.IO; 5 | using UnityEngine; 6 | using ClickThroughFix; 7 | using System.Reflection; 8 | 9 | namespace ClickThroughFix 10 | { 11 | [KSPAddon(KSPAddon.Startup.SpaceCentre, false)] 12 | public class OneTimePopup : MonoBehaviour 13 | { 14 | internal static OneTimePopup Instance = null; 15 | const int WIDTH = 600; 16 | const int HEIGHT = 350; 17 | Rect popupRect = new Rect(300, 50, WIDTH, HEIGHT); 18 | bool visible = false; 19 | static string popUpShownCfgPath { get { 20 | return Path.Combine( 21 | Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "../PluginData/PopUpShown.cfg"); ; 22 | } } 23 | 24 | string cancelStr = "Cancel (window will open next startup)"; 25 | Game curGame; 26 | public void Awake() 27 | { 28 | //popUpShownCfgPath = Path.Combine( 29 | // Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "../PluginData/PopUpShown.cfg"); 30 | if (HighLogic.CurrentGame != curGame) 31 | { 32 | ClearInputLocks.focusFollowsclick = HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick; 33 | curGame = HighLogic.CurrentGame; 34 | } 35 | if (!HighLogic.CurrentGame.Parameters.CustomParams().showPopup) 36 | Destroy(this); 37 | Instance = this; 38 | } 39 | 40 | public void Start() 41 | { 42 | 43 | visible = true; 44 | if (ClearInputLocks.modeWindow != null) 45 | { 46 | visible = true; 47 | focusFollowsClick = oldFocusFollowsClick = HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick; 48 | focusFollowsMouse = oldFocusFollowsMouse = !focusFollowsClick; 49 | cancelStr = "Cancel"; 50 | } 51 | else 52 | { 53 | if (visible) 54 | DontDestroyOnLoad(this); 55 | } 56 | popupRect.x = (Screen.width - WIDTH) / 2; 57 | popupRect.y = (Screen.height - HEIGHT) / 2; 58 | 59 | } 60 | 61 | void OnDestroy() 62 | { 63 | Instance = null; 64 | } 65 | 66 | 67 | public void OnGUI() 68 | { 69 | if (visible) 70 | { 71 | GUI.skin = HighLogic.Skin; 72 | //popupRect = GUILayout.Window(847733455, popupRect, PopUpWindow, "Click Through Blocker Focus Setting"); 73 | popupRect = ClickThruBlocker.GUILayoutWindow(84733455, popupRect, PopUpWindow, "Click Through Blocker Focus Setting"); 74 | } 75 | } 76 | 77 | bool focusFollowsMouse = false; 78 | bool focusFollowsClick = false; 79 | bool oldFocusFollowsMouse = false; 80 | bool oldFocusFollowsClick = false; 81 | void PopUpWindow(int id) 82 | { 83 | GUILayout.BeginVertical(); 84 | GUILayout.Space(10); 85 | GUILayout.Label("Up until this release, the Click Through Blocker (CTB) has used a model of"); 86 | GUILayout.Label("Focus-Follows-Mouse, meaning that the focus was on whatever window the mouse was"); 87 | GUILayout.Label("over. This release provides a new model of Focus-Follows-Click, which means that"); 88 | GUILayout.Label("you will need to click on a window for that window to have the focus, and the focus"); 89 | GUILayout.Label("won't leave the window without clicking outside the window"); 90 | GUILayout.Space(10); 91 | GUILayout.Label("This window will only appear once to offer the choice of focus model. It can always"); 92 | GUILayout.Label("be changed in the stock settings window, under the Click-Through-Blocker tab"); 93 | GUILayout.Space(20); 94 | focusFollowsMouse = GUILayout.Toggle(focusFollowsMouse, "Focus-Follows-Mouse"); 95 | focusFollowsClick = GUILayout.Toggle(focusFollowsClick, "Focus-Follows-Click"); 96 | if (focusFollowsMouse && !oldFocusFollowsMouse) 97 | { 98 | oldFocusFollowsMouse = true; 99 | focusFollowsClick = oldFocusFollowsClick = false; 100 | } 101 | if (focusFollowsClick && !oldFocusFollowsClick) 102 | { 103 | oldFocusFollowsClick = true; 104 | focusFollowsMouse = oldFocusFollowsMouse = false; 105 | } 106 | if (!focusFollowsClick && !focusFollowsMouse) 107 | GUI.enabled = false; 108 | GUILayout.BeginHorizontal(); 109 | if (GUILayout.Button("Save as global default for all new saves")) 110 | { 111 | SaveGlobalDefault(focusFollowsClick); 112 | } 113 | if (GUILayout.Button("Accept")) 114 | { 115 | HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick = focusFollowsClick; 116 | HighLogic.CurrentGame.Parameters.CustomParams().showPopup = false; 117 | CreatePopUpFlagFile(); 118 | ClearInputLocks.ClearInputLocksToggle(); 119 | visible = false; 120 | Destroy(this); 121 | } 122 | GUI.enabled = true; 123 | 124 | if (GUILayout.Button(cancelStr)) 125 | { 126 | visible = false; 127 | ClearInputLocks.ClearInputLocksToggle(); 128 | Destroy(this); 129 | } 130 | GUILayout.EndHorizontal(); 131 | GUILayout.EndVertical(); 132 | GUI.enabled = true; 133 | GUI.DragWindow(); 134 | } 135 | 136 | static string GlobalDefaultFile 137 | { 138 | get 139 | { 140 | return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/../Global.cfg"; 141 | } 142 | } 143 | static internal void SaveGlobalDefault(bool focusFollowsClick) 144 | { 145 | ConfigNode node = new ConfigNode(); 146 | node.AddValue("focusFollowsClick", focusFollowsClick); 147 | node.Save(GlobalDefaultFile); 148 | } 149 | 150 | static internal bool GetGlobalDefault(ref bool b) 151 | { 152 | if (System.IO.File.Exists(GlobalDefaultFile)) 153 | { 154 | if (HighLogic.CurrentGame == null || HighLogic.CurrentGame.Parameters.CustomParams().global) 155 | { 156 | ConfigNode node = ConfigNode.Load(GlobalDefaultFile); 157 | if (node.TryGetValue("focusFollowsClick", ref b)) 158 | { 159 | return true; 160 | } 161 | } 162 | else 163 | return HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick; 164 | } 165 | return false; 166 | } 167 | static internal void CreatePopUpFlagFile() 168 | { 169 | RemovePopUpFlagFile(); // remove first to avoid any overwriting 170 | System.IO.File.WriteAllText(popUpShownCfgPath, "popupshown = true"); 171 | } 172 | 173 | static public void RemovePopUpFlagFile() 174 | { 175 | System.IO.File.Delete(popUpShownCfgPath); 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /GameData/000_ClickThroughBlocker/LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /ClickThroughBlocker/ClickThroughBlocker.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using KSP.UI.Screens; 4 | 5 | 6 | namespace ClickThroughFix 7 | { 8 | 9 | public static class ClickThruBlocker 10 | { 11 | #if !DUMMY2 12 | internal static Dictionary winList = new Dictionary(); 13 | #endif 14 | 15 | 16 | // Most of this is from JanitorsCloset, ImportExportSelect.cs 17 | 18 | public class CTBWin 19 | { 20 | #if !DUMMY2 21 | //public Rect rect; 22 | internal int id; 23 | 24 | internal bool weLockedEditorInputs = false; 25 | internal bool weLockedFlightInputs = false; 26 | internal string windowName; 27 | internal string lockName; 28 | internal long lastLockCycle; 29 | internal double lastUpdated = 0; 30 | // Rect activeWindow; 31 | 32 | 33 | public CTBWin(int id, Rect screenRect, string winName, string lockName) 34 | { 35 | #if !DUMMY 36 | this.id = id; 37 | this.windowName = winName; 38 | this.lockName = lockName; 39 | lastUpdated = CBTGlobalMonitor.globalTimeTics; // Planetarium.GetUniversalTime(); 40 | #endif 41 | } 42 | 43 | public void SetLockString(string s) 44 | { 45 | this.lockName = s; 46 | } 47 | #if !DUMMY 48 | static Vector2 mousePos = new Vector2(); 49 | public static bool MouseIsOverWindow(Rect rect) 50 | { 51 | mousePos.x = Input.mousePosition.x; 52 | mousePos.y = Screen.height - Input.mousePosition.y; 53 | return rect.Contains(mousePos); 54 | } 55 | #endif 56 | 57 | 58 | internal static int activeBlockerCnt = 0; 59 | internal static List selectedParts = null; 60 | 61 | //Lifted this more or less directly from the Kerbal Engineer source. Thanks cybutek! 62 | internal void PreventEditorClickthrough(Rect r) 63 | { 64 | #if DUMMY 65 | return; 66 | #else 67 | if (lockName == null || EditorLogic.fetch == null) 68 | return; 69 | //Log.Info("ClickThruBlocker: PreventEditorClickthrough"); 70 | bool mouseOverWindow = MouseIsOverWindow(r); 71 | //Log.Info("PreventEditorClickthrough, mouseOverWindow: " + mouseOverWindow); 72 | if (ClearInputLocks.focusFollowsclick) 73 | { 74 | bool mouseClicked = Input.GetMouseButton(0) || Input.GetMouseButton(1); 75 | if (mouseClicked) 76 | { 77 | if (mouseOverWindow) 78 | { 79 | if (!weLockedEditorInputs) 80 | { 81 | //Log.Info("PreventEditorClickthrough, locking on window: " + windowName); 82 | //EditorLogic.fetch.Lock(true, true, true, lockName); 83 | FocusLock.SetLock(lockName, win, 2); 84 | weLockedEditorInputs = true; 85 | activeBlockerCnt++; 86 | selectedParts = EditorActionGroups.Instance.GetSelectedParts(); 87 | } 88 | //lastLockCycle = OnGUILoopCount.GetOnGUICnt(); 89 | return; 90 | } 91 | else 92 | { 93 | if (weLockedEditorInputs) 94 | { 95 | FocusLock.FreeLock(lockName, 3); 96 | weLockedEditorInputs = false; 97 | activeBlockerCnt--; 98 | } 99 | } 100 | 101 | } 102 | } 103 | else 104 | { 105 | if (mouseOverWindow) 106 | { 107 | if (!weLockedEditorInputs) 108 | { 109 | //Log.Info("PreventEditorClickthrough, locking on window: " + windowName); 110 | //EditorLogic.fetch.Lock(true, true, true, lockName); 111 | FocusLock.SetLock(lockName, win, 4); 112 | weLockedEditorInputs = true; 113 | activeBlockerCnt++; 114 | selectedParts = EditorActionGroups.Instance.GetSelectedParts(); 115 | } 116 | lastLockCycle = OnGUILoopCount.GetOnGUICnt(); 117 | return; 118 | } 119 | 120 | if (!weLockedEditorInputs) return; 121 | //Log.Info("PreventEditorClickthrough, unlocking on window: " + windowName); 122 | //EditorLogic.fetch.Unlock(lockName); 123 | FocusLock.FreeLock(lockName, 5); 124 | 125 | weLockedEditorInputs = false; 126 | activeBlockerCnt--; 127 | } 128 | #endif 129 | } 130 | 131 | // Following lifted from MechJeb 132 | internal void PreventInFlightClickthrough(Rect r) 133 | { 134 | #if !DUMMY 135 | //Log.Info("ClickThruBlocker: PreventInFlightClickthrough"); 136 | bool mouseOverWindow = MouseIsOverWindow(r); 137 | // 138 | // This section for the Click to Focus option 139 | // 140 | if (ClearInputLocks.focusFollowsclick) 141 | { 142 | bool mouseClicked = Input.GetMouseButton(0) || Input.GetMouseButton(1); 143 | if (mouseClicked) 144 | { 145 | if (mouseOverWindow) 146 | { 147 | //Log.Info("PreventInFlightClickthrough, mouse clicked and over window, weLockedFlightInputs:" + weLockedFlightInputs + ", lockName: " + lockName); 148 | if (!weLockedFlightInputs && !Input.GetMouseButton(1) && lockName != null) 149 | { 150 | //InputLockManager.SetControlLock(ControlTypes.ALLBUTCAMERAS, lockName); 151 | FocusLock.SetLock(lockName, win, 6); 152 | weLockedFlightInputs = true; 153 | } 154 | } 155 | else 156 | { 157 | //Log.Info("PreventInFlightClickthrough, mouse clicked and NOT over window, weLockedFlightInputs:" + weLockedFlightInputs + ", lockName: " + lockName); 158 | 159 | if (weLockedFlightInputs && lockName != null) 160 | { 161 | // InputLockManager.RemoveControlLock(lockName); 162 | FocusLock.FreeLock(lockName, 7); 163 | weLockedFlightInputs = false; 164 | } 165 | } 166 | } 167 | } 168 | else 169 | { 170 | // 171 | // This section for the Focus Follows Mouse option 172 | // 173 | if (mouseOverWindow) 174 | { 175 | if (!weLockedFlightInputs && !Input.GetMouseButton(1) && lockName != null) 176 | { 177 | //Log.Info("PreventInFlightClickthrough, locking on window: " + windowName); ; 178 | 179 | //InputLockManager.SetControlLock(ControlTypes.ALLBUTCAMERAS, lockName); 180 | FocusLock.SetLock(lockName, win, 8); 181 | weLockedFlightInputs = true; 182 | 183 | } 184 | if (weLockedFlightInputs) 185 | lastLockCycle = OnGUILoopCount.GetOnGUICnt(); 186 | } 187 | if (weLockedFlightInputs && !mouseOverWindow && lockName != null) 188 | { 189 | //Log.Info("PreventInFlightClickthrough, unlocking on window: " + windowName); 190 | //InputLockManager.RemoveControlLock(lockName); 191 | FocusLock.FreeLock(lockName, 9); 192 | weLockedFlightInputs = false; 193 | } 194 | } 195 | #endif 196 | } 197 | 198 | internal void OnDestroy() 199 | { 200 | #if !DUMMY 201 | // Log.Info("OnDestroy, windowName: " + windowName + ", lockName: " + lockName + ", weLockedEditorInputs: " + weLockedEditorInputs.ToString() + ", weLockedFlightInputs: " + weLockedFlightInputs.ToString()); 202 | winList.Remove(id); 203 | if (lockName != null) 204 | { 205 | if (HighLogic.LoadedSceneIsEditor) 206 | EditorLogic.fetch.Unlock(lockName); 207 | else 208 | InputLockManager.RemoveControlLock(lockName); 209 | } 210 | if (EditorLogic.fetch != null && weLockedEditorInputs) 211 | { 212 | //EditorLogic.fetch.Unlock(lockName); 213 | weLockedEditorInputs = false; 214 | activeBlockerCnt--; 215 | } 216 | if (weLockedFlightInputs) 217 | { 218 | //InputLockManager.RemoveControlLock(lockName); 219 | weLockedFlightInputs = false; 220 | } 221 | #endif 222 | } 223 | } 224 | #endif 225 | // This is outside the UpdateList method for runtime optimization 226 | static CTBWin win = null; 227 | private static Rect UpdateList(int id, Rect rect, string text) 228 | { 229 | #if !DUMMY 230 | win = null; 231 | if (!winList.TryGetValue(id, out win)) 232 | { 233 | win = new CTBWin(id, rect, text, text); 234 | winList.Add(id, win); 235 | } 236 | 237 | if (HighLogic.LoadedSceneIsEditor) 238 | { 239 | win.PreventEditorClickthrough(rect); 240 | win.lastUpdated = CBTGlobalMonitor.globalTimeTics; // Planetarium.GetUniversalTime(); 241 | } 242 | else 243 | win.lastUpdated = CBTGlobalMonitor.globalTimeTics; 244 | if (HighLogic.LoadedSceneIsFlight || HighLogic.LoadedSceneHasPlanetarium) 245 | win.PreventInFlightClickthrough(rect); 246 | 247 | #endif 248 | return rect; 249 | } 250 | 251 | // This is outside all the GuiLayoutWindow methods for runtime optimization 252 | static Rect r; 253 | public static Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, string text, GUIStyle style, params GUILayoutOption[] options) 254 | { 255 | r = GUILayout.Window(id, screenRect, func, text, style, options); 256 | 257 | return UpdateList(id, r, text); 258 | } 259 | 260 | public static Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, string text, params GUILayoutOption[] options) 261 | { 262 | r = GUILayout.Window(id, screenRect, func, text, options); 263 | 264 | return UpdateList(id, r, text); 265 | } 266 | 267 | public static Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, GUIContent content, params GUILayoutOption[] options) 268 | { 269 | r = GUILayout.Window(id, screenRect, func, content, options); 270 | 271 | return UpdateList(id, r, id.ToString()); 272 | } 273 | 274 | public static Rect GUILayoutWindow(int id, Rect screenRect, GUI.WindowFunction func, Texture image, params GUILayoutOption[] options) 275 | { 276 | r = GUILayout.Window(id, screenRect, func, image, options); 277 | 278 | return UpdateList(id, r, id.ToString()); 279 | } 280 | 281 | public static Rect GUIWindow(int id, Rect clientRect, GUI.WindowFunction func, Texture image, GUIStyle style) 282 | { 283 | r = GUI.Window(id, clientRect, func, image, style); 284 | 285 | return UpdateList(id, r, id.ToString()); 286 | } 287 | public static Rect GUIWindow(int id, Rect clientRect, GUI.WindowFunction func, string text, GUIStyle style) 288 | { 289 | r = GUI.Window(id, clientRect, func, text, style); 290 | 291 | return UpdateList(id, r, text); 292 | } 293 | public static Rect GUIWindow(int id, Rect clientRect, GUI.WindowFunction func, GUIContent content) 294 | { 295 | r = GUI.Window(id, clientRect, func, content); 296 | 297 | return UpdateList(id, r, id.ToString()); 298 | 299 | } 300 | public static Rect GUIWindow(int id, Rect clientRect, GUI.WindowFunction func, Texture image) 301 | { 302 | r = GUI.Window(id, clientRect, func, image); 303 | 304 | return UpdateList(id, r, id.ToString()); 305 | 306 | } 307 | public static Rect GUIWindow(int id, Rect clientRect, GUI.WindowFunction func, string text) 308 | { 309 | r = GUI.Window(id, clientRect, func, text); 310 | 311 | return UpdateList(id, r, text); 312 | } 313 | public static Rect GUIWindow(int id, Rect clientRect, GUI.WindowFunction func, GUIContent title, GUIStyle style) 314 | { 315 | r = GUI.Window(id, clientRect, func, title, style); 316 | 317 | return UpdateList(id, r, title.ToString()); 318 | } 319 | 320 | public static Rect GUILayoutWindow(int id, Rect screenRect, UnityEngine.GUI.WindowFunction func, Texture image, GUIStyle style, params GUILayoutOption[] options) 321 | { 322 | r = GUILayout.Window(id, screenRect, func, image, style, options); 323 | return UpdateList(id, r, id.ToString()); 324 | } 325 | public static Rect GUILayoutWindow(int id, Rect screenRect, UnityEngine.GUI.WindowFunction func, GUIContent content, GUIStyle style, params GUILayoutOption[] options) 326 | { 327 | r = GUILayout.Window(id, screenRect, func, content, style, options); 328 | return UpdateList(id, r, id.ToString()); 329 | } 330 | 331 | public static Rect GUIModalWindow(int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, string text) 332 | { 333 | r = GUI.ModalWindow(id, clientRect, func, text); 334 | return UpdateList(id, r, id.ToString()); 335 | } 336 | public static Rect GUIModalWindow(int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, Texture image) 337 | { 338 | r = GUI.ModalWindow(id, clientRect, func, image); 339 | return UpdateList(id, r, id.ToString()); 340 | } 341 | public static Rect GUIModalWindow(int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, GUIContent content) 342 | { 343 | r = GUI.ModalWindow(id, clientRect, func, content); 344 | return UpdateList(id, r, id.ToString()); 345 | } 346 | public static Rect GUIModalWindow(int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, string text, GUIStyle style) 347 | { 348 | r = GUI.ModalWindow(id, clientRect, func, text, style); 349 | return UpdateList(id, r, id.ToString()); 350 | } 351 | public static Rect GUIModalWindow(int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, Texture image, GUIStyle style) 352 | { 353 | r = GUI.ModalWindow(id, clientRect, func, image, style); 354 | return UpdateList(id, r, id.ToString()); 355 | } 356 | public static Rect GUIModalWindow(int id, Rect clientRect, UnityEngine.GUI.WindowFunction func, GUIContent content, GUIStyle style) 357 | { 358 | r = GUI.ModalWindow(id, clientRect, func, content, style); 359 | return UpdateList(id, r, id.ToString()); 360 | } 361 | 362 | 363 | 364 | #if false 365 | 366 | static bool fieldHasFocus() 367 | { 368 | GameObject obj; 369 | bool inputFieldIsFocused; 370 | // First check for a text field ??? 371 | // Ignore keystrokes when a text field has focus (e.g. part search, craft title box) 372 | obj = EventSystem.current.currentSelectedGameObject; 373 | inputFieldIsFocused = (obj != null && obj.GetComponent() != null && obj.GetComponent().isFocused); 374 | //if (inputFieldIsFocused) 375 | //return false; 376 | 377 | //inputFieldIsFocused = (inputObj != null && inputObj.GetComponent() != null && inputObj.GetComponent().isFocused); 378 | 379 | return inputFieldIsFocused; 380 | } 381 | 382 | // GUI.TextArea 383 | public static string GUITextArea(Rect position, string text) 384 | { 385 | string t = text; 386 | text = GUI.TextArea(position, text); 387 | if (!fieldHasFocus()) 388 | return t; 389 | return text; 390 | } 391 | 392 | public static string GUITextArea(Rect position, string text, int maxLength) 393 | { 394 | string t = text; 395 | text = GUI.TextArea(position, text, maxLength); 396 | if (!fieldHasFocus()) 397 | return t; 398 | return text; 399 | } 400 | 401 | public static string GUITextArea(Rect position, string text, GUIStyle style) 402 | { 403 | string t = text; 404 | text = GUI.TextArea(position, text, style); 405 | if (!fieldHasFocus()) 406 | return t; 407 | return text; 408 | } 409 | 410 | public static string GUITextArea(Rect position, string text, int maxLength, GUIStyle style) 411 | { 412 | string t = text; 413 | text = GUI.TextArea(position, text, maxLength, style); 414 | if (!fieldHasFocus()) 415 | return t; 416 | return text; 417 | } 418 | 419 | // GUI.TextField 420 | public static string GUITextField(Rect position, string text, GUIStyle style) 421 | { 422 | string t = text; 423 | text = GUI.TextField(position, text, style); 424 | if (!fieldHasFocus()) 425 | return t; 426 | return text; 427 | } 428 | 429 | public static string GUITextField(Rect position, string text, int maxLength) 430 | { 431 | string t = text; 432 | text = GUI.TextField(position, text, maxLength); 433 | if (!fieldHasFocus()) 434 | return t; 435 | return text; 436 | } 437 | 438 | public static string GUITextField(Rect position, string text) 439 | { 440 | string t = text; 441 | text = GUI.TextField(position, text); 442 | if (!fieldHasFocus()) 443 | return t; 444 | return text; 445 | } 446 | 447 | public static string GUITextField(Rect position, string text, int maxLength, GUIStyle style) 448 | { 449 | string t = text; 450 | text = GUI.TextField(position, text, maxLength, style); 451 | if (!fieldHasFocus()) 452 | return t; 453 | return text; 454 | } 455 | 456 | // GUILayout.TextArea 457 | 458 | public static string GUILayoutTextArea(string text, int maxLength, GUIStyle style, params GUILayoutOption[] options) 459 | { 460 | string t = text; 461 | text = GUILayout.TextArea(text, maxLength, style, options); 462 | if (!fieldHasFocus()) 463 | return t; 464 | return text; 465 | } 466 | 467 | public static string GUILayoutTextArea(string text, GUIStyle style, params GUILayoutOption[] options) 468 | { 469 | string t = text; 470 | text = GUILayout.TextArea(text, style, options); 471 | if (!fieldHasFocus()) 472 | return t; 473 | return text; 474 | } 475 | 476 | public static string GUILayoutTextArea(string text, int maxLength, params GUILayoutOption[] options) 477 | { 478 | string t = text; 479 | text = GUILayout.TextArea(text, maxLength, options); 480 | if (!fieldHasFocus()) 481 | return t; 482 | return text; 483 | } 484 | 485 | public static string GUILayoutTextArea(string text, params GUILayoutOption[] options) 486 | { 487 | string t = text; 488 | text = GUILayout.TextArea(text, options); 489 | if (!fieldHasFocus()) 490 | return t; 491 | return text; 492 | } 493 | 494 | // GUILayout.TextField 495 | 496 | public static string GUILayoutTextField(string text, int maxLength, GUIStyle style, params GUILayoutOption[] options) 497 | { 498 | string t = text; 499 | text = GUILayout.TextField(text, maxLength, style, options); 500 | if (!fieldHasFocus()) 501 | return t; 502 | return text; 503 | } 504 | 505 | public static string GUILayoutTextField(string text, GUIStyle style, params GUILayoutOption[] options) 506 | { 507 | string t = text; 508 | text = GUILayout.TextField(text, style, options); 509 | if (!fieldHasFocus()) 510 | return t; 511 | return text; 512 | } 513 | 514 | public static string GUILayoutTextField(string text, int maxLength, params GUILayoutOption[] options) 515 | { 516 | string t = text; 517 | text = GUILayout.TextField(text, maxLength, options); 518 | if (!fieldHasFocus()) 519 | return t; 520 | return text; 521 | } 522 | 523 | public static string GUILayoutTextField(string text, params GUILayoutOption[] options) 524 | { 525 | string t = text; 526 | text = GUILayout.TextField(text, options); 527 | if (!fieldHasFocus()) 528 | return t; 529 | return text; 530 | } 531 | #endif 532 | } 533 | } 534 | --------------------------------------------------------------------------------