[Bf-blender-cvs] [5be0e3430d1] master: GHOST/Keymap: support for detecting repeat events

Campbell Barton noreply at git.blender.org
Fri Mar 6 07:33:35 CET 2020


Commit: 5be0e3430d13341feddee739997130239daf71d5
Author: Campbell Barton
Date:   Fri Mar 6 17:24:12 2020 +1100
Branches: master
https://developer.blender.org/rB5be0e3430d13341feddee739997130239daf71d5

GHOST/Keymap: support for detecting repeat events

- Keymap items now have 'repeat' boolean which can be set
  to make keymap items respond to key repeat events or not.
- Support for X11 & WIN32 (not macOS currently).

This allows for the possibility to perform actions while a key is held
and finish the action upon release.

Thanks to @Severin for review and WIN32 support.

===================================================================

M	intern/ghost/GHOST_Types.h
M	intern/ghost/intern/GHOST_EventKey.h
M	intern/ghost/intern/GHOST_NDOFManager.cpp
M	intern/ghost/intern/GHOST_SystemCocoa.mm
M	intern/ghost/intern/GHOST_SystemSDL.cpp
M	intern/ghost/intern/GHOST_SystemWin32.cpp
M	intern/ghost/intern/GHOST_SystemWin32.h
M	intern/ghost/intern/GHOST_SystemX11.cpp
M	intern/ghost/intern/GHOST_SystemX11.h
M	release/scripts/modules/rna_keymap_ui.py
M	source/blender/makesdna/DNA_windowmanager_types.h
M	source/blender/makesrna/intern/rna_wm.c
M	source/blender/makesrna/intern/rna_wm_api.c
M	source/blender/windowmanager/WM_types.h
M	source/blender/windowmanager/intern/wm_event_system.c
M	source/blender/windowmanager/intern/wm_keymap.c

===================================================================

diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 38a6a0b04d2..8bc75d01b96 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -542,6 +542,9 @@ typedef struct {
   char ascii;
   /** The unicode character. if the length is 6, not NULL terminated if all 6 are set */
   char utf8_buf[6];
+
+  /** Generated by auto-repeat. */
+  char is_repeat;
 } GHOST_TEventKeyData;
 
 typedef struct {
diff --git a/intern/ghost/intern/GHOST_EventKey.h b/intern/ghost/intern/GHOST_EventKey.h
index f42dc99aaa5..24e20b20659 100644
--- a/intern/ghost/intern/GHOST_EventKey.h
+++ b/intern/ghost/intern/GHOST_EventKey.h
@@ -38,12 +38,17 @@ class GHOST_EventKey : public GHOST_Event {
    * \param type  The type of key event.
    * \param key   The key code of the key.
    */
-  GHOST_EventKey(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow *window, GHOST_TKey key)
+  GHOST_EventKey(GHOST_TUns64 msec,
+                 GHOST_TEventType type,
+                 GHOST_IWindow *window,
+                 GHOST_TKey key,
+                 bool is_repeat)
       : GHOST_Event(msec, type, window)
   {
     m_keyEventData.key = key;
     m_keyEventData.ascii = '\0';
     m_keyEventData.utf8_buf[0] = '\0';
+    m_keyEventData.is_repeat = is_repeat;
     m_data = &m_keyEventData;
   }
 
@@ -59,7 +64,8 @@ class GHOST_EventKey : public GHOST_Event {
                  GHOST_IWindow *window,
                  GHOST_TKey key,
                  char ascii,
-                 const char utf8_buf[6])
+                 const char utf8_buf[6],
+                 bool is_repeat)
       : GHOST_Event(msec, type, window)
   {
     m_keyEventData.key = key;
@@ -68,6 +74,7 @@ class GHOST_EventKey : public GHOST_Event {
       memcpy(m_keyEventData.utf8_buf, utf8_buf, sizeof(m_keyEventData.utf8_buf));
     else
       m_keyEventData.utf8_buf[0] = '\0';
+    m_keyEventData.is_repeat = is_repeat;
     m_data = &m_keyEventData;
   }
 
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index 9999bfd7ea6..3fe61ee0aa9 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -318,7 +318,7 @@ void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key,
                                      GHOST_IWindow *window)
 {
   GHOST_TEventType type = press ? GHOST_kEventKeyDown : GHOST_kEventKeyUp;
-  GHOST_EventKey *event = new GHOST_EventKey(time, type, window, key);
+  GHOST_EventKey *event = new GHOST_EventKey(time, type, window, key, false);
 
 #ifdef DEBUG_NDOF_BUTTONS
   printf("keyboard %s\n", press ? "down" : "up");
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index b65404cf9b1..ee05505f682 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -1806,7 +1806,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
 
       if ([event type] == NSEventTypeKeyDown) {
         pushEvent(new GHOST_EventKey(
-            [event timestamp] * 1000, GHOST_kEventKeyDown, window, keyCode, ascii, utf8_buf));
+            [event timestamp] * 1000, GHOST_kEventKeyDown, window, keyCode, ascii, utf8_buf, false));
 #if 0
         printf("Key down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",
                [event keyCode],
@@ -1820,7 +1820,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
       }
       else {
         pushEvent(new GHOST_EventKey(
-            [event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, 0, NULL));
+            [event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, 0, NULL, false));
 #if 0
         printf("Key up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",
                [event keyCode],
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index 7ed912b8218..656afb9d050 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -591,7 +591,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
         }
       }
 
-      g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, sym, NULL);
+      g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, sym, NULL, false);
       break;
     }
   }
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 7d2a8f5810c..5bf40ba33d0 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -1047,6 +1047,20 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
   if (key != GHOST_kKeyUnknown) {
     char utf8_char[6] = {0};
     char ascii = 0;
+    bool is_repeat = false;
+
+    /* Unlike on Linux, not all keys can send repeat events. E.g. modifier keys don't. */
+    if (keyDown) {
+      if (system->m_keycode_last_repeat_key == vk) {
+          is_repeat = true;
+      }
+      system->m_keycode_last_repeat_key = vk;
+    }
+    else {
+      if (system->m_keycode_last_repeat_key == vk) {
+        system->m_keycode_last_repeat_key = 0;
+      }
+    }
 
     wchar_t utf16[3] = {0};
     BYTE state[256] = {0};
@@ -1083,7 +1097,8 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
                                window,
                                key,
                                ascii,
-                               utf8_char);
+                               utf8_char,
+                               is_repeat);
 
     // GHOST_PRINTF("%c\n", ascii); // we already get this info via EventPrinter
   }
@@ -1520,6 +1535,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
             modifiers.clear();
             system->storeModifierKeys(modifiers);
             system->m_wheelDeltaAccum = 0;
+            system->m_keycode_last_repeat_key = 0;
             event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate :
                                                         GHOST_kEventWindowDeactivate,
                                        window);
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index c5af3e120be..bf9d18ca380 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -414,6 +414,8 @@ class GHOST_SystemWin32 : public GHOST_System {
 
   /** The current state of the modifier keys. */
   GHOST_ModifierKeys m_modifierKeys;
+  /** The virtual-key code (VKey) of the last press event. Used to detect repeat events. */
+  unsigned short m_keycode_last_repeat_key;
   /** State variable set at initialization. */
   bool m_hasPerformanceCounter;
   /** High frequency timer variable. */
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 60d08305621..05c311077f9 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -93,6 +93,11 @@
  * instead of active one. See T47228 and D1746 */
 #define USE_NON_LATIN_KB_WORKAROUND
 
+static uchar bit_is_on(const uchar *ptr, int bit)
+{
+  return ptr[bit >> 3] & (1 << (bit & 7));
+}
+
 static GHOST_TKey ghost_key_from_keysym(const KeySym key);
 static GHOST_TKey ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCode keycode);
 static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key,
@@ -196,6 +201,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_
     m_xkb_descr = XkbGetMap(m_display, 0, XkbUseCoreKbd);
     if (m_xkb_descr) {
       XkbGetNames(m_display, XkbKeyNamesMask, m_xkb_descr);
+      XkbGetControls(m_display, XkbPerKeyRepeatMask | XkbRepeatKeysMask, m_xkb_descr);
     }
   }
 
@@ -747,7 +753,8 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
                                                window,
                                                ghost_key_from_keysym(modifiers[i]),
                                                '\0',
-                                               NULL));
+                                               NULL,
+                                               false));
                 }
               }
             }
@@ -822,6 +829,64 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
   GHOST_WindowX11 *window = findGhostWindow(xe->xany.window);
   GHOST_Event *g_event = NULL;
 
+  /* Detect auto-repeat. */
+  bool is_repeat = false;
+  if (xe->type == KeyPress || xe->type == KeyRelease) {
+    XKeyEvent *xke = &(xe->xkey);
+
+    /* Set to true if this key will repeat. */
+    bool is_repeat_keycode = false;
+
+    if (m_xkb_descr != NULL) {
+      /* Use XKB support. */
+      is_repeat_keycode = (
+          /* Should always be true, check just in case. */
+          (xke->keycode < (XkbPerKeyBitArraySize << 3)) &&
+          bit_is_on(m_xkb_descr->ctrls->per_key_repeat, xke->keycode));
+    }
+    else {
+      /* No XKB support (filter by modifier). */
+      switch (XLookupKeysym(xke, 0)) {
+        case XK_Shift_L:
+        case XK_Shift_R:
+        case XK_Control_L:
+        case XK_Control_R:
+        case XK_Alt_L:
+        case XK_Alt_R:
+        case XK_Super_L:
+        case XK_Super_R:
+        case XK_Hyper_L:
+        case XK_Hyper_R:
+        case XK_Caps_Lock:
+        case XK_Scroll_Lock:
+        case XK_Num_Lock: {
+          break;
+        }
+        default: {
+          is_repeat_keycode = true;
+        }
+      }
+    }
+
+    if (is_repeat_keycode) {
+      if (xe->type == KeyPress) {
+        if (m_keycode_last_repeat_key == xke->keycode) {
+          is_repeat = true;
+        }
+        m_keycode_last_repeat_key = xke->keycode;
+      }
+      else {
+        if (m_keycode_last_repeat_key == xke->keycode) {
+          m_keycode_last_repeat_key = (uint)-1;
+        }
+      }
+    }
+  }
+  else if (xe->type == EnterNotify) {
+    /* We can't tell how the key state changed, clear it to avoid stuck keys. */
+    m_keycode_last_repeat_key = (uint)-1;
+  }
+
 #ifdef USE_XINPUT_HOTPLUG
   /* Hot-Plug support */
   if (m_xinput_ve

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list