Hi Andreas,

On 30.03.2011 22:03, Andreas Ekstrand wrote:
Hi,

I have a situation where my rendering of an Fl_Gl_Window gets stuck while I'm 
holding Shift or Ctrl.

Normally, it works fine and I'm using shift + right mouse click + drag for 
zooming in a 3D model and ctrl + right mouse click + drag for moving.

But next to the Fl_Gl_Window is an Fl_Scroll and when that widget contains a 
lot of widgets

more than 20.000, I guess? ;-)

(don't know why that is related), the "while (have_message != 0&&  have_message != 
-1)" loop in fl_wait in Fl_win32.cxx gets stuck, so that PeekMessageW always returns 1 with 
a WM_KEYDOWN
or WM_MOUSEFIRST message.

WM_MOUSEMOVE ?

The result is that Fl::flush won't be called until I release Shift or Ctrl.

Any idea why this can happen

Yep. I think that your Fl_Scroll handles more FL_KEYDOWN and/or FL_SHORTCUT events than it can handle between two events.

The reason is that Windows sends WM_KEYDOWN events for *repeating*
Shift and Control keys. If FLTK can't deliver a FL_KEYDOWN event, it
converts it to FL_SHORTCUT, and sends this eventually to all widgets
(including children in your Fl_Scroll).

and how could I avoid it?

You should filter (consume) the events that lead to this problem.
There are two ways: (a) at the source (Fl_Gl_Window), (b) by
healing the symptoms (in Fl_Scroll). In both cases you must
derive a class and write your own handle() method. Then add
something like the following code in your handle() method.

(a) Fl_Gl_Window: I assume that this has the focus, and thus it
will get the FL_KEYDOWN and FL_SHJORTCUT events first. Then this
should help:

int My_Gl_Window::handle(int e) {
  /* ... */
  int key = Fl::event_key();
  if (dragging && e == FL_SHORTCUT &&
      (key==FL_Shift_L || key==FL_Shift_R ||
       key==FL_Control_L || key==FL_Control_R))
    return 1;           // *consume* repeating Shift/Ctrl keys
  /* ... */
  return Fl_Gl_Window::handle(e);
}

This assumes that you know when you're "dragging".


(b) Fl_Scroll:

int My_Scroll::handle(int e) {
  /* ... */
  int key = Fl::event_key();
  if (e == FL_SHORTCUT &&
      (key==FL_Shift_L || key==FL_Shift_R ||
       key==FL_Control_L || key==FL_Control_R))
    return 0;           // don't send repeating Shift/Ctrl keys
                        // to children
  /* ... */
  return Fl_Scroll::handle(e);
}


Notes:
 (1) Maybe you get FL_KEYBOARD events first, and you can filter
     these instead of FL_SHORTCUT.
 (2) Whatever you do, be careful not to filter useful events.
 (3) I'd prefer (a), and maybe you can filter unused events with
     better with the knowledge about your specific needs.
 (4) Repeating keys don't send FL_KEYUP events between FL_KEYDOWN
     events, so you can ignore these - or use this as a criterion
     for filtering...
 (5) Current FLTK versions don't distinguish FL_Shift_L and FL_Shift_R
     (you always get FL_Shift_L), but this is going to change...

WRT (5): I'm working on this, and I'll attach a patch for testing
purposes that I had lying around and that can help you to see what's
going on. Use it on the FLTK source tree: it patches test/keyboard.cxx.
Then make and run test/keyboard.exe. Currently this doesn't report
FL_SHORTCUT events, but this is probably caused by /using/ all the
FL_KEYDOWN events (I didn't check yet). This may be different in your
case.

Albrecht
Index: test/keyboard.cxx
===================================================================
--- test/keyboard.cxx   (Revision 8549)
+++ test/keyboard.cxx   (Arbeitskopie)
@@ -55,7 +55,49 @@
   return (e == FL_SHORTCUT); // eat all keystrokes
 }
 
+void handle_key(int e) {
+  const char *event;
+  const char *keyname = 0;
+  static int count;
+
+  switch (e) {
+    case FL_KEYDOWN:
+    case FL_KEYUP:
+      if (e==FL_KEYDOWN)
+        event = "KEYDOWN ";
+      else if (e==FL_KEYUP)
+       event = "KEYUP   ";
+      else if (e==FL_SHORTCUT)
+       event = "SHORTCUT";
+      switch (Fl::event_key()) {
+        case FL_Shift_L:
+         keyname = "Shift_L";
+         break;
+        case FL_Shift_R:
+         keyname = "Shift_R";
+         break;
+        case FL_Control_L:
+         keyname = "Ctrl_L ";
+         break;
+        case FL_Control_R:
+         keyname = "Ctrl_R ";
+         break;
+       default:
+         break;
+      }
+      if (keyname) {
+        count++;
+        printf("%5d: FL_%s (%s)\n",count,event,keyname);
+       fflush(stdout);
+      }
+      break;
+    default:
+      break;
+  }
+}
+
 int MyWindow::handle(int msg) {
+  handle_key(msg);
   if (msg==FL_MOUSEWHEEL)
   {
     roller_x->value( roller_x->value() + Fl::e_dx * roller_x->step() );
_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk

Reply via email to