Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2020-03-06 09:24:12 +0300
committerCampbell Barton <ideasman42@gmail.com>2020-03-06 09:31:28 +0300
commit5be0e3430d13341feddee739997130239daf71d5 (patch)
treeb8af4c1d47d40425d0703883f8efdc0c297e37ea /intern/ghost
parent73ef27f15611ccb254816e199f8c74103b3d5172 (diff)
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.
Diffstat (limited to 'intern/ghost')
-rw-r--r--intern/ghost/GHOST_Types.h3
-rw-r--r--intern/ghost/intern/GHOST_EventKey.h11
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm4
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp18
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp73
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h2
9 files changed, 107 insertions, 10 deletions
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_version.present) {
@@ -1129,7 +1194,8 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
}
#endif
- g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, ascii, utf8_buf);
+ g_event = new GHOST_EventKey(
+ getMilliSeconds(), type, window, gkey, ascii, utf8_buf, is_repeat);
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
/* when using IM for some languages such as Japanese,
@@ -1153,7 +1219,8 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* enqueue previous character */
pushEvent(g_event);
- g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, '\0', &utf8_buf[i]);
+ g_event = new GHOST_EventKey(
+ getMilliSeconds(), type, window, gkey, '\0', &utf8_buf[i], is_repeat);
}
}
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index 67dd0789ac3..8736e20c57f 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -366,6 +366,8 @@ class GHOST_SystemX11 : public GHOST_System {
unsigned int m_last_release_keycode;
Time m_last_release_time;
+ uint m_keycode_last_repeat_key;
+
/**
* Return the ghost window associated with the
* X11 window xwind