Hi all,
I’m Miky, I’m looking to write a script to manage input by wacom tablet in unity.
I try to understand and integrate in my unity project the WintabDN exemple that you find here:
I recompile the project in framework 3.5 and integrate the dll in unity. I try to use the TestForm code class in a unity script and so I can see and read input from Wacom, but my problem is that when I try to close the application I cant and I need to force it to close.
I found that the problem could be in the context.Open() function but I can’t figure out how to solve it. could someone please help me.
Thanks a lot Miky.
Here after the class code:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using UnityEngine;
using System.Threading;
using System.Windows;
//using Assets.Resource.Plugin;
//using System.Data;
using WintabDN;
namespace Assets.Resource.Scripts
{
public class WacomTabletTest : MonoBehaviour
{
public CWintabContext m_logContext = null;
private CWintabData m_wtData = null;
private UInt32 m_maxPkts = 1; // max num pkts to capture/display at a time
private Int32 m_pkX = 0;
private Int32 m_pkY = 0;
public UInt32 m_pressure = 0;
private UInt32 m_pkTime = 0;
private UInt32 m_pkTimeLast = 0;
// These constants can be used to force Wintab X/Y data to map into a
// a 10000 x 10000 grid, as an example of mapping tablet data to values
// that make sense for your application.
private const Int32 m_TABEXTX = 10000;
private const Int32 m_TABEXTY = 10000;
private bool m_showingTextButton = true;
public WacomTabletTest()
{
//InitializeComponent();
//this.FormClosing += new FormClosingEventHandler(TestForm_FormClosing);
}
///////////////////////////////////////////////////////////////////////
public HCTX HLogContext { get { return m_logContext.HCtx; } }
void OnApplicationQuit()
{
CloseCurrentContext();
//DestroyImmediate(this);
}
///////////////////////////////////////////////////////////////////////
//private void TestForm_FormClosing(System.Object sender, FormClosingEventArgs e)
//{
// CloseCurrentContext();
//}
///////////////////////////////////////////////////////////////////////
private void testButton_Click()
{
// Close whatever context is open.
CloseCurrentContext();
if (m_showingTextButton)
{
// Set up to STOP the next time button is pushed.
m_showingTextButton = false;
// Run the tests
Test_IsWintabAvailable();
Test_GetDeviceInfo();
Test_GetDefaultDigitizingContext();
Test_GetDefaultSystemContext();
Test_GetDefaultDeviceIndex();
Test_GetDeviceAxis();
Test_GetDeviceOrientation();
Test_GetDeviceRotation();
Test_GetNumberOfDevices();
Test_IsStylusActive();
Test_GetStylusName();
Test_GetExtensionMask();
//Test_Context();
//Test_DataPacketQueueSize();
Test_MaxPressure();
Test_GetDataPackets(1);
//Test_QueryDataPackets(); // opens up another form
}
else
{
CloseCurrentContext();
m_showingTextButton = true;
}
}
///////////////////////////////////////////////////////////////////////
private void Test_IsWintabAvailable()
{
if (CWintabInfo.IsWintabAvailable())
{
Debug.Log(“Wintab was found!\n”);
}
else
{
Debug.Log(“Wintab was not found!\nCheck to see if tablet driver service is running.\n”);
}
}
///////////////////////////////////////////////////////////////////////
private void Test_GetDeviceInfo()
{
//Debug.Log("DeviceInfo: " + CWintabInfo.GetDeviceInfo() + “\n”);
string devInfo = CWintabInfo.GetDeviceInfo();
Debug.Log("DeviceInfo: " + devInfo + “\n”);
}
///////////////////////////////////////////////////////////////////////
private void Test_GetDefaultDigitizingContext()
{
CWintabContext context = CWintabInfo.GetDefaultDigitizingContext();
Debug.Log(“Default Digitizing Context:\n”);
Debug.Log(“\tSysOrgX, SysOrgY, SysExtX, SysExtY\t[” +
context.SysOrgX + “,” + context.SysOrgY + “,” +
context.SysExtX + “,” + context.SysExtY + “]\n”);
Debug.Log(“\tInOrgX, InOrgY, InExtX, InExtY\t[” +
context.InOrgX + “,” + context.InOrgY + “,” +
context.InExtX + “,” + context.InExtY + “]\n”);
Debug.Log(“\tOutOrgX, OutOrgY, OutExtX, OutExt\t[” +
context.OutOrgX + “,” + context.OutOrgY + “,” +
context.OutExtX + “,” + context.OutExtY + “]\n”);
}
///////////////////////////////////////////////////////////////////////
private void Test_GetDefaultSystemContext()
{
CWintabContext context = CWintabInfo.GetDefaultSystemContext();
Debug.Log(“Default System Context:\n”);
Debug.Log(“\tSysOrgX, SysOrgY, SysExtX, SysExtY\t[” +
context.SysOrgX + “,” + context.SysOrgY + “,” +
context.SysExtX + “,” + context.SysExtY + “]\n”);
Debug.Log(“\tInOrgX, InOrgY, InExtX, InExtY\t[” +
context.InOrgX + “,” + context.InOrgY + “,” +
context.InExtX + “,” + context.InExtY + “]\n”);
Debug.Log(“\tOutOrgX, OutOrgY, OutExtX, OutExt\t[” +
context.OutOrgX + “,” + context.OutOrgY + “,” +
context.OutExtX + “,” + context.OutExtY + “]\n”);
}
///////////////////////////////////////////////////////////////////////
private void Test_GetDefaultDeviceIndex()
{
Int32 devIndex = CWintabInfo.GetDefaultDeviceIndex();
Debug.Log(“Default device index is: " + devIndex + (devIndex == -1 ? " (virtual device)\n” : “\n”));
}
///////////////////////////////////////////////////////////////////////
private void Test_GetDeviceAxis()
{
WintabAxis axis;
// Get virtual device axis for X, Y and Z.
axis = CWintabInfo.GetDeviceAxis(-1, EAxisDimension.AXIS_X);
Debug.Log(“Device axis X for virtual device:\n”);
Debug.Log("\taxMin, axMax, axUnits, axResolution: " + axis.axMin + “,” + axis.axMax + “,” + axis.axUnits + “,” + axis.axResolution.ToString() + “\n”);
axis = CWintabInfo.GetDeviceAxis(-1, EAxisDimension.AXIS_Y);
Debug.Log(“Device axis Y for virtual device:\n”);
Debug.Log("\taxMin, axMax, axUnits, axResolution: " + axis.axMin + “,” + axis.axMax + “,” + axis.axUnits + “,” + axis.axResolution.ToString() + “\n”);
axis = CWintabInfo.GetDeviceAxis(-1, EAxisDimension.AXIS_Z);
Debug.Log(“Device axis Z for virtual device:\n”);
Debug.Log("\taxMin, axMax, axUnits, axResolution: " + axis.axMin + “,” + axis.axMax + “,” + axis.axUnits + “,” + axis.axResolution.ToString() + “\n”);
}
///////////////////////////////////////////////////////////////////////
private void Test_GetDeviceOrientation()
{
bool tiltSupported = false;
WintabAxisArray axisArray = CWintabInfo.GetDeviceOrientation(out tiltSupported);
Debug.Log(“Device orientation:\n”);
Debug.Log("\ttilt supported for current tablet: " + (tiltSupported ? “YES\n” : “NO\n”));
if (tiltSupported)
{
for (int idx = 0; idx < axisArray.array.Length; idx++)
{
Debug.Log(“\t[” + idx + "] axMin, axMax, axResolution, axUnits: " +
axisArray.array[idx].axMin + “,” +
axisArray.array[idx].axMax + “,” +
axisArray.array[idx].axResolution + “,” +
axisArray.array[idx].axUnits + “\n”);
}
}
}
///////////////////////////////////////////////////////////////////////
private void Test_GetDeviceRotation()
{
bool rotationSupported = false;
WintabAxisArray axisArray = CWintabInfo.GetDeviceRotation(out rotationSupported);
Debug.Log(“Device rotation:\n”);
Debug.Log("\trotation supported for current tablet: " + (rotationSupported ? “YES\n” : “NO\n”));
if (rotationSupported)
{
for (int idx = 0; idx < axisArray.array.Length; idx++)
{
Debug.Log(“\t[” + idx + "] axMin, axMax, axResolution, axUnits: " +
axisArray.array[idx].axMin + “,” +
axisArray.array[idx].axMax + “,” +
axisArray.array[idx].axResolution + “,” +
axisArray.array[idx].axUnits + “\n”);
}
}
}
///////////////////////////////////////////////////////////////////////
private void Test_GetNumberOfDevices()
{
UInt32 numDevices = CWintabInfo.GetNumberOfDevices();
Debug.Log("Number of tablets connected: " + numDevices + “\n”);
}
///////////////////////////////////////////////////////////////////////
private void Test_IsStylusActive()
{
bool isStylusActive = CWintabInfo.IsStylusActive();
Debug.Log("Is stylus active: " + (isStylusActive ? “YES\n” : “NO\n”));
}
///////////////////////////////////////////////////////////////////////
private void Test_GetStylusName()
{
Debug.Log("Stylus name (puck): " + CWintabInfo.GetStylusName(EWTICursorNameIndex.CSR_NAME_PUCK) + “\n”);
Debug.Log("Stylus name (pen): " + CWintabInfo.GetStylusName(EWTICursorNameIndex.CSR_NAME_PRESSURE_STYLUS) + “\n”);
Debug.Log("Stylus name (eraser): " + CWintabInfo.GetStylusName(EWTICursorNameIndex.CSR_NAME_ERASER) + “\n”);
}
///////////////////////////////////////////////////////////////////////
private void Test_GetExtensionMask()
{
Debug.Log(“Extension touchring mask: 0x” + CWintabExtensions.GetWTExtensionMask(EWTXExtensionTag.WTX_TOUCHRING).ToString(“x”) + “\n”);
Debug.Log(“Extension touchstring mask: 0x” + CWintabExtensions.GetWTExtensionMask(EWTXExtensionTag.WTX_TOUCHSTRIP).ToString(“x”) + “\n”);
Debug.Log(“Extension express key mask: 0x” + CWintabExtensions.GetWTExtensionMask(EWTXExtensionTag.WTX_EXPKEYS2).ToString(“x”) + “\n”);
}
///////////////////////////////////////////////////////////////////////
private void Test_Context()
{
bool status = false;
CWintabContext logContext = null;
try
{
logContext = OpenTestDigitizerContext();
if (logContext == null)
{
Debug.Log(“Test_Context: FAILED OpenTestDigitizerContext - bailing out…\n”);
return;
}
status = logContext.Enable(true);
Debug.Log("Context Enable: " + (status ? “PASSED” : “FAILED”) + “\n”);
status = logContext.SetOverlapOrder(false);
Debug.Log("Context SetOverlapOrder to bottom: " + (status ? “PASSED” : “FAILED”) + “\n”);
status = logContext.SetOverlapOrder(true);
Debug.Log("Context SetOverlapOrder to top: " + (status ? “PASSED” : “FAILED”) + “\n”);
Debug.Log(“Modified Context:\n”);
Debug.Log(" Name: " + logContext.Name + “\n”);
Debug.Log(" Options: " + logContext.Options + “\n”);
Debug.Log(" Status: " + logContext.Status + “\n”);
Debug.Log(" Locks: " + logContext.Locks + “\n”);
Debug.Log(" MsgBase: " + logContext.MsgBase + “\n”);
Debug.Log(" Device: " + logContext.Device + “\n”);
Debug.Log(" PktRate: 0x" + logContext.PktRate.ToString(“x”) + “\n”);
Debug.Log(" PktData: 0x" + ((uint)logContext.PktData).ToString(“x”) + “\n”);
Debug.Log(" PktMode: 0x" + ((uint)logContext.PktMode).ToString(“x”) + “\n”);
Debug.Log(" MoveMask: " + logContext.MoveMask + “\n”);
Debug.Log(" BZtnDnMask: 0x" + logContext.BtnDnMask.ToString(“x”) + “\n”);
Debug.Log(" BtnUpMask: 0x" + logContext.BtnUpMask.ToString(“x”) + “\n”);
Debug.Log(" InOrgX: " + logContext.InOrgX + “\n”);
Debug.Log(" InOrgY: " + logContext.InOrgY + “\n”);
Debug.Log(" InOrgZ: " + logContext.InOrgZ + “\n”);
Debug.Log(" InExtX: " + logContext.InExtX + “\n”);
Debug.Log(" InExtY: " + logContext.InExtY + “\n”);
Debug.Log(" InExtZ: " + logContext.InExtZ + “\n”);
Debug.Log(" OutOrgX: " + logContext.OutOrgX + “\n”);
Debug.Log(" OutOrgY: " + logContext.OutOrgY + “\n”);
Debug.Log(" OutOrgZ: " + logContext.OutOrgZ + “\n”);
Debug.Log(" OutExtX: " + logContext.OutExtX + “\n”);
Debug.Log(" OutExtY: " + logContext.OutExtY + “\n”);
Debug.Log(" OutExtZ: " + logContext.OutExtZ + “\n”);
Debug.Log(" SensX: " + logContext.SensX + “\n”);
Debug.Log(" SensY: " + logContext.SensY + “\n”);
Debug.Log(" SensZ: " + logContext.SensZ + “\n”);
Debug.Log(" SysMode: " + logContext.SysMode + “\n”);
Debug.Log(" SysOrgX: " + logContext.SysOrgX + “\n”);
Debug.Log(" SysOrgY: " + logContext.SysOrgY + “\n”);
Debug.Log(" SysExtX: " + logContext.SysExtX + “\n”);
Debug.Log(" SysExtY: " + logContext.SysExtY + “\n”);
Debug.Log(" SysSensX: " + logContext.SysSensX + “\n”);
Debug.Log(" SysSensY: " + logContext.SysSensY + “\n”);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
finally
{
logContext = null;
if (logContext != null)
{
status = logContext.Close();
Debug.Log("Context Close: " + (status ? “PASSED” : “FAILED”) + “\n”);
logContext = null;
}
}
}
///////////////////////////////////////////////////////////////////////
private CWintabContext OpenTestDigitizerContext(
int width_I = m_TABEXTX, int height_I = m_TABEXTY, bool ctrlSysCursor = true)
{
bool status = false;
CWintabContext logContext = null;
try
{
// Get the default digitizing context.
// Default is to receive data events.
logContext = CWintabInfo.GetDefaultDigitizingContext(ECTXOptionValues.CXO_MESSAGES);
// Set system cursor if caller wants it.
if (ctrlSysCursor)
{
logContext.Options |= (uint)ECTXOptionValues.CXO_SYSTEM;
}
if (logContext == null)
{
Debug.Log(“FAILED to get default digitizing context.\n”);
return null;
}
// Modify the digitizing region.
logContext.Name = “WintabDN Event Data Context”;
// output in a grid of the specified dimensions.
logContext.OutOrgX = logContext.OutOrgY = 0;
logContext.OutExtX = width_I;
logContext.OutExtY = height_I;
// Open the context, which will also tell Wintab to send data packets.
status = logContext.Open();
Debug.Log("Context Open: " + (status ? “PASSED [ctx=” + logContext.HCtx + “]” : “FAILED”) + “\n”);
}
catch (Exception ex)
{
Debug.Log("OpenTestDigitizerContext ERROR: " + ex.ToString());
}
return logContext;
}
///////////////////////////////////////////////////////////////////////
private CWintabContext OpenTestSystemContext(
int width_I = m_TABEXTX, int height_I = m_TABEXTY, bool ctrlSysCursor = true)
{
bool status = false;
CWintabContext logContext = null;
try
{
// Get the default system context.
// Default is to receive data events.
logContext = CWintabInfo.GetDefaultDigitizingContext(ECTXOptionValues.CXO_MESSAGES);
//logContext = CWintabInfo.GetDefaultSystemContext(ECTXOptionValues.CXO_MESSAGES);
// Set system cursor if caller wants it.
if (ctrlSysCursor)
{
logContext.Options |= (uint)ECTXOptionValues.CXO_SYSTEM;
}
else
{
logContext.Options &= ~(uint)ECTXOptionValues.CXO_SYSTEM;
}
if (logContext == null)
{
Debug.Log(“FAILED to get default digitizing context.\n”);
return null;
}
//Modify the digitizing region.
logContext.Name = “WintabDN Event Data Context”;
WintabAxis tabletX = CWintabInfo.GetTabletAxis(EAxisDimension.AXIS_X);
WintabAxis tabletY = CWintabInfo.GetTabletAxis(EAxisDimension.AXIS_Y);
logContext.InOrgX = 0;
logContext.InOrgY = 0;
logContext.InExtX = tabletX.axMax;
logContext.InExtY = tabletY.axMax;
// SetSystemExtents() is (almost) a NO-OP redundant if you opened a system context.
//SetSystemExtents(ref logContext);
// Open the context, which will also tell Wintab to send data packets.
//status = logContext.Open();
Debug.Log("Context Open: " + (status ? “PASSED [ctx=” + logContext.HCtx + “]” : “FAILED”) + “\n”);
}
catch (Exception ex)
{
Debug.Log("OpenTestDigitizerContext ERROR: " + ex.ToString());
}
return logContext;
}
///////////////////////////////////////////////////////////////////////
private void Test_DataPacketQueueSize()
{
bool status = false;
UInt32 numPackets = 0;
CWintabContext logContext = null;
try
{
logContext = OpenTestDigitizerContext();
if (logContext == null)
{
Debug.Log(“Test_DataPacketQueueSize: FAILED OpenTestDigitizerContext - bailing out…\n”);
return;
}
CWintabData wtData = new CWintabData(logContext);
Debug.Log("Creating CWintabData object: " + (wtData != null ? “PASSED” : “FAILED”) + “\n”);
if (wtData == null)
{
throw new Exception(“Could not create CWintabData object.”);
}
numPackets = wtData.GetPacketQueueSize();
Debug.Log("Initial packet queue size: " + numPackets + “\n”);
status = wtData.SetPacketQueueSize(17);
Debug.Log("Setting packet queue size: " + (status ? “PASSED” : “FAILED”) + “\n”);
numPackets = wtData.GetPacketQueueSize();
Debug.Log("Modified packet queue size: " + numPackets + “\n”);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
finally
{
if (logContext != null)
{
status = logContext.Close();
Debug.Log("Context Close: " + (status ? “PASSED” : “FAILED”) + “\n”);
}
}
}
///////////////////////////////////////////////////////////////////////
private void Test_MaxPressure()
{
Debug.Log("Max normal pressure is: " + CWintabInfo.GetMaxPressure() + “\n”);
Debug.Log("Max tangential pressure is: " + CWintabInfo.GetMaxPressure(false) + “\n”);
}
///////////////////////////////////////////////////////////////////////
private void Test_GetDataPackets(UInt32 maxNumPkts_I)
{
// Set up to capture/display maxNumPkts_I packet at a time.
m_maxPkts = maxNumPkts_I;
// Open a context and try to capture pen data.
InitDataCapture();
// Touch pen to the tablet. You should see data appear in the TestForm window.
}
///////////////////////////////////////////////////////////////////////
//private void Test_QueryDataPackets()
//{
// QueryDataForm qdForm = new QueryDataForm();
// qdForm.ShowDialog();
//}
///////////////////////////////////////////////////////////////////////
// Helper functions
//
///////////////////////////////////////////////////////////////////////
private void InitDataCapture(
int ctxWidth_I = m_TABEXTX, int ctxHeight_I = m_TABEXTY, bool ctrlSysCursor_I = true)
{
try
{
// Close context from any previous test.
CloseCurrentContext();
Debug.Log(“Opening context…\n”);
m_logContext = OpenTestSystemContext(ctxWidth_I, ctxHeight_I, ctrlSysCursor_I);
if (m_logContext == null)
{
Debug.Log(“Test_DataPacketQueueSize: FAILED OpenTestSystemContext - bailing out…\n”);
return;
}
// Create a data object and set its WT_PACKET handler.
// m_wtData = new CWintabData(m_logContext);
// m_wtData.SetWTPacketEventHandler(MyWTPacketEventHandler);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
}
///////////////////////////////////////////////////////////////////////
private void CloseCurrentContext()
{
try
{
Debug.Log(“Closing context…\n”);
if (m_logContext != null)
{
//m_logContext.Close();
m_logContext = null;
m_wtData = null;
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString());
}
}
///////////////////////////////////////////////////////////////////////
// Sets logContext.Out
//
// Note:
// SystemParameters.VirtualScreenLeft{Top} and SystemParameters.VirtualScreenWidth{Height}
// don’t always give correct answers.
//
// Uncomment the TODO code below that enumerates all system displays
// if you want to customize.
// Else assume the passed-in extents were already set by call to WTInfo,
// in which case we still have to invert the Y extent.
private void SetSystemExtents(ref CWintabContext logContext)
{
//TODO Rectangle rect = new Rectangle(int.MaxValue, int.MaxValue, int.MinValue, int.MinValue);
//TODO foreach (Screen screen in Screen.AllScreens)
//TODO rect = Rectangle.Union(rect, screen.Bounds);
//TODO logContext.OutOrgX = rect.Left;
//TODO logContext.OutOrgY = rect.Top;
//TODO logContext.OutExtX = rect.Width;
//TODO logContext.OutExtY = rect.Height;
// In Wintab, the tablet origin is lower left. Move origin to upper left
// so that it coincides with screen origin.
logContext.OutExtY = -logContext.OutExtY;
}
///////////////////////////////////////////////////////////////////////
///
/// Called when Wintab WT_PACKET events are received.
///
/// The EventMessage object sending the report.
/// eventArgs_I.Message.WParam contains ID of packet containing the data.
public void MyWTPacketEventHandler(System.Object sender_I, MessageReceivedEventArgs eventArgs_I)
{
//System.Diagnostics.Debug.WriteLine(“Received WT_PACKET event”);
if (m_wtData == null)
{
return;
}
try
{
if (m_maxPkts == 1)
{
uint pktID = (uint)eventArgs_I.Message.WParam;
WintabPacket pkt = m_wtData.GetDataPacket((uint)eventArgs_I.Message.LParam, pktID);
//DEPRECATED WintabPacket pkt = m_wtData.GetDataPacket(pktID);
if (pkt.pkContext != 0)
{
m_pkX = pkt.pkX;
m_pkY = pkt.pkY;
m_pressure = pkt.pkNormalPressure;
Debug.Log("SCREEN: pkX: " + pkt.pkX + “, pkY:” + pkt.pkY + ", pressure: " + pkt.pkNormalPressure);
m_pkTime = pkt.pkTime;
//if (m_graphics == null)
//{
// display data mode
Debug.Log(“Received WT_PACKET event[” + pktID + "]: X/Y/P = " +
pkt.pkX + " / " + pkt.pkY + " / " + pkt.pkNormalPressure + “\n”);
//}
//else
//{
// // scribble mode
// int clientWidth = scribblePanel.Width;
// int clientHeight = scribblePanel.Height;
// // m_pkX and m_pkY are in screen (system) coordinates.
// Point clientPoint = scribblePanel.PointToClient(new Point(m_pkX, m_pkY));
// Debug.Log("CLIENT: X: " + clientPoint.X + “, Y:” + clientPoint.Y);
// if (m_lastPoint.Equals(Point.Empty))
// {
// m_lastPoint = clientPoint;
// m_pkTimeLast = m_pkTime;
// }
// m_pen.Width = (float)(m_pressure / 200);
// if (m_pressure > 0)
// {
// if (m_pkTime - m_pkTimeLast < 5)
// {
// m_graphics.DrawRectangle(m_pen, clientPoint.X, clientPoint.Y, 1, 1);
// }
// else
// {
// m_graphics.DrawLine(m_pen, clientPoint, m_lastPoint);
// }
// }
// m_lastPoint = clientPoint;
// m_pkTimeLast = m_pkTime;
//}
}
}
}
catch (Exception ex)
{
throw new Exception("FAILED to get packet data: " + ex.ToString());
}
}
private void testQDPButton_Click(object sender, EventArgs e)
{
//Test_QueryDataPackets();
}
public void ShowIt()
{
Color c = m_showingTextButton == true ? Color.green : Color.white;
GUI.color = c;
// if button pressed
if (GUI.Button(new Rect(10, 10, 250, 60), “Press Here” ))
{
testButton_Click();
}
GUI.Box(new Rect(10, 80, 250, 70), m_pressure.ToString());
}
}
}