Closed lazerW0lf closed 5 months ago
@lazerW0lf I have the same problem, any workaround?
Yeah,
Build the project from source and then you have a few options. I think I outlined a few of them in my issue. Let me know if any of those work for you.
I can get you more details tomorrow if you are still stuck.
Thanks, Jonathan
On Thu, Jul 14, 2022 at 11:45 PM xhuan8 @.***> wrote:
@lazerW0lf https://github.com/lazerW0lf I have the same problem, any workaround?
— Reply to this email directly, view it on GitHub https://github.com/opentk/GLWpfControl/issues/82#issuecomment-1185230008, or unsubscribe https://github.com/notifications/unsubscribe-auth/AZ6I5XDIQKBFLTWKXUUOMADVUECHFANCNFSM522QUHGQ . You are receiving this because you were mentioned.Message ID: @.***>
thanks, the problem is clear enough. the control should provide some method to unregister event handles
in my case, I only need one instance, but call Start() multiple times on window initialization I'll try keep the instance of control and avoid multiple Start() calls
This happens because the way we register currently to the KeyDown and KeyUp events. What we are doing currently is not the "correct" way, it's more of a workaround which seems to break badly in this example.
I think this issue is that the control is not considered "Focusable" and should therefore not be able to get keyboard events. I'm currently experimenting with a proper fix to this but I've not found a full solution as of yet.
I have same problem.If two windows contains GLWpfControl.Any key press will cause stackoverflow exception.for a single window ,It's Ok,but reopen this window .press any key,Then stackoverflow exception.
This happens because the way we register currently to the KeyDown and KeyUp events. What we are doing currently is not the "correct" way, it's more of a workaround which seems to break badly in this example.
I think this issue is that the control is not considered "Focusable" and should therefore not be able to get keyboard events. I'm currently experimenting with a proper fix to this but I've not found a full solution as of yet.
We handle keyboard and mouse event in Render methods.What about don't handle event by control itself?
I have not looked at this in too great of detail, but I believe #90 should at least create a workaround for this issue.
I have not looked at this in too great of detail, but I believe #90 should at least create a workaround for this issue.
Thanks .I gonna check
I also have this issue in version 4.2.3. Setting RegisterToEventsDirectly
and CanInvokeOnHandledEvents
to false on my controls seem to fix it though.
I also have this issue in version 4.2.3.
I have this issue as well. Setting RegisterToEventsDirectly
and CanInvokeOnHandledEvents
both to false also worked for me as @nrankin18 mentioned above.
Firstly, thanks for creating this control. It's very useful.
There are 2 ways to fix this issue.
The simplest fix is to set RegisterToEventsDirectly to false as suggested earlier. Setting RegisterToEventsDirectly to false simply causes the EventManager.RegisterClassHandler code to never be called. The EventManager.RegisterClassHandler code and it's associated event handlers have bugs in them, which I outline below in OPTION B.
With RegisterToEventsDirectly set to false, you can set Focusable="True" for the control if you need to get key events. This has worked for me without any problems. However, if you need your control to get key events when it doesn't have focus, then this solution is not viable.
There are 3 problems related to the event system that need to be addressed:
If for some reason you want to use the existing event system, or you don't want your control to be focusable, but still want key events, then the current event system's flaws need to be fixed. I have a fix for it here.
EventManager.RegisterClassHandler should be used in a static constructor normally, but for this code it's not and so it should be as follows (note that areEventsRegistered is a static bool added to the class and set to false initially) if used inside an instance member such as Start:
if (!areEventsRegistered )
{
areEventsRegistered = true;
EventManager.RegisterClassHandler(typeof(Control), Keyboard.KeyDownEvent, new KeyEventHandler(OnKeyDown), true );
EventManager.RegisterClassHandler(typeof(Control), Keyboard.KeyUpEvent, new KeyEventHandler(OnKeyUp), true );
}
The check for areEventsRegistered prevents more than 1 call to EventManager.RegisterClassHandler from occurring. Remember that EventManager.RegisterClassHandler creates a permanent event handler that lives for the entire lifetime of the application, not the class that called it.
The other issue, the actual cause of the stack overflow, was how the code decided if the event should be recycled or not. The check it used would only work for 1 instance of the control per application lifetime.
This is how I changed the OnKeyDown and OnKeyUp code to fix the stack overflow error (note that the handler is static, as it should be):
internal static void OnKeyDown(object sender, KeyEventArgs e)
{
foreach (var loadedGLWpfControl in loadedGLWpfControls)
{
if
(
(e.OriginalSource.GetType() != loadedGLWpfControl.GetType()) &&
(loadedGLWpfControl.IsFocused || loadedGLWpfControl.EnableGlobalEvents)
)
{
KeyEventArgs args = new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key);
args.RoutedEvent = Keyboard.KeyDownEvent;
loadedGLWpfControl.RaiseEvent(args);
}
}
}
Note the loadedGLWpfControl.EnableGlobalEvents check. This is there so that if you need your control to get the key event even when it doesn't have focus, then you set this to true.
If loadedGLWpfControl.EnableGlobalEvents is set to false, then your control only gets the event if it has focus using the loadedGLWpfControl.IsFocused check (for this to work your control must have Focusable="True").
So there are now 3 additional variables added to the class. I also removed CanInvokeOnHandledEvents and RegisterToEventsDirectly from my copy of the code since I don't need them.
private static List<GLWpfControlM> loadedGLWpfControls = new List<GLWpfControlM> ();
private static bool areEventsRegistered = false;
/// <summary>
/// Set to true to allow OnKeyDown and OnKeyUp to receive global events.
/// <para/>
///
/// Set to false to allow OnKeyDown and OnKeyUp to receive events only
/// when the control <see cref="UIElement.IsFocused"/> is set the true.
/// </summary>
public bool EnableGlobalEvents { get; set; } = true;
The static loadedGLWpfControls member is maintained by adding code to the existing Loaded and Unloaded handlers in the control as follows:
...
Loaded += (a, b) => {
loadedGLWpfControls.Add(this);
InvalidateVisual();
};
...
private void OnUnloaded()
{
loadedGLWpfControls.Remove(this);
_renderer?.SetSize(0,0, 1, 1, Format.X8R8G8B8);
}
With these changes, the stack overflow bug is fixed and with EnableGlobalEvents set to false you have the option of your control receiving key events only when it's in focus, or with EnableGlobalEvents set to true your control always receives key events even when not in focus, which can be useful in some cases.
With #86 we no longer call EventManager.RegisterClassHandler
so this should not be an issue after that is merged.
I still have this issue. I was on version 4.8.1 that i acquired from nuget. I just used the workaround RegisterToEventsDirectly = false;
note: I updated to the package and its fixed. oops
Problem: I am using version 4.2.2 and am instantiating multiple GLWpfControls (my application can have multiple tabs with an OGL-based scene) and am encountering a stack overflow upon launching the other GLWpf controller. I've found the root cause of this to be related to the OnKeyUp/OnKeyDown functions that ultimately call RaiseEvent.
Some possible solutions: I've worked around this in my local repo by checking if the event is handled or not. In my KeyUp/Down callbacks I've set the event's
Handled
property totrue
and I made the following edit:In GLWpfControl.cs:
Note that I added the
&& !e.Handled
and am flagging the event as Handled=true in my own key callbacks.My working theory is that two GLWpfControllers get into an infinite loop by catching/raising the event until the stack overflows.
At the very least, could we get some kind of user-level setting to enable/disable the event handling to avoid this. Or even a setting in
Start()
's to protect from this block:Something like