mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Fixed an issue where active x component would not receive all key events
This commit is contained in:
parent
e8ac4a7c27
commit
1169800b8a
3 changed files with 139 additions and 83 deletions
|
|
@ -112,6 +112,10 @@ namespace WindowsMessageHelpers
|
|||
}
|
||||
}
|
||||
|
||||
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
|
||||
LRESULT juce_offerEventToActiveXControl (::MSG&);
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages)
|
||||
{
|
||||
|
|
@ -123,6 +127,11 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPend
|
|||
|
||||
if (GetMessage (&m, (HWND) 0, 0, 0) >= 0)
|
||||
{
|
||||
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
|
||||
if (juce_offerEventToActiveXControl (m) != S_FALSE)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if (m.message == customMessageID && m.hwnd == juce_messageWindowHandle)
|
||||
{
|
||||
dispatchMessageFromLParam (m.lParam);
|
||||
|
|
|
|||
|
|
@ -107,11 +107,15 @@ public:
|
|||
/** @internal */
|
||||
void paint (Graphics&) override;
|
||||
|
||||
/** @internal */
|
||||
intptr_t offerEventToActiveXControl (void*);
|
||||
static intptr_t offerEventToActiveXControlStatic (void*);
|
||||
|
||||
private:
|
||||
class Pimpl;
|
||||
friend struct ContainerDeletePolicy<Pimpl>;
|
||||
ScopedPointer<Pimpl> control;
|
||||
bool mouseEventsAllowed;
|
||||
bool mouseEventsAllowed = true;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ActiveXControlComponent)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,16 +38,15 @@ extern int64 getMouseEventTime();
|
|||
#define JUCE_COMCLASS(name, guid)
|
||||
#endif
|
||||
|
||||
JUCE_COMCLASS (IOleObject, "00000112-0000-0000-C000-000000000046")
|
||||
JUCE_COMCLASS (IOleWindow, "00000114-0000-0000-C000-000000000046")
|
||||
JUCE_COMCLASS (IOleInPlaceSite, "00000119-0000-0000-C000-000000000046")
|
||||
JUCE_COMCLASS (IOleObject, "00000112-0000-0000-C000-000000000046")
|
||||
JUCE_COMCLASS (IOleWindow, "00000114-0000-0000-C000-000000000046")
|
||||
JUCE_COMCLASS (IOleInPlaceSite, "00000119-0000-0000-C000-000000000046")
|
||||
|
||||
namespace ActiveXHelpers
|
||||
{
|
||||
//==============================================================================
|
||||
class JuceIStorage : public ComBaseClassHelper <IStorage>
|
||||
struct JuceIStorage : public ComBaseClassHelper<IStorage>
|
||||
{
|
||||
public:
|
||||
JuceIStorage() {}
|
||||
|
||||
JUCE_COMRESULT CreateStream (const WCHAR*, DWORD, DWORD, DWORD, IStream**) { return E_NOTIMPL; }
|
||||
|
|
@ -68,32 +67,38 @@ namespace ActiveXHelpers
|
|||
};
|
||||
|
||||
//==============================================================================
|
||||
class JuceOleInPlaceFrame : public ComBaseClassHelper <IOleInPlaceFrame>
|
||||
struct JuceOleInPlaceFrame : public ComBaseClassHelper<IOleInPlaceFrame>
|
||||
{
|
||||
public:
|
||||
JuceOleInPlaceFrame (HWND hwnd) : window (hwnd) {}
|
||||
|
||||
JUCE_COMRESULT GetWindow (HWND* lphwnd) { *lphwnd = window; return S_OK; }
|
||||
JUCE_COMRESULT ContextSensitiveHelp (BOOL) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT GetBorder (LPRECT) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT RequestBorderSpace (LPCBORDERWIDTHS) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT SetBorderSpace (LPCBORDERWIDTHS) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT SetActiveObject (IOleInPlaceActiveObject*, LPCOLESTR) { return S_OK; }
|
||||
JUCE_COMRESULT InsertMenus (HMENU, LPOLEMENUGROUPWIDTHS) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT SetMenu (HMENU, HOLEMENU, HWND) { return S_OK; }
|
||||
JUCE_COMRESULT RemoveMenus (HMENU) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT SetStatusText (LPCOLESTR) { return S_OK; }
|
||||
JUCE_COMRESULT EnableModeless (BOOL) { return S_OK; }
|
||||
JUCE_COMRESULT TranslateAccelerator (LPMSG, WORD) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT GetWindow (HWND* lphwnd) { *lphwnd = window; return S_OK; }
|
||||
JUCE_COMRESULT ContextSensitiveHelp (BOOL) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT GetBorder (LPRECT) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT RequestBorderSpace (LPCBORDERWIDTHS) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT SetBorderSpace (LPCBORDERWIDTHS) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT SetActiveObject (IOleInPlaceActiveObject* a, LPCOLESTR) { activeObject = a; return S_OK; }
|
||||
JUCE_COMRESULT InsertMenus (HMENU, LPOLEMENUGROUPWIDTHS) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT SetMenu (HMENU, HOLEMENU, HWND) { return S_OK; }
|
||||
JUCE_COMRESULT RemoveMenus (HMENU) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT SetStatusText (LPCOLESTR) { return S_OK; }
|
||||
JUCE_COMRESULT EnableModeless (BOOL) { return S_OK; }
|
||||
JUCE_COMRESULT TranslateAccelerator (LPMSG, WORD) { return E_NOTIMPL; }
|
||||
|
||||
HRESULT OfferKeyTranslation (LPMSG lpmsg)
|
||||
{
|
||||
if (activeObject != nullptr)
|
||||
return activeObject->TranslateAcceleratorW (lpmsg);
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
private:
|
||||
HWND window;
|
||||
ComSmartPtr<IOleInPlaceActiveObject> activeObject;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class JuceIOleInPlaceSite : public ComBaseClassHelper <IOleInPlaceSite>
|
||||
struct JuceIOleInPlaceSite : public ComBaseClassHelper<IOleInPlaceSite>
|
||||
{
|
||||
public:
|
||||
JuceIOleInPlaceSite (HWND hwnd)
|
||||
: window (hwnd),
|
||||
frame (new JuceOleInPlaceFrame (window))
|
||||
|
|
@ -131,17 +136,22 @@ namespace ActiveXHelpers
|
|||
JUCE_COMRESULT DeactivateAndUndo() { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT OnPosRectChange (LPCRECT) { return S_OK; }
|
||||
|
||||
private:
|
||||
LRESULT offerEventToActiveXControl (::MSG& msg)
|
||||
{
|
||||
if (frame != nullptr)
|
||||
return frame->OfferKeyTranslation (&msg);
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
HWND window;
|
||||
JuceOleInPlaceFrame* frame;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class JuceIOleClientSite : public ComBaseClassHelper <IOleClientSite>
|
||||
struct JuceIOleClientSite : public ComBaseClassHelper<IOleClientSite>
|
||||
{
|
||||
public:
|
||||
JuceIOleClientSite (HWND window)
|
||||
: inplaceSite (new JuceIOleInPlaceSite (window))
|
||||
JuceIOleClientSite (HWND window) : inplaceSite (new JuceIOleInPlaceSite (window))
|
||||
{}
|
||||
|
||||
~JuceIOleClientSite()
|
||||
|
|
@ -168,19 +178,26 @@ namespace ActiveXHelpers
|
|||
JUCE_COMRESULT OnShowWindow (BOOL) { return E_NOTIMPL; }
|
||||
JUCE_COMRESULT RequestNewObjectLayout() { return E_NOTIMPL; }
|
||||
|
||||
private:
|
||||
LRESULT offerEventToActiveXControl (::MSG& msg)
|
||||
{
|
||||
if (inplaceSite != nullptr)
|
||||
return inplaceSite->offerEventToActiveXControl (msg);
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
JuceIOleInPlaceSite* inplaceSite;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static Array<ActiveXControlComponent*> activeXComps;
|
||||
|
||||
HWND getHWND (const ActiveXControlComponent* const component)
|
||||
static inline HWND getHWND (const ActiveXControlComponent* const component)
|
||||
{
|
||||
HWND hwnd = 0;
|
||||
const IID iid = __uuidof(IOleWindow);
|
||||
HWND hwnd = {};
|
||||
const IID iid = __uuidof (IOleWindow);
|
||||
|
||||
if (IOleWindow* const window = (IOleWindow*) component->queryInterface (&iid))
|
||||
if (auto* window = (IOleWindow*) component->queryInterface (&iid))
|
||||
{
|
||||
window->GetWindow (&hwnd);
|
||||
window->Release();
|
||||
|
|
@ -189,12 +206,8 @@ namespace ActiveXHelpers
|
|||
return hwnd;
|
||||
}
|
||||
|
||||
void offerActiveXMouseEventToPeer (ComponentPeer* const peer, HWND hwnd, UINT message, LPARAM lParam)
|
||||
static inline void offerActiveXMouseEventToPeer (ComponentPeer* peer, HWND hwnd, UINT message, LPARAM lParam)
|
||||
{
|
||||
RECT activeXRect, peerRect;
|
||||
GetWindowRect (hwnd, &activeXRect);
|
||||
GetWindowRect ((HWND) peer->getNativeHandle(), &peerRect);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_MOUSEMOVE:
|
||||
|
|
@ -204,13 +217,20 @@ namespace ActiveXHelpers
|
|||
case WM_LBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
{
|
||||
RECT activeXRect, peerRect;
|
||||
GetWindowRect (hwnd, &activeXRect);
|
||||
GetWindowRect ((HWND) peer->getNativeHandle(), &peerRect);
|
||||
|
||||
peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse,
|
||||
{ (float) (GET_X_LPARAM (lParam) + activeXRect.left - peerRect.left),
|
||||
(float) (GET_Y_LPARAM (lParam) + activeXRect.top - peerRect.top) },
|
||||
ModifierKeys::getCurrentModifiersRealtime(),
|
||||
MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation,
|
||||
MouseInputSource::invalidPressure,
|
||||
MouseInputSource::invalidOrientation,
|
||||
getMouseEventTime());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
@ -225,11 +245,8 @@ public:
|
|||
Pimpl (HWND hwnd, ActiveXControlComponent& activeXComp)
|
||||
: ComponentMovementWatcher (&activeXComp),
|
||||
owner (activeXComp),
|
||||
controlHWND (0),
|
||||
storage (new ActiveXHelpers::JuceIStorage()),
|
||||
clientSite (new ActiveXHelpers::JuceIOleClientSite (hwnd)),
|
||||
control (nullptr),
|
||||
originalWndProc (0)
|
||||
clientSite (new ActiveXHelpers::JuceIOleClientSite (hwnd))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +262,7 @@ public:
|
|||
storage->Release();
|
||||
}
|
||||
|
||||
void setControlBounds (const Rectangle<int>& newBounds) const
|
||||
void setControlBounds (Rectangle<int> newBounds) const
|
||||
{
|
||||
if (controlHWND != 0)
|
||||
MoveWindow (controlHWND, newBounds.getX(), newBounds.getY(), newBounds.getWidth(), newBounds.getHeight(), TRUE);
|
||||
|
|
@ -260,8 +277,8 @@ public:
|
|||
//==============================================================================
|
||||
void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
|
||||
{
|
||||
if (ComponentPeer* const peer = owner.getTopLevelComponent()->getPeer())
|
||||
setControlBounds (peer->getAreaCoveredBy (owner));
|
||||
if (auto* peer = owner.getTopLevelComponent()->getPeer())
|
||||
setControlBounds (peer->getAreaCoveredBy(owner));
|
||||
}
|
||||
|
||||
void componentPeerChanged() override
|
||||
|
|
@ -278,38 +295,36 @@ public:
|
|||
// intercepts events going to an activeX control, so we can sneakily use the mouse events
|
||||
static LRESULT CALLBACK activeXHookWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
for (int i = ActiveXHelpers::activeXComps.size(); --i >= 0;)
|
||||
for (auto* ax : ActiveXHelpers::activeXComps)
|
||||
{
|
||||
const ActiveXControlComponent* const ax = ActiveXHelpers::activeXComps.getUnchecked(i);
|
||||
|
||||
if (ax->control != nullptr && ax->control->controlHWND == hwnd)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_LBUTTONDBLCLK:
|
||||
case WM_MBUTTONDBLCLK:
|
||||
case WM_RBUTTONDBLCLK:
|
||||
if (ax->isShowing())
|
||||
{
|
||||
if (ComponentPeer* const peer = ax->getPeer())
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_LBUTTONDBLCLK:
|
||||
case WM_MBUTTONDBLCLK:
|
||||
case WM_RBUTTONDBLCLK:
|
||||
if (ax->isShowing())
|
||||
{
|
||||
ActiveXHelpers::offerActiveXMouseEventToPeer (peer, hwnd, message, lParam);
|
||||
if (auto* peer = ax->getPeer())
|
||||
{
|
||||
ActiveXHelpers::offerActiveXMouseEventToPeer (peer, hwnd, message, lParam);
|
||||
|
||||
if (! ax->areMouseEventsAllowed())
|
||||
return 0;
|
||||
if (! ax->areMouseEventsAllowed())
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc (ax->control->originalWndProc, hwnd, message, wParam, lParam);
|
||||
|
|
@ -320,16 +335,15 @@ public:
|
|||
}
|
||||
|
||||
ActiveXControlComponent& owner;
|
||||
HWND controlHWND;
|
||||
IStorage* storage;
|
||||
IOleClientSite* clientSite;
|
||||
IOleObject* control;
|
||||
WNDPROC originalWndProc;
|
||||
HWND controlHWND = {};
|
||||
IStorage* storage = nullptr;
|
||||
ActiveXHelpers::JuceIOleClientSite* clientSite = nullptr;
|
||||
IOleObject* control = nullptr;
|
||||
WNDPROC originalWndProc = 0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
ActiveXControlComponent::ActiveXControlComponent()
|
||||
: mouseEventsAllowed (true)
|
||||
{
|
||||
ActiveXHelpers::activeXComps.add (this);
|
||||
}
|
||||
|
|
@ -350,18 +364,18 @@ bool ActiveXControlComponent::createControl (const void* controlIID)
|
|||
{
|
||||
deleteControl();
|
||||
|
||||
if (ComponentPeer* const peer = getPeer())
|
||||
if (auto* peer = getPeer())
|
||||
{
|
||||
const Rectangle<int> controlBounds (peer->getAreaCoveredBy (*this));
|
||||
|
||||
HWND hwnd = (HWND) peer->getNativeHandle();
|
||||
auto controlBounds = peer->getAreaCoveredBy (*this);
|
||||
auto hwnd = (HWND) peer->getNativeHandle();
|
||||
|
||||
ScopedPointer<Pimpl> newControl (new Pimpl (hwnd, *this));
|
||||
|
||||
HRESULT hr;
|
||||
if ((hr = OleCreate (*(const IID*) controlIID, __uuidof (IOleObject), 1 /*OLERENDER_DRAW*/, 0,
|
||||
newControl->clientSite, newControl->storage,
|
||||
(void**) &(newControl->control))) == S_OK)
|
||||
HRESULT hr = OleCreate (*(const IID*) controlIID, __uuidof (IOleObject), 1 /*OLERENDER_DRAW*/, 0,
|
||||
newControl->clientSite, newControl->storage,
|
||||
(void**) &(newControl->control));
|
||||
|
||||
if (hr == S_OK)
|
||||
{
|
||||
newControl->control->SetHostNames (L"JUCE", 0);
|
||||
|
||||
|
|
@ -420,3 +434,32 @@ void ActiveXControlComponent::setMouseEventsAllowed (const bool eventsCanReachCo
|
|||
{
|
||||
mouseEventsAllowed = eventsCanReachControl;
|
||||
}
|
||||
|
||||
intptr_t ActiveXControlComponent::offerEventToActiveXControl (void* ptr)
|
||||
{
|
||||
if (control != nullptr && control->clientSite != nullptr)
|
||||
return (intptr_t) control->clientSite->offerEventToActiveXControl (*reinterpret_cast<::MSG*> (ptr));
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
intptr_t ActiveXControlComponent::offerEventToActiveXControlStatic (void* ptr)
|
||||
{
|
||||
for (auto* ax : ActiveXHelpers::activeXComps)
|
||||
{
|
||||
auto result = ax->offerEventToActiveXControl (ptr);
|
||||
|
||||
if (result != S_FALSE)
|
||||
return result;
|
||||
}
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
LRESULT juce_offerEventToActiveXControl (::MSG& msg)
|
||||
{
|
||||
if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)
|
||||
return ActiveXControlComponent::offerEventToActiveXControlStatic (&msg);
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue