|
|
|
@@ -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:
|
|
|
|
|