Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Ebb <matt@mke3.net>2006-08-03 16:23:00 +0400
committerMatt Ebb <matt@mke3.net>2006-08-03 16:23:00 +0400
commitc85de34c267983bfc5dca388d5bcf6f092cf60ee (patch)
tree1fe782d1a1691de1814758d52bf9ed72fa3850e3
parent454fceb5f51809974be2ba3620c24d4eff7cf3a3 (diff)
* Tablet Pressure support in GHOST
This is 'ported' from Nicholas Bishop's sculpting GSoC tree. I'm bringing it over now so a) it can be there for when lukep does his GHOST refactor b) it's something that GHOST should have anyway, particularly now there's interest in painting tools and c) it's missing support in Windows, so hopefully now some enterprising Windows coder can add that more easily in the main bf tree. Right now X11 and Mac OS X are supported. I added and can maintain the Mac OS X part, but I'm not familiar with the Xinput stuff, which Nicholas wrote. Both X11 and Mac are collecting active device and pressure, and Mac is also collecting x and y tilt data. Up to coders how they want to use this info! :) Although the data's coming in, I haven't actually made this do anything. I thought it best to leave it to brecht to figure out what he wants to do with the painting stuff, and I wonder what other interesting uses there could be for it (proportional edit?). I'll write implementation details in a separate mail to the committers list.
-rw-r--r--intern/ghost/GHOST_C-api.h8
-rw-r--r--intern/ghost/GHOST_IWindow.h6
-rw-r--r--intern/ghost/GHOST_Types.h7
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp8
-rw-r--r--intern/ghost/intern/GHOST_SystemCarbon.cpp90
-rw-r--r--intern/ghost/intern/GHOST_SystemCarbon.h7
-rwxr-xr-xintern/ghost/intern/GHOST_SystemX11.cpp20
-rw-r--r--intern/ghost/intern/GHOST_WindowCarbon.cpp2
-rw-r--r--intern/ghost/intern/GHOST_WindowCarbon.h7
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h3
-rwxr-xr-xintern/ghost/intern/GHOST_WindowX11.cpp65
-rwxr-xr-xintern/ghost/intern/GHOST_WindowX11.h29
12 files changed, 239 insertions, 13 deletions
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
@@ -608,6 +608,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
* @return width of 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; i<device_count; ++i) {
+ if(!strcmp(device_info[i].name, "stylus")) {
+ m_xtablet.StylusID= device_info[i].id;
+ m_xtablet.StylusDevice = XOpenDevice(m_display, m_xtablet.StylusID);
+
+ /* Find how many pressure levels tablet has */
+ XAnyClassPtr ici = device_info[i].inputclassinfo;
+ for(int j=0; j<m_xtablet.StylusDevice->num_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 <X11/Xlib.h>
#include <GL/glx.h>
+// For tablets
+#include <X11/extensions/XInput.h>
#include <map>
@@ -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<unsigned int, Cursor> m_standard_cursors;
+
+ /* Tablet devices */
+ XTablet m_xtablet;
};