1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

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
This commit is contained in:
reuk 2023-10-10 20:17:35 +01:00
parent 4fa2839a3f
commit 86d496d424
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
2 changed files with 50 additions and 32 deletions

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 };
const auto messageTypeMatches = [&] (UINT msg) { return m.message == msg; };
if (std::none_of (std::begin (keyMessages), std::end (keyMessages), messageTypeMatches))
if (hwnd == nullptr)
return false;
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { m.hwnd };
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { hwnd };
if (m.message == WM_CHAR)
return peer->doKeyChar ((int) m.wParam, m.lParam);
// If we've been sent a text character, process it as text.
switch (m.message)
if (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)
return peer->doKeyChar ((int) msg.wParam, msg.lParam);
// The event was a keypress, rather than a text character
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: