mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-02-09 04:30:09 +00:00
Experimental support for Win7 multi-touch.
This commit is contained in:
parent
c3492b99e3
commit
e647ea8a90
4 changed files with 226 additions and 22 deletions
|
|
@ -242,6 +242,7 @@ BEGIN_JUCE_NAMESPACE
|
|||
#include "../juce_graphics/native/juce_mac_CoreGraphicsContext.h"
|
||||
|
||||
#if JUCE_IOS
|
||||
#include "native/juce_MultiTouchMapper.h"
|
||||
#include "native/juce_ios_UIViewComponentPeer.mm"
|
||||
#include "native/juce_ios_Windowing.mm"
|
||||
#else
|
||||
|
|
@ -256,6 +257,7 @@ BEGIN_JUCE_NAMESPACE
|
|||
#elif JUCE_WINDOWS
|
||||
#include "../juce_core/native/juce_win32_ComSmartPtr.h"
|
||||
#include "../juce_events/native/juce_win32_HiddenMessageWindow.h"
|
||||
#include "native/juce_MultiTouchMapper.h"
|
||||
#include "native/juce_win32_Windowing.cpp"
|
||||
#include "native/juce_win32_DragAndDrop.cpp"
|
||||
#include "native/juce_win32_FileChooser.cpp"
|
||||
|
|
|
|||
78
modules/juce_gui_basics/native/juce_MultiTouchMapper.h
Normal file
78
modules/juce_gui_basics/native/juce_MultiTouchMapper.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
||||
Copyright 2004-11 by Raw Material Software Ltd.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
JUCE can be redistributed and/or modified under the terms of the GNU General
|
||||
Public License (Version 2), as published by the Free Software Foundation.
|
||||
A copy of the license is included in the JUCE distribution, or can be found
|
||||
online at www.gnu.org/licenses.
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.rawmaterialsoftware.com/juce for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCE_MULTITOUCHMAPPER_JUCEHEADER__
|
||||
#define __JUCE_MULTITOUCHMAPPER_JUCEHEADER__
|
||||
|
||||
template <typename IDType>
|
||||
class MultiTouchMapper
|
||||
{
|
||||
public:
|
||||
MultiTouchMapper() {}
|
||||
|
||||
int getIndexOfTouch (IDType touchID)
|
||||
{
|
||||
jassert (touchID != 0); // need to rethink this if IDs can be 0!
|
||||
|
||||
int touchIndex = currentTouches.indexOf (touchID);
|
||||
|
||||
if (touchIndex < 0)
|
||||
{
|
||||
for (touchIndex = 0; touchIndex < currentTouches.size(); ++touchIndex)
|
||||
if (currentTouches.getUnchecked (touchIndex) == 0)
|
||||
break;
|
||||
|
||||
currentTouches.set (touchIndex, touchID);
|
||||
}
|
||||
|
||||
return touchIndex;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
currentTouches.clear();
|
||||
}
|
||||
|
||||
void clearTouch (int index)
|
||||
{
|
||||
currentTouches.set (index, 0);
|
||||
}
|
||||
|
||||
bool areAnyTouchesActive() const noexcept
|
||||
{
|
||||
for (int i = currentTouches.size(); --i >= 0;)
|
||||
if (currentTouches.getUnchecked(i) != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
Array<IDType> currentTouches;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiTouchMapper);
|
||||
};
|
||||
|
||||
#endif // __JUCE_MULTITOUCHMAPPER_JUCEHEADER__
|
||||
|
|
@ -160,7 +160,7 @@ public:
|
|||
+ (int64) ([e timestamp] * 1000.0);
|
||||
}
|
||||
|
||||
static const Rectangle<int> rotatedScreenPosToReal (const Rectangle<int>& r)
|
||||
static Rectangle<int> rotatedScreenPosToReal (const Rectangle<int>& r)
|
||||
{
|
||||
const Rectangle<int> screen (convertToRectInt ([[UIScreen mainScreen] bounds]));
|
||||
|
||||
|
|
@ -187,7 +187,7 @@ public:
|
|||
return r;
|
||||
}
|
||||
|
||||
static const Rectangle<int> realScreenPosToRotated (const Rectangle<int>& r)
|
||||
static Rectangle<int> realScreenPosToRotated (const Rectangle<int>& r)
|
||||
{
|
||||
const Rectangle<int> screen (convertToRectInt ([[UIScreen mainScreen] bounds]));
|
||||
|
||||
|
|
@ -214,7 +214,7 @@ public:
|
|||
return r;
|
||||
}
|
||||
|
||||
Array <UITouch*> currentTouches;
|
||||
MultiTouchMapper<UITouch*> currentTouches;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIViewComponentPeer);
|
||||
|
|
@ -739,17 +739,7 @@ void UIViewComponentPeer::handleTouches (UIEvent* event, const bool isDown, cons
|
|||
juce_lastMousePos = pos + getScreenPosition();
|
||||
|
||||
const int64 time = getMouseTime (event);
|
||||
|
||||
int touchIndex = currentTouches.indexOf (touch);
|
||||
|
||||
if (touchIndex < 0)
|
||||
{
|
||||
for (touchIndex = 0; touchIndex < currentTouches.size(); ++touchIndex)
|
||||
if (currentTouches.getUnchecked (touchIndex) == nil)
|
||||
break;
|
||||
|
||||
currentTouches.set (touchIndex, touch);
|
||||
}
|
||||
const int touchIndex = currentTouches.getIndexOfTouch (touch);
|
||||
|
||||
ModifierKeys modsToSend (currentModifiers);
|
||||
|
||||
|
|
@ -772,14 +762,9 @@ void UIViewComponentPeer::handleTouches (UIEvent* event, const bool isDown, cons
|
|||
continue;
|
||||
|
||||
modsToSend = modsToSend.withoutMouseButtons();
|
||||
currentTouches.set (touchIndex, nil);
|
||||
currentTouches.clearTouch (touchIndex);
|
||||
|
||||
int totalActiveTouches = 0;
|
||||
for (int j = currentTouches.size(); --j >= 0;)
|
||||
if (currentTouches.getUnchecked(j) != nil)
|
||||
++totalActiveTouches;
|
||||
|
||||
if (totalActiveTouches == 0)
|
||||
if (! currentTouches.areAnyTouchesActive())
|
||||
isCancel = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ static bool shouldDeactivateTitleBar = true;
|
|||
|
||||
//==============================================================================
|
||||
typedef BOOL (WINAPI* UpdateLayeredWinFunc) (HWND, HDC, POINT*, SIZE*, HDC, POINT*, COLORREF, BLENDFUNCTION*, DWORD);
|
||||
static UpdateLayeredWinFunc updateLayeredWindow = 0;
|
||||
static UpdateLayeredWinFunc updateLayeredWindow = nullptr;
|
||||
|
||||
bool Desktop::canUseSemiTransparentWindows() noexcept
|
||||
{
|
||||
|
|
@ -55,6 +55,7 @@ bool Desktop::canUseSemiTransparentWindows() noexcept
|
|||
if (! juce_IsRunningInWine())
|
||||
{
|
||||
HMODULE user32Mod = GetModuleHandle (_T("user32.dll"));
|
||||
jassert (user32Mod != 0);
|
||||
updateLayeredWindow = (UpdateLayeredWinFunc) GetProcAddress (user32Mod, "UpdateLayeredWindow");
|
||||
}
|
||||
}
|
||||
|
|
@ -62,6 +63,59 @@ bool Desktop::canUseSemiTransparentWindows() noexcept
|
|||
return updateLayeredWindow != 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#ifndef WM_TOUCH
|
||||
#define WM_TOUCH 0x0240
|
||||
DECLARE_HANDLE (HTOUCHINPUT);
|
||||
|
||||
typedef struct tagTOUCHINPUT
|
||||
{
|
||||
LONG x;
|
||||
LONG y;
|
||||
HANDLE hSource;
|
||||
DWORD dwID;
|
||||
DWORD dwFlags;
|
||||
DWORD dwMask;
|
||||
DWORD dwTime;
|
||||
ULONG_PTR dwExtraInfo;
|
||||
DWORD cxContact;
|
||||
DWORD cyContact;
|
||||
} TOUCHINPUT, *PTOUCHINPUT;
|
||||
|
||||
#define TOUCH_COORD_TO_PIXEL(l) ((l) / 100)
|
||||
|
||||
#define TOUCHEVENTF_MOVE 0x0001
|
||||
#define TOUCHEVENTF_DOWN 0x0002
|
||||
#define TOUCHEVENTF_UP 0x0004
|
||||
#endif
|
||||
|
||||
typedef BOOL (WINAPI* RegisterTouchWindowFunc) (HWND, ULONG);
|
||||
typedef BOOL (WINAPI* GetTouchInputInfoFunc) (HTOUCHINPUT, UINT, PTOUCHINPUT, int);
|
||||
typedef BOOL (WINAPI* CloseTouchInputHandleFunc) (HTOUCHINPUT);
|
||||
|
||||
static RegisterTouchWindowFunc registerTouchWindow = nullptr;
|
||||
static GetTouchInputInfoFunc getTouchInputInfo = nullptr;
|
||||
static CloseTouchInputHandleFunc closeTouchInputHandle = nullptr;
|
||||
static bool hasCheckedForMultiTouch = false;
|
||||
|
||||
static bool canUseMultiTouch()
|
||||
{
|
||||
if (registerTouchWindow == nullptr && ! hasCheckedForMultiTouch)
|
||||
{
|
||||
hasCheckedForMultiTouch = true;
|
||||
|
||||
HMODULE user32Mod = GetModuleHandle (_T("user32.dll"));
|
||||
jassert (user32Mod != 0);
|
||||
|
||||
registerTouchWindow = (RegisterTouchWindowFunc) GetProcAddress (user32Mod, "RegisterTouchWindow");
|
||||
getTouchInputInfo = (GetTouchInputInfoFunc) GetProcAddress (user32Mod, "GetTouchInputInfo");
|
||||
closeTouchInputHandle = (CloseTouchInputHandleFunc) GetProcAddress (user32Mod, "CloseTouchInputHandle");
|
||||
}
|
||||
|
||||
return registerTouchWindow != nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
|
||||
{
|
||||
return upright;
|
||||
|
|
@ -864,6 +918,7 @@ private:
|
|||
HICON currentWindowIcon;
|
||||
IDropTarget* dropTarget;
|
||||
uint8 updateLayeredWindowAlpha;
|
||||
MultiTouchMapper<DWORD> currentTouches;
|
||||
|
||||
//==============================================================================
|
||||
class TemporaryImage : public Timer
|
||||
|
|
@ -981,6 +1036,7 @@ private:
|
|||
case WM_MOUSEACTIVATE:
|
||||
case WM_NCMOUSEHOVER:
|
||||
case WM_MOUSEHOVER:
|
||||
case WM_TOUCH:
|
||||
return isHWNDBlockedByModalComponents (m.hwnd);
|
||||
|
||||
case WM_NCLBUTTONDOWN:
|
||||
|
|
@ -1086,6 +1142,9 @@ private:
|
|||
|
||||
RegisterDragDrop (hwnd, dropTarget);
|
||||
|
||||
if (canUseMultiTouch())
|
||||
registerTouchWindow (hwnd, 0);
|
||||
|
||||
updateBorderSize();
|
||||
|
||||
// Calling this function here is (for some reason) necessary to make Windows
|
||||
|
|
@ -1472,6 +1531,75 @@ private:
|
|||
isVertical ? amount : 0.0f);
|
||||
}
|
||||
|
||||
void doTouchEvent (const int numInputs, HTOUCHINPUT eventHandle)
|
||||
{
|
||||
HeapBlock<TOUCHINPUT> inputInfo (numInputs);
|
||||
|
||||
if (getTouchInputInfo (eventHandle, numInputs, inputInfo, sizeof (TOUCHINPUT)))
|
||||
{
|
||||
for (int i = 0; i < numInputs; ++i)
|
||||
{
|
||||
const DWORD flags = inputInfo[i].dwFlags;
|
||||
|
||||
if ((flags & (TOUCHEVENTF_DOWN | TOUCHEVENTF_MOVE | TOUCHEVENTF_UP)) != 0)
|
||||
handleTouchInput (inputInfo[i], (flags & TOUCHEVENTF_DOWN) != 0,
|
||||
(flags & TOUCHEVENTF_UP) != 0,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
closeTouchInputHandle (eventHandle);
|
||||
}
|
||||
|
||||
void handleTouchInput (const TOUCHINPUT& touch, const bool isDown, const bool isUp, bool isCancel)
|
||||
{
|
||||
POINT p = { TOUCH_COORD_TO_PIXEL (touch.x),
|
||||
TOUCH_COORD_TO_PIXEL (touch.y) };
|
||||
ScreenToClient (hwnd, &p);
|
||||
|
||||
const Point<int> pos ((int) p.x, (int) p.y);
|
||||
const int64 time = getMouseEventTime();
|
||||
const int touchIndex = currentTouches.getIndexOfTouch (touch.dwID);
|
||||
|
||||
ModifierKeys modsToSend (currentModifiers);
|
||||
|
||||
if (isDown)
|
||||
{
|
||||
currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier);
|
||||
modsToSend = currentModifiers;
|
||||
|
||||
// this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before.
|
||||
handleMouseEvent (touchIndex + 1, pos, modsToSend.withoutMouseButtons(), time);
|
||||
if (! isValidPeer (this)) // (in case this component was deleted by the event)
|
||||
return;
|
||||
}
|
||||
else if (isUp)
|
||||
{
|
||||
modsToSend = modsToSend.withoutMouseButtons();
|
||||
currentTouches.clearTouch (touchIndex);
|
||||
|
||||
if (! currentTouches.areAnyTouchesActive())
|
||||
isCancel = true;
|
||||
}
|
||||
|
||||
if (isCancel)
|
||||
{
|
||||
currentTouches.clear();
|
||||
currentModifiers = currentModifiers.withoutMouseButtons();
|
||||
}
|
||||
|
||||
handleMouseEvent (touchIndex + 1, pos, modsToSend, time);
|
||||
if (! isValidPeer (this)) // (in case this component was deleted by the event)
|
||||
return;
|
||||
|
||||
if (isUp || isCancel)
|
||||
{
|
||||
handleMouseEvent (touchIndex + 1, Point<int> (-1, -1), currentModifiers, time);
|
||||
if (! isValidPeer (this))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void sendModifierKeyChangeIfNeeded()
|
||||
{
|
||||
|
|
@ -2008,6 +2136,13 @@ private:
|
|||
doMouseWheel (getCurrentMousePosGlobal(), wParam, message == 0x020A);
|
||||
return 0;
|
||||
|
||||
case WM_TOUCH:
|
||||
if (getTouchInputInfo == nullptr)
|
||||
break;
|
||||
|
||||
doTouchEvent ((int) wParam, (HTOUCHINPUT) lParam);
|
||||
return 0;
|
||||
|
||||
//==============================================================================
|
||||
case WM_SIZING: return handleSizeConstraining ((RECT*) lParam, wParam);
|
||||
case WM_WINDOWPOSCHANGING: return handlePositionChanging ((WINDOWPOS*) lParam);
|
||||
|
|
@ -2680,6 +2815,10 @@ int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconTy
|
|||
void Desktop::createMouseInputSources()
|
||||
{
|
||||
mouseSources.add (new MouseInputSource (0, true));
|
||||
|
||||
if (canUseMultiTouch())
|
||||
for (int i = 1; i <= 10; ++i)
|
||||
mouseSources.add (new MouseInputSource (i, false));
|
||||
}
|
||||
|
||||
Point<int> MouseInputSource::getCurrentMousePosition()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue