From 1819daa6c51c31cc0012b5960a084360829c3eda Mon Sep 17 00:00:00 2001 From: Dunbaratu Date: Sat, 9 May 2020 17:43:30 -0500 Subject: [PATCH 1/8] I will probably abandon this branch - will use reflection instead so it can tolerate having no ClickThruBlocker installed. --- CONTRIBUTING.md | 9 ++++++++- src/kOS/Properties/AssemblyInfo.cs | 1 + src/kOS/Screen/DelegateDialog.cs | 5 +++-- src/kOS/Screen/GUIWindow.cs | 5 +++-- src/kOS/Screen/KOSManagedWindow.cs | 11 ++++++++++- src/kOS/Screen/KOSNameTagWindow.cs | 5 +++-- src/kOS/Screen/KOSTextEditPopup.cs | 3 ++- src/kOS/Screen/KOSToolbarWindow.cs | 4 +++- src/kOS/Screen/ListPickerDialog.cs | 6 ++++-- src/kOS/Screen/TermWindow.cs | 3 ++- src/kOS/UserIO/TelnetMainServer.cs | 8 +++++--- src/kOS/kOS.csproj | 3 +++ 12 files changed, 47 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f47f621bce..e65cc68274 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -213,7 +213,14 @@ Setting Up Your Environment * Click on the resulting link to go to that class's documentation page. * The Unity documentation for that class will start with some faint grey text at the top of the page that says, "Implemented in:", which tells you which DLL you need to reference to get code using that class to compile properly. - 3. If you do not have a copy of KSP locally, you may + 3. Make sure your installation of KSP has LinuxGuruGamer's ClivkThroughBlocker + mod installed. kOS now needs it in order to compile. After it is + installed, create a reference for it in your kOS project's References + like so: + + * $KSP_INSTALL_DIR/GameData/00_ClickThroughBlocker/Plugins/ClickThroughBlocker.dll + + 4. If you do not have a copy of KSP locally, you may download dummy assemblies at https://github.com/KSP-KOS/KSP_LIB 3. Make sure you are targeting this version of .Net: ".Net 4.0 Framework". diff --git a/src/kOS/Properties/AssemblyInfo.cs b/src/kOS/Properties/AssemblyInfo.cs index 52fa1b3b68..380136409f 100644 --- a/src/kOS/Properties/AssemblyInfo.cs +++ b/src/kOS/Properties/AssemblyInfo.cs @@ -34,3 +34,4 @@ [assembly: AssemblyFileVersion("1.2.1.0")] [assembly: AssemblyVersion("1.2.1.0")] [assembly: KSPAssembly("kOS", 1, 7)] +[assembly: KSPAssemblyDependency("ClickThroughBlocker", 1, 0)] \ No newline at end of file diff --git a/src/kOS/Screen/DelegateDialog.cs b/src/kOS/Screen/DelegateDialog.cs index 8836ac6e64..d8cce5fcf7 100644 --- a/src/kOS/Screen/DelegateDialog.cs +++ b/src/kOS/Screen/DelegateDialog.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections.Generic; +using ClickThroughFix; // Needs ClickThroughBlocker DLL to be in the Reference directory. using UnityEngine; namespace kOS.Screen @@ -38,7 +39,7 @@ public void OnGUI() if (invoked) { float guessWidth = GUI.skin.label.CalcSize( new GUIContent(message) ).x; - GUILayout.Window( parent.GetUniqueId()+1, new Rect( parent.GetRect().xMin+200, + ClickThruBlocker.GUILayoutWindow( parent.GetUniqueId()+1, new Rect( parent.GetRect().xMin+200, parent.GetRect().yMin+10, guessWidth, 0) , DrawConfirm, "Confirm", GUILayout.ExpandWidth(true) ); diff --git a/src/kOS/Screen/GUIWindow.cs b/src/kOS/Screen/GUIWindow.cs index a5f6e30e8c..2d5e54ad9b 100644 --- a/src/kOS/Screen/GUIWindow.cs +++ b/src/kOS/Screen/GUIWindow.cs @@ -14,6 +14,7 @@ using kOS.Utilities; using kOS.Communication; using kOS.Safe; +using ClickThroughFix; // Needs ClickThroughBlocker DLL to be in the Reference directory. namespace kOS.Screen { @@ -116,7 +117,7 @@ void OnGUI() GUI.skin = HighLogic.Skin; - WindowRect = GUILayout.Window(UniqueId, WindowRect, WidgetGui, TitleText, style); + WindowRect = ClickThruBlocker.GUILayoutWindow(UniqueId, WindowRect, WidgetGui, TitleText, style); if (currentPopup != null) { var r = RectExtensions.EnsureCompletelyVisible(currentPopup.popupRect); @@ -124,7 +125,7 @@ void OnGUI() currentPopup.PopDown(); } else { GUI.BringWindowToFront(UniqueId + 1); - currentPopup.popupRect = GUILayout.Window(UniqueId + 1, r, PopupGui, "", style); + currentPopup.popupRect = ClickThruBlocker.GUILayoutWindow(UniqueId + 1, r, PopupGui, "", style); } } } diff --git a/src/kOS/Screen/KOSManagedWindow.cs b/src/kOS/Screen/KOSManagedWindow.cs index 5759c8b67e..77267fc2ef 100644 --- a/src/kOS/Screen/KOSManagedWindow.cs +++ b/src/kOS/Screen/KOSManagedWindow.cs @@ -1,14 +1,23 @@ using System.Collections.Generic; using UnityEngine; +using ClickThroughFix; // Needs ClickThroughBlocker DLL to be in the Reference directory. namespace kOS.Screen { /// /// kOSManagedWindow is for any Unity Monobehavior that you'd like to - /// have contain a GUI.Window, and you need kOS to keep track of the + /// have contain an IMGUI Window, and you need kOS to keep track of the /// window stacking for which click is on top of which other click. /// Unity's built in systems for this don't work well at all, so /// we had to make up our own. + /// + /// Issue #2697 - In addition to KOS's own system to handle this, + /// This also is now layered on top of Linuxgurugamer's ClickThroughBlocker + /// mod, so it uses its wrappers around GUI.Window. That was needed because + /// if SOME mods use ClickThruBlocker windows, then those windows will get first + /// dibs on events before kOS gets to, making kOS helpless to intercept events it's + /// trying to protect other windows from seeing. ClickThruBlocker is a mod that + /// once some mods use it, then all the other mods have to as well. /// public abstract class KOSManagedWindow : MonoBehaviour { diff --git a/src/kOS/Screen/KOSNameTagWindow.cs b/src/kOS/Screen/KOSNameTagWindow.cs index 2a6b462c27..4dc414b5da 100644 --- a/src/kOS/Screen/KOSNameTagWindow.cs +++ b/src/kOS/Screen/KOSNameTagWindow.cs @@ -1,6 +1,7 @@ -using kOS.Utilities; +using kOS.Utilities; using UnityEngine; using kOS.Module; +using ClickThroughFix; // Needs ClickThroughBlocker DLL to be in the Reference directory. using System; namespace kOS.Screen @@ -124,7 +125,7 @@ public void OnGUI() EditorLogic.fetch.Lock(false, false, false, "KOSNameTagLock"); GUI.skin = HighLogic.Skin; - GUILayout.Window(myWindowId, windowRect, DrawWindow,"KOS nametag"); + ClickThruBlocker.GUILayoutWindow(myWindowId, windowRect, DrawWindow,"KOS nametag"); // Ensure that the first time the window is made, it gets keybaord focus, // but allow the focus to leave the window after that: diff --git a/src/kOS/Screen/KOSTextEditPopup.cs b/src/kOS/Screen/KOSTextEditPopup.cs index c5dfd823e6..f351a94c02 100644 --- a/src/kOS/Screen/KOSTextEditPopup.cs +++ b/src/kOS/Screen/KOSTextEditPopup.cs @@ -6,6 +6,7 @@ using kOS.Safe.Exceptions; using kOS.Safe.Utilities; using kOS.Module; +using ClickThroughFix; // Needs ClickThroughBlocker DLL to be in the Reference directory. namespace kOS.Screen { @@ -170,7 +171,7 @@ public void OnGUI() CalcOuterCoords(); // force windowRect to lock to bottom edge of the parents CalcInnerCoords(); - WindowRect = GUI.Window(UniqueId, WindowRect, ProcessWindow, ""); + WindowRect = ClickThruBlocker.GUIWindow(UniqueId, WindowRect, ProcessWindow, ""); // Some mouse global state data used by several of the checks: if (consumeEvent) diff --git a/src/kOS/Screen/KOSToolbarWindow.cs b/src/kOS/Screen/KOSToolbarWindow.cs index ce18c7f4cc..e5e461db9c 100644 --- a/src/kOS/Screen/KOSToolbarWindow.cs +++ b/src/kOS/Screen/KOSToolbarWindow.cs @@ -10,6 +10,8 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; +using ClickThroughFix; // Needs ClickThroughBlocker DLL to be in the Reference directory. + namespace kOS.Screen { @@ -443,7 +445,7 @@ public void OnGUI() GUI.skin = HighLogic.Skin; - windowRect = GUILayout.Window(UNIQUE_ID, windowRect, DrawWindow, "kOS " + versionString); + windowRect = ClickThruBlocker.GUILayoutWindow(UNIQUE_ID, windowRect, DrawWindow, "kOS " + versionString); windowRect = RectExtensions.ClampToRectAngle(windowRect, rectToFit); } diff --git a/src/kOS/Screen/ListPickerDialog.cs b/src/kOS/Screen/ListPickerDialog.cs index 483c3d3c18..c902c13740 100644 --- a/src/kOS/Screen/ListPickerDialog.cs +++ b/src/kOS/Screen/ListPickerDialog.cs @@ -1,5 +1,7 @@ -using System.Collections.Generic; +using System.Collections.Generic; using UnityEngine; +using ClickThroughFix; // Needs ClickThroughBlocker DLL to be in the Reference directory. + namespace kOS.Screen { @@ -110,7 +112,7 @@ public void OnGUI() // Make sure it shifts enough to the left to fit the biggest string: outerWindowRect.x = Mathf.Min(outerWindowRect.x, UnityEngine.Screen.width - outerWindowRect.width - 60); - outerWindowRect = GUILayout.Window( + outerWindowRect = ClickThruBlocker.GUILayoutWindow( title.GetHashCode(), outerWindowRect, DrawInnards, diff --git a/src/kOS/Screen/TermWindow.cs b/src/kOS/Screen/TermWindow.cs index b9eba082f7..a15bb85202 100644 --- a/src/kOS/Screen/TermWindow.cs +++ b/src/kOS/Screen/TermWindow.cs @@ -10,6 +10,7 @@ using kOS.Safe.UserIO; using KSP.UI.Dialogs; using kOS.Safe.Utilities; +using ClickThroughFix; // Needs ClickThroughBlocker DLL to be in the Reference directory. namespace kOS.Screen { @@ -360,7 +361,7 @@ void OnGUI() // Should probably make "gui screen name for my CPU part" into some sort of utility method: ChangeTitle(CalcualteTitle()); - WindowRect = GUI.Window(UniqueId, WindowRect, TerminalGui, TitleText); + WindowRect = ClickThruBlocker.GUIWindow(UniqueId, WindowRect, TerminalGui, TitleText); if (consumeEvent) { diff --git a/src/kOS/UserIO/TelnetMainServer.cs b/src/kOS/UserIO/TelnetMainServer.cs index f8c9919b3c..3759201f9a 100644 --- a/src/kOS/UserIO/TelnetMainServer.cs +++ b/src/kOS/UserIO/TelnetMainServer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Net; using System.Net.NetworkInformation; using System.Collections.Generic; @@ -8,6 +8,8 @@ using kOS.Suffixed; using UnityEngine; using Debug = UnityEngine.Debug; +using ClickThroughFix; // Needs ClickThroughBlocker DLL to be in the Reference directory. + namespace kOS.UserIO { @@ -371,10 +373,10 @@ public bool SetBindAddrFromString(string s) void OnGUI() { if (activeOptInDialog) - optInRect = GUILayout.Window(401123, // any made up number unlikely to clash is okay here + optInRect = ClickThruBlocker.GUILayoutWindow(401123, // any made up number unlikely to clash is okay here optInRect, OptInOnGui, "kOS Telnet Opt-In Permisssion"); if (activeRealIPDialog) - realIPRect = GUILayout.Window(401124, // any made up number unlikely to clash is okay here + realIPRect = ClickThruBlocker.GUILayoutWindow(401124, // any made up number unlikely to clash is okay here realIPRect, RealIPOnGui, "kOS Telnet Non-Loopback Permisssion"); if (activeBgSimDialog) bgSimRect = GUILayout.Window(401125, // any made up number unlikely to clash is okay here diff --git a/src/kOS/kOS.csproj b/src/kOS/kOS.csproj index f7f8495605..defe6b8d64 100644 --- a/src/kOS/kOS.csproj +++ b/src/kOS/kOS.csproj @@ -37,6 +37,9 @@ ..\..\Resources\Assembly-CSharp-firstpass.dll + + ..\..\Resources\ClickThroughBlocker.dll + ..\..\Resources\GameData\kOS\Plugins\ICSharpCode.SharpZipLib.dll From ac8c7434fc9a5341f4fd0777ecb95a8d1fdbf186 Mon Sep 17 00:00:00 2001 From: Dunbaratu Date: Sat, 9 May 2020 18:10:16 -0500 Subject: [PATCH 2/8] Noted the new dependency on clickthru in compile instructions --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e65cc68274..fdace4f5c8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -218,7 +218,7 @@ Setting Up Your Environment installed, create a reference for it in your kOS project's References like so: - * $KSP_INSTALL_DIR/GameData/00_ClickThroughBlocker/Plugins/ClickThroughBlocker.dll + * $KSP/GameData/00_ClickThroughBlocker/Plugins/ClickThroughBlocker.dll 4. If you do not have a copy of KSP locally, you may download dummy assemblies at https://github.com/KSP-KOS/KSP_LIB From e373d02c00306e52afc9236b7d8b04fe4c6a2e2a Mon Sep 17 00:00:00 2001 From: Dunbaratu Date: Mon, 11 May 2020 14:39:20 -0500 Subject: [PATCH 3/8] added clickthroughblocker dependency to CKAN --- kOS.netkan | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kOS.netkan b/kOS.netkan index 7e7562daef..12795ff032 100644 --- a/kOS.netkan +++ b/kOS.netkan @@ -16,6 +16,12 @@ "repository" : "https://github.com/KSP-KOS/KOS" }, "conflicts" : [ { "name" : "kOS-Classic" } ], + "depends" : [ + { + "name" : ClickThroughBlocker", + "comment" : "For better cooperation with the many other mods that use it, kOS now also uses ClickThroughBlocker to open its GUI windows. But this means kOS won't work if ClickThroughBlocker is missing.
(Geek technical note: Any implementation that tried to make this dependency optional would have involved too much expensive Reflection.)" + } + ], "recommends" : [ { "name": "ModuleManager", From dab46b0a774bbb2a4a7e8f2eea560c75954287f7 Mon Sep 17 00:00:00 2001 From: Dunbaratu Date: Thu, 6 Aug 2020 23:41:25 -0500 Subject: [PATCH 4/8] Added focus-follows-mouse logic to kOS for CTB --- CONTRIBUTING.md | 13 ++++++- src/kOS/Screen/KOSManagedWindow.cs | 60 ++++++++++++++++++------------ src/kOS/kOS.csproj | 3 +- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fdace4f5c8..89d4155e9a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -215,11 +215,20 @@ Setting Up Your Environment 3. Make sure your installation of KSP has LinuxGuruGamer's ClivkThroughBlocker mod installed. kOS now needs it in order to compile. After it is - installed, create a reference for it in your kOS project's References - like so: + installed, copy its DLL file into Resources/ from your GameData folder. + + Copy This file: * $KSP/GameData/00_ClickThroughBlocker/Plugins/ClickThroughBlocker.dll + To here: + + * Resources/ + + Then *make a Reference to Resoruces/ClickThroughBlocker.dll in your kOS project + file*. This is needed for it to let you compile parts of kOS that use classes + from ClickThroughBlocker. + 4. If you do not have a copy of KSP locally, you may download dummy assemblies at https://github.com/KSP-KOS/KSP_LIB diff --git a/src/kOS/Screen/KOSManagedWindow.cs b/src/kOS/Screen/KOSManagedWindow.cs index 77267fc2ef..95e2496bf5 100644 --- a/src/kOS/Screen/KOSManagedWindow.cs +++ b/src/kOS/Screen/KOSManagedWindow.cs @@ -231,14 +231,13 @@ public bool IsOpen } /// - /// Pass in the absolute GUI screen location of a mouse click to decide whether - /// or not this widget gets keyboard focus because of that click. - /// (Clicking outside the window takes focus away. Clicking inside - /// the window gives focus to the window and brings it to the front.) - /// + /// Pass in the absolute GUI screen location of the mouse to decide whether + /// or not this window gets keyboard focus because of that position. + /// (If you want focus-follows-mouse logic, call this every Update(). If you + /// want click-to-focus logic, only call this in Update()s where a click just happened.) /// Absolute position of mouse on whole screen /// True if the window got focused, false if it didn't. - public bool FocusClickLocationCheck(Vector2 absMousePos) + public bool FocusMouseLocationCheck(Vector2 absMousePos) { bool wasInside = false; if (IsInsideMyExposedPortion(absMousePos)) @@ -295,18 +294,17 @@ public bool IsInsideMyExposedPortion(Vector2 posAbsolute) /// /// When you subclass KOSManagedWindow, make sure that you call this - /// from inside your Update. It does not use OnGUI because of the fact - /// that the OnGUI event handler is broken - it only sends MouseDown - /// and MouseUp events when the mouse is OUTSIDE the window, which is - /// utterly backward, and it's hard to work out how to fix this, - /// given how badly documented the Unity GUI API is. If anyone who - /// actually understands the Unity GUI system wants to fix this, - /// please feel free to do so. + /// from inside your Update() to check for focus change on the window. + /// Calling this will maybe call GetFocus() or LoseFocus() depending on + /// what the mouse is doing. + /// Note, you call this during *Update()*, NOT the OnGUI() call. + /// It does not use OnGUI() because the raw mousebutton state it + /// needs to see can get consumed and wiped by Unity's IMGUI widgets + /// before application code like this can see it. /// - /// True if there was a mouseclick within this window. - public bool UpdateLogic() + public void UpdateLogic() { - if (!IsOpen) return false; + if (!IsOpen) return; // Input.mousePosition, unlike Event.current.MousePosition, puts the origin at the // lower-left instead of upper-left of the screen, thus the subtraction in the y coord below: @@ -314,23 +312,37 @@ public bool UpdateLogic() // Mouse coord within the window, rather than within the screen. mousePosRelative = new Vector2( mousePosAbsolute.x - windowRect.xMin, mousePosAbsolute.y - windowRect.yMin); - - bool clickUp = false; + + // Could maybe cache the CustomParams call once up front to get a reference to the CTB instance, then only + // repeat the ".focusFollowsclick" part each update. The reason that's not being done here is that I + // noticed ClickThroughBlocker's OWN code always does it like this, and for all I know there might be + // an important reason. It always gets this value by using the fully qualified long chain you see + // here, starting from HighLogic, each update. : + bool clickToFocus = HighLogic.CurrentGame.Parameters.CustomParams().focusFollowsclick; + if (Input.GetMouseButtonDown(0)) { mouseButtonDownPosAbsolute = mousePosAbsolute; mouseButtonDownPosRelative = mousePosRelative; } - - if (Input.GetMouseButtonUp(0)) + + bool mousePositionCanSetFocus = !(clickToFocus); // Always true in focus-follows-mouse mode + + if (clickToFocus) { - clickUp = true; - if (Vector2.Distance(mousePosAbsolute,mouseButtonDownPosAbsolute) <= dragTolerance) + if (Input.GetMouseButtonUp(0)) { - FocusClickLocationCheck(mousePosAbsolute); + if (Vector2.Distance(mousePosAbsolute, mouseButtonDownPosAbsolute) <= dragTolerance) + { + mousePositionCanSetFocus = true; + } } } - return IsInsideMyExposedPortion(mousePosAbsolute) && clickUp; + + if (mousePositionCanSetFocus) + { + FocusMouseLocationCheck(mousePosAbsolute); + } } } } diff --git a/src/kOS/kOS.csproj b/src/kOS/kOS.csproj index defe6b8d64..4a7d441a02 100644 --- a/src/kOS/kOS.csproj +++ b/src/kOS/kOS.csproj @@ -37,7 +37,8 @@ ..\..\Resources\Assembly-CSharp-firstpass.dll - + + False ..\..\Resources\ClickThroughBlocker.dll From 7293f9237daa049e4af5e3b41f0152ca8da2b3b5 Mon Sep 17 00:00:00 2001 From: Dunbaratu Date: Fri, 7 Aug 2020 00:00:13 -0500 Subject: [PATCH 5/8] added min version to clickthroughblocker dependancy --- kOS.netkan | 1 + 1 file changed, 1 insertion(+) diff --git a/kOS.netkan b/kOS.netkan index 12795ff032..f35e006d3d 100644 --- a/kOS.netkan +++ b/kOS.netkan @@ -19,6 +19,7 @@ "depends" : [ { "name" : ClickThroughBlocker", + "min_version" : "0.10.0", "comment" : "For better cooperation with the many other mods that use it, kOS now also uses ClickThroughBlocker to open its GUI windows. But this means kOS won't work if ClickThroughBlocker is missing.
(Geek technical note: Any implementation that tried to make this dependency optional would have involved too much expensive Reflection.)" } ], From ec438dc498e6daa0f27cb0d03a89c82b4d775e6f Mon Sep 17 00:00:00 2001 From: Dunbaratu Date: Fri, 7 Aug 2020 00:19:30 -0500 Subject: [PATCH 6/8] fixed typo in netkan file. --- kOS.netkan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kOS.netkan b/kOS.netkan index f35e006d3d..a7435607e6 100644 --- a/kOS.netkan +++ b/kOS.netkan @@ -18,7 +18,7 @@ "conflicts" : [ { "name" : "kOS-Classic" } ], "depends" : [ { - "name" : ClickThroughBlocker", + "name" : "ClickThroughBlocker", "min_version" : "0.10.0", "comment" : "For better cooperation with the many other mods that use it, kOS now also uses ClickThroughBlocker to open its GUI windows. But this means kOS won't work if ClickThroughBlocker is missing.
(Geek technical note: Any implementation that tried to make this dependency optional would have involved too much expensive Reflection.)" } From f1399c96d895fa685d68241ebe169bccf308ee09 Mon Sep 17 00:00:00 2001 From: Dunbaratu Date: Fri, 7 Aug 2020 04:18:00 -0500 Subject: [PATCH 7/8] Removed netkan edit (it has to be a separate PR). After a long back and forth on the KSP forum with a CKAN expert, it seems I cannot put the kOS.netkan edit into the master branch until *after* I've cut a release from it or else CKAN's crawlerbot will incorrrectly associate that netkan change with the old previous release of kOS. (Thus making the old kOS say it's dependant on ClickThrougBlocker even though it's not.) That means I have to move the kOS.netkan edit into a separate PR that MUST come later after release (which feels very wrong). --- kOS.netkan | 7 ------- 1 file changed, 7 deletions(-) diff --git a/kOS.netkan b/kOS.netkan index a7435607e6..7e7562daef 100644 --- a/kOS.netkan +++ b/kOS.netkan @@ -16,13 +16,6 @@ "repository" : "https://github.com/KSP-KOS/KOS" }, "conflicts" : [ { "name" : "kOS-Classic" } ], - "depends" : [ - { - "name" : "ClickThroughBlocker", - "min_version" : "0.10.0", - "comment" : "For better cooperation with the many other mods that use it, kOS now also uses ClickThroughBlocker to open its GUI windows. But this means kOS won't work if ClickThroughBlocker is missing.
(Geek technical note: Any implementation that tried to make this dependency optional would have involved too much expensive Reflection.)" - } - ], "recommends" : [ { "name": "ModuleManager", From 02cc9cd735387297fa0a3adbfb9bc66df32d9122 Mon Sep 17 00:00:00 2001 From: Dunbaratu Date: Sat, 8 Aug 2020 00:20:56 -0500 Subject: [PATCH 8/8] Added popup on start about ClickThruBlocker. In case someone installs kOS without using CKAN, they won't know about the ClickThroughBlocker requirement. This addes a popup on Start() that will tell them what's going on with ClickThroughBlocker and warn them that kOS won't work without it. --- src/kOS/Module/kOSCustomParameters.cs | 93 +++++++++++++++++++++++++++ src/kOS/Module/kOSSettingsChecker.cs | 1 + src/kOS/Properties/AssemblyInfo.cs | 6 +- 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/kOS/Module/kOSCustomParameters.cs b/src/kOS/Module/kOSCustomParameters.cs index 65d270b222..32bccdfbb6 100644 --- a/src/kOS/Module/kOSCustomParameters.cs +++ b/src/kOS/Module/kOSCustomParameters.cs @@ -1,6 +1,7 @@ using KSP.IO; using System; using System.Reflection; +using System.Linq; namespace kOS.Module { @@ -46,6 +47,9 @@ public static kOSCustomParameters Instance [GameParameters.CustomIntParameterUI("")] public int version = 0; + [GameParameters.CustomParameterUI("")] + public bool passedClickThroughCheck = false; + // these values constrain and back the InstructionsPerUpdate property so that it is clamped both in the // user interface and when set from within a script. private const int ipuMin = 50; @@ -202,6 +206,95 @@ public void CheckMigrateSettings() } } + public void CheckClickThroughBlockerExists() + { + if (passedClickThroughCheck) + return; + bool clickThroughExists = false; + + var loadedCTBAssembly = AssemblyLoader.loadedAssemblies.FirstOrDefault(a => a.dllName.Equals("ClickThroughBlocker")); + if (loadedCTBAssembly != null) + { + // Must be at least version 0.10 of ClickThroughBlocker: + if (loadedCTBAssembly.versionMajor > 0 || loadedCTBAssembly.versionMinor >= 10) + { + Type ctbType = loadedCTBAssembly.assembly.GetType("ClickThroughFix.CTB", false); + if (ctbType != null) + { + if (ctbType.GetField("focusFollowsclick") != null) + { + clickThroughExists = true; + } + } + } + } + + string popupText = + "=======================================\n" + + "kOS is Checking for ClickThroughBlocker\n" + + "=======================================\n\n" + + "Starting with kOS v1.3, kOS has become dependent on the existence of the ClickThroughBlocker mod. " + + "(And it must be at least version 0.10 of ClickThroughBlocker.)\n\n"; + + if (clickThroughExists) + { + popupText += + " <<<< CHECK SUCCEEDED >>>>>\n\n" + + "kOS has found ClickThroughBlocker installed, and it appears to be a version that will work with kOS.\n" + + "\n" + + "Please note that while in the past the kOS terminal has always been click-to-focus, from now " + + "on it will behave however ClickThroughBlocker is set to act, which may be focus-follows-mouse.\n" + + "You can use ClickThroughBlocker's settings to change this behvior like this:\n\n" + + "[Hit Escape] Settings ->\n" + + " Difficulty Options ->\n" + + " ClickThroughBlocker ->\n" + + " [x] Focus Follows Click\n\n"; + } + else + { + popupText += + " !!! CHECK FAILED !!!\n\n" + + "kOS couldn't find a version of ClickThroughBlocker that works with kOS. This could be " + + "because ClickThroughBlocker is not installed at all, or it could be because its version is too old " + + "(or too new, if ClickThroughBlocker ever renames some things that kOS is using).\n" + + "\n\n" + + "To use kOS v1.3 or higher you'll need to quit Kerbal Space Program and install a version of ClickThroughBlocker that it supports.\n"; + } + + string buttonText; + global::Callback clickThroughAck; + if (clickThroughExists) + { + clickThroughAck = AcceptClickThrough; + buttonText = "Acknowledged."; + } + else + { + clickThroughAck = FailedClickThrough; + buttonText = "Acknowledged. I'll have to quit and change my mods."; + } + + kOSSettingsChecker.QueueDialog( + 0.75f, 0.6f, + new MultiOptionDialog( + "ClickThroughBlockerCheck", + popupText, + "kOS ClickThroughBlocker Check", + HighLogic.UISkin, + new DialogGUIButton(buttonText, clickThroughAck, true) + )); + } + + public void AcceptClickThrough() + { + passedClickThroughCheck = true; + } + + public void FailedClickThrough() + { + passedClickThroughCheck = false; + } + public void MigrateSettingsNormal() { MigrateSettings(false); diff --git a/src/kOS/Module/kOSSettingsChecker.cs b/src/kOS/Module/kOSSettingsChecker.cs index 89acb97f43..3e01f6be24 100644 --- a/src/kOS/Module/kOSSettingsChecker.cs +++ b/src/kOS/Module/kOSSettingsChecker.cs @@ -22,6 +22,7 @@ private void CheckSettings() SafeHouse.Logger.SuperVerbose("kOSSettingsChecker.CheckSettings()"); HighLogic.CurrentGame.Parameters.CustomParams().CheckMigrateSettings(); HighLogic.CurrentGame.Parameters.CustomParams().CheckNewManagers(); + HighLogic.CurrentGame.Parameters.CustomParams().CheckClickThroughBlockerExists(); } // Because rapidly showing dialogs can prevent some from being shown, we can just queue up diff --git a/src/kOS/Properties/AssemblyInfo.cs b/src/kOS/Properties/AssemblyInfo.cs index 380136409f..f9de84228d 100644 --- a/src/kOS/Properties/AssemblyInfo.cs +++ b/src/kOS/Properties/AssemblyInfo.cs @@ -34,4 +34,8 @@ [assembly: AssemblyFileVersion("1.2.1.0")] [assembly: AssemblyVersion("1.2.1.0")] [assembly: KSPAssembly("kOS", 1, 7)] -[assembly: KSPAssemblyDependency("ClickThroughBlocker", 1, 0)] \ No newline at end of file + +// No longer a hard dependancy, because we want to tell the user why kOS isn't working +// if ClickThroughBlocker is not there, rather than just have it silently refuse to +// load kOS with no explanation as would happen if this line was enabled: +// [assembly: KSPAssemblyDependency("ClickThroughBlocker", 1, 0)] \ No newline at end of file