Browse Source

WindowsHooks: Attempt to fix keyboard issues for plugin clients

This patch should resolve an issue introduced in
0ab30555fc where arrow keys and other
directional keys (home, end, page up, page down) stopped working as
expected.

With this patch in place,
- IME input in plugins should work correctly, including for languages
  with a selection palette (Japanese) and languages where multiple
  keypresses combine to a single character (Korean).
- Keyboard shortcuts should work (cut, copy, paste)
- Directional keys should work
v7.0.9
reuk 2 years ago
parent
commit
86d496d424
No known key found for this signature in database GPG Key ID: FCB43929F012EE5C
2 changed files with 49 additions and 31 deletions
  1. +46
    -27
      modules/juce_gui_basics/native/juce_Windowing_windows.cpp
  2. +3
    -4
      modules/juce_gui_basics/native/juce_WindowsHooks_windows.cpp

+ 46
- 27
modules/juce_gui_basics/native/juce_Windowing_windows.cpp View File

@@ -2329,49 +2329,68 @@ public:
JUCE_DECLARE_NON_COPYABLE (FileDropTarget)
};
static bool offerKeyMessageToJUCEWindow (MSG& m)
static bool offerKeyMessageToJUCEWindow (const MSG& msg)
{
auto* peer = getOwnerOfWindow (m.hwnd);
// If this isn't a keyboard message, let the host deal with it.
if (peer == nullptr)
constexpr UINT messages[] { WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP, WM_CHAR, WM_SYSCHAR };
if (std::find (std::begin (messages), std::end (messages), msg.message) == std::end (messages))
return false;
auto* peer = getOwnerOfWindow (msg.hwnd);
auto* focused = Component::getCurrentlyFocusedComponent();
if (focused == nullptr || focused->getPeer() != peer)
if (focused == nullptr || peer == nullptr || focused->getPeer() != peer)
return false;
if (TranslateMessage (&m))
return true;
auto* hwnd = static_cast<HWND> (peer->getNativeHandle());
constexpr UINT keyMessages[] { WM_KEYDOWN,
WM_KEYUP,
WM_SYSKEYDOWN,
WM_SYSKEYUP,
WM_CHAR };
if (hwnd == nullptr)
return false;
const auto messageTypeMatches = [&] (UINT msg) { return m.message == msg; };
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { hwnd };
if (std::none_of (std::begin (keyMessages), std::end (keyMessages), messageTypeMatches))
return false;
// If we've been sent a text character, process it as text.
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { m.hwnd };
if (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)
return peer->doKeyChar ((int) msg.wParam, msg.lParam);
if (m.message == WM_CHAR)
return peer->doKeyChar ((int) m.wParam, m.lParam);
// The event was a keypress, rather than a text character
switch (m.message)
if (auto* target = peer->findCurrentTextInputTarget())
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
return peer->doKeyDown (m.wParam);
// If there's a focused text input target, we want to attempt "real" text input with an
// IME, and we want to prevent the host from eating keystrokes (spaces etc.).
case WM_KEYUP:
case WM_SYSKEYUP:
return peer->doKeyUp (m.wParam);
TranslateMessage (&msg);
// TranslateMessage may post WM_CHAR back to the window, so we remove those messages
// from the queue before the host gets to see them.
// This will dispatch pending WM_CHAR messages, so we may end up reentering
// offerKeyMessageToJUCEWindow and hitting the WM_CHAR case above.
// We always return true if WM_CHAR is posted so that the keypress is not forwarded
// to the host. Otherwise, the host may call TranslateMessage again on this message,
// resulting in duplicate WM_CHAR messages being posted.
MSG peeked{};
if (PeekMessage (&peeked, hwnd, WM_CHAR, WM_DEADCHAR, PM_REMOVE)
|| PeekMessage (&peeked, hwnd, WM_SYSCHAR, WM_SYSDEADCHAR, PM_REMOVE))
{
return true;
}
// If TranslateMessage didn't add a WM_CHAR to the queue, fall back to processing the
// event as a plain keypress
}
return false;
// There's no text input target, or the key event wasn't translated, so we'll just see if we
// can use the plain keystroke event
if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
return peer->doKeyDown (msg.wParam);
return peer->doKeyUp (msg.wParam);
}
double getPlatformScaleFactor() const noexcept override
@@ -4350,10 +4369,10 @@ private:
case WM_IME_SETCONTEXT:
imeHandler.handleSetContext (h, wParam == TRUE);
lParam &= ~(LPARAM) ISC_SHOWUICOMPOSITIONWINDOW;
break;
return ImmIsUIMessage (h, message, wParam, lParam);
case WM_IME_STARTCOMPOSITION: imeHandler.handleStartComposition (*this); return 0;
case WM_IME_ENDCOMPOSITION: imeHandler.handleEndComposition (*this, h); break;
case WM_IME_ENDCOMPOSITION: imeHandler.handleEndComposition (*this, h); return 0;
case WM_IME_COMPOSITION: imeHandler.handleComposition (*this, h, lParam); return 0;
case WM_GETDLGCODE:


+ 3
- 4
modules/juce_gui_basics/native/juce_WindowsHooks_windows.cpp View File

@@ -65,12 +65,11 @@ private:
static LRESULT CALLBACK keyboardHookCallback (int nCode, WPARAM wParam, LPARAM lParam)
{
MSG& msg = *(MSG*) lParam;
auto& msg = *reinterpret_cast<MSG*> (lParam);
if (nCode == HC_ACTION && wParam == PM_REMOVE
&& HWNDComponentPeer::offerKeyMessageToJUCEWindow (msg))
if (nCode == HC_ACTION && wParam == PM_REMOVE && HWNDComponentPeer::offerKeyMessageToJUCEWindow (msg))
{
zerostruct (msg);
msg = {};
msg.message = WM_USER;
return 0;
}


Loading…
Cancel
Save