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:
parent
4fa2839a3f
commit
86d496d424
2 changed files with 50 additions and 32 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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…
Add table
Add a link
Reference in a new issue