committed by
GitHub
8 changed files with 2663 additions and 42 deletions
@ -0,0 +1,532 @@ |
|||
///////////////////////////////////////////////////////////////////////////////
|
|||
//
|
|||
// PURPOSE
|
|||
// Wintab context management for WintabDN
|
|||
//
|
|||
// COPYRIGHT
|
|||
// Copyright (c) 2010-2020 Wacom Co., Ltd.
|
|||
//
|
|||
// The text and information contained in this file may be freely used,
|
|||
// copied, or distributed without compensation or licensing restrictions.
|
|||
//
|
|||
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace Avalonia.Win32.WintabImpl |
|||
{ |
|||
/// <summary>
|
|||
/// Managed version of AXIS struct.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct WintabAxis |
|||
{ |
|||
/// <summary>
|
|||
/// Specifies the minimum value of the data item in the tablet's na-tive coordinates.
|
|||
/// </summary>
|
|||
public Int32 axMin; |
|||
|
|||
/// <summary>
|
|||
/// Specifies the maximum value of the data item in the tablet's na-tive coordinates.
|
|||
/// </summary>
|
|||
public Int32 axMax; |
|||
|
|||
/// <summary>
|
|||
/// Indicates the units used in calculating the resolution for the data item.
|
|||
/// </summary>
|
|||
public UInt32 axUnits; |
|||
|
|||
/// <summary>
|
|||
/// Is a fixed-point number giving the number of data item incre-ments per physical unit.
|
|||
/// </summary>
|
|||
public FIX32 axResolution; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Array of WintabAxis objects.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct WintabAxisArray |
|||
{ |
|||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] |
|||
public WintabAxis[] array; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Values to use when asking for X, Y or Z WintabAxis object.
|
|||
/// </summary>
|
|||
public enum EAxisDimension |
|||
{ |
|||
AXIS_X = EWTIDevicesIndex.DVC_X, |
|||
AXIS_Y = EWTIDevicesIndex.DVC_Y, |
|||
AXIS_Z = EWTIDevicesIndex.DVC_Z |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Context option values.
|
|||
/// </summary>
|
|||
public enum ECTXOptionValues |
|||
{ |
|||
CXO_SYSTEM = 0x0001, |
|||
CXO_PEN = 0x0002, |
|||
CXO_MESSAGES = 0x0004, |
|||
CXO_CSRMESSAGES = 0x0008, |
|||
CXO_MGNINSIDE = 0x4000, |
|||
CXO_MARGIN = 0x8000, |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Context status values.
|
|||
/// </summary>
|
|||
public enum ECTXStatusValues |
|||
{ |
|||
CXS_DISABLED = 0x0001, |
|||
CXS_OBSCURED = 0x0002, |
|||
CXS_ONTOP = 0x0004 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Context lock values.
|
|||
/// </summary>
|
|||
public enum ECTXLockValues |
|||
{ |
|||
CXL_INSIZE = 0x0001, |
|||
CXL_INASPECT = 0x0002, |
|||
CXL_SENSITIVITY = 0x0004, |
|||
CXL_MARGIN = 0x0008, |
|||
CXL_SYSOUT = 0x0010 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Managed version of Wintab LOGCONTEXT struct. This structure determines what events an
|
|||
/// application will get, how they will be processed, and how they will be delivered to the
|
|||
/// application or to Windows itself.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct WintabLogContext |
|||
{ |
|||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)] //LCNAMELEN
|
|||
public string lcName; |
|||
|
|||
public UInt32 lcOptions; |
|||
public UInt32 lcStatus; |
|||
public UInt32 lcLocks; |
|||
public UInt32 lcMsgBase; |
|||
public UInt32 lcDevice; |
|||
public UInt32 lcPktRate; |
|||
public WTPKT lcPktData; |
|||
public WTPKT lcPktMode; |
|||
public WTPKT lcMoveMask; |
|||
public UInt32 lcBtnDnMask; |
|||
public UInt32 lcBtnUpMask; |
|||
public Int32 lcInOrgX; |
|||
public Int32 lcInOrgY; |
|||
public Int32 lcInOrgZ; |
|||
public Int32 lcInExtX; |
|||
public Int32 lcInExtY; |
|||
public Int32 lcInExtZ; |
|||
public Int32 lcOutOrgX; |
|||
public Int32 lcOutOrgY; |
|||
public Int32 lcOutOrgZ; |
|||
public Int32 lcOutExtX; |
|||
public Int32 lcOutExtY; |
|||
public Int32 lcOutExtZ; |
|||
public FIX32 lcSensX; |
|||
public FIX32 lcSensY; |
|||
public FIX32 lcSensZ; |
|||
public bool lcSysMode; |
|||
public Int32 lcSysOrgX; |
|||
public Int32 lcSysOrgY; |
|||
public Int32 lcSysExtX; |
|||
public Int32 lcSysExtY; |
|||
public FIX32 lcSysSensX; |
|||
public FIX32 lcSysSensY; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Class to support access to Wintab context management.
|
|||
/// </summary>
|
|||
public class WintabContext |
|||
{ |
|||
// Context data.
|
|||
private WintabLogContext m_logContext = new WintabLogContext(); |
|||
private HCTX m_hCTX = new HCTX(IntPtr.Zero); |
|||
|
|||
public static WintabContext GetDefaultContext(EWTICategoryIndex contextIndex_I) |
|||
{ |
|||
WintabContext context = new WintabContext(); |
|||
int sizeOfLogContext = Marshal.SizeOf<WintabLogContext>(); |
|||
IntPtr buf = Marshal.AllocHGlobal(sizeOfLogContext); |
|||
|
|||
int size = (int)WintabFuncs.WTInfoA((uint)contextIndex_I, 0, buf); |
|||
|
|||
context.LogContext = Marshal.PtrToStructure<WintabLogContext>(buf); |
|||
|
|||
context.PktData = (uint) |
|||
(EWintabPacketBit.PK_CONTEXT | |
|||
EWintabPacketBit.PK_STATUS | |
|||
EWintabPacketBit.PK_TIME | |
|||
EWintabPacketBit.PK_CHANGED | |
|||
EWintabPacketBit.PK_SERIAL_NUMBER | |
|||
EWintabPacketBit.PK_CURSOR | |
|||
EWintabPacketBit.PK_BUTTONS | |
|||
EWintabPacketBit.PK_X | |
|||
EWintabPacketBit.PK_Y | |
|||
EWintabPacketBit.PK_Z | |
|||
EWintabPacketBit.PK_NORMAL_PRESSURE | |
|||
EWintabPacketBit.PK_TANGENT_PRESSURE | |
|||
EWintabPacketBit.PK_ORIENTATION); |
|||
context.MoveMask = context.PktData; |
|||
|
|||
Marshal.FreeHGlobal(buf); |
|||
|
|||
return context; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Default constructor sets all data bits to be captured.
|
|||
/// </summary>
|
|||
public WintabContext() |
|||
{ |
|||
// Init with all bits set (The Full Monty) to get all non-extended data types.
|
|||
PktData = (uint) |
|||
(EWintabPacketBit.PK_CONTEXT | |
|||
EWintabPacketBit.PK_STATUS | |
|||
EWintabPacketBit.PK_TIME | |
|||
EWintabPacketBit.PK_CHANGED | |
|||
EWintabPacketBit.PK_SERIAL_NUMBER | |
|||
EWintabPacketBit.PK_CURSOR | |
|||
EWintabPacketBit.PK_BUTTONS | |
|||
EWintabPacketBit.PK_X | |
|||
EWintabPacketBit.PK_Y | |
|||
EWintabPacketBit.PK_Z | |
|||
EWintabPacketBit.PK_NORMAL_PRESSURE | |
|||
EWintabPacketBit.PK_TANGENT_PRESSURE | |
|||
EWintabPacketBit.PK_ORIENTATION); |
|||
MoveMask = PktData; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Open a Wintab context to the specified hwnd.
|
|||
/// </summary>
|
|||
/// <param name="hwnd_I">parent window for the context</param>
|
|||
/// <param name="enable_I">true to enable, false to disable</param>
|
|||
/// <returns>Returns non-zero context handle if successful.</returns>
|
|||
public HCTX Open(HWND hwnd_I, bool enable_I) |
|||
{ |
|||
try |
|||
{ |
|||
m_hCTX = new HCTX((IntPtr)WintabFuncs.WTOpenA(hwnd_I, ref m_logContext, enable_I)); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
// TODO: Throw
|
|||
//MessageBox.Show("FAILED OpenContext: " + ex.ToString());
|
|||
} |
|||
|
|||
return m_hCTX; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Open a Wintab context that will send packet events to a message window.
|
|||
/// </summary>
|
|||
/// <returns>Returns true if successful.</returns>
|
|||
public bool Open(IntPtr hwnd) |
|||
{ |
|||
m_hCTX = new HCTX((IntPtr)WintabFuncs.WTOpenA(hwnd, ref m_logContext, true)); |
|||
return m_hCTX.Value != IntPtr.Zero; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Close the context for this object.
|
|||
/// </summary>
|
|||
/// <returns>true if context successfully closed</returns>
|
|||
public bool Close() |
|||
{ |
|||
bool status = false; |
|||
|
|||
|
|||
if (m_hCTX.Value == IntPtr.Zero) |
|||
{ |
|||
throw new Exception("CloseContext: invalid context"); |
|||
} |
|||
|
|||
status = WintabFuncs.WTClose(m_hCTX.Value); |
|||
m_hCTX = new HCTX(IntPtr.Zero); |
|||
m_logContext = new WintabLogContext(); |
|||
|
|||
|
|||
return status; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Enable/disable this Wintab context.
|
|||
/// </summary>
|
|||
/// <param name="enable_I">true = enable</param>
|
|||
/// <returns>Returns true if completed successfully</returns>
|
|||
public bool Enable(bool enable_I) |
|||
{ |
|||
bool status = false; |
|||
|
|||
try |
|||
{ |
|||
if (m_hCTX.Value == IntPtr.Zero) |
|||
{ |
|||
throw new Exception("EnableContext: invalid context"); |
|||
} |
|||
|
|||
status = WintabFuncs.WTEnable(m_hCTX.Value, enable_I); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
// TODO: Throw
|
|||
//MessageBox.Show("FAILED EnableContext: " + ex.ToString());
|
|||
} |
|||
|
|||
return status; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sends a tablet context to the top or bottom of the order of overlapping tablet contexts
|
|||
/// </summary>
|
|||
/// <param name="toTop_I">true = send tablet to top of order</param>
|
|||
/// <returns>Returns true if successsful</returns>
|
|||
public bool SetOverlapOrder(bool toTop_I) |
|||
{ |
|||
bool status = false; |
|||
|
|||
if (m_hCTX.Value == IntPtr.Zero) |
|||
{ |
|||
throw new Exception("EnableContext: invalid context"); |
|||
} |
|||
|
|||
status = WintabFuncs.WTOverlap(m_hCTX.Value, toTop_I); |
|||
|
|||
return status; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Logical Wintab context managed by this object.
|
|||
/// </summary>
|
|||
public WintabLogContext LogContext { get { return m_logContext; } set { m_logContext = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Handle (identifier) used to identify this context.
|
|||
/// </summary>
|
|||
public HCTX HCtx { get { return m_hCTX; } } |
|||
|
|||
/// <summary>
|
|||
/// Get/Set context name.
|
|||
/// </summary>
|
|||
public string Name { get { return m_logContext.lcName; } set { m_logContext.lcName = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies options for the context. These options can be
|
|||
/// combined by using the bitwise OR operator. The lcOptions
|
|||
/// field can be any combination of the values defined in
|
|||
/// ECTXOptionValues.
|
|||
/// </summary>
|
|||
public UInt32 Options { get { return m_logContext.lcOptions; } set { m_logContext.lcOptions = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies current status conditions for the context.
|
|||
/// These conditions can be combined by using the bitwise OR
|
|||
/// operator. The lcStatus field can be any combination of
|
|||
/// the values defined in ECTXStatusValues.
|
|||
/// </summary>
|
|||
public UInt32 Status { get { return m_logContext.lcStatus; } set { m_logContext.lcStatus = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies which attributes of the context the application
|
|||
/// wishes to be locked. Lock conditions specify attributes
|
|||
/// of the context that cannot be changed once the context
|
|||
/// has been opened (calls to WTConfig will have no effect
|
|||
/// on the locked attributes). The lock conditions can be
|
|||
/// combined by using the bitwise OR operator. The lcLocks
|
|||
/// field can be any combination of the values defined in
|
|||
/// ECTXLockValues. Locks can only be changed by the task
|
|||
/// or process that owns the context.
|
|||
/// </summary>
|
|||
public UInt32 Locks { get { return m_logContext.lcLocks; } set { m_logContext.lcLocks = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the range of message numbers that will be used for
|
|||
/// reporting the activity of the context.
|
|||
/// </summary>
|
|||
public UInt32 MsgBase { get { return m_logContext.lcMsgBase; } set { m_logContext.lcMsgBase = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the device whose input the context processes.
|
|||
/// </summary>
|
|||
public UInt32 Device { get { return m_logContext.lcDevice; } set { m_logContext.lcDevice = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the desired packet report rate in Hertz. Once the con-text is opened, this field will
|
|||
/// contain the actual report rate.
|
|||
/// </summary>
|
|||
public UInt32 PktRate { get { return m_logContext.lcPktRate; } set { m_logContext.lcPktRate = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies which optional data items will be in packets returned from the context. Requesting
|
|||
/// unsupported data items will cause Open() to fail.
|
|||
/// </summary>
|
|||
public WTPKT PktData { get { return m_logContext.lcPktData; } set { m_logContext.lcPktData = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies whether the packet data items will be returned in absolute or relative mode. If the item's
|
|||
/// bit is set in this field, the item will be returned in relative mode. Bits in this field for items not
|
|||
/// selected in the PktData property will be ignored. Bits for data items that only allow one mode (such
|
|||
/// as the packet identifier) will also be ignored.
|
|||
/// </summary>
|
|||
public WTPKT PktMode { get { return m_logContext.lcPktMode; } set { m_logContext.lcPktMode = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies which packet data items can generate move events in the context. Bits for items that
|
|||
/// are not part of the packet definition in the PktData property will be ignored. The bits for buttons,
|
|||
/// time stamp, and the packet identifier will also be ignored. In the case of overlapping contexts, movement
|
|||
/// events for data items not selected in this field may be processed by underlying contexts.
|
|||
/// </summary>
|
|||
public WTPKT MoveMask { get { return m_logContext.lcMoveMask; } set { m_logContext.lcMoveMask = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the buttons for which button press events will be processed in the context. In the case of
|
|||
/// overlapping contexts, button press events for buttons that are not selected in this field may be
|
|||
/// processed by underlying contexts.
|
|||
/// </summary>
|
|||
public UInt32 BtnDnMask { get { return m_logContext.lcBtnDnMask; } set { m_logContext.lcBtnDnMask = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the buttons for which button release events will be processed in the context. In the case
|
|||
/// of overlapping contexts, button release events for buttons that are not selected in this field may be
|
|||
/// processed by underlying contexts. If both press and release events are selected for a button (see the
|
|||
/// BtnDnMask property), then the interface will cause the context to implicitly capture all tablet events
|
|||
/// while the button is down. In this case, events occurring outside the context will be clipped to the
|
|||
/// context and processed as if they had occurred in the context. When the button is released, the context
|
|||
/// will receive the button release event, and then event processing will return to normal.
|
|||
/// </summary>
|
|||
public UInt32 BtnUpMask { get { return m_logContext.lcBtnUpMask; } set { m_logContext.lcBtnUpMask = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the X origin of the context's input area in the tablet's native coordinates. Value is clipped
|
|||
/// to the tablet native coordinate space when the context is opened or modified.
|
|||
/// </summary>
|
|||
public Int32 InOrgX { get { return m_logContext.lcInOrgX; } set { m_logContext.lcInOrgX = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the Y origin of the context's input area in the tablet's native coordinates. Value is clipped
|
|||
/// to the tablet native coordinate space when the context is opened or modified.
|
|||
/// </summary>
|
|||
public Int32 InOrgY { get { return m_logContext.lcInOrgY; } set { m_logContext.lcInOrgY = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the Z origin of the context's input area in the tablet's native coordinates. Value is clipped
|
|||
/// to the tablet native coordinate space when the context is opened or modified.
|
|||
/// </summary>
|
|||
public Int32 InOrgZ { get { return m_logContext.lcInOrgZ; } set { m_logContext.lcInOrgZ = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the X extent of the context's input area in the tablet's native coordinates. Value is clipped
|
|||
/// to the tablet native coordinate space when the context is opened or modified.
|
|||
/// </summary>
|
|||
public Int32 InExtX { get { return m_logContext.lcInExtX; } set { m_logContext.lcInExtX = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the Y extent of the context's input area in the tablet's native coordinates. Value is clipped
|
|||
/// to the tablet native coordinate space when the context is opened or modified.
|
|||
/// </summary>
|
|||
public Int32 InExtY { get { return m_logContext.lcInExtY; } set { m_logContext.lcInExtY = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the Z extent of the context's input area in the tablet's native coordinates. Value is clipped
|
|||
/// to the tablet native coordinate space when the context is opened or modified.
|
|||
/// </summary>
|
|||
public Int32 InExtZ { get { return m_logContext.lcInExtZ; } set { m_logContext.lcInExtZ = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the X origin of the context's output area in context output coordinates. Value is used in
|
|||
/// coordinate scaling for absolute mode only.
|
|||
/// </summary>
|
|||
public Int32 OutOrgX { get { return m_logContext.lcOutOrgX; } set { m_logContext.lcOutOrgX = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the Y origin of the context's output area in context output coordinates. Value is used in
|
|||
/// coordinate scaling for absolute mode only.
|
|||
/// </summary>
|
|||
public Int32 OutOrgY { get { return m_logContext.lcOutOrgY; } set { m_logContext.lcOutOrgY = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the Z origin of the context's output area in context output coordinates. Value is used in
|
|||
/// coordinate scaling for absolute mode only.
|
|||
/// </summary>
|
|||
public Int32 OutOrgZ { get { return m_logContext.lcOutOrgZ; } set { m_logContext.lcOutOrgZ = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the X extent of the context's output area in context output coordinates. Value is used
|
|||
/// in coordinate scaling for absolute mode only.
|
|||
/// </summary>
|
|||
public Int32 OutExtX { get { return m_logContext.lcOutExtX; } set { m_logContext.lcOutExtX = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the Y extent of the context's output area in context output coordinates. Value is used
|
|||
/// in coordinate scaling for absolute mode only.
|
|||
/// </summary>
|
|||
public Int32 OutExtY { get { return m_logContext.lcOutExtY; } set { m_logContext.lcOutExtY = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the Z extent of the context's output area in context output coordinates. Value is used
|
|||
/// in coordinate scaling for absolute mode only.
|
|||
/// </summary>
|
|||
public Int32 OutExtZ { get { return m_logContext.lcOutExtZ; } set { m_logContext.lcOutExtZ = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the relative-mode sensitivity factor for the x axis.
|
|||
/// </summary>
|
|||
public FIX32 SensX { get { return m_logContext.lcSensX; } set { m_logContext.lcSensX = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the relative-mode sensitivity factor for the y axis.
|
|||
/// </summary>
|
|||
public FIX32 SensY { get { return m_logContext.lcSensY; } set { m_logContext.lcSensY = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the relative-mode sensitivity factor for the Z axis.
|
|||
/// </summary>
|
|||
public FIX32 SensZ { get { return m_logContext.lcSensZ; } set { m_logContext.lcSensZ = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the system cursor tracking mode. Zero specifies absolute; non-zero means relative.
|
|||
/// </summary>
|
|||
public bool SysMode { get { return m_logContext.lcSysMode; } set { m_logContext.lcSysMode = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the X origin of the screen mapping area for system cursor tracking, in screen coordinates.
|
|||
/// </summary>
|
|||
public Int32 SysOrgX { get { return m_logContext.lcSysOrgX; } set { m_logContext.lcSysOrgX = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the Y origin of the screen mapping area for system cursor tracking, in screen coordinates.
|
|||
/// </summary>
|
|||
public Int32 SysOrgY { get { return m_logContext.lcSysOrgY; } set { m_logContext.lcSysOrgY = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the X extent of the screen mapping area for system cursor tracking, in screen coordinates.
|
|||
/// </summary>
|
|||
public Int32 SysExtX { get { return m_logContext.lcSysExtX; } set { m_logContext.lcSysExtX = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the Y extent of the screen mapping area for system cursor tracking, in screen coordinates.
|
|||
/// </summary>
|
|||
public Int32 SysExtY { get { return m_logContext.lcSysExtY; } set { m_logContext.lcSysExtY = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the system-cursor relative-mode sensitivity factor for the x axis.
|
|||
/// </summary>
|
|||
public FIX32 SysSensX { get { return m_logContext.lcSysSensX; } set { m_logContext.lcSysSensX = value; } } |
|||
|
|||
/// <summary>
|
|||
/// Specifies the system-cursor relative-mode sensitivity factor for the y axis.
|
|||
/// </summary>
|
|||
public FIX32 SysSensY { get { return m_logContext.lcSysSensY; } set { m_logContext.lcSysSensY = value; } } |
|||
} |
|||
} |
|||
@ -0,0 +1,705 @@ |
|||
///////////////////////////////////////////////////////////////////////////////
|
|||
//
|
|||
// PURPOSE
|
|||
// Wintab data management for WintabDN
|
|||
//
|
|||
// COPYRIGHT
|
|||
// Copyright (c) 2010-2020 Wacom Co., Ltd.
|
|||
//
|
|||
// The text and information contained in this file may be freely used,
|
|||
// copied, or distributed without compensation or licensing restrictions.
|
|||
//
|
|||
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace Avalonia.Win32.WintabImpl |
|||
{ |
|||
/// <summary>
|
|||
/// Wintab Packet bits.
|
|||
/// </summary>
|
|||
public enum EWintabPacketBit |
|||
{ |
|||
PK_CONTEXT = 0x0001, /* reporting context */ |
|||
PK_STATUS = 0x0002, /* status bits */ |
|||
PK_TIME = 0x0004, /* time stamp */ |
|||
PK_CHANGED = 0x0008, /* change bit vector */ |
|||
PK_SERIAL_NUMBER = 0x0010, /* packet serial number */ |
|||
PK_CURSOR = 0x0020, /* reporting cursor */ |
|||
PK_BUTTONS = 0x0040, /* button information */ |
|||
PK_X = 0x0080, /* x axis */ |
|||
PK_Y = 0x0100, /* y axis */ |
|||
PK_Z = 0x0200, /* z axis */ |
|||
PK_NORMAL_PRESSURE = 0x0400, /* normal or tip pressure */ |
|||
PK_TANGENT_PRESSURE = 0x0800, /* tangential or barrel pressure */ |
|||
PK_ORIENTATION = 0x1000, /* orientation info: tilts */ |
|||
PK_PKTBITS_ALL = 0x1FFF // The Full Monty - all the bits execept Rotation - not supported
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Wintab event messsages sent to an application.
|
|||
/// See Wintab Spec 1.4 for a description of these messages.
|
|||
/// </summary>
|
|||
public enum EWintabEventMessage |
|||
{ |
|||
WT_PACKET = 0x7FF0, |
|||
WT_CTXOPEN = 0x7FF1, |
|||
WT_CTXCLOSE = 0x7FF2, |
|||
WT_CTXUPDATE = 0x7FF3, |
|||
WT_CTXOVERLAP = 0x7FF4, |
|||
WT_PROXIMITY = 0x7FF5, |
|||
WT_INFOCHANGE = 0x7FF6, |
|||
WT_CSRCHANGE = 0x7FF7, |
|||
WT_PACKETEXT = 0x7FF8 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Wintab packet status values.
|
|||
/// </summary>
|
|||
public enum EWintabPacketStatusValue |
|||
{ |
|||
/// <summary>
|
|||
/// Specifies that the cursor is out of the context.
|
|||
/// </summary>
|
|||
TPS_PROXIMITY = 0x0001, |
|||
|
|||
/// <summary>
|
|||
/// Specifies that the event queue for the context has overflowed.
|
|||
/// </summary>
|
|||
TPS_QUEUE_ERR = 0x0002, |
|||
|
|||
/// <summary>
|
|||
/// Specifies that the cursor is in the margin of the context.
|
|||
/// </summary>
|
|||
TPS_MARGIN = 0x0004, |
|||
|
|||
/// <summary>
|
|||
/// Specifies that the cursor is out of the context, but that the
|
|||
/// context has grabbed input while waiting for a button release event.
|
|||
/// </summary>
|
|||
TPS_GRAB = 0x0008, |
|||
|
|||
/// <summary>
|
|||
/// Specifies that the cursor is in its inverted state.
|
|||
/// </summary>
|
|||
TPS_INVERT = 0x0010 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// WintabPacket.pkButton codes.
|
|||
/// </summary>
|
|||
public enum EWintabPacketButtonCode |
|||
{ |
|||
/// <summary>
|
|||
/// No change in button state.
|
|||
/// </summary>
|
|||
TBN_NONE = 0, |
|||
|
|||
/// <summary>
|
|||
/// Button was released.
|
|||
/// </summary>
|
|||
TBN_UP = 1, |
|||
|
|||
/// <summary>
|
|||
/// Button was pressed.
|
|||
/// </summary>
|
|||
TBN_DOWN = 2 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Pen Orientation
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct WTOrientation |
|||
{ |
|||
/// <summary>
|
|||
/// Specifies the clockwise rotation of the cursor about the
|
|||
/// z axis through a full circular range.
|
|||
/// </summary>
|
|||
public Int32 orAzimuth; |
|||
|
|||
/// <summary>
|
|||
/// Specifies the angle with the x-y plane through a signed, semicircular range.
|
|||
/// Positive values specify an angle upward toward the positive z axis; negative
|
|||
/// values specify an angle downward toward the negative z axis.
|
|||
/// </summary>
|
|||
public Int32 orAltitude; |
|||
|
|||
/// <summary>
|
|||
/// Specifies the clockwise rotation of the cursor about its own major axis.
|
|||
/// </summary>
|
|||
public Int32 orTwist; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Pen Rotation
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct WTRotation |
|||
{ |
|||
/// <summary>
|
|||
/// Specifies the pitch of the cursor.
|
|||
/// </summary>
|
|||
public Int32 rotPitch; |
|||
|
|||
/// <summary>
|
|||
/// Specifies the roll of the cursor.
|
|||
/// </summary>
|
|||
public Int32 rotRoll; |
|||
|
|||
/// <summary>
|
|||
/// Specifies the yaw of the cursor.
|
|||
/// </summary>
|
|||
public Int32 rotYaw; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Wintab data packet. Contains the "Full Monty" for all possible data values.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct WintabPacket |
|||
{ |
|||
/// <summary>
|
|||
/// Specifies the context that generated the event.
|
|||
/// </summary>
|
|||
public HCTX pkContext; // PK_CONTEXT
|
|||
|
|||
/// <summary>
|
|||
/// Specifies various status and error conditions. These conditions can be
|
|||
/// combined by using the bitwise OR opera-tor. The pkStatus field can be any
|
|||
/// any combination of the values defined in EWintabPacketStatusValue.
|
|||
/// </summary>
|
|||
public UInt32 pkStatus; // PK_STATUS
|
|||
|
|||
/// <summary>
|
|||
/// In absolute mode, specifies the system time at which the event was posted. In
|
|||
/// relative mode, specifies the elapsed time in milliseconds since the last packet.
|
|||
/// </summary>
|
|||
public UInt32 pkTime; // PK_TIME
|
|||
|
|||
/// <summary>
|
|||
/// Specifies which of the included packet data items have changed since the
|
|||
/// previously posted event.
|
|||
/// </summary>
|
|||
public WTPKT pkChanged; // PK_CHANGED
|
|||
|
|||
/// <summary>
|
|||
/// This is an identifier assigned to the packet by the context. Consecutive
|
|||
/// packets will have consecutive serial numbers.
|
|||
/// </summary>
|
|||
public UInt32 pkSerialNumber; // PK_SERIAL_NUMBER
|
|||
|
|||
/// <summary>
|
|||
/// Specifies which cursor type generated the packet.
|
|||
/// </summary>
|
|||
public UInt32 pkCursor; // PK_CURSOR
|
|||
|
|||
/// <summary>
|
|||
/// In absolute mode, is a UInt32 containing the current button state.
|
|||
/// In relative mode, is a UInt32 whose low word contains a button number,
|
|||
/// and whose high word contains one of the codes in EWintabPacketButtonCode.
|
|||
/// </summary>
|
|||
public UInt32 pkButtons; // PK_BUTTONS
|
|||
|
|||
/// <summary>
|
|||
/// In absolute mode, each is a UInt32 containing the scaled cursor location
|
|||
/// along the X axis. In relative mode, this is an Int32 containing
|
|||
/// scaled change in cursor position.
|
|||
/// </summary>
|
|||
public Int32 pkX; // PK_X
|
|||
|
|||
/// <summary>
|
|||
/// In absolute mode, each is a UInt32 containing the scaled cursor location
|
|||
/// along the Y axis. In relative mode, this is an Int32 containing
|
|||
/// scaled change in cursor position.
|
|||
/// </summary>
|
|||
public Int32 pkY; // PK_Y
|
|||
|
|||
/// <summary>
|
|||
/// In absolute mode, each is a UInt32 containing the scaled cursor location
|
|||
/// along the Z axis. In relative mode, this is an Int32 containing
|
|||
/// scaled change in cursor position.
|
|||
/// </summary>
|
|||
public Int32 pkZ; // PK_Z
|
|||
|
|||
/// <summary>
|
|||
/// In absolute mode, this is a UINT containing the adjusted state
|
|||
/// of the normal pressure, respectively. In relative mode, this is
|
|||
/// an int containing the change in adjusted pressure state.
|
|||
/// </summary>
|
|||
public UInt32 pkNormalPressure; // PK_NORMAL_PRESSURE
|
|||
|
|||
/// <summary>
|
|||
/// In absolute mode, this is a UINT containing the adjusted state
|
|||
/// of the tangential pressure, respectively. In relative mode, this is
|
|||
/// an int containing the change in adjusted pressure state.
|
|||
/// </summary>
|
|||
public UInt32 pkTangentPressure; // PK_TANGENT_PRESSURE
|
|||
|
|||
/// <summary>
|
|||
/// Contains updated cursor orientation information. See the
|
|||
/// WTOrientation structure for details.
|
|||
/// </summary>
|
|||
public WTOrientation pkOrientation; // ORIENTATION
|
|||
|
|||
public static int ByteSize { get; } = Marshal.SizeOf<WintabPacket>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Common properties for control extension data transactions.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct WTExtensionBase |
|||
{ |
|||
/// <summary>
|
|||
/// Specifies the Wintab context to which these properties apply.
|
|||
/// </summary>
|
|||
public HCTX nContext; |
|||
|
|||
/// <summary>
|
|||
/// Status of setting/getting properties.
|
|||
/// </summary>
|
|||
public UInt32 nStatus; |
|||
|
|||
/// <summary>
|
|||
/// Timestamp applied to property transaction.
|
|||
/// </summary>
|
|||
public WTPKT nTime; |
|||
|
|||
/// <summary>
|
|||
/// Reserved - not used.
|
|||
/// </summary>
|
|||
public UInt32 nSerialNumber; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Extension data for one Express Key.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct WTExpKeyData |
|||
{ |
|||
/// <summary>
|
|||
/// Tablet index where control is found.
|
|||
/// </summary>
|
|||
public byte nTablet; |
|||
|
|||
/// <summary>
|
|||
/// Zero-based control index.
|
|||
/// </summary>
|
|||
public byte nControl; |
|||
|
|||
/// <summary>
|
|||
/// Zero-based index indicating side of tablet where control found (0 = left, 1 = right).
|
|||
/// </summary>
|
|||
public byte nLocation; |
|||
|
|||
/// <summary>
|
|||
/// Reserved - not used
|
|||
/// </summary>
|
|||
public byte nReserved; |
|||
|
|||
/// <summary>
|
|||
/// Indicates Express Key button press (1 = pressed, 0 = released)
|
|||
/// </summary>
|
|||
public WTPKT nState; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Extension data for one touch ring or one touch strip.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct WTSliderData |
|||
{ |
|||
/// <summary>
|
|||
/// Tablet index where control is found.
|
|||
/// </summary>
|
|||
public byte nTablet; |
|||
|
|||
/// <summary>
|
|||
/// Zero-based control index.
|
|||
/// </summary>
|
|||
public byte nControl; |
|||
|
|||
/// <summary>
|
|||
/// Zero-based current active mode of control.
|
|||
/// This is the mode selected by control's toggle button.
|
|||
/// </summary>
|
|||
public byte nMode; |
|||
|
|||
/// <summary>
|
|||
/// Reserved - not used
|
|||
/// </summary>
|
|||
public byte nReserved; |
|||
|
|||
/// <summary>
|
|||
/// An integer representing the position of the user's finger on the control.
|
|||
/// When there is no finger on the control, this value is negative.
|
|||
/// </summary>
|
|||
public WTPKT nPosition; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Wintab extension data packet for one tablet control.
|
|||
/// The tablet controls for which extension data is available are: Express Key, Touch Ring and Touch Strip controls.
|
|||
/// Note that tablets will have either Touch Rings or Touch Strips - not both.
|
|||
/// All tablets have Express Keys.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct WintabPacketExt |
|||
{ |
|||
/// <summary>
|
|||
/// Extension control properties common to all control types.
|
|||
/// </summary>
|
|||
public WTExtensionBase pkBase; |
|||
|
|||
/// <summary>
|
|||
/// Extension data for one Express Key.
|
|||
/// </summary>
|
|||
public WTExpKeyData pkExpKey; |
|||
|
|||
/// <summary>
|
|||
/// Extension data for one Touch Strip.
|
|||
/// </summary>
|
|||
public WTSliderData pkTouchStrip; |
|||
|
|||
/// <summary>
|
|||
/// Extension data for one Touch Ring.
|
|||
/// </summary>
|
|||
public WTSliderData pkTouchRing; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Class to support capture and management of Wintab daa.
|
|||
/// </summary>
|
|||
public class WintabData |
|||
{ |
|||
private WintabContext m_context; |
|||
|
|||
/// <summary>
|
|||
/// CWintabData constructor
|
|||
/// </summary>
|
|||
/// <param name="context_I">logical context for this data object</param>
|
|||
public WintabData(WintabContext context_I) |
|||
{ |
|||
m_context = context_I; |
|||
} |
|||
|
|||
/* |
|||
/// <summary>
|
|||
/// Removes the WTPacket handler so that messages are ignored.
|
|||
/// </summary>
|
|||
/// <param name="handler_I">WT_PACKET event handler supplied by the client.</param>
|
|||
public void RemoveWTPacketEventHandler(EventHandler<MessageReceivedEventArgs> handler_I) |
|||
{ |
|||
try |
|||
{ |
|||
MessageEvents.UnWatchMessage(EWintabEventMessage.WT_PACKET); |
|||
MessageEvents.UnWatchMessage(EWintabEventMessage.WT_PACKETEXT); |
|||
MessageEvents.UnWatchMessage(EWintabEventMessage.WT_CSRCHANGE); |
|||
MessageEvents.PacketMessageReceived -= handler_I; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED CWintabData.RemoveWTPacketEventHandler: " + ex.ToString()); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set the handler to be called when WT_CTX* messages are received.
|
|||
/// </summary>
|
|||
/// <param name="handler_I">WT_CTX* event handler supplied by the client.</param>
|
|||
public void SetStatusEventHandler(EventHandler<MessageReceivedEventArgs> handler_I) |
|||
{ |
|||
try |
|||
{ |
|||
MessageEvents.StatusMessageReceived += handler_I; |
|||
MessageEvents.WatchMessage(EWintabEventMessage.WT_CTXOPEN); |
|||
MessageEvents.WatchMessage(EWintabEventMessage.WT_CTXCLOSE); |
|||
MessageEvents.WatchMessage(EWintabEventMessage.WT_CTXUPDATE); |
|||
MessageEvents.WatchMessage(EWintabEventMessage.WT_CTXOVERLAP); |
|||
MessageEvents.WatchMessage(EWintabEventMessage.WT_PROXIMITY); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED CWintabData.SetStatusEventHandler: " + ex.ToString()); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the WT_CTX* handler so that messages are ignored.
|
|||
/// </summary>
|
|||
/// <param name="handler_I"> WT_CTX* event handler supplied by the client.</param>
|
|||
public void RemoveStatusEventHandler(EventHandler<MessageReceivedEventArgs> handler_I) |
|||
{ |
|||
try |
|||
{ |
|||
MessageEvents.UnWatchMessage(EWintabEventMessage.WT_CTXOPEN); |
|||
MessageEvents.UnWatchMessage(EWintabEventMessage.WT_CTXCLOSE); |
|||
MessageEvents.UnWatchMessage(EWintabEventMessage.WT_CTXUPDATE); |
|||
MessageEvents.UnWatchMessage(EWintabEventMessage.WT_CTXOVERLAP); |
|||
MessageEvents.UnWatchMessage(EWintabEventMessage.WT_PROXIMITY); |
|||
MessageEvents.StatusMessageReceived -= handler_I; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED CWintabData.RemoveStatusEventHandler: " + ex.ToString()); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Set the handler to be called when WT_INFOCHANGE messages are received.
|
|||
/// </summary>
|
|||
/// <param name="handler_I">WT_INFOCHANGE event handler supplied by the client.</param>
|
|||
public void SetInfoChangeEventHandler(EventHandler<MessageReceivedEventArgs> handler_I) |
|||
{ |
|||
try |
|||
{ |
|||
MessageEvents.InfoChgMessageReceived += handler_I; |
|||
MessageEvents.WatchMessage(EWintabEventMessage.WT_INFOCHANGE); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED CWintabData.SetWTInfoChangeEventHandler: " + ex.ToString()); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the WT_INFOCHANGE handler so that messages are ignored.
|
|||
/// </summary>
|
|||
/// <param name="handler_I">WT_INFOCHANGE event handler supplied by the client.</param>
|
|||
public void RemoveInfoChangeEventHandler(EventHandler<MessageReceivedEventArgs> handler_I) |
|||
{ |
|||
try |
|||
{ |
|||
MessageEvents.UnWatchMessage(EWintabEventMessage.WT_INFOCHANGE); |
|||
MessageEvents.InfoChgMessageReceived -= handler_I; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED CWintabData.RemoveWTInfoChangeEventHandler: " + ex.ToString()); |
|||
} |
|||
} |
|||
*/ |
|||
|
|||
/// <summary>
|
|||
/// Set packet queue size for this data object's context.
|
|||
/// </summary>
|
|||
/// <param name="numPkts_I">desired #packets in queue</param>
|
|||
/// <returns>Returns true if operation successful</returns>
|
|||
public bool SetPacketQueueSize(UInt32 numPkts_I) |
|||
{ |
|||
bool status = false; |
|||
|
|||
|
|||
CheckForValidHCTX("SetPacketQueueSize"); |
|||
status = WintabFuncs.WTQueueSizeSet(m_context.HCtx, numPkts_I); |
|||
|
|||
return status; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Get packet queue size for this data object's context.
|
|||
/// </summary>
|
|||
/// <returns>Returns a packet queue size in #packets or 0 if fails</returns>
|
|||
public UInt32 GetPacketQueueSize() |
|||
{ |
|||
UInt32 numPkts = 0; |
|||
|
|||
CheckForValidHCTX("GetPacketQueueSize"); |
|||
numPkts = WintabFuncs.WTQueueSizeGet(m_context.HCtx); |
|||
|
|||
return numPkts; |
|||
} |
|||
|
|||
public void BringToFront() |
|||
{ |
|||
CheckForValidHCTX("BringToFront"); |
|||
WintabFuncs.WTOverlap(m_context.HCtx, true); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns one packet of WintabPacketExt data from the packet queue.
|
|||
/// </summary>
|
|||
/// <param name="hCtx">Wintab context to be used when asking for the data</param>
|
|||
/// <param name="pktID_I">Identifier for the tablet event packet to return.</param>
|
|||
/// <returns>Returns a data packet with non-null context if successful.</returns>
|
|||
public WintabPacketExt GetDataPacketExt(IntPtr hCtx, UInt32 pktID_I) |
|||
{ |
|||
int size = (int)(Marshal.SizeOf(new WintabPacketExt())); |
|||
IntPtr buf = Marshal.AllocHGlobal(size); |
|||
WintabPacketExt[] packets = []; |
|||
|
|||
bool status = false; |
|||
|
|||
if (pktID_I == 0) |
|||
{ |
|||
throw new Exception("GetDataPacket - invalid pktID"); |
|||
} |
|||
|
|||
CheckForValidHCTX("GetDataPacket"); |
|||
status = WintabFuncs.WTPacket(hCtx, pktID_I, buf); |
|||
|
|||
if (status) |
|||
{ |
|||
packets = WintabMemUtils.MarshalDataExtPackets(1, buf); |
|||
} |
|||
else |
|||
{ |
|||
// If fails, make sure context is zero.
|
|||
packets[0].pkBase.nContext = new HCTX(IntPtr.Zero); |
|||
} |
|||
|
|||
Marshal.FreeHGlobal(buf); |
|||
|
|||
return packets[0]; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns one packet of WintabPacket data from the packet queue. (Deprecated)
|
|||
/// </summary>
|
|||
/// <param name="pktID_I">Identifier for the tablet event packet to return.</param>
|
|||
/// <returns>Returns a data packet with non-null context if successful.</returns>
|
|||
public WintabPacket GetDataPacket(UInt32 pktID_I) |
|||
{ |
|||
return GetDataPacket(m_context.HCtx, pktID_I); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns one packet of Wintab data from the packet queue.
|
|||
/// </summary>
|
|||
/// <param name="hCtx">Wintab context to be used when asking for the data</param>
|
|||
/// <param name="pktID_I">Identifier for the tablet event packet to return.</param>
|
|||
/// <returns>Returns a data packet with non-null context if successful.</returns>
|
|||
public WintabPacket GetDataPacket(IntPtr hCtx, UInt32 pktID_I) |
|||
{ |
|||
IntPtr buf = Marshal.AllocHGlobal(Marshal.SizeOf<WintabPacket>()); |
|||
WintabPacket packet = new WintabPacket(); |
|||
|
|||
if (pktID_I == 0) |
|||
{ |
|||
throw new Exception("GetDataPacket - invalid pktID"); |
|||
} |
|||
|
|||
CheckForValidHCTX("GetDataPacket"); |
|||
|
|||
if (WintabFuncs.WTPacket(hCtx, pktID_I, buf)) |
|||
{ |
|||
packet = Marshal.PtrToStructure<WintabPacket>(buf); |
|||
} |
|||
else |
|||
{ |
|||
//
|
|||
// If fails, make sure context is zero.
|
|||
//
|
|||
packet.pkContext = new HCTX(IntPtr.Zero); |
|||
} |
|||
|
|||
Marshal.FreeHGlobal(buf); |
|||
|
|||
return packet; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes all pending data packets from the context's queue.
|
|||
/// </summary>
|
|||
public void FlushDataPackets(uint numPacketsToFlush_I) |
|||
{ |
|||
CheckForValidHCTX("FlushDataPackets"); |
|||
WintabFuncs.WTPacketsGet(m_context.HCtx, numPacketsToFlush_I, IntPtr.Zero); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an array of Wintab data packets from the packet queue.
|
|||
/// </summary>
|
|||
/// <param name="maxPkts_I">Specifies the maximum number of packets to return.</param>
|
|||
/// <param name="remove_I">If true, returns data packets and removes them from the queue.</param>
|
|||
/// <param name="numPkts_O">Number of packets actually returned.</param>
|
|||
/// <returns>Returns the next maxPkts_I from the list. Note that if remove_I is false, then
|
|||
/// repeated calls will return the same packets. If remove_I is true, then packets will be
|
|||
/// removed and subsequent calls will get different packets (if any).</returns>
|
|||
public WintabPacket[] GetDataPackets(UInt32 maxPkts_I, bool remove_I, ref UInt32 numPkts_O) |
|||
{ |
|||
WintabPacket[] packets = []; |
|||
|
|||
CheckForValidHCTX("GetDataPackets"); |
|||
|
|||
if (maxPkts_I == 0) |
|||
{ |
|||
throw new Exception("GetDataPackets - maxPkts_I is zero."); |
|||
} |
|||
|
|||
// Packet array is used whether we're just looking or buying.
|
|||
int size = (int)(maxPkts_I * Marshal.SizeOf(new WintabPacket())); |
|||
IntPtr buf = Marshal.AllocHGlobal(size); |
|||
|
|||
try |
|||
{ |
|||
if (remove_I) |
|||
{ |
|||
// Return data packets and remove packets from queue.
|
|||
numPkts_O = WintabFuncs.WTPacketsGet(m_context.HCtx, maxPkts_I, buf); |
|||
|
|||
if (numPkts_O > 0) |
|||
{ |
|||
packets = WintabMemUtils.MarshalDataPackets(numPkts_O, buf); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// Return data packets, but leave on queue. (Peek mode)
|
|||
UInt32 pktIDOldest = 0; |
|||
UInt32 pktIDNewest = 0; |
|||
|
|||
// Get oldest and newest packet identifiers in the queue. These will bound the
|
|||
// packets that are actually returned.
|
|||
if (WintabFuncs.WTQueuePacketsEx(m_context.HCtx, ref pktIDOldest, ref pktIDNewest)) |
|||
{ |
|||
UInt32 pktIDStart = pktIDOldest; |
|||
UInt32 pktIDEnd = pktIDNewest; |
|||
|
|||
if (pktIDStart == 0) |
|||
{ |
|||
throw new Exception("WTQueuePacketsEx reports zero start packet identifier"); |
|||
} |
|||
|
|||
if (pktIDEnd == 0) |
|||
{ |
|||
throw new Exception("WTQueuePacketsEx reports zero end packet identifier"); |
|||
} |
|||
|
|||
// Peek up to the max number of packets specified.
|
|||
UInt32 numFoundPkts = WintabFuncs.WTDataPeek(m_context.HCtx, pktIDStart, pktIDEnd, maxPkts_I, |
|||
buf, |
|||
ref numPkts_O); |
|||
|
|||
if (numFoundPkts > 0 && numFoundPkts < numPkts_O) |
|||
{ |
|||
throw new Exception( |
|||
"WTDataPeek reports more packets returned than actually exist in queue."); |
|||
} |
|||
|
|||
packets = WintabMemUtils.MarshalDataPackets(numPkts_O, buf); |
|||
} |
|||
} |
|||
} |
|||
finally |
|||
{ |
|||
Marshal.FreeHGlobal(buf); |
|||
} |
|||
|
|||
return packets; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Throws exception if logical context for this data object is zero.
|
|||
/// </summary>
|
|||
private void CheckForValidHCTX(string msg) |
|||
{ |
|||
if (m_context.HCtx == 0) |
|||
{ |
|||
throw new Exception(msg + " - Bad Context"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,484 @@ |
|||
///////////////////////////////////////////////////////////////////////////////
|
|||
//
|
|||
// PURPOSE
|
|||
// Wintab32 function wrappers for WintabDN
|
|||
//
|
|||
// COPYRIGHT
|
|||
// Copyright (c) 2010-2020 Wacom Co., Ltd.
|
|||
//
|
|||
// The text and information contained in this file may be freely used,
|
|||
// copied, or distributed without compensation or licensing restrictions.
|
|||
//
|
|||
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace Avalonia.Win32.WintabImpl |
|||
{ |
|||
using P_HCTX = System.IntPtr; |
|||
using P_HWND = System.IntPtr; |
|||
|
|||
//Implementation note: cannot use statement such as:
|
|||
// using WTPKT = UInt32;
|
|||
// because the scope of the statement is this file only.
|
|||
// Thus we need to implement the 'typedef' using a class that
|
|||
// implicitly defines the type. Also remember to make it
|
|||
// sequential so it won't make marshalling barf.
|
|||
|
|||
/// <summary>
|
|||
/// Managed implementation of Wintab HWND typedef.
|
|||
/// Holds native Window handle.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public struct HWND |
|||
{ |
|||
[MarshalAs(UnmanagedType.I4)] public IntPtr value; |
|||
|
|||
public HWND(IntPtr value) |
|||
{ |
|||
this.value = value; |
|||
} |
|||
|
|||
public static implicit operator IntPtr(HWND hwnd_I) |
|||
{ |
|||
return hwnd_I.value; |
|||
} |
|||
|
|||
public static implicit operator HWND(IntPtr ptr_I) |
|||
{ |
|||
return new HWND(ptr_I); |
|||
} |
|||
|
|||
public static bool operator ==(HWND hwnd1, HWND hwnd2) |
|||
{ |
|||
return hwnd1.value == hwnd2.value; |
|||
} |
|||
|
|||
public static bool operator !=(HWND hwnd1, HWND hwnd2) |
|||
{ |
|||
return hwnd1.value != hwnd2.value; |
|||
} |
|||
|
|||
public override bool Equals(object? obj) |
|||
{ |
|||
if (obj == null || obj.GetType() != typeof(HWND)) |
|||
return false; |
|||
|
|||
return (HWND)obj == this; |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Managed implementation of Wintab WTPKT typedef.
|
|||
/// Holds Wintab packet identifier.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public class WTPKT |
|||
{ |
|||
[MarshalAs(UnmanagedType.U4)] UInt32 value; |
|||
|
|||
public WTPKT(UInt32 value) |
|||
{ |
|||
this.value = value; |
|||
} |
|||
|
|||
public static implicit operator UInt32(WTPKT pkt_I) |
|||
{ |
|||
return pkt_I.value; |
|||
} |
|||
|
|||
public static implicit operator WTPKT(UInt32 value) |
|||
{ |
|||
return new WTPKT(value); |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return value.ToString(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Managed implementation of Wintab FIX32 typedef.
|
|||
/// Used for a fixed-point arithmetic value.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] |
|||
public class FIX32 |
|||
{ |
|||
[MarshalAs(UnmanagedType.U4)] UInt32 value; |
|||
|
|||
public FIX32(UInt32 value) |
|||
{ |
|||
this.value = value; |
|||
} |
|||
|
|||
public static implicit operator UInt32(FIX32 fix32_I) |
|||
{ |
|||
return fix32_I.value; |
|||
} |
|||
|
|||
public static implicit operator FIX32(UInt32 value) |
|||
{ |
|||
return new FIX32(value); |
|||
} |
|||
|
|||
public double FixToDouble() |
|||
{ |
|||
uint x = this; |
|||
ushort integerPart = (ushort)(x >> 16); |
|||
|
|||
ushort fractionalPart = (ushort)(x & 0xFFFF); |
|||
|
|||
return integerPart + (fractionalPart / 65536.0); |
|||
} |
|||
|
|||
public static double Frac(double x) |
|||
{ |
|||
return x - Math.Floor(x); |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return value.ToString(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Managed implementation of Wintab HCTX typedef.
|
|||
/// Holds a Wintab context identifier.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public readonly struct HCTX : IEquatable<HCTX> |
|||
{ |
|||
public readonly IntPtr Value; |
|||
|
|||
public HCTX(IntPtr value) |
|||
{ |
|||
Value = value; |
|||
} |
|||
|
|||
public bool Equals(HCTX other) => Value == other.Value; |
|||
public override bool Equals(object? obj) => obj is HCTX other && Equals(other); |
|||
public override int GetHashCode() => Value.GetHashCode(); |
|||
|
|||
public static bool operator ==(HCTX a, HCTX b) => a.Value == b.Value; |
|||
public static bool operator !=(HCTX a, HCTX b) => a.Value != b.Value; |
|||
|
|||
public static implicit operator IntPtr(HCTX hctx_I) |
|||
{ |
|||
return hctx_I.Value; |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return Value.ToString(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Index values for WTInfo wCategory parameter.
|
|||
/// </summary>
|
|||
public enum EWTICategoryIndex |
|||
{ |
|||
WTI_INTERFACE = 1, |
|||
WTI_STATUS = 2, |
|||
WTI_DEFCONTEXT = 3, |
|||
WTI_DEFSYSCTX = 4, |
|||
WTI_DEVICES = 100, |
|||
WTI_CURSORS = 200, |
|||
WTI_EXTENSIONS = 300, |
|||
WTI_DDCTXS = 400, |
|||
WTI_DSCTXS = 500 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Index values for WTI_INTERFACE.
|
|||
/// </summary>
|
|||
public enum EWTIInterfaceIndex |
|||
{ |
|||
IFC_WINTABID = 1, |
|||
IFC_SPECVERSION = 2, |
|||
IFC_IMPLVERSION = 3, |
|||
IFC_NDEVICES = 4, |
|||
IFC_NCURSORS = 5, |
|||
IFC_NCONTEXTS = 6, |
|||
IFC_CTXOPTIONS = 7, |
|||
IFC_CTXSAVESIZE = 8, |
|||
IFC_NEXTENSIONS = 9, |
|||
IFC_NMANAGERS = 10 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Index values for WTI_DEVICES
|
|||
/// </summary>
|
|||
public enum EWTIDevicesIndex |
|||
{ |
|||
DVC_NAME = 1, |
|||
DVC_HARDWARE = 2, |
|||
DVC_NCSRTYPES = 3, |
|||
DVC_FIRSTCSR = 4, |
|||
DVC_PKTRATE = 5, |
|||
DVC_PKTDATA = 6, |
|||
DVC_PKTMODE = 7, |
|||
DVC_CSRDATA = 8, |
|||
DVC_XMARGIN = 9, |
|||
DVC_YMARGIN = 10, |
|||
DVC_ZMARGIN = 11, |
|||
DVC_X = 12, |
|||
DVC_Y = 13, |
|||
DVC_Z = 14, |
|||
DVC_NPRESSURE = 15, |
|||
DVC_TPRESSURE = 16, |
|||
DVC_ORIENTATION = 17, |
|||
DVC_ROTATION = 18, |
|||
DVC_PNPID = 19 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Index values for WTI_CURSORS.
|
|||
/// </summary>
|
|||
public enum EWTICursorsIndex |
|||
{ |
|||
CSR_NAME = 1, |
|||
CSR_ACTIVE = 2, |
|||
CSR_PKTDATA = 3, |
|||
CSR_BUTTONS = 4, |
|||
CSR_BUTTONBITS = 5, |
|||
CSR_BTNNAMES = 6, |
|||
CSR_BUTTONMAP = 7, |
|||
CSR_SYSBTNMAP = 8, |
|||
CSR_NPBUTTON = 9, |
|||
CSR_NPBTNMARKS = 10, |
|||
CSR_NPRESPONSE = 11, |
|||
CSR_TPBUTTON = 12, |
|||
CSR_TPBTNMARKS = 13, |
|||
CSR_TPRESPONSE = 14, |
|||
CSR_PHYSID = 15, |
|||
CSR_MODE = 16, |
|||
CSR_MINPKTDATA = 17, |
|||
CSR_MINBUTTONS = 18, |
|||
CSR_CAPABILITIES = 19, |
|||
CSR_TYPE = 20 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Index used with CSR_NAME to get stylus types.
|
|||
/// </summary>
|
|||
public enum EWTICursorNameIndex |
|||
{ |
|||
CSR_NAME_PUCK = EWTICategoryIndex.WTI_CURSORS + 0, |
|||
CSR_NAME_PRESSURE_STYLUS = EWTICategoryIndex.WTI_CURSORS + 1, |
|||
CSR_NAME_ERASER = EWTICategoryIndex.WTI_CURSORS + 2 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Index values for WTI contexts.
|
|||
/// </summary>
|
|||
public enum EWTIContextIndex |
|||
{ |
|||
CTX_NAME = 1, |
|||
CTX_OPTIONS = 2, |
|||
CTX_STATUS = 3, |
|||
CTX_LOCKS = 4, |
|||
CTX_MSGBASE = 5, |
|||
CTX_DEVICE = 6, |
|||
CTX_PKTRATE = 7, |
|||
CTX_PKTDATA = 8, |
|||
CTX_PKTMODE = 9, |
|||
CTX_MOVEMASK = 10, |
|||
CTX_BTNDNMASK = 11, |
|||
CTX_BTNUPMASK = 12, |
|||
CTX_INORGX = 13, |
|||
CTX_INORGY = 14, |
|||
CTX_INORGZ = 15, |
|||
CTX_INEXTX = 16, |
|||
CTX_INEXTY = 17, |
|||
CTX_INEXTZ = 18, |
|||
CTX_OUTORGX = 19, |
|||
CTX_OUTORGY = 20, |
|||
CTX_OUTORGZ = 21, |
|||
CTX_OUTEXTX = 22, |
|||
CTX_OUTEXTY = 23, |
|||
CTX_OUTEXTZ = 24, |
|||
CTX_SENSX = 25, |
|||
CTX_SENSY = 26, |
|||
CTX_SENSZ = 27, |
|||
CTX_SYSMODE = 28, |
|||
CTX_SYSORGX = 29, |
|||
CTX_SYSORGY = 30, |
|||
CTX_SYSEXTX = 31, |
|||
CTX_SYSEXTY = 32, |
|||
CTX_SYSSENSX = 33, |
|||
CTX_SYSSENSY = 34 |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// P/Invoke wrappers for Wintab functions.
|
|||
/// See Wintab_v140.doc (Wintab 1.4 spec) and related Wintab documentation for details.
|
|||
/// </summary>
|
|||
public class WintabFuncs |
|||
{ |
|||
/// <summary>
|
|||
/// This function returns global information about the interface in an application-supplied buffer.
|
|||
/// Different types of information are specified by different index arguments. Applications use this
|
|||
/// function to receive information about tablet coordinates, physical dimensions, capabilities, and
|
|||
/// cursor types.
|
|||
/// </summary>
|
|||
/// <param name="wCategory_I">Identifies the category from which information is being requested.</param>
|
|||
/// <param name="nIndex_I">Identifies which information is being requested from within the category.</param>
|
|||
/// <param name="lpOutput_O">Points to a buffer to hold the requested information.</param>
|
|||
/// <returns>The return value specifies the size of the returned information in bytes. If the information
|
|||
/// is not supported, the function returns zero. If a tablet is not physically present, this function
|
|||
/// always returns zero.
|
|||
/// </returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern UInt32 WTInfoA(UInt32 wCategory_I, UInt32 nIndex_I, IntPtr lpOutput_O); |
|||
|
|||
/// <summary>
|
|||
/// This function establishes an active context on the tablet. On successful completion of this function,
|
|||
/// the application may begin receiving tablet events via messages (if they were requested), and may use
|
|||
/// the handle returned to poll the context, or to perform other context-related functions.
|
|||
/// </summary>
|
|||
/// <param name="hWnd_I">Identifies the window that owns the tablet context, and receives messages from the context.</param>
|
|||
/// <param name="logContext_I">Points to an application-provided WintabLogContext data structure describing the context to be opened.</param>
|
|||
/// <param name="enable_I">Specifies whether the new context will immediately begin processing input data.</param>
|
|||
/// <returns>The return value identifies the new context. It is NULL if the context is not opened.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern P_HCTX WTOpenA(P_HWND hWnd_I, ref WintabLogContext logContext_I, bool enable_I); |
|||
|
|||
/// <summary>
|
|||
/// This function closes and destroys the tablet context object.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context to be closed.</param>
|
|||
/// <returns>The function returns a non-zero value if the context was valid and was destroyed. Otherwise, it returns zero.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern bool WTClose(P_HCTX hctx_I); |
|||
|
|||
/// <summary>
|
|||
/// This function enables or disables a tablet context, temporarily turning on or off the processing of packets.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context to be enabled or disabled.</param>
|
|||
/// <param name="enable_I">Specifies enabling if non-zero, disabling if zero.</param>
|
|||
/// <returns>The function returns true if the enable or disable request was satisfied.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern bool WTEnable(P_HCTX hctx_I, bool enable_I); |
|||
|
|||
/// <summary>
|
|||
/// This function sends a tablet context to the top or bottom of the order of overlapping tablet contexts.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context to move within the overlap order.</param>
|
|||
/// <param name="toTop_I">Specifies sending the context to the top of the overlap order true, or to the bottom if false.</param>
|
|||
/// <returns>The function returns true if successful.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern bool WTOverlap(P_HCTX hctx_I, bool toTop_I); |
|||
|
|||
/// <summary>
|
|||
/// This function returns the number of packets the context's queue can hold.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context whose queue size is being returned.</param>
|
|||
/// <returns>The number of packets the queue can hold.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern UInt32 WTQueueSizeGet(P_HCTX hctx_I); |
|||
|
|||
/// <summary>
|
|||
/// This function attempts to change the context's queue size to the value specified in nPkts_I.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context whose queue size is being set.</param>
|
|||
/// <param name="nPkts_I">Specifies the requested queue size.</param>
|
|||
/// <returns>The return value is true if the queue size was successfully changed.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern bool WTQueueSizeSet(P_HCTX hctx_I, UInt32 nPkts_I); |
|||
|
|||
/// <summary>
|
|||
/// This function fills in the passed pktBuf_O buffer with the context event packet having
|
|||
/// the specified serial number. The returned packet and any older packets are removed from
|
|||
/// the context's internal queue.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context whose packets are being returned.</param>
|
|||
/// <param name="pktSerialNum_I">Serial number of the tablet event to return.</param>
|
|||
/// <param name="pktBuf_O">Buffer to receive the event packet.</param>
|
|||
/// <returns>The return value is true if the specified packet was found and returned.
|
|||
/// It is false if the specified packet was not found in the queue.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern bool WTPacket(P_HCTX hctx_I, UInt32 pktSerialNum_I, IntPtr pktBuf_O); |
|||
|
|||
/// <summary>
|
|||
/// This function copies the next maxPkts_I events from the packet queue of context hCtx to
|
|||
/// the passed pktBuf_O buffer and removes them from the queue
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context whose packets are being returned.</param>
|
|||
/// <param name="maxPkts_I">Specifies the maximum number of packets to return</param>
|
|||
/// <param name="pktBuf_O">Buffer to receive the event packets.</param>
|
|||
/// <returns>The return value is the number of packets copied in the buffer.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern UInt32 WTPacketsGet(P_HCTX hctx_I, UInt32 maxPkts_I, IntPtr pktBuf_O); |
|||
|
|||
/// <summary>A
|
|||
/// This function copies all packets with Identifiers between pktIDStart_I and pktIDEnd_I
|
|||
/// inclusive from the context's queue to the passed buffer and removes them from the queue.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context whose packets are being returned.</param>
|
|||
/// <param name="pktIDStart_I">Identifier of the oldest tablet event to return.</param>
|
|||
/// <param name="pktIDEnd_I">Identifier of the newest tablet event to return.</param>
|
|||
/// <param name="maxPkts_I">Specifies the maximum number of packets to return.</param>
|
|||
/// <param name="pktBuf_O">Buffer to receive the event packets.</param>
|
|||
/// <param name="numPkts_O">Number of packets actually copied.</param>
|
|||
/// <returns>The return value is the total number of packets found in the queue
|
|||
/// between pktIDStart_I and pktIDEnd_I.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern UInt32 WTDataGet(P_HCTX hctx_I, UInt32 pktIDStart_I, UInt32 pktIDEnd_I, |
|||
UInt32 maxPkts_I, IntPtr pktBuf_O, ref UInt32 numPkts_O); |
|||
|
|||
/// <summary>
|
|||
/// This function copies all packets with serial numbers between pktIDStart_I and pktIDEnd_I
|
|||
/// inclusive, from the context's queue to the passed buffer without removing them from the queue.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context whose packets are being read.</param>
|
|||
/// <param name="pktIDStart_I">Identifier of the oldest tablet event to return.</param>
|
|||
/// <param name="pktIDEnd_I">Identifier of the newest tablet event to return.</param>
|
|||
/// <param name="maxPkts_I">Specifies the maximum number of packets to return.</param>
|
|||
/// <param name="pktBuf_O">Buffer to receive the event packets.</param>
|
|||
/// <param name="numPkts_O">Number of packets actually copied.</param>
|
|||
/// <returns>The return value is the total number of packets found in the queue between
|
|||
/// pktIDStart_I and pktIDEnd_I.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern UInt32 WTDataPeek(P_HCTX hctx_I, UInt32 pktIDStart_I, UInt32 pktIDEnd_I, |
|||
UInt32 maxPkts_I, IntPtr pktBuf_O, ref UInt32 numPkts_O); |
|||
|
|||
/// <summary>
|
|||
/// This function returns the identifiers of the oldest and newest packets currently in the queue.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context whose queue is being queried.</param>
|
|||
/// <param name="pktIDOldest_O">Identifier of the oldest packet in the queue.</param>
|
|||
/// <param name="pktIDNewest_O">Identifier of the newest packet in the queue.</param>
|
|||
/// <returns>This function returns bool if successful.</returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern bool WTQueuePacketsEx(P_HCTX hctx_I, ref UInt32 pktIDOldest_O, ref UInt32 pktIDNewest_O); |
|||
|
|||
/// <summary>
|
|||
/// This function retrieves any context-specific data for an extension.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context whose extension attributes are being retrieved.</param>
|
|||
/// <param name="extTag_I">Identifies the extension tag for which context-specific data is being retrieved.</param>
|
|||
/// <param name="extData_O">Points to a buffer to hold retrieved data (WTExtensionProperty).</param>
|
|||
/// <returns></returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern bool WTExtGet(P_HCTX hctx_I, UInt32 extTag_I, IntPtr extData_O); |
|||
|
|||
/// <summary>
|
|||
/// This function sets any context-specific data for an extension.
|
|||
/// </summary>
|
|||
/// <param name="hctx_I">Identifies the context whose extension attributes are being modified.</param>
|
|||
/// <param name="extTag_I">Identifies the extension tag for which context-specific data is being modified.</param>
|
|||
/// <param name="extData_I">Points to the new data (WTExtensionProperty).</param>
|
|||
/// <returns></returns>
|
|||
[DllImport("Wintab32.dll", CharSet = CharSet.Auto)] |
|||
public static extern bool WTExtSet(P_HCTX hctx_I, UInt32 extTag_I, IntPtr extData_I); |
|||
} |
|||
} |
|||
@ -0,0 +1,512 @@ |
|||
///////////////////////////////////////////////////////////////////////////////
|
|||
//
|
|||
// PURPOSE
|
|||
// Wintab information access for WintabDN
|
|||
//
|
|||
// COPYRIGHT
|
|||
// Copyright (c) 2010-2020 Wacom Co., Ltd.
|
|||
//
|
|||
// The text and information contained in this file may be freely used,
|
|||
// copied, or distributed without compensation or licensing restrictions.
|
|||
//
|
|||
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace Avalonia.Win32.WintabImpl |
|||
{ |
|||
/// <summary>
|
|||
/// Class to access Wintab interface data.
|
|||
/// </summary>
|
|||
public class WintabInfo |
|||
{ |
|||
public const Int32 MAX_STRING_SIZE = 256; |
|||
public const Int32 MAX_NUM_ATTACHED_TABLETS = 16; |
|||
public const Int32 MAX_NUM_CURSORS = 6; |
|||
|
|||
/// <summary>
|
|||
/// Returns TRUE if Wintab service is running and responsive.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public static bool IsWintabAvailable() |
|||
{ |
|||
try |
|||
{ |
|||
IntPtr buf = IntPtr.Zero; |
|||
|
|||
var status = (WintabFuncs.WTInfoA(0, 0, buf) > 0); |
|||
|
|||
return status; |
|||
} |
|||
catch |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Return max normal pressure supported by tablet.
|
|||
/// </summary>
|
|||
/// <param name="getNormalPressure_I">TRUE=> normal pressure;
|
|||
/// FALSE=> tangential pressure (not supported on all tablets)</param>
|
|||
/// <returns>maximum pressure value or zero on error</returns>
|
|||
public static Int32 GetMaxPressure(bool getNormalPressure_I = true) |
|||
{ |
|||
WintabAxis pressureAxis = new WintabAxis(); |
|||
int numBytes = Marshal.SizeOf(pressureAxis); |
|||
IntPtr buf = Marshal.AllocHGlobal(numBytes); |
|||
|
|||
EWTIDevicesIndex devIdx = (getNormalPressure_I ? |
|||
EWTIDevicesIndex.DVC_NPRESSURE : |
|||
EWTIDevicesIndex.DVC_TPRESSURE); |
|||
|
|||
int size = (int)WintabFuncs.WTInfoA( |
|||
(uint)EWTICategoryIndex.WTI_DEVICES, |
|||
(uint)devIdx, buf); |
|||
|
|||
pressureAxis = Marshal.PtrToStructure<WintabAxis>(buf); |
|||
|
|||
Marshal.FreeHGlobal(buf); |
|||
|
|||
return pressureAxis.axMax; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a 3-element array describing the tablet's orientation range and resolution capabilities.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public static WintabAxisArray GetDeviceOrientation(out bool tiltSupported_O) |
|||
{ |
|||
WintabAxisArray axisArray = new WintabAxisArray(); |
|||
tiltSupported_O = false; |
|||
IntPtr buf = Marshal.AllocHGlobal(Marshal.SizeOf(axisArray)); |
|||
|
|||
int size = (int)WintabFuncs.WTInfoA( |
|||
(uint)EWTICategoryIndex.WTI_DEVICES, |
|||
(uint)EWTIDevicesIndex.DVC_ORIENTATION, buf); |
|||
|
|||
// If size == 0, then returns a zeroed struct.
|
|||
axisArray = Marshal.PtrToStructure<WintabAxisArray>(buf); |
|||
tiltSupported_O = (axisArray.array[0].axResolution != 0 && axisArray.array[1].axResolution != 0); |
|||
|
|||
Marshal.FreeHGlobal(buf); |
|||
|
|||
return axisArray; |
|||
} |
|||
|
|||
/*/// <summary>
|
|||
/// Returns a string containing device name.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public static string GetDeviceInfo() |
|||
{ |
|||
string devInfo = null; |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(MAX_STRING_SIZE); |
|||
|
|||
try |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA( |
|||
(uint)EWTICategoryIndex.WTI_DEVICES, |
|||
(uint)EWTIDevicesIndex.DVC_NAME, buf); |
|||
|
|||
if (size < 1) |
|||
{ |
|||
throw new Exception("GetDeviceInfo returned empty string."); |
|||
} |
|||
|
|||
// Strip off final null character before marshalling.
|
|||
devInfo = CMemUtils.MarshalUnmanagedString(buf, size - 1); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetDeviceInfo: " + ex.ToString()); |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
return devInfo; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the default digitizing context, with useful context overrides.
|
|||
/// </summary>
|
|||
/// <param name="options_I">caller's options; OR'd into context options</param>
|
|||
/// <returns>A valid context object or null on error.</returns>
|
|||
public static CWintabContext GetDefaultDigitizingContext(ECTXOptionValues options_I = 0) |
|||
{ |
|||
// Send all possible data bits (not including extended data).
|
|||
// This is redundant with CWintabContext initialization, which
|
|||
// also inits with PK_PKTBITS_ALL.
|
|||
uint PACKETDATA = (uint)EWintabPacketBit.PK_PKTBITS_ALL; // The Full Monty
|
|||
uint PACKETMODE = (uint)EWintabPacketBit.PK_BUTTONS; |
|||
|
|||
CWintabContext context = GetDefaultContext(EWTICategoryIndex.WTI_DEFCONTEXT); |
|||
|
|||
if (context != null) |
|||
{ |
|||
// Add digitizer-specific context tweaks.
|
|||
context.PktMode = 0; // all data in absolute mode (set EWintabPacketBit bit(s) for relative mode)
|
|||
context.SysMode = false; // system cursor tracks in absolute mode (zero)
|
|||
|
|||
// Add caller's options.
|
|||
context.Options |= (uint)options_I; |
|||
|
|||
// Set the context data bits.
|
|||
context.PktData = PACKETDATA; |
|||
context.PktMode = PACKETMODE; |
|||
context.MoveMask = PACKETDATA; |
|||
context.BtnUpMask = context.BtnDnMask; |
|||
} |
|||
|
|||
return context; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the default system context, with useful context overrides.
|
|||
/// </summary>
|
|||
/// <param name="options_I">caller's options; OR'd into context options</param>
|
|||
/// <returns>A valid context object or null on error.</returns>
|
|||
public static CWintabContext GetDefaultSystemContext(ECTXOptionValues options_I = 0) |
|||
{ |
|||
// Send all possible data bits (not including extended data).
|
|||
// This is redundant with CWintabContext initialization, which
|
|||
// also inits with PK_PKTBITS_ALL.
|
|||
uint PACKETDATA = (uint)EWintabPacketBit.PK_PKTBITS_ALL; // The Full Monty
|
|||
uint PACKETMODE = (uint)EWintabPacketBit.PK_BUTTONS; |
|||
|
|||
CWintabContext context = GetDefaultContext(EWTICategoryIndex.WTI_DEFSYSCTX); |
|||
|
|||
if (context != null) |
|||
{ |
|||
// TODO: Add system-specific context tweaks.
|
|||
|
|||
// Add caller's options.
|
|||
context.Options |= (uint)options_I; |
|||
|
|||
// Make sure we get data packet messages.
|
|||
context.Options |= (uint)ECTXOptionValues.CXO_MESSAGES; |
|||
|
|||
// Set the context data bits.
|
|||
context.PktData = PACKETDATA; |
|||
context.PktMode = PACKETMODE; |
|||
context.MoveMask = PACKETDATA; |
|||
context.BtnUpMask = context.BtnDnMask; |
|||
|
|||
context.Name = "WintabDN Event Data Context"; |
|||
} |
|||
|
|||
return context; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Helper function to get digitizing or system default context.
|
|||
/// </summary>
|
|||
/// <param name="contextType_I">Use WTI_DEFCONTEXT for digital context or WTI_DEFSYSCTX for system context</param>
|
|||
/// <returns>Returns the default context or null on error.</returns>
|
|||
private static CWintabContext GetDefaultContext(EWTICategoryIndex contextIndex_I) |
|||
{ |
|||
CWintabContext context = new CWintabContext(); |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(context.LogContext); |
|||
|
|||
try |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA((uint)contextIndex_I, 0, buf); |
|||
|
|||
context.LogContext = CMemUtils.MarshalUnmanagedBuf<WintabLogContext>(buf, size); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetDefaultContext: " + ex.ToString()); |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
|
|||
return context; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the default device. If this value is -1, then it also known as a "virtual device".
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public static Int32 GetDefaultDeviceIndex() |
|||
{ |
|||
Int32 devIndex = 0; |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(devIndex); |
|||
|
|||
try |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA( |
|||
(uint)EWTICategoryIndex.WTI_DEFCONTEXT, |
|||
(uint)EWTIContextIndex.CTX_DEVICE, buf); |
|||
|
|||
devIndex = CMemUtils.MarshalUnmanagedBuf<Int32>(buf, size); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetDefaultDeviceIndex: " + ex.ToString()); |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
|
|||
return devIndex; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the WintabAxis object for specified device and dimension.
|
|||
/// </summary>
|
|||
/// <param name="devIndex_I">Device index (-1 = virtual device)</param>
|
|||
/// <param name="dim_I">Dimension: AXIS_X, AXIS_Y or AXIS_Z</param>
|
|||
/// <returns></returns>
|
|||
public static WintabAxis GetDeviceAxis(Int32 devIndex_I, EAxisDimension dim_I) |
|||
{ |
|||
WintabAxis axis = new WintabAxis(); |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(axis); |
|||
|
|||
try |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA( |
|||
(uint)(EWTICategoryIndex.WTI_DEVICES + devIndex_I), |
|||
(uint)dim_I, buf); |
|||
|
|||
// If size == 0, then returns a zeroed struct.
|
|||
axis = CMemUtils.MarshalUnmanagedBuf<WintabAxis>(buf, size); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetDeviceAxis: " + ex.ToString()); |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
|
|||
return axis; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a 3-element array describing the tablet's rotation range and resolution capabilities
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public static WintabAxisArray GetDeviceRotation(out bool rotationSupported_O) |
|||
{ |
|||
WintabAxisArray axisArray = new WintabAxisArray(); |
|||
rotationSupported_O = false; |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(axisArray); |
|||
|
|||
try |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA( |
|||
(uint)EWTICategoryIndex.WTI_DEVICES, |
|||
(uint)EWTIDevicesIndex.DVC_ROTATION, buf); |
|||
|
|||
// If size == 0, then returns a zeroed struct.
|
|||
axisArray = CMemUtils.MarshalUnmanagedBuf<WintabAxisArray>(buf, size); |
|||
rotationSupported_O = (axisArray.array[0].axResolution != 0 && axisArray.array[1].axResolution != 0); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetDeviceRotation: " + ex.ToString()); |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
|
|||
return axisArray; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the number of devices connected (attached).
|
|||
/// </summary>
|
|||
/// <returns>tablet count</returns>
|
|||
public static UInt32 GetNumberOfDevices() |
|||
{ |
|||
UInt32 numDevices = 0; |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(numDevices); |
|||
|
|||
try |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA( |
|||
(uint)EWTICategoryIndex.WTI_INTERFACE, |
|||
(uint)EWTIInterfaceIndex.IFC_NDEVICES, buf); |
|||
|
|||
numDevices = CMemUtils.MarshalUnmanagedBuf<UInt32>(buf, size); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetNumberOfDevices: " + ex.ToString()); |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
|
|||
return numDevices; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns whether a stylus is currently connected to the active cursor.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public static bool IsStylusActive() |
|||
{ |
|||
bool isStylusActive = false; |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(isStylusActive); |
|||
|
|||
try |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA( |
|||
(uint)EWTICategoryIndex.WTI_INTERFACE, |
|||
(uint)EWTIInterfaceIndex.IFC_NDEVICES, buf); |
|||
|
|||
isStylusActive = CMemUtils.MarshalUnmanagedBuf<bool>(buf, size); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetNumberOfDevices: " + ex.ToString()); |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
|
|||
return isStylusActive; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a string containing the name of the selected stylus.
|
|||
/// </summary>
|
|||
/// <param name="index_I">indicates stylus type</param>
|
|||
/// <returns></returns>
|
|||
public static string GetStylusName(EWTICursorNameIndex index_I) |
|||
{ |
|||
string stylusName = null; |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(MAX_STRING_SIZE); |
|||
|
|||
try |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA( |
|||
(uint)index_I, |
|||
(uint)EWTICursorsIndex.CSR_NAME, buf); |
|||
|
|||
if (size < 1) |
|||
{ |
|||
throw new Exception("GetStylusName returned empty string."); |
|||
} |
|||
|
|||
// Strip off final null character before marshalling.
|
|||
stylusName = CMemUtils.MarshalUnmanagedString(buf, size - 1); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetDeviceInfo: " + ex.ToString()); |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
|
|||
return stylusName; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Return the WintabAxis object for the specified dimension.
|
|||
/// </summary>
|
|||
/// <param name="dimension_I">Dimension to fetch (eg: x, y)</param>
|
|||
/// <returns></returns>
|
|||
public static WintabAxis GetTabletAxis(EAxisDimension dimension_I) |
|||
{ |
|||
WintabAxis axis = new WintabAxis(); |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(axis); |
|||
|
|||
try |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA( |
|||
(uint)EWTICategoryIndex.WTI_DEVICES, |
|||
(uint)dimension_I, buf); |
|||
|
|||
axis = CMemUtils.MarshalUnmanagedBuf<WintabAxis>(buf, size); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetMaxPressure: " + ex.ToString()); |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
|
|||
return axis; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Return the number of tablets that have at some time been attached.
|
|||
/// A record of these devices is in the tablet settings. Since there
|
|||
/// is no direct query for this value, we have to enumerate all of
|
|||
/// the tablet settings.
|
|||
/// </summary>
|
|||
/// <returns>tablet count</returns>
|
|||
public static UInt32 GetNumberOfConfiguredDevices() |
|||
{ |
|||
UInt32 numConfiguredTablets = 0; |
|||
try |
|||
{ |
|||
WintabLogContext ctx = new WintabLogContext(); |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(ctx); |
|||
|
|||
for (Int32 idx = 0; idx < MAX_NUM_ATTACHED_TABLETS; idx++) |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA( |
|||
(UInt32)(EWTICategoryIndex.WTI_DDCTXS + idx), 0, buf); |
|||
if (size == 0) |
|||
{ |
|||
break; |
|||
} |
|||
else |
|||
{ |
|||
numConfiguredTablets++; |
|||
} |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetNumberOfConfiguredDevices: " + ex.ToString()); |
|||
} |
|||
|
|||
return numConfiguredTablets; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a list of indecies of previous or currently attached devices.
|
|||
/// It is up to the caller to use the list to determine which devices are
|
|||
/// actually physically device by responding to data events for those devices.
|
|||
/// Devices that are not physically attached will, of course, never send
|
|||
/// a data event.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
public static List<Byte> GetFoundDevicesIndexList() |
|||
{ |
|||
List<Byte> list = new List<Byte>(); |
|||
|
|||
try |
|||
{ |
|||
WintabLogContext ctx = new WintabLogContext(); |
|||
IntPtr buf = CMemUtils.AllocUnmanagedBuf(ctx); |
|||
|
|||
for (Int32 idx = 0; idx < MAX_NUM_ATTACHED_TABLETS; idx++) |
|||
{ |
|||
int size = (int)CWintabFuncs.WTInfoA( |
|||
(UInt32)(EWTICategoryIndex.WTI_DDCTXS + idx), 0, buf); |
|||
if (size == 0) |
|||
{ |
|||
break; |
|||
} |
|||
else |
|||
{ |
|||
list.Add((Byte)idx); |
|||
} |
|||
} |
|||
|
|||
CMemUtils.FreeUnmanagedBuf(buf); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
MessageBox.Show("FAILED GetNumberOfConfiguredDevices: " + ex.ToString()); |
|||
} |
|||
|
|||
return list; |
|||
} |
|||
}*/ |
|||
} |
|||
} |
|||
@ -0,0 +1,81 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace Avalonia.Win32.WintabImpl; |
|||
|
|||
public static class WintabMemUtils |
|||
{ |
|||
/// <summary>
|
|||
/// Marshal unmanaged data packets into managed WintabPacket data.
|
|||
/// </summary>
|
|||
/// <param name="numPkts_I">number of packets to marshal</param>
|
|||
/// <param name="buf_I">pointer to unmanaged heap memory containing data packets</param>
|
|||
/// <returns></returns>
|
|||
|
|||
/// <summary>
|
|||
/// Marshal unmanaged data packets into managed WintabPacket data.
|
|||
/// </summary>
|
|||
/// <param name="numPkts_I">number of packets to marshal</param>
|
|||
/// <param name="buf_I">pointer to unmanaged heap memory containing data packets</param>
|
|||
/// <returns></returns>
|
|||
public static WintabPacket[] MarshalDataPackets(UInt32 numPkts_I, IntPtr buf_I) |
|||
{ |
|||
if (numPkts_I == 0 || buf_I == IntPtr.Zero) |
|||
{ |
|||
return []; |
|||
} |
|||
|
|||
WintabPacket[] packets = new WintabPacket[numPkts_I]; |
|||
|
|||
int pktSize = Marshal.SizeOf(new WintabPacket()); |
|||
|
|||
for (int pktsIdx = 0; pktsIdx < numPkts_I; pktsIdx++) |
|||
{ |
|||
// Tracing can be added here to capture raw packet data if desired
|
|||
|
|||
packets[pktsIdx] = Marshal.PtrToStructure<WintabPacket>(IntPtr.Add(buf_I, pktsIdx * pktSize)); |
|||
} |
|||
|
|||
return packets; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Marshal unmanaged Extension data packets into managed WintabPacketExt data.
|
|||
/// </summary>
|
|||
/// <param name="numPkts_I">number of packets to marshal</param>
|
|||
/// <param name="buf_I">pointer to unmanaged heap memory containing data packets</param>
|
|||
/// <returns></returns>
|
|||
public static WintabPacketExt[] MarshalDataExtPackets(UInt32 numPkts_I, IntPtr buf_I) |
|||
{ |
|||
WintabPacketExt[] packets = new WintabPacketExt[numPkts_I]; |
|||
|
|||
if (numPkts_I == 0 || buf_I == IntPtr.Zero) |
|||
{ |
|||
return []; |
|||
} |
|||
|
|||
// Marshal each WintabPacketExt in the array separately.
|
|||
// This is "necessary" because none of the other ways I tried to marshal
|
|||
// seemed to work. It's ugly, but it works.
|
|||
int pktSize = Marshal.SizeOf(new WintabPacketExt()); |
|||
Byte[] byteArray = new Byte[numPkts_I * pktSize]; |
|||
Marshal.Copy(buf_I, byteArray, 0, (int)numPkts_I * pktSize); |
|||
|
|||
Byte[] byteArray2 = new Byte[pktSize]; |
|||
|
|||
for (int pktsIdx = 0; pktsIdx < numPkts_I; pktsIdx++) |
|||
{ |
|||
for (int idx = 0; idx < pktSize; idx++) |
|||
{ |
|||
byteArray2[idx] = byteArray[(pktsIdx * pktSize) + idx]; |
|||
} |
|||
|
|||
IntPtr tmp = Marshal.AllocHGlobal(pktSize); |
|||
Marshal.Copy(byteArray2, 0, tmp, pktSize); |
|||
|
|||
packets[pktsIdx] = Marshal.PtrToStructure<WintabPacketExt>(tmp); |
|||
} |
|||
|
|||
return packets; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue