|
1 | 1 | using System.Collections.Generic; |
2 | 2 | using UnityEngine; |
| 3 | +using ClickThroughFix; // Needs ClickThroughBlocker DLL to be in the Reference directory. |
3 | 4 |
|
4 | 5 | namespace kOS.Screen |
5 | 6 | { |
6 | 7 | /// <summary> |
7 | 8 | /// kOSManagedWindow is for any Unity Monobehavior that you'd like to |
8 | | - /// have contain a GUI.Window, and you need kOS to keep track of the |
| 9 | + /// have contain an IMGUI Window, and you need kOS to keep track of the |
9 | 10 | /// window stacking for which click is on top of which other click. |
10 | 11 | /// Unity's built in systems for this don't work well at all, so |
11 | 12 | /// we had to make up our own. |
| 13 | + /// |
| 14 | + /// Issue #2697 - In addition to KOS's own system to handle this, |
| 15 | + /// This also is now layered on top of Linuxgurugamer's ClickThroughBlocker |
| 16 | + /// mod, so it uses its wrappers around GUI.Window. That was needed because |
| 17 | + /// if SOME mods use ClickThruBlocker windows, then those windows will get first |
| 18 | + /// dibs on events before kOS gets to, making kOS helpless to intercept events it's |
| 19 | + /// trying to protect other windows from seeing. ClickThruBlocker is a mod that |
| 20 | + /// once some mods use it, then all the other mods have to as well. |
12 | 21 | /// </summary> |
13 | 22 | public abstract class KOSManagedWindow : MonoBehaviour |
14 | 23 | { |
@@ -222,14 +231,13 @@ public bool IsOpen |
222 | 231 | } |
223 | 232 |
|
224 | 233 | /// <summary> |
225 | | - /// Pass in the absolute GUI screen location of a mouse click to decide whether |
226 | | - /// or not this widget gets keyboard focus because of that click. |
227 | | - /// (Clicking outside the window takes focus away. Clicking inside |
228 | | - /// the window gives focus to the window and brings it to the front.) |
229 | | - /// </summary> |
| 234 | + /// Pass in the absolute GUI screen location of the mouse to decide whether |
| 235 | + /// or not this window gets keyboard focus because of that position. |
| 236 | + /// (If you want focus-follows-mouse logic, call this every Update(). If you |
| 237 | + /// want click-to-focus logic, only call this in Update()s where a click just happened.) |
230 | 238 | /// <param name="absMousePos">Absolute position of mouse on whole screen</param> |
231 | 239 | /// <returns>True if the window got focused, false if it didn't.</returns> |
232 | | - public bool FocusClickLocationCheck(Vector2 absMousePos) |
| 240 | + public bool FocusMouseLocationCheck(Vector2 absMousePos) |
233 | 241 | { |
234 | 242 | bool wasInside = false; |
235 | 243 | if (IsInsideMyExposedPortion(absMousePos)) |
@@ -286,42 +294,55 @@ public bool IsInsideMyExposedPortion(Vector2 posAbsolute) |
286 | 294 |
|
287 | 295 | /// <summary> |
288 | 296 | /// When you subclass KOSManagedWindow, make sure that you call this |
289 | | - /// from inside your Update. It does not use OnGUI because of the fact |
290 | | - /// that the OnGUI event handler is broken - it only sends MouseDown |
291 | | - /// and MouseUp events when the mouse is OUTSIDE the window, which is |
292 | | - /// utterly backward, and it's hard to work out how to fix this, |
293 | | - /// given how badly documented the Unity GUI API is. If anyone who |
294 | | - /// actually understands the Unity GUI system wants to fix this, |
295 | | - /// please feel free to do so. |
| 297 | + /// from inside your Update() to check for focus change on the window. |
| 298 | + /// Calling this will maybe call GetFocus() or LoseFocus() depending on |
| 299 | + /// what the mouse is doing. |
| 300 | + /// Note, you call this during *Update()*, NOT the OnGUI() call. |
| 301 | + /// It does not use OnGUI() because the raw mousebutton state it |
| 302 | + /// needs to see can get consumed and wiped by Unity's IMGUI widgets |
| 303 | + /// before application code like this can see it. |
296 | 304 | /// </summary> |
297 | | - /// <returns>True if there was a mouseclick within this window.</returns> |
298 | | - public bool UpdateLogic() |
| 305 | + public void UpdateLogic() |
299 | 306 | { |
300 | | - if (!IsOpen) return false; |
| 307 | + if (!IsOpen) return; |
301 | 308 |
|
302 | 309 | // Input.mousePosition, unlike Event.current.MousePosition, puts the origin at the |
303 | 310 | // lower-left instead of upper-left of the screen, thus the subtraction in the y coord below: |
304 | 311 | mousePosAbsolute = new Vector2( Input.mousePosition.x, UnityEngine.Screen.height - Input.mousePosition.y); |
305 | 312 |
|
306 | 313 | // Mouse coord within the window, rather than within the screen. |
307 | 314 | mousePosRelative = new Vector2( mousePosAbsolute.x - windowRect.xMin, mousePosAbsolute.y - windowRect.yMin); |
308 | | - |
309 | | - bool clickUp = false; |
| 315 | + |
| 316 | + // Could maybe cache the CustomParams call once up front to get a reference to the CTB instance, then only |
| 317 | + // repeat the ".focusFollowsclick" part each update. The reason that's not being done here is that I |
| 318 | + // noticed ClickThroughBlocker's OWN code always does it like this, and for all I know there might be |
| 319 | + // an important reason. It always gets this value by using the fully qualified long chain you see |
| 320 | + // here, starting from HighLogic, each update. : |
| 321 | + bool clickToFocus = HighLogic.CurrentGame.Parameters.CustomParams<ClickThroughFix.CTB>().focusFollowsclick; |
| 322 | + |
310 | 323 | if (Input.GetMouseButtonDown(0)) |
311 | 324 | { |
312 | 325 | mouseButtonDownPosAbsolute = mousePosAbsolute; |
313 | 326 | mouseButtonDownPosRelative = mousePosRelative; |
314 | 327 | } |
315 | | - |
316 | | - if (Input.GetMouseButtonUp(0)) |
| 328 | + |
| 329 | + bool mousePositionCanSetFocus = !(clickToFocus); // Always true in focus-follows-mouse mode |
| 330 | + |
| 331 | + if (clickToFocus) |
317 | 332 | { |
318 | | - clickUp = true; |
319 | | - if (Vector2.Distance(mousePosAbsolute,mouseButtonDownPosAbsolute) <= dragTolerance) |
| 333 | + if (Input.GetMouseButtonUp(0)) |
320 | 334 | { |
321 | | - FocusClickLocationCheck(mousePosAbsolute); |
| 335 | + if (Vector2.Distance(mousePosAbsolute, mouseButtonDownPosAbsolute) <= dragTolerance) |
| 336 | + { |
| 337 | + mousePositionCanSetFocus = true; |
| 338 | + } |
322 | 339 | } |
323 | 340 | } |
324 | | - return IsInsideMyExposedPortion(mousePosAbsolute) && clickUp; |
| 341 | + |
| 342 | + if (mousePositionCanSetFocus) |
| 343 | + { |
| 344 | + FocusMouseLocationCheck(mousePosAbsolute); |
| 345 | + } |
325 | 346 | } |
326 | 347 | } |
327 | 348 | } |
0 commit comments