diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index ba22074a620..4c4094409dd 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -607,6 +607,13 @@ extern GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle wind */ extern GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle); +/** + * Returns the status of the tablet + * @param windowhandle The handle to the window + * @return Status of tablet + */ +extern const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle); + /** * Access to rectangle width. * @param rectanglehandle The handle to the rectangle @@ -751,7 +758,6 @@ extern void GHOST_SetRectangleCenter(GHOST_RectangleHandle rectanglehandle, */ extern GHOST_TSuccess GHOST_ClipRectangle(GHOST_RectangleHandle rectanglehandle, GHOST_RectangleHandle anotherrectanglehandle); - #ifdef __cplusplus } #endif diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 903d1e4498d..5f6bbe553c6 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -201,6 +201,12 @@ public: */ virtual void setUserData(const GHOST_TUserDataPtr userData) = 0; + /** + * Returns the tablet data (pressure etc). + * @return The tablet data (pressure etc). + */ + virtual const GHOST_TabletData* GetTabletData() = 0; + /*************************************************************************************** ** Cursor management functionality ***************************************************************************************/ diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 8e439cfc9e3..4abecce50c1 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -55,6 +55,13 @@ typedef enum GHOST_kSuccess } GHOST_TSuccess; +typedef struct GHOST_TabletData { + char Active; /* 0=None, 1=Stylus, 2=Eraser */ + float Pressure; + float Xtilt; + float Ytilt; +} GHOST_TabletData; + typedef enum { GHOST_kNotVisible = 0, diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 6f8ddd858ef..fbb4cca91e0 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -649,6 +649,11 @@ GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle) } +extern const GHOST_TabletData* GHOST_GetTabletData(GHOST_WindowHandle windowhandle) +{ + return ((GHOST_IWindow*)windowhandle)->GetTabletData(); +} + GHOST_TInt32 GHOST_GetWidthRectangle(GHOST_RectangleHandle rectanglehandle) { @@ -795,6 +800,3 @@ GHOST_TSuccess GHOST_ClipRectangle(GHOST_RectangleHandle rectanglehandle, return result; } - - - diff --git a/intern/ghost/intern/GHOST_SystemCarbon.cpp b/intern/ghost/intern/GHOST_SystemCarbon.cpp index ef9e91ec3df..9e790154eb9 100644 --- a/intern/ghost/intern/GHOST_SystemCarbon.cpp +++ b/intern/ghost/intern/GHOST_SystemCarbon.cpp @@ -688,6 +688,79 @@ OSStatus GHOST_SystemCarbon::handleWindowEvent(EventRef event) return err; } +OSStatus GHOST_SystemCarbon::handleTabletEvent(EventRef event) +{ + GHOST_IWindow* window = m_windowManager->getActiveWindow(); + TabletPointRec tabletPointRecord; + TabletProximityRec tabletProximityRecord; + UInt32 anInt32; + GHOST_TabletData& ct=((GHOST_WindowCarbon*)window)->GetCarbonTabletData(); + OSStatus err = eventNotHandledErr; + + ct.Pressure = 0; + ct.Xtilt = 0; + ct.Ytilt = 0; + + // is there an embedded tablet event inside this mouse event? + if(noErr == GetEventParameter(event, kEventParamTabletEventType, typeUInt32, NULL, sizeof(UInt32), NULL, (void *)&anInt32)) + { + // yes there is one! + // Embedded tablet events can either be a proximity or pointer event. + if(anInt32 == kEventTabletPoint) + { + //GHOST_PRINT("Embedded pointer event!\n"); + + // Extract the tablet Pointer Event. If there is no Tablet Pointer data + // in this event, then this call will return an error. Just ignore the + // error and go on. This can occur when a proximity event is embedded in + // a mouse event and you did not check the mouse event to see which type + // of tablet event was embedded. + if(noErr == GetEventParameter(event, kEventParamTabletPointRec, + typeTabletPointRec, NULL, + sizeof(TabletPointRec), + NULL, (void *)&tabletPointRecord)) + { + ct.Pressure = tabletPointRecord.pressure / 65535.0f; + ct.Xtilt = tabletPointRecord.tiltX / 32767.0f; /* can be positive or negative */ + ct.Ytilt = tabletPointRecord.tiltY / 32767.0f; /* can be positive or negative */ + } + } else { + //GHOST_PRINT("Embedded proximity event\n"); + + // Extract the Tablet Proximity record from the event. + if(noErr == GetEventParameter(event, kEventParamTabletProximityRec, + typeTabletProximityRec, NULL, + sizeof(TabletProximityRec), + NULL, (void *)&tabletProximityRecord)) + { + if (tabletProximityRecord.enterProximity) { + //pointer is entering tablet area proximity + + switch(tabletProximityRecord.pointerType) + { + case 1: /* stylus */ + ct.Active = 1; + break; + case 2: /* puck, not supported so far */ + ct.Active = 0; + break; + case 3: /* eraser */ + ct.Active = 2; + break; + default: + ct.Active = 0; + break; + } + } else { + // pointer is leaving - return to mouse + ct.Active = 0; + } + } + } + err = noErr; + } +} + OSStatus GHOST_SystemCarbon::handleMouseEvent(EventRef event) { OSStatus err = eventNotHandledErr; @@ -708,6 +781,9 @@ OSStatus GHOST_SystemCarbon::handleMouseEvent(EventRef event) /* Window still gets mouse up after command-H */ if (m_windowManager->getActiveWindow()) { + // handle any tablet events that may have come with the mouse event (optional) + handleTabletEvent(event); + ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); pushEvent(new GHOST_EventButton(getMilliSeconds(), type, window, convertButton(button))); err = noErr; @@ -716,15 +792,19 @@ OSStatus GHOST_SystemCarbon::handleMouseEvent(EventRef event) break; case kEventMouseMoved: - case kEventMouseDragged: - Point mousePos; + case kEventMouseDragged: { + Point mousePos; + if (window) { + //handle any tablet events that may have come with the mouse event (optional) + handleTabletEvent(event); + ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos); pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, mousePos.h, mousePos.v)); err = noErr; - } - break; - + } + break; + } case kEventMouseWheelMoved: { OSStatus status; diff --git a/intern/ghost/intern/GHOST_SystemCarbon.h b/intern/ghost/intern/GHOST_SystemCarbon.h index 740006a335f..93022aa78ff 100644 --- a/intern/ghost/intern/GHOST_SystemCarbon.h +++ b/intern/ghost/intern/GHOST_SystemCarbon.h @@ -182,6 +182,13 @@ protected: */ virtual GHOST_TSuccess exit(); + + /** + * Handles a tablet event. + * @param event A Mac event. + * @return Indication whether the event was handled. + */ + OSStatus handleTabletEvent(EventRef event); /** * Handles a mouse event. * @param event A Mac event. diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index e6d1962958a..68bdd1a09a3 100755 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -338,7 +338,7 @@ processEvent( if (!window) { return; } - + switch (xe->type) { case Expose: { @@ -357,6 +357,7 @@ processEvent( } break; } + case MotionNotify: { XMotionEvent &xme = xe->xmotion; @@ -506,8 +507,23 @@ processEvent( case ReparentNotify: break; - default: + default: { + if(xe->type == window->GetXTablet().MotionEvent) { + XDeviceMotionEvent* data = (XDeviceMotionEvent*)xe; + window->GetXTablet().CommonData.Pressure= data->axis_data[2]/((float)window->GetXTablet().PressureLevels); + } + else if(xe->type == window->GetXTablet().ProxInEvent) { + XProximityNotifyEvent* data = (XProximityNotifyEvent*)xe; + if(data->deviceid == window->GetXTablet().StylusID) + window->GetXTablet().CommonData.Active= 1; + else if(data->deviceid == window->GetXTablet().EraserID) + window->GetXTablet().CommonData.Active= 2; + } + else if(xe->type == window->GetXTablet().ProxOutEvent) + window->GetXTablet().CommonData.Active= 0; + break; + } } if (g_event) { diff --git a/intern/ghost/intern/GHOST_WindowCarbon.cpp b/intern/ghost/intern/GHOST_WindowCarbon.cpp index 30c88ccd777..4484ec54da6 100644 --- a/intern/ghost/intern/GHOST_WindowCarbon.cpp +++ b/intern/ghost/intern/GHOST_WindowCarbon.cpp @@ -185,6 +185,8 @@ GHOST_WindowCarbon::GHOST_WindowCarbon( setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);;installDrawingContext(GHOST_kDrawingContextTypeOpenGL); updateDrawingContext(); activateDrawingContext(); + + m_tablet.Active = 0; } } diff --git a/intern/ghost/intern/GHOST_WindowCarbon.h b/intern/ghost/intern/GHOST_WindowCarbon.h index 582979e6248..5b81470a030 100644 --- a/intern/ghost/intern/GHOST_WindowCarbon.h +++ b/intern/ghost/intern/GHOST_WindowCarbon.h @@ -213,6 +213,11 @@ public: virtual short getMac_windowState(); + const GHOST_TabletData* GetTabletData() + { return &m_tablet; } + + GHOST_TabletData& GetCarbonTabletData() + { return m_tablet; } protected: /** * Tries to install a rendering context in this window. @@ -276,6 +281,8 @@ protected: static AGLContext s_firstaglCtx; Cursor* m_customCursor; + + GHOST_TabletData m_tablet; /** When running in full-screen this tells whether to refresh the window. */ bool m_fullScreenDirty; diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index b96e0f401ea..5a0ff3e2052 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -216,7 +216,8 @@ public: */ void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const; - + const GHOST_TabletData* GetTabletData() + { return NULL; } protected: /** * Tries to install a rendering context in this window. diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index cfdc1739074..87798b02ff4 100755 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -193,7 +193,9 @@ GHOST_WindowX11( XFree(xclasshint); setTitle(title); - + + initXInputDevices(); + // now set up the rendering context. if (installDrawingContext(type) == GHOST_kSuccess) { m_valid_setup = true; @@ -206,6 +208,67 @@ GHOST_WindowX11( XFlush(m_display); } +void GHOST_WindowX11::initXInputDevices() +{ + XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); + if(version && (version != (XExtensionVersion*)NoSuchExtension)) { + if(version->present) { + int device_count; + XDeviceInfo* device_info = XListInputDevices(m_display, &device_count); + m_xtablet.StylusDevice = 0; + m_xtablet.EraserDevice = 0; + m_xtablet.CommonData.Active= 0; + + for(int i=0; inum_classes; ++j) { + if(ici->c_class==ValuatorClass) { + XValuatorInfo* xvi = (XValuatorInfo*)ici; + m_xtablet.PressureLevels = xvi->axes[2].max_value; + break; + } + + ici = (XAnyClassPtr)(((char *)ici) + ici->length); + } + } + if(!strcmp(device_info[i].name, "eraser")) { + m_xtablet.EraserID= device_info[i].id; + m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID); + } + } + XFreeDeviceList(device_info); + + XEventClass xevents[10], ev; + int dcount = 0; + if(m_xtablet.StylusDevice) { + DeviceMotionNotify(m_xtablet.StylusDevice, m_xtablet.MotionEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityIn(m_xtablet.StylusDevice, m_xtablet.ProxInEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityOut(m_xtablet.StylusDevice, m_xtablet.ProxOutEvent, ev); + if(ev) xevents[dcount++] = ev; + } + if(m_xtablet.EraserDevice) { + DeviceMotionNotify(m_xtablet.EraserDevice, m_xtablet.MotionEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityIn(m_xtablet.EraserDevice, m_xtablet.ProxInEvent, ev); + if(ev) xevents[dcount++] = ev; + ProximityOut(m_xtablet.EraserDevice, m_xtablet.ProxOutEvent, ev); + if(ev) xevents[dcount++] = ev; + } + + XSelectExtensionEvent(m_display, m_window, xevents, dcount); + } + XFree(version); + } +} + + Window GHOST_WindowX11:: getXWindow( diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index d8b5f61697e..863644da095 100755 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -39,6 +39,8 @@ #include "GHOST_Window.h" #include #include +// For tablets +#include #include @@ -188,6 +190,28 @@ public: getXWindow( ); + class XTablet + { + public: + GHOST_TabletData CommonData; + + XDevice* StylusDevice; + XDevice* EraserDevice; + + XID StylusID, EraserID; + + int MotionEvent; + int ProxInEvent; + int ProxOutEvent; + + int PressureLevels; + }; + + XTablet& GetXTablet() + { return m_xtablet; } + + const GHOST_TabletData* GetTabletData() + { return &m_xtablet.CommonData; } protected: /** * Tries to install a rendering context in this window. @@ -272,6 +296,8 @@ private : Cursor getEmptyCursor( ); + + void initXInputDevices(); GLXContext m_context; Window m_window; @@ -298,6 +324,9 @@ private : /** Cache of XC_* ID's to XCursor structures */ std::map m_standard_cursors; + + /* Tablet devices */ + XTablet m_xtablet; };