GHOST: bundle tablet data with GHOST event
Previously the window manager would receive the GHOST event and then query the latest tablet data from the window to go along with it. If multiple events were queued, it would then use too new tablet data for handling older events. Fixes T62565: tablet pressure not working on macOS with some devices
This commit is contained in:
@@ -247,7 +247,11 @@ class GHOST_IWindow {
|
||||
* Returns the tablet data (pressure etc).
|
||||
* \return The tablet data (pressure etc).
|
||||
*/
|
||||
virtual const GHOST_TabletData *GetTabletData() = 0;
|
||||
virtual const GHOST_TabletData &GetTabletData()
|
||||
{
|
||||
/* Default state when no tablet is used, for systems without tablet support. */
|
||||
return GHOST_TABLET_DATA_DEFAULT;
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
* Progress bar functionality
|
||||
|
||||
@@ -101,6 +101,12 @@ typedef struct GHOST_TabletData {
|
||||
float Ytilt; /* as above */
|
||||
} GHOST_TabletData;
|
||||
|
||||
static const GHOST_TabletData GHOST_TABLET_DATA_DEFAULT = {
|
||||
GHOST_kTabletModeNone, /* No tablet connected. */
|
||||
1.0f, /* Pressure */
|
||||
0.0f, /* Xtilt */
|
||||
0.0f}; /* Ytilt */
|
||||
|
||||
typedef enum {
|
||||
GHOST_kNotVisible = 0,
|
||||
GHOST_kPartiallyVisible,
|
||||
@@ -409,11 +415,15 @@ typedef struct {
|
||||
GHOST_TInt32 x;
|
||||
/** The y-coordinate of the cursor position. */
|
||||
GHOST_TInt32 y;
|
||||
/** Associated tablet data. */
|
||||
GHOST_TabletData tablet;
|
||||
} GHOST_TEventCursorData;
|
||||
|
||||
typedef struct {
|
||||
/** The mask of the mouse button. */
|
||||
GHOST_TButtonMask button;
|
||||
/** Associated tablet data. */
|
||||
GHOST_TabletData tablet;
|
||||
} GHOST_TEventButtonData;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -708,7 +708,7 @@ void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api)
|
||||
|
||||
const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle)
|
||||
{
|
||||
return ((GHOST_IWindow *)windowhandle)->GetTabletData();
|
||||
return &((GHOST_IWindow *)windowhandle)->GetTabletData();
|
||||
}
|
||||
|
||||
GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle)
|
||||
|
||||
@@ -46,6 +46,7 @@ class GHOST_EventButton : public GHOST_Event {
|
||||
: GHOST_Event(time, type, window)
|
||||
{
|
||||
m_buttonEventData.button = button;
|
||||
m_buttonEventData.tablet = window->GetTabletData();
|
||||
m_data = &m_buttonEventData;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ class GHOST_EventCursor : public GHOST_Event {
|
||||
{
|
||||
m_cursorEventData.x = x;
|
||||
m_cursorEventData.y = y;
|
||||
m_cursorEventData.tablet = window->GetTabletData();
|
||||
m_data = &m_cursorEventData;
|
||||
}
|
||||
|
||||
|
||||
@@ -1451,11 +1451,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
|
||||
break;
|
||||
|
||||
case NSEventTypeTabletProximity:
|
||||
ct.Pressure = 0;
|
||||
ct.Xtilt = 0;
|
||||
ct.Ytilt = 0;
|
||||
/* Reset tablet data when device enters proximity or leaves. */
|
||||
ct = GHOST_TABLET_DATA_DEFAULT;
|
||||
if ([event isEnteringProximity]) {
|
||||
// pointer is entering tablet area proximity
|
||||
/* Pointer is entering tablet area proximity. */
|
||||
switch ([event pointingDeviceType]) {
|
||||
case NSPointingDeviceTypePen:
|
||||
ct.Active = GHOST_kTabletModeStylus;
|
||||
@@ -1466,14 +1465,9 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
|
||||
case NSPointingDeviceTypeCursor:
|
||||
case NSPointingDeviceTypeUnknown:
|
||||
default:
|
||||
ct.Active = GHOST_kTabletModeNone;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// pointer is leaving - return to mouse
|
||||
ct.Active = GHOST_kTabletModeNone;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1524,46 +1518,45 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
|
||||
|
||||
switch ([event type]) {
|
||||
case NSEventTypeLeftMouseDown:
|
||||
handleTabletEvent(event); // Update window tablet state to be included in event.
|
||||
pushEvent(new GHOST_EventButton(
|
||||
[event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft));
|
||||
handleTabletEvent(event); // Handle tablet events combined with mouse events
|
||||
break;
|
||||
case NSEventTypeRightMouseDown:
|
||||
handleTabletEvent(event); // Update window tablet state to be included in event.
|
||||
pushEvent(new GHOST_EventButton(
|
||||
[event timestamp] * 1000, GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight));
|
||||
handleTabletEvent(event); // Handle tablet events combined with mouse events
|
||||
break;
|
||||
case NSEventTypeOtherMouseDown:
|
||||
handleTabletEvent(event); // Handle tablet events combined with mouse events
|
||||
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
|
||||
GHOST_kEventButtonDown,
|
||||
window,
|
||||
convertButton([event buttonNumber])));
|
||||
handleTabletEvent(event); // Handle tablet events combined with mouse events
|
||||
break;
|
||||
|
||||
case NSEventTypeLeftMouseUp:
|
||||
handleTabletEvent(event); // Update window tablet state to be included in event.
|
||||
pushEvent(new GHOST_EventButton(
|
||||
[event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft));
|
||||
handleTabletEvent(event); // Handle tablet events combined with mouse events
|
||||
break;
|
||||
case NSEventTypeRightMouseUp:
|
||||
handleTabletEvent(event); // Update window tablet state to be included in event.
|
||||
pushEvent(new GHOST_EventButton(
|
||||
[event timestamp] * 1000, GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight));
|
||||
handleTabletEvent(event); // Handle tablet events combined with mouse events
|
||||
break;
|
||||
case NSEventTypeOtherMouseUp:
|
||||
handleTabletEvent(event); // Update window tablet state to be included in event.
|
||||
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
|
||||
GHOST_kEventButtonUp,
|
||||
window,
|
||||
convertButton([event buttonNumber])));
|
||||
handleTabletEvent(event); // Handle tablet events combined with mouse events
|
||||
break;
|
||||
|
||||
case NSEventTypeLeftMouseDragged:
|
||||
case NSEventTypeRightMouseDragged:
|
||||
case NSEventTypeOtherMouseDragged:
|
||||
// Handle tablet events combined with mouse events
|
||||
handleTabletEvent(event);
|
||||
handleTabletEvent(event); // Update window tablet state to be included in event.
|
||||
|
||||
case NSEventTypeMouseMoved: {
|
||||
GHOST_TGrabCursorMode grab_mode = window->getCursorGrabMode();
|
||||
|
||||
@@ -894,6 +894,7 @@ GHOST_Event *GHOST_SystemWin32::processPointerEvent(GHOST_TEventType type,
|
||||
|
||||
switch (type) {
|
||||
case GHOST_kEventButtonDown:
|
||||
/* Update window tablet data to be included in event. */
|
||||
window->setTabletData(&pointerInfo.tabletData);
|
||||
eventHandled = true;
|
||||
return new GHOST_EventButton(
|
||||
@@ -903,6 +904,7 @@ GHOST_Event *GHOST_SystemWin32::processPointerEvent(GHOST_TEventType type,
|
||||
return new GHOST_EventButton(
|
||||
system->getMilliSeconds(), GHOST_kEventButtonUp, window, pointerInfo.buttonMask);
|
||||
case GHOST_kEventCursorMove:
|
||||
/* Update window tablet data to be included in event. */
|
||||
window->setTabletData(&pointerInfo.tabletData);
|
||||
eventHandled = true;
|
||||
return new GHOST_EventCursor(system->getMilliSeconds(),
|
||||
|
||||
@@ -823,7 +823,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
* in the future we could have a ghost call window->CheckTabletProximity()
|
||||
* but for now enough parts of the code are checking 'Active'
|
||||
* - campbell */
|
||||
if (window->GetTabletData()->Active != GHOST_kTabletModeNone) {
|
||||
if (window->GetTabletData().Active != GHOST_kTabletModeNone) {
|
||||
bool any_proximity = false;
|
||||
|
||||
for (GHOST_TabletX11 &xtablet : m_xtablets) {
|
||||
@@ -834,7 +834,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
|
||||
if (!any_proximity) {
|
||||
// printf("proximity disable\n");
|
||||
window->GetTabletData()->Active = GHOST_kTabletModeNone;
|
||||
window->GetTabletData().Active = GHOST_kTabletModeNone;
|
||||
}
|
||||
}
|
||||
#endif /* WITH_X11_XINPUT */
|
||||
@@ -855,7 +855,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
XMotionEvent &xme = xe->xmotion;
|
||||
|
||||
#ifdef WITH_X11_XINPUT
|
||||
bool is_tablet = window->GetTabletData()->Active != GHOST_kTabletModeNone;
|
||||
bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone;
|
||||
#else
|
||||
bool is_tablet = false;
|
||||
#endif
|
||||
@@ -1395,7 +1395,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
/* stroke might begin without leading ProxyIn event,
|
||||
* this happens when window is opened when stylus is already hovering
|
||||
* around tablet surface */
|
||||
window->GetTabletData()->Active = xtablet.mode;
|
||||
window->GetTabletData().Active = xtablet.mode;
|
||||
|
||||
/* Note: This event might be generated with incomplete dataset
|
||||
* (don't exactly know why, looks like in some cases, if the value does not change,
|
||||
@@ -1408,7 +1408,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
((void)(val = data->axis_data[axis - axis_first]), true))
|
||||
|
||||
if (AXIS_VALUE_GET(2, axis_value)) {
|
||||
window->GetTabletData()->Pressure = axis_value / ((float)xtablet.PressureLevels);
|
||||
window->GetTabletData().Pressure = axis_value / ((float)xtablet.PressureLevels);
|
||||
}
|
||||
|
||||
/* the (short) cast and the & 0xffff is bizarre and unexplained anywhere,
|
||||
@@ -1420,12 +1420,12 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
* check this. --mont29
|
||||
*/
|
||||
if (AXIS_VALUE_GET(3, axis_value)) {
|
||||
window->GetTabletData()->Xtilt = (short)(axis_value & 0xffff) /
|
||||
((float)xtablet.XtiltLevels);
|
||||
window->GetTabletData().Xtilt = (short)(axis_value & 0xffff) /
|
||||
((float)xtablet.XtiltLevels);
|
||||
}
|
||||
if (AXIS_VALUE_GET(4, axis_value)) {
|
||||
window->GetTabletData()->Ytilt = (short)(axis_value & 0xffff) /
|
||||
((float)xtablet.YtiltLevels);
|
||||
window->GetTabletData().Ytilt = (short)(axis_value & 0xffff) /
|
||||
((float)xtablet.YtiltLevels);
|
||||
}
|
||||
|
||||
# undef AXIS_VALUE_GET
|
||||
@@ -1436,10 +1436,10 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
continue;
|
||||
}
|
||||
|
||||
window->GetTabletData()->Active = xtablet.mode;
|
||||
window->GetTabletData().Active = xtablet.mode;
|
||||
}
|
||||
else if (xe->type == xtablet.ProxOutEvent) {
|
||||
window->GetTabletData()->Active = GHOST_kTabletModeNone;
|
||||
window->GetTabletData().Active = GHOST_kTabletModeNone;
|
||||
}
|
||||
}
|
||||
#endif // WITH_X11_XINPUT
|
||||
|
||||
@@ -222,9 +222,9 @@ class GHOST_WindowCocoa : public GHOST_Window {
|
||||
|
||||
bool isDialog() const;
|
||||
|
||||
const GHOST_TabletData *GetTabletData()
|
||||
const GHOST_TabletData &GetTabletData()
|
||||
{
|
||||
return &m_tablet;
|
||||
return m_tablet;
|
||||
}
|
||||
|
||||
GHOST_TabletData &GetCocoaTabletData()
|
||||
|
||||
@@ -387,7 +387,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
|
||||
|
||||
setTitle(title);
|
||||
|
||||
m_tablet.Active = GHOST_kTabletModeNone;
|
||||
m_tablet = GHOST_TABLET_DATA_DEFAULT;
|
||||
|
||||
CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init];
|
||||
[windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
|
||||
@@ -31,11 +31,6 @@ class GHOST_SystemNULL;
|
||||
|
||||
class GHOST_WindowNULL : public GHOST_Window {
|
||||
public:
|
||||
const GHOST_TabletData *GetTabletData()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor)
|
||||
{
|
||||
return GHOST_kSuccess;
|
||||
|
||||
@@ -48,11 +48,6 @@ class GHOST_WindowSDL : public GHOST_Window {
|
||||
SDL_Cursor *m_sdl_custom_cursor;
|
||||
|
||||
public:
|
||||
const GHOST_TabletData *GetTabletData()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GHOST_WindowSDL(GHOST_SystemSDL *system,
|
||||
const STR_String &title,
|
||||
GHOST_TInt32 left,
|
||||
|
||||
@@ -89,8 +89,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
||||
{
|
||||
// Initialize tablet variables
|
||||
memset(&m_wintab, 0, sizeof(m_wintab));
|
||||
memset(&m_tabletData, 0, sizeof(m_tabletData));
|
||||
m_tabletData.Active = GHOST_kTabletModeNone;
|
||||
m_tabletData = GHOST_TABLET_DATA_DEFAULT;
|
||||
|
||||
// Create window
|
||||
if (state != GHOST_kWindowStateFullScreen) {
|
||||
@@ -1085,10 +1084,7 @@ void GHOST_WindowWin32::setTabletData(GHOST_TabletData *pTabletData)
|
||||
m_tabletData = *pTabletData;
|
||||
}
|
||||
else {
|
||||
m_tabletData.Active = GHOST_kTabletModeNone;
|
||||
m_tabletData.Pressure = 1.0f;
|
||||
m_tabletData.Xtilt = 0.0f;
|
||||
m_tabletData.Ytilt = 0.0f;
|
||||
m_tabletData = GHOST_TABLET_DATA_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1150,8 +1146,6 @@ void GHOST_WindowWin32::processWin32TabletInitEvent()
|
||||
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_tabletData.Active = GHOST_kTabletModeNone;
|
||||
}
|
||||
|
||||
m_tabletData.Active = GHOST_kTabletModeNone;
|
||||
|
||||
@@ -392,9 +392,9 @@ class GHOST_WindowWin32 : public GHOST_Window {
|
||||
HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const;
|
||||
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
|
||||
|
||||
const GHOST_TabletData *GetTabletData()
|
||||
const GHOST_TabletData &GetTabletData()
|
||||
{
|
||||
return &m_tabletData;
|
||||
return m_tabletData;
|
||||
}
|
||||
|
||||
void setTabletData(GHOST_TabletData *tabletData);
|
||||
|
||||
@@ -478,7 +478,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
|
||||
#ifdef WITH_X11_XINPUT
|
||||
refreshXInputDevices();
|
||||
|
||||
m_tabletData.Active = GHOST_kTabletModeNone;
|
||||
m_tabletData = GHOST_TABLET_DATA_DEFAULT;
|
||||
#endif
|
||||
|
||||
/* now set up the rendering context. */
|
||||
|
||||
@@ -145,14 +145,9 @@ class GHOST_WindowX11 : public GHOST_Window {
|
||||
*/
|
||||
Window getXWindow();
|
||||
#ifdef WITH_X11_XINPUT
|
||||
GHOST_TabletData *GetTabletData()
|
||||
GHOST_TabletData &GetTabletData()
|
||||
{
|
||||
return &m_tabletData;
|
||||
}
|
||||
#else // WITH_X11_XINPUT
|
||||
const GHOST_TabletData *GetTabletData()
|
||||
{
|
||||
return NULL;
|
||||
return m_tabletData;
|
||||
}
|
||||
#endif // WITH_X11_XINPUT
|
||||
|
||||
|
||||
@@ -560,7 +560,7 @@ typedef struct wmEvent {
|
||||
char check_click;
|
||||
char check_drag;
|
||||
|
||||
/** Tablet info, only use when the tablet is active. */
|
||||
/** Tablet info, available for mouse move and button events. */
|
||||
wmTabletData tablet;
|
||||
|
||||
/* custom data */
|
||||
|
||||
@@ -101,7 +101,6 @@
|
||||
#define USE_GIZMO_MOUSE_PRIORITY_HACK
|
||||
|
||||
static void wm_notifier_clear(wmNotifier *note);
|
||||
static void update_tablet_data(wmWindow *win, wmEvent *event);
|
||||
|
||||
static int wm_operator_call_internal(bContext *C,
|
||||
wmOperatorType *ot,
|
||||
@@ -125,8 +124,6 @@ wmEvent *wm_event_add_ex(wmWindow *win,
|
||||
|
||||
*event = *event_to_add;
|
||||
|
||||
update_tablet_data(win, event);
|
||||
|
||||
if (event_to_add_after == NULL) {
|
||||
BLI_addtail(&win->queue, event);
|
||||
}
|
||||
@@ -4087,20 +4084,15 @@ static void wm_eventemulation(wmEvent *event, bool test_only)
|
||||
}
|
||||
}
|
||||
|
||||
/* adds customdata to event */
|
||||
static void update_tablet_data(wmWindow *win, wmEvent *event)
|
||||
void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab)
|
||||
{
|
||||
const GHOST_TabletData *td = GHOST_GetTabletData(win->ghostwin);
|
||||
wmTabletData *wmtab = &event->tablet;
|
||||
|
||||
/* if there's tablet data from an active tablet device then add it */
|
||||
if ((td != NULL) && td->Active != GHOST_kTabletModeNone) {
|
||||
wmtab->active = (int)td->Active;
|
||||
wmtab->pressure = wm_pressure_curve(td->Pressure);
|
||||
wmtab->x_tilt = td->Xtilt;
|
||||
wmtab->y_tilt = td->Ytilt;
|
||||
if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) {
|
||||
wmtab->active = (int)tablet_data->Active;
|
||||
wmtab->pressure = wm_pressure_curve(tablet_data->Pressure);
|
||||
wmtab->x_tilt = tablet_data->Xtilt;
|
||||
wmtab->y_tilt = tablet_data->Ytilt;
|
||||
/* We could have a preference to support relative tablet motion (we can't detect that). */
|
||||
wmtab->is_motion_absolute = ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE);
|
||||
wmtab->is_motion_absolute = true;
|
||||
// printf("%s: using tablet %.5f\n", __func__, wmtab->pressure);
|
||||
}
|
||||
else {
|
||||
@@ -4260,6 +4252,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
|
||||
|
||||
copy_v2_v2_int(&event.x, &cd->x);
|
||||
wm_stereo3d_mouse_offset_apply(win, &event.x);
|
||||
wm_tablet_data_from_ghost(&cd->tablet, &event.tablet);
|
||||
|
||||
event.prevtype = event.type;
|
||||
event.prevval = event.val;
|
||||
@@ -4349,6 +4342,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
|
||||
event.type = MIDDLEMOUSE;
|
||||
}
|
||||
|
||||
/* Get tablet data. */
|
||||
wm_tablet_data_from_ghost(&bd->tablet, &event.tablet);
|
||||
|
||||
wm_eventemulation(&event, false);
|
||||
|
||||
/* copy previous state to prev event state (two old!) */
|
||||
@@ -4379,6 +4375,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
|
||||
oevent.y = event.y;
|
||||
oevent.type = event.type;
|
||||
oevent.val = event.val;
|
||||
oevent.tablet = event.tablet;
|
||||
|
||||
wm_event_add(owin, &oevent);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#define WM_HANDLER_MODAL 4 /* MODAL|BREAK means unhandled */
|
||||
|
||||
struct ARegion;
|
||||
struct GHOST_TabletData;
|
||||
struct ScrArea;
|
||||
|
||||
/* wmKeyMap is in DNA_windowmanager.h, it's saveable */
|
||||
@@ -150,6 +151,7 @@ void wm_event_do_notifiers(bContext *C);
|
||||
|
||||
/* wm_event_query.c */
|
||||
float wm_pressure_curve(float raw_pressure);
|
||||
void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTabletData *wmtab);
|
||||
|
||||
/* wm_keymap.c */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user