No probs. Myself, I have something in the works that I'll be using it in, so there's that.
Done a bit more work. Now you can find out what information your device supports and base packet requests on that, so no more guessing. Likewise, tablet pressure now normalises based on actual device range.
To use this you'll now need
Diggsey's Arguments Library (
ArgLib_Include.dba, as named in examples in this post). If it's cool with Diggsey, I'll include it here for convenience.
Changes
CHANGELOG
v0.1 (12Jun13)
- Initial release.
- Very incomplete but workable.
v0.2 (13Jun13)
- Now requires Diggsey's Args Library (used for getters returning UDTs).
- Improved Fix32-Float functions.
- Can now get device data and compatibility; use WT_Set_CtxPktData(WT_Get_CtxPktData() && WT_GetDeviceSupportedData()) to limit requests for packet data to available items.
v0.3
- TODO: Add more general info query functions.
- TODO: Respond to messages and changes.
// ------------------------------------------------------------
NEW FUNCTIONS
string = WT_GetWintabVersion()
integer = WT_GetDevice() // update device data. Use: init & dvc change
dword = WT_GetDeviceSupportedData() // returns DvcPktData||DvccsrData
// WT_Get_DvcX(tyWT_Axis) essentially performs tyWT_Axis = WT_Get_DvcX().
string = WT_Get_DvcName()
integer = WT_Get_DvcHardware()
integer = WT_Get_DvcNCsrTypes()
integer = WT_Get_DvcFirstCsr()
integer = WT_Get_DvcPktRate()
dword = WT_Get_DvcPktData()
dword = WT_Get_DvcPktMode()
dword = WT_Get_DvcCsrData()
integer = WT_Get_DvcXMargin()
integer = WT_Get_DvcYMargin()
integer = WT_Get_DvcZMargin()
WT_Get_DvcX(tyWT_Axis) // arglib
WT_Get_DvcY(tyWT_Axis) // arglib
WT_Get_DvcZ(tyWT_Axis) // arglib
WT_Get_DvcNPressure(tyWT_Axis) // arglib
WT_Get_DvcTPressure(tyWT_Axis // arglib
WT_Get_DvcAzimuth(tyWT_Axis) // arglib
WT_Get_DvcAltitude(tyWT_Axis) // arglib
WT_Get_DvcTwist(tyWT_Axis) // arglib
WT_Get_DvcPitch(tyWT_Axis) // arglib
WT_Get_DvcRoll(tyWT_Axis) // arglib
WT_Get_DvcYaw(tyWT_Axis) // arglib
string = WT_Get_DvcPNPId()
// ------------------------------------------------------------
NOTES
DATATYPES
for datatypes like uint, fix32, long etc. that are not DBP native, I am
using what I think is the best bet in each case. For example, In most
cases where negative numbers aren't expected, I use dwords if I expect
potentially lage numbers or integers otherwise, but I'm not being
particularly rigorous about it at the moment. If it becomes a problem
proper then I'll go back over things and standardise them.
ORIENTATION AND ROTATION
Orientation: Azimuth, Altitude, Twist.
Rotation: Pitch, Roll, Yaw.
WT_Include.dba - v0.2
// WT_Include v0.2 : TomJK 2013
// basic required types [put in your main file].
remstart
type tyPoint2d x, y endtype
type tyBound x1, y1, x2, y2 endtype
remend
// WT specific types [used in some cases].
type tyWT_Axis
axMin as integer, axMax as integer, axUnits as integer, axResolution as float
endtype
// WT data.
type tyWT_PktOffset
context, status, time, changed, serial_number, cursor, buttons, x, y, z
normal_pressure, tangent_pressure, orientation, rotation
endtype
type tyWT_DvcOffset
main // hardware,ncsrtypes,firstcsr,pktrate,pktdata,pktmode,csrdata,xyzmargin
x, y, z, npressure, tpressure, orientation, rotation, pnpid
endtype
type tyWT_Data
// handles and pointers.
hWnd as dword // handle to dbp window.
hCtx as dword // handle to context.
lpPkts as dword // pointer to packets.
lpOutput as dword // pointer to general WTInfo return data.
lpDvc as dword // pointer to device data.
lpCtx as dword // pointer to default context data.
// state.
wintabDLL as byte // dll num. for loaded wintab32. 0: WT not init'd.
vScr as tyBound // virtual screen bounds (y2 is absolute bottom).
pktOffset as tyWT_PktOffset // lookup of in-packet offset of each data item.
dvcOffset as tyWT_DvcOffset // lookup of offset of each device info data item.
pktLen // bytes per package. Used for seeking to packet.
pktData as dword // copy of current active context pktData property.
dvcData as dword // current device's compatible data items.
msgBase as dword // copy of current active context msgBase property.
// misc.
tmpAxis as tyWT_Axis // a tyWT_Axis value, can be used for data retrieval.
maxNPressure // max normal pressure (0-1023 maps to 0.0-1.0).
maxTPressure // max tangent pressure.
endtype
global WT_Data as tyWT_Data
// WT Functions. ----------------------------------------------------------------
// -- General --
function WT_InitWintab(hWnd as dword)
// cancel if already initiated.
if WT_Data.wintabDLL <> 0 then exitfunction 0
// attempt to load wintab32.
local wintabDLL as byte
wintabDLL = find free dll()
load dll "Wintab32.dll", wintabDLL
// failed (wintab unavailable)?
if dll exist(wintabDLL) = 0 then exitfunction 0
// cancel if tablet not physically present (if WTInfoA returns zero).
local szCtx, szOutput, szDvc
szCtx = call dll(wintabDLL, "WTInfoA", WTI_DSCTXS, 0, 0)
if szCtx = 0 then exitfunction 0
// create buffers of max required size.
szOutput = call dll(wintabDLL, "WTInfoA", 0, 0, 0)
szDvc = call dll(wintabDLL, "WTInfoA", WTI_DEVICES, 0, 0)
WT_Data.lpOutput = alloc( szOutput )
WT_Data.lpDvc = alloc zeroed( szDvc )
WT_Data.lpCtx = alloc( szCtx )
// get system default context.
err = call dll(wintabDLL, "WTInfoA", WTI_DSCTXS, 0, WT_Data.lpCtx)
// store data for later use.
WT_Data.hWnd = hWnd
WT_Data.wintabDLL = wintabDLL
endfunction 1
function WT_CloseWintab()
// cancel if not initiated.
if WT_Data.wintabDLL = 0 then exitfunction 0
// close context if still open.
if WT_Data.hCtx <> 0
err = WT_CloseContext()
endif
// unload wintab32.
delete dll WT_Data.wintabDLL
// cleanup.
free WT_Data.lpOutput
free WT_Data.lpDvc
free WT_Data.lpCtx
if WT_Data.lpPkts <> 0 then free WT_Data.lpPkts
WT_Data.lpOutput = 0
WT_Data.lpDvc = 0
WT_Data.lpCtx = 0
WT_Data.wintabDLL = 0
endfunction 1
function WT_SetDisplay(vScr as tyBound)
// update virtual screen bounds.
WT_Data.vScr = vScr
endfunction
// -- Information --
function WT_GetWintabVersion()
// cancel if not initiated.
if WT_Data.wintabDLL = 0 then exitfunction "spec[n/a] impl[n/a]"
local version as string
err = call dll(WT_Data.wintabDLL, "WTInfoA", WTI_INTERFACE, IFC_SPECVERSION||IFC_IMPLVERSION, WT_Data.lpOutput)
version = "spec[" + str$(peek byte(WT_Data.lpOutput)) + "." + str$(peek byte(WT_Data.lpOutput+1)) + "] impl[" + str$(peek byte(WT_Data.lpOutput+2)) + "." + str$(peek byte(WT_Data.lpOutput+3)) + "]"
endfunction version
function WT_GetNumDevices()
// cancel if not initiated.
if WT_Data.wintabDLL = 0 then exitfunction 0
// get data.
local nDevices
err = call dll(WT_Data.wintabDLL, "WTInfoA", WTI_INTERFACE, IFC_NDEVICES, WT_Data.lpOutput)
nDevices = peek integer(WT_Data.lpOutput)
endfunction nDevices
// -- Device & Compatibility --
function WT_GetDevice()
// cancel if not initiated.
if WT_Data.wintabDLL = 0 then exitfunction 0
// get device data.
err = call dll(WT_Data.wintabDLL, "WTInfoA", WTI_DEVICES, 0, WT_Data.lpDvc)
// update device info.
WT_UpdateDeviceInfoDataOffsets()
if WT_Data.dvcData && PK_NORMAL_PRESSURE
WT_Get_DvcNPressure(WT_Data.tmpAxis)
WT_Data.maxNPressure = WT_Data.tmpAxis.axMax
endif
if WT_Data.dvcData && PK_TANGENT_PRESSURE
WT_Get_DvcTPressure(WT_Data.tmpAxis)
WT_Data.maxTPressure = WT_Data.tmpAxis.axMax
endif
endfunction 1
function WT_GetDeviceSupportedData()
endfunction WT_Data.dvcData
function WT_Get_DvcName() : local v as string
v = peek string( WT_GetDeviceInfoDataAddress(DVC_NAME) )
endfunction v
function WT_Get_DvcHardware() : local v as integer
v = peek integer( WT_GetDeviceInfoDataAddress(DVC_HARDWARE) )
endfunction v
function WT_Get_DvcNCsrTypes() : local v as integer
v = peek integer( WT_GetDeviceInfoDataAddress(DVC_NCSRTYPES) )
endfunction v
function WT_Get_DvcFirstCsr() : local v as integer
v = peek integer( WT_GetDeviceInfoDataAddress(DVC_FIRSTCSR) )
endfunction v
function WT_Get_DvcPktRate() : local v as integer
v = peek integer( WT_GetDeviceInfoDataAddress(DVC_PKTRATE) )
endfunction v
function WT_Get_DvcPktData() : local v as dword
v = peek dword( WT_GetDeviceInfoDataAddress(DVC_PKTDATA) )
endfunction v
function WT_Get_DvcPktMode() : local v as dword
v = peek dword( WT_GetDeviceInfoDataAddress(DVC_PKTMODE) )
endfunction v
function WT_Get_DvcCsrData() : local v as dword
v = peek dword( WT_GetDeviceInfoDataAddress(DVC_CSRDATA) )
endfunction v
function WT_Get_DvcXMargin() : local v as integer
v = peek integer( WT_GetDeviceInfoDataAddress(DVC_XMARGIN) )
endfunction v
function WT_Get_DvcYMargin() : local v as integer
v = peek integer( WT_GetDeviceInfoDataAddress(DVC_YMARGIN) )
endfunction v
function WT_Get_DvcZMargin() : local v as integer
v = peek integer( WT_GetDeviceInfoDataAddress(DVC_ZMARGIN) )
endfunction v
function WT_Get_DvcX(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_X) )
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcY(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_Y) )
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcZ(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_Z) )
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcNPressure(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_NPRESSURE) )
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcTPressure(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_TPRESSURE) )
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcAzimuth(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_ORIENTATION) )
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcAltitude(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_ORIENTATION) + 16 )
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcTwist(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_ORIENTATION) + 32)
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcPitch(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_ROTATION) )
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcRoll(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_ROTATION) + 16)
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcYaw(v as tyWT_Axis)
WT_GetAxisData(v, WT_GetDeviceInfoDataAddress(DVC_ROTATION) + 32)
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(v.axMin), "tyWT_Axis")
endfunction
function WT_Get_DvcPNPId() : local v as string `dword
v = peek string( WT_GetDeviceInfoDataAddress(DVC_PNPID) )
endfunction v
// -- Packets --
function WT_GetPackets(maxPackets as integer)
// cancel if context not open.
if WT_Data.hCtx = 0 then exitfunction 0
// get packets.
local pktsAcquired
pktsAcquired = call dll(WT_Data.wintabDLL, "WTPacketsGet", WT_Data.hCtx, maxPackets, WT_Data.lpPkts)
// @TODO: if errors flagged, resolve.
endfunction pktsAcquired
function WT_FlushPackets(maxPackets as integer)
// cancel if context not open.
if WT_Data.hCtx = 0 then exitfunction 0
// flush packets.
err = call dll(WT_Data.wintabDLL, "WTPacketsGet", WT_Data.hCtx, maxPackets, 0)
// @TEST: does WTPacketsGet indicate actual num flushed packets?
endfunction 1
function WT_EnablePackets(bEnable as boolean)
// cancel if context not open.
if WT_Data.hCtx = 0 then exitfunction 0
// pause/resume flow of packets (disable/enable).
err = call dll(WT_Data.wintabDLL, "WTEnable", WT_Data.hCtx, bEnable)
if err = 0 then exitfunction 0
endfunction 1
// -- Packet Data Getters --
function WT_Get_PktContext(iPkt as integer) : local v as dword
v = peek dword( WT_GetPacketDataAddress(iPkt, PK_CONTEXT) )
endfunction v
function WT_Get_PktStatus(iPkt as integer) : local v as dword
v = peek dword( WT_GetPacketDataAddress(iPkt, PK_STATUS) )
endfunction v
function WT_Get_PktTime(iPkt as integer) : local v as dword
v = peek dword( WT_GetPacketDataAddress(iPkt, PK_TIME) )
endfunction v
function WT_Get_PktChanged(iPkt as integer) : local v as dword
v = peek dword( WT_GetPacketDataAddress(iPkt, PK_CHANGED) )
endfunction v
function WT_Get_PktSerial(iPkt as integer) : local v as dword
v = peek dword( WT_GetPacketDataAddress(iPkt, PK_SERIAL_NUMBER) )
endfunction v
function WT_Get_PktCursor(iPkt as integer) : local v as dword
v = peek dword( WT_GetPacketDataAddress(iPkt, PK_CURSOR) )
endfunction v
function WT_Get_PktButtons(iPkt as integer) : local v as integer
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_BUTTONS) )
endfunction v
// @NOTE: get sysOrgXY from WT_Get_CtxSysOrgXY(), or hold in WT_Data (get and
// store each WT_SetDisplay call)? If user edits context --> inconsistency?
// @NOTE: give additional option to transform to dbp space (wnd stretch and all)?
function WT_Get_PktX(iPkt as integer, raw as boolean) : local v as integer
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_X) )
if raw = 0 then v = WT_Get_CtxSysOrgX() - WT_Data.vScr.x1 + v
endfunction v
function WT_Get_PktY(iPkt as integer, raw as boolean) : local v as integer
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_Y) )
if raw = 0 then v = WT_Get_CtxSysOrgY() + (WT_Data.vScr.y2 - 1 - v) // flip y.
endfunction v
function WT_Get_PktZ(iPkt as integer, raw as boolean) : local v as integer
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_Z) )
// @NOTE: raw unused but here for consistency and just-in-case for future.
endfunction v
function WT_Get_PktNPressure(iPkt as integer, raw as boolean) : local v as float
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_NORMAL_PRESSURE) )
if raw = 0 then v = 1.0 / WT_Data.maxNPressure * v
endfunction v
function WT_Get_PktTPressure(iPkt as integer, raw as boolean) : local v as float
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_TANGENT_PRESSURE) )
if raw = 0 then v = 1.0 / WT_Data.maxTPressure * v
endfunction v
function WT_Get_PktAzimuth(iPkt as integer) : local v as integer
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_ORIENTATION) )
endfunction v
function WT_Get_PktAltitude(iPkt as integer) : local v as integer
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_ORIENTATION) + 4 )
endfunction v
function WT_Get_PktTwist(iPkt as integer) : local v as integer
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_ORIENTATION) + 8 )
endfunction v
function WT_Get_PktPitch(iPkt as integer) : local v as integer
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_ROTATION) )
endfunction v
function WT_Get_PktRoll(iPkt as integer) : local v as integer
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_ROTATION) + 4 )
endfunction v
function WT_Get_PktYaw(iPkt as integer) : local v as integer
v = peek integer( WT_GetPacketDataAddress(iPkt, PK_ROTATION) + 8 )
endfunction v
// -- Context --
function WT_OpenContext(bEnable as boolean)
// cancel if not initiated or already open.
if WT_Data.wintabDLL = 0 then exitfunction 0
if WT_Data.hCtx <> 0 then exitfunction 0
// attempt to open context.
local hCtx
hCtx = call dll(WT_Data.wintabDLL, "WTOpenA", WT_Data.hWnd, WT_Data.lpCtx, bEnable)
// failed?
if hCtx = 0 then exitfunction 0
// store handle to context.
WT_Data.hCtx = hCtx
// create buffer for packets. @NOTE: for now, just make "big enough".
WT_Data.lpPkts = alloc zeroed( 7200 ) // 7200: 100 big pkts. (fix'd, put 16800)
// update packet info.
WT_Data.pktData = WT_Get_CtxPktData()
WT_Data.msgBase = WT_Get_CtxMsgBase()
WT_UpdatePacketDataOffsets()
endfunction 1
function WT_CloseContext()
// cancel if not already open.
if WT_Data.hCtx = 0 then exitfunction 0
// close context.
err = call dll(WT_Data.wintabDLL, "WTClose", WT_Data.hCtx)
if err = 0 then exitfunction 0
// cleanup.
WT_Data.hCtx = 0
endfunction 1
function WT_GetCurrentContext()
// cancel if not already open.
if WT_Data.hCtx = 0 then exitfunction 0
// renew our copy of context.
err = call dll(WT_Data.wintabDLL, "WTGetA", WT_Data.hCtx, WT_Data.lpCtx)
if err = 0 then exitfunction 0
endfunction 1
function WT_SetCurrentContext()
// cancel if not already open.
if WT_Data.hCtx = 0 then exitfunction 0
// update context from our copy. @TEST: docs vague if partial fail=no change.
err = call dll(WT_Data.wintabDLL, "WTSetA", WT_Data.hCtx, WT_Data.lpCtx)
if err = 0 then exitfunction 0
// update packet info.
WT_Data.pktData = WT_Get_CtxPktData()
WT_Data.msgBase = WT_Get_CtxMsgBase()
WT_UpdatePacketDataOffsets()
endfunction 1
// -- Context Getters --
// @NOTE: probably should make getters/setters wrap general function which tests
// for context being open etc.
function WT_Get_CtxName()
v$ = peek string(WT_Data.lpCtx + CTXOFF_NAME)
endfunction v$
function WT_Get_CtxOptions() : v as dword
v = peek dword(WT_Data.lpCtx + CTXOFF_OPTIONS)
endfunction v
function WT_Get_CtxStatus() : v as dword
v = peek dword(WT_Data.lpCtx + CTXOFF_STATUS)
endfunction v
function WT_Get_CtxLocks() : v as dword
v = peek dword(WT_Data.lpCtx + CTXOFF_LOCKS)
endfunction v
function WT_Get_CtxMsgBase() : v as dword
v = peek dword(WT_Data.lpCtx + CTXOFF_MSGBASE)
endfunction v
function WT_Get_CtxDevice() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_DEVICE)
endfunction v
function WT_Get_CtxPktRate() : v as dword
v = peek dword(WT_Data.lpCtx + CTXOFF_PKTRATE)
endfunction v
function WT_Get_CtxPktData() : v as dword
v = peek dword(WT_Data.lpCtx + CTXOFF_PKTDATA)
endfunction v
function WT_Get_CtxPktMode() : v as dword
v = peek dword(WT_Data.lpCtx + CTXOFF_PKTMODE)
endfunction v
function WT_Get_CtxMoveMask() : v as dword
v = peek dword(WT_Data.lpCtx + CTXOFF_MOVEMASK)
endfunction v
function WT_Get_CtxBtnDnMask() : v as dword
v = peek dword(WT_Data.lpCtx + CTXOFF_BTNDNMASK)
endfunction v
function WT_Get_CtxBtnUpMask() : v as dword
v = peek dword(WT_Data.lpCtx + CTXOFF_BTNUPMASK)
endfunction v
function WT_Get_CtxInOrgX() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_INORGX)
endfunction v
function WT_Get_CtxInOrgY() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_INORGY)
endfunction v
function WT_Get_CtxInOrgZ() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_INORGZ)
endfunction v
function WT_Get_CtxInExtX() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_INEXTX)
endfunction v
function WT_Get_CtxInExtY() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_INEXTY)
endfunction v
function WT_Get_CtxInExtZ() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_INEXTZ)
endfunction v
function WT_Get_CtxOutOrgX() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_OUTORGX)
endfunction v
function WT_Get_CtxOutOrgY() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_OUTORGY)
endfunction v
function WT_Get_CtxOutOrgZ() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_OUTORGZ)
endfunction v
function WT_Get_CtxOutExtX() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_OUTEXTX)
endfunction v
function WT_Get_CtxOutExtY() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_OUTEXTY)
endfunction v
function WT_Get_CtxOutExtZ() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_OUTEXTZ)
endfunction v
function WT_Get_CtxSensX() : v as float
v = FIX32_To_Float(peek dword(WT_Data.lpCtx + CTXOFF_SENSX))
endfunction v
function WT_Get_CtxSensY() : v as float
v = FIX32_To_Float(peek dword(WT_Data.lpCtx + CTXOFF_SENSY))
endfunction v
function WT_Get_CtxSensZ() : v as float
v = FIX32_To_Float(peek dword(WT_Data.lpCtx + CTXOFF_SENSZ))
endfunction v
function WT_Get_CtxSysMode() : v as boolean
v = peek integer(WT_Data.lpCtx + CTXOFF_SYSMODE)
endfunction v
function WT_Get_CtxSysOrgX() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_SYSORGX)
endfunction v
function WT_Get_CtxSysOrgY() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_SYSORGY)
endfunction v
function WT_Get_CtxSysExtX() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_SYSEXTX)
endfunction v
function WT_Get_CtxSysExtY() : v as integer
v = peek integer(WT_Data.lpCtx + CTXOFF_SYSEXTY)
endfunction v
function WT_Get_CtxSysSensX() : v as float
v = FIX32_To_Float(peek dword(WT_Data.lpCtx + CTXOFF_SYSSENSX))
endfunction v
function WT_Get_CtxSysSensY() : v as float
v = FIX32_To_Float(peek dword(WT_Data.lpCtx + CTXOFF_SYSSENSY))
endfunction v
// -- Context Setters --
function WT_Set_CtxName(name as string)
poke string WT_Data.lpCtx + CTXOFF_NAME, name
endfunction
function WT_Set_CtxOptions(options as dword)
poke dword WT_Data.lpCtx + CTXOFF_OPTIONS, options
endfunction
function WT_Set_CtxStatus(status as dword)
poke dword WT_Data.lpCtx + CTXOFF_STATUS, status
endfunction
function WT_Set_CtxLocks(locks as dword)
poke dword WT_Data.lpCtx + CTXOFF_LOCKS, locks
endfunction
function WT_Set_CtxMsgBase(msgBase as dword)
poke dword WT_Data.lpCtx + CTXOFF_MSGBASE, msgBase
endfunction
function WT_Set_CtxDevice(device as integer)
poke integer WT_Data.lpCtx + CTXOFF_DEVICE, device
endfunction
function WT_Set_CtxPktRate(pktRate as dword)
poke dword WT_Data.lpCtx + CTXOFF_PKTRATE, pktRate
endfunction
function WT_Set_CtxPktData(pktData as dword)
poke dword WT_Data.lpCtx + CTXOFF_PKTDATA, pktData
endfunction
function WT_Set_CtxPktMode(pktMode as dword)
poke dword WT_Data.lpCtx + CTXOFF_PKTMODE, pktMode
endfunction
function WT_Set_CtxMoveMask(moveMask as dword)
poke dword WT_Data.lpCtx + CTXOFF_MOVEMASK, moveMask
endfunction
function WT_Set_CtxBtnDnMask(btnDnMask as dword)
poke dword WT_Data.lpCtx + CTXOFF_BTNDNMASK, btnDnMask
endfunction
function WT_Set_CtxBtnUpMask(btnUpMask as dword)
poke dword WT_Data.lpCtx + CTXOFF_BTNUPMASK, btnUpMask
endfunction
function WT_Set_CtxInOrgX(x as integer)
poke integer WT_Data.lpCtx + CTXOFF_INORGX, x
endfunction
function WT_Set_CtxInOrgY(y as integer)
poke integer WT_Data.lpCtx + CTXOFF_INORGY, y
endfunction
function WT_Set_CtxInOrgZ(z as integer)
poke integer WT_Data.lpCtx + CTXOFF_INORGZ, z
endfunction
function WT_Set_CtxInExtX(x as integer)
poke integer WT_Data.lpCtx + CTXOFF_INEXTX, x
endfunction
function WT_Set_CtxInExtY(y as integer)
poke integer WT_Data.lpCtx + CTXOFF_INEXTY, y
endfunction
function WT_Set_CtxInExtZ(z as integer)
poke integer WT_Data.lpCtx + CTXOFF_INEXTZ, z
endfunction
function WT_Set_CtxOutOrgX(x as integer)
poke integer WT_Data.lpCtx + CTXOFF_OUTORGX, x
endfunction
function WT_Set_CtxOutOrgY(y as integer)
poke integer WT_Data.lpCtx + CTXOFF_OUTORGY, y
endfunction
function WT_Set_CtxOutOrgZ(z as integer)
poke integer WT_Data.lpCtx + CTXOFF_OUTORGZ, z
endfunction
function WT_Set_CtxOutExtX(x as integer)
poke integer WT_Data.lpCtx + CTXOFF_OUTEXTX, x
endfunction
function WT_Set_CtxOutExtY(y as integer)
poke integer WT_Data.lpCtx + CTXOFF_OUTEXTY, y
endfunction
function WT_Set_CtxOutExtZ(z as integer)
poke integer WT_Data.lpCtx + CTXOFF_OUTEXTZ, z
endfunction
function WT_Set_CtxSensX(x as float)
poke dword WT_Data.lpCtx + CTXOFF_SENSX, Float_To_FIX32(x)
endfunction
function WT_Set_CtxSensY(y as float)
poke dword WT_Data.lpCtx + CTXOFF_SENSY, Float_To_FIX32(y)
endfunction
function WT_Set_CtxSensZ(z as float)
poke dword WT_Data.lpCtx + CTXOFF_SENSZ, Float_To_FIX32(z)
endfunction
function WT_Set_CtxSysMode(sysMode as integer)
poke integer WT_Data.lpCtx + CTXOFF_SYSMODE, sysMode
endfunction
function WT_Set_CtxSysOrgX(x as integer)
poke integer WT_Data.lpCtx + CTXOFF_SYSORGX, x
endfunction
function WT_Set_CtxSysOrgY(y as integer)
poke integer WT_Data.lpCtx + CTXOFF_SYSORGY, y
endfunction
function WT_Set_CtxSysExtX(x as integer)
poke integer WT_Data.lpCtx + CTXOFF_SYSEXTX, x
endfunction
function WT_Set_CtxSysExtY(y as integer)
poke integer WT_Data.lpCtx + CTXOFF_SYSEXTY, y
endfunction
function WT_Set_CtxSysSensX(x as float)
poke dword WT_Data.lpCtx + CTXOFF_SYSSENSX, Float_To_FIX32(x)
endfunction
function WT_Set_CtxSysSensY(y as float)
poke dword WT_Data.lpCtx + CTXOFF_SYSSENSY, Float_To_FIX32(y)
endfunction
// -- WNDPROC BASE --
REMSTART
function WndProc(hWnd as dword, msg as dword, wParam as dword, lParam as dword)
`print "WndProc: ", hWnd, " - ", msg, " - ", wParam, " - ", lParam
select msg
// WM_A, WM_B, WM_C... all your standard message checks.
// WT messages do not have fixed values; will use a nested select.
case default
select msg - WT_Data.msgBase
case WT_PACKET
// packet data available.
endcase
case WT_CTXOPEN
// context opened.
endcase
case WT_CTXCLOSE
// context about to close.
endcase
case WT_CTXUPDATE
// context has changed.
endcase
case WT_CTXOVERLAP
// context has changed order.
endcase
case WT_PROXIMITY
// cursor entered/left proximity.
endcase
case WT_INFOCHANGE
// tablet plugged in or unplugged.
endcase
case WT_CSRCHANGE
// a cursor has entered context.
endcase
endselect
endcase
endselect
endfunction
REMEND
// -- "PRIVATE" FUNCTIONS --
function WT_UpdatePacketDataOffsets()
local offset = 0
local pktData as dword
pktData = WT_Data.pktData
// set offset for each data item. @NOTE: if there's a size diff between abs and
// rel modes, it's not currently accounted for here.
if pktData && PK_CONTEXT then WT_Data.pktOffset.context = offset : inc offset, 4
if pktData && PK_STATUS then WT_Data.pktOffset.status = offset : inc offset, 4
if pktData && PK_TIME then WT_Data.pktOffset.time = offset : inc offset, 4
if pktData && PK_CHANGED then WT_Data.pktOffset.changed = offset : inc offset, 4
if pktData && PK_SERIAL_NUMBER then WT_Data.pktOffset.serial_number = offset : inc offset, 4
if pktData && PK_CURSOR then WT_Data.pktOffset.cursor = offset : inc offset, 4
if pktData && PK_BUTTONS then WT_Data.pktOffset.buttons = offset : inc offset, 4
if pktData && PK_X then WT_Data.pktOffset.x = offset : inc offset, 4
if pktData && PK_Y then WT_Data.pktOffset.y = offset : inc offset, 4
if pktData && PK_Z then WT_Data.pktOffset.z = offset : inc offset, 4
if pktData && PK_NORMAL_PRESSURE then WT_Data.pktOffset.normal_pressure = offset : inc offset, 4
if pktData && PK_TANGENT_PRESSURE then WT_Data.pktOffset.tangent_pressure = offset : inc offset, 4
if pktData && PK_ORIENTATION then WT_Data.pktOffset.orientation = offset : inc offset, 12
if pktData && PK_ROTATION then WT_Data.pktOffset.rotation = offset : inc offset, 12
// final value of offset specifies total length of packet.
WT_Data.pktLen = offset
endfunction
function WT_GetPacketDataAddress(iPkt as integer, pktDataItem as dword)
local addr as dword = 0
local offset = 0
local pktData as dword
pktData = WT_Data.pktData
// check data item is valid. @NOTE: returns 0, will crash on use. More useful to
// crash outright or try to error gracefully (eg. point to known zero bytes)?
if not pktData && pktDataItem then exitfunction 0
// start with packet base address. Note that iPkt is zero-based.
addr = WT_Data.lpPkts + iPkt * WT_Data.pktLen
select pktDataItem
case PK_CONTEXT : offset = WT_Data.pktOffset.context : endcase
case PK_STATUS : offset = WT_Data.pktOffset.status : endcase
case PK_TIME : offset = WT_Data.pktOffset.time : endcase
case PK_CHANGED : offset = WT_Data.pktOffset.changed : endcase
case PK_SERIAL_NUMBER : offset = WT_Data.pktOffset.serial_number : endcase
case PK_CURSOR : offset = WT_Data.pktOffset.cursor : endcase
case PK_BUTTONS : offset = WT_Data.pktOffset.buttons : endcase
case PK_X : offset = WT_Data.pktOffset.x : endcase
case PK_Y : offset = WT_Data.pktOffset.y : endcase
case PK_Z : offset = WT_Data.pktOffset.z : endcase
case PK_NORMAL_PRESSURE : offset = WT_Data.pktOffset.normal_pressure : endcase
case PK_TANGENT_PRESSURE: offset = WT_Data.pktOffset.tangent_pressure : endcase
case PK_ORIENTATION : offset = WT_Data.pktOffset.orientation : endcase
case PK_ROTATION : offset = WT_Data.pktOffset.rotation : endcase
endselect
// add offset to packet base address.
addr = addr + offset
endfunction addr
function WT_UpdateDeviceInfoDataOffsets()
local offset = 0
// name is first item, offset zero.
offset = fast len( peek string(WT_Data.lpDvc) ) + 1
// hardware is first item after, and first of 40 bytes contiguous data items.
WT_Data.dvcOffset.main = offset
inc offset, 40
// which items are available given by union of DvcPktData and DvcCsrData.
local dvcData as dword
dvcData = peek dword( WT_Data.lpDvc + WT_Data.dvcOffset.main + 16 )
dvcData = dvcData || peek dword( WT_Data.lpDvc + WT_Data.dvcOffset.main + 24 )
// main data item set is 36 bytes long. X is first of set of variable items.
if dvcData && PK_X then WT_Data.dvcOffset.x = offset : inc offset, 16
if dvcData && PK_Y then WT_Data.dvcOffset.y = offset : inc offset, 16
if dvcData && PK_Z then WT_Data.dvcOffset.z = offset : inc offset, 16
if (dvcData && PK_NORMAL_PRESSURE) <> 0 then WT_Data.dvcOffset.npressure = offset : inc offset, 16
if (dvcData && PK_TANGENT_PRESSURE) <> 0 then WT_Data.dvcOffset.tpressure = offset : inc offset, 16
if (dvcData && PK_ORIENTATION) <> 0 then WT_Data.dvcOffset.orientation = offset : inc offset, 48
if (dvcData && PK_ROTATION) <> 0 then WT_Data.dvcOffset.rotation = offset : inc offset, 48
// last item, PNPId, always present. @NOTE: Mine's blank... lol?
WT_Data.dvcOffset.pnpid = offset
// keep hold of dvcData.
WT_Data.dvcData = dvcData
endfunction
function WT_GetDeviceInfoDataAddress(dvcDataItem as dword)
local addr as dword = 0
local offset = 0
local dvcData as dword
dvcData = WT_Data.dvcData
// check data item is valid.
if not dvcData && dvcDataItem then exitfunction 0
// start with device base address.
addr = WT_Data.lpDvc
select dvcDataItem
case DVC_NAME : offset = 0 : endcase
case DVC_HARDWARE : offset = WT_Data.dvcOffset.main : endcase
case DVC_NCSRTYPES : offset = WT_Data.dvcOffset.main + 4 : endcase
case DVC_FIRSTCSR : offset = WT_Data.dvcOffset.main + 8 : endcase
case DVC_PKTRATE : offset = WT_Data.dvcOffset.main + 12 : endcase
case DVC_PKTDATA : offset = WT_Data.dvcOffset.main + 16 : endcase
case DVC_PKTMODE : offset = WT_Data.dvcOffset.main + 20 : endcase
case DVC_CSRDATA : offset = WT_Data.dvcOffset.main + 24 : endcase
case DVC_XMARGIN : offset = WT_Data.dvcOffset.main + 28 : endcase
case DVC_YMARGIN : offset = WT_Data.dvcOffset.main + 32 : endcase
case DVC_ZMARGIN : offset = WT_Data.dvcOffset.main + 36 : endcase
case DVC_X : offset = WT_Data.dvcOffset.x : endcase
case DVC_Y : offset = WT_Data.dvcOffset.y : endcase
case DVC_Z : offset = WT_Data.dvcOffset.z : endcase
case DVC_NPRESSURE : offset = WT_Data.dvcOffset.npressure : endcase
case DVC_TPRESSURE : offset = WT_Data.dvcOffset.tpressure : endcase
case DVC_ORIENTATION : offset = WT_Data.dvcOffset.orientation : endcase
case DVC_ROTATION : offset = WT_Data.dvcOffset.rotation : endcase
case DVC_PNPID : offset = WT_Data.dvcOffset.pnpid : endcase
endselect
// add offset to device base address.
addr = addr + offset
endfunction addr
// 16:16 (16 bits to left and to right of binary point)
// @FIXME: almost correct, but imprecise/truncated (eg. 12345.8642 -> 12345.9)
function FIX32_To_Float(fixed as dword)
local floating as float
major = fixed >> 16 && 0x0000FFFF
minor = fixed && 0x0000FFFF
floating = major + (minor*1.0)/(2.0^16)
// floating = fixed / (2^15) //(2^16-1)
endfunction floating
function Float_To_FIX32(floating as float)
local fixed as dword
fixed = Round(floating * (2.0^16))
endfunction fixed
function Round(f as float)
i = int(f+f) - int(f)
endfunction i
function WT_GetAxisData(in as tyWT_Axis, addr as dword)
in.axMin = peek integer(addr)
in.axMax = peek integer(addr + 4)
in.axUnits = peek integer(addr + 8)
in.axResolution = FIX32_To_Float( peek dword(addr + 12) )
arg = argGetFirst()
arg = argSetUDT(arg, addressOfInteger(in.axMin), "tyWT_Axis")
endfunction
// WT Constants. ----------------------------------------------------------------
// type constants (same as M1Utils array type return, for consistency, just in case).
// @NOTE: not currently using.
#constant TYPE_INTEGER 0
#constant TYPE_FLOAT 1
#constant TYPE_STRING 2
#constant TYPE_BOOLEAN 3
#constant TYPE_BYTE 4
#constant TYPE_WORD 5
#constant TYPE_DWORD 6
#constant TYPE_DOUBLEFLOAT 7
#constant TYPE_DOUBLEINTEGER 8
#constant TYPE_UDT 9
#constant WTI_INTERFACE 1
#constant WTI_STATUS 2
#constant WTI_DEFCONTEXT 3
#constant WTI_DEFSYSCTX 4
#constant WTI_DDCTXS 400 ` 1.1
#constant WTI_DSCTXS 500 ` 1.1
#constant WTI_DEVICES 100
#constant WTI_CURSORS 200
#constant WTI_EXTENSIONS 300
// wti_interface
#constant IFC_WINTABID 1
#constant IFC_SPECVERSION 2
#constant IFC_IMPLVERSION 3
#constant IFC_NDEVICES 4
#constant IFC_NCURSORS 5
#constant IFC_NCONTEXTS 6
#constant IFC_CTXOPTIONS 7
#constant IFC_CTXSAVESIZE 8
#constant IFC_NEXTENSIONS 9
#constant IFC_NMANAGERS 10
#constant IFC_MAX 10
// wti_status
#constant STA_CONTEXTS 1
#constant STA_SYSCTXS 2
#constant STA_PKTRATE 3
#constant STA_PKTDATA 4
#constant STA_MANAGERS 5
#constant STA_SYSTEM 6
#constant STA_BUTTONUSE 7
#constant STA_SYSBTNUSE 8
#constant STA_MAX 8
// context
#constant LC_NAMELEN 40
#constant CTX_NAME 1
#constant CTX_OPTIONS 2
#constant CTX_STATUS 3
#constant CTX_LOCKS 4
#constant CTX_MSGBASE 5
#constant CTX_DEVICE 6
#constant CTX_PKTRATE 7
#constant CTX_PKTDATA 8
#constant CTX_PKTMODE 9
#constant CTX_MOVEMASK 10
#constant CTX_BTNDNMASK 11
#constant CTX_BTNUPMASK 12
#constant CTX_INORGX 13
#constant CTX_INORGY 14
#constant CTX_INORGZ 15
#constant CTX_INEXTX 16
#constant CTX_INEXTY 17
#constant CTX_INEXTZ 18
#constant CTX_OUTORGX 19
#constant CTX_OUTORGY 20
#constant CTX_OUTORGZ 21
#constant CTX_OUTEXTX 22
#constant CTX_OUTEXTY 23
#constant CTX_OUTEXTZ 24
#constant CTX_SENSX 25
#constant CTX_SENSY 26
#constant CTX_SENSZ 27
#constant CTX_SYSMODE 28
#constant CTX_SYSORGX 29
#constant CTX_SYSORGY 30
#constant CTX_SYSEXTX 31
#constant CTX_SYSEXTY 32
#constant CTX_SYSSENSX 33
#constant CTX_SYSSENSY 34
#constant CTX_MAX 34
// WTI_DEVICES
// global DVC_NAMELEN as integer
#constant DVC_NAME 1 `tchar[]
#constant DVC_HARDWARE 2 `uint
#constant DVC_NCSRTYPES 3 `uint
#constant DVC_FIRSTCSR 4 `uint
#constant DVC_PKTRATE 5 `uint
#constant DVC_PKTDATA 6 `wtpkt
#constant DVC_PKTMODE 7 `wtpkt
#constant DVC_CSRDATA 8 `wtpkt
#constant DVC_XMARGIN 9 `int
#constant DVC_YMARGIN 10 `int
#constant DVC_ZMARGIN 11 `int
#constant DVC_X 12 `axis (16 bytes)
#constant DVC_Y 13 `axis
#constant DVC_Z 14 `axis
#constant DVC_NPRESSURE 15 `axis
#constant DVC_TPRESSURE 16 `axis
#constant DVC_ORIENTATION 17 `axis[3]
#constant DVC_ROTATION 18 `axis[3] ` 1.1
#constant DVC_PNPID 19 `tchar[] ` 1.1
#constant DVC_MAX 19
// unit specifiers
#constant TU_NONE 0
#constant TU_INCHES 1
#constant TU_CENTIMETERS 2
#constant TU_CIRCLE 3
// hardware capabilities
#constant HWC_INTEGRATED 0x0001
#constant HWC_TOUCH 0x0002
#constant HWC_HARDPROX 0x0004
#constant HWC_PHYSID_CURSORS 0x0008 ` 1.1
// Offsets for context data (assumes LC_NAMELEN = 40). WTPKT, FIX32 and BOOL types are all 4 bytes big.
#constant CTXOFF_NAME 0 `tchar[LC_NAMELEN]
#constant CTXOFF_OPTIONS 40 `uint
#constant CTXOFF_STATUS 44 `uint
#constant CTXOFF_LOCKS 48 `uint
#constant CTXOFF_MSGBASE 52 `uint
#constant CTXOFF_DEVICE 56 `uint
#constant CTXOFF_PKTRATE 60 `uint
#constant CTXOFF_PKTDATA 64 `wtpkt
#constant CTXOFF_PKTMODE 68 `wtpkt
#constant CTXOFF_MOVEMASK 72 `wtpkt
#constant CTXOFF_BTNDNMASK 76 `dword
#constant CTXOFF_BTNUPMASK 80 `dword
#constant CTXOFF_INORGX 84 `long
#constant CTXOFF_INORGY 88 `long
#constant CTXOFF_INORGZ 92 `long
#constant CTXOFF_INEXTX 96 `long
#constant CTXOFF_INEXTY 100 `long
#constant CTXOFF_INEXTZ 104 `long
#constant CTXOFF_OUTORGX 108 `long
#constant CTXOFF_OUTORGY 112 `long
#constant CTXOFF_OUTORGZ 116 `long
#constant CTXOFF_OUTEXTX 120 `long
#constant CTXOFF_OUTEXTY 124 `long
#constant CTXOFF_OUTEXTZ 128 `long
#constant CTXOFF_SENSX 132 `fix32
#constant CTXOFF_SENSY 136 `fix32
#constant CTXOFF_SENSZ 140 `fix32
#constant CTXOFF_SYSMODE 144 `bool
#constant CTXOFF_SYSORGX 148 `int
#constant CTXOFF_SYSORGY 152 `int
#constant CTXOFF_SYSEXTX 156 `int
#constant CTXOFF_SYSEXTY 160 `int
#constant CTXOFF_SYSSENSX 164 `fix32
#constant CTXOFF_SYSSENSY 168 `fix32
// cursor
#constant CSR_NAME 1
#constant CSR_ACTIVE 2
#constant CSR_PKTDATA 3
#constant CSR_BUTTONS 4
#constant CSR_BUTTONBITS 5
#constant CSR_BTNNAMES 6
#constant CSR_BUTTONMAP 7
#constant CSR_SYSBTNMAP 8
#constant CSR_NPBUTTON 9
#constant CSR_NPBTNMARKS 10
#constant CSR_NPRESPONSE 11
#constant CSR_TPBUTTON 12
#constant CSR_TPBTNMARKS 13
#constant CSR_TPRESPONSE 14
#constant CSR_PHYSID 15 ` 1.1
#constant CSR_MODE 16 ` 1.1
#constant CSR_MINPKTDATA 17 ` 1.1
#constant CSR_MINBUTTONS 18 ` 1.1
#constant CSR_CAPABILITIES 19 ` 1.1
#constant CSR_TYPE 20
#constant CSR_MAX 20
// cursor capabilities
#constant CRC_MULTIMODE 0x0001 ` 1.1
#constant CRC_AGGREGATE 0x0002 ` 1.1
#constant CRC_INVERT 0x0004 ` 1.1
// wti_extensions
#constant EXT_NAME 1
#constant EXT_TAG 2
#constant EXT_MASK 3
#constant EXT_SIZE 4
#constant EXT_AXES 5
#constant EXT_DEFAULT 6
#constant EXT_DEFCONTEXT 7
#constant EXT_DEFSYSCTX 8
#constant EXT_CURSORS 9
#constant EXT_MAX 109 ` Allow 100 cursors
// WTPKT bits
#constant PK_CONTEXT 0x0001 ` /* reporting context */
#constant PK_STATUS 0x0002 ` /* status bits */
#constant PK_TIME 0x0004 ` /* time stamp */
#constant PK_CHANGED 0x0008 ` /* change bit vector */
#constant PK_SERIAL_NUMBER 0x0010 ` /* packet serial number */
#constant PK_CURSOR 0x0020 ` /* reporting cursor */
#constant PK_BUTTONS 0x0040 ` /* button information */
#constant PK_X 0x0080 ` /* x axis */
#constant PK_Y 0x0100 ` /* y axis */
#constant PK_Z 0x0200 ` /* z axis */
#constant PK_NORMAL_PRESSURE 0x0400 ` /* normal or tip pressure */
#constant PK_TANGENT_PRESSURE 0x0800 ` /* tangential or barrel pressure */
#constant PK_ORIENTATION 0x1000 ` /* orientation info: tilts */
#constant PK_ROTATION 0x2000 ` /* rotation info; 1.1 */
// packet status values
#constant TPS_PROXIMITY 0x0001
#constant TPS_QUEUE_ERR 0x0002
#constant TPS_MARGIN 0x0004
#constant TPS_GRAB 0x0008
#constant TPS_INVERT 0x0010 ` 1.1
// relative buttons
#constant TBN_NONE 0
#constant TBN_UP 1
#constant TBN_DOWN 2
// context option values.
#constant CXO_SYSTEM 0x0001
#constant CXO_PEN 0x0002
#constant CXO_MESSAGES 0x0004
#constant CXO_MARGIN 0x8000
#constant CXO_MGNINSIDE 0x4000
#constant CXO_CSRMESSAGES 0x0008 ` 1.1
// context status values.
#constant CXS_DISABLED 0x0001
#constant CXS_OBSCURED 0x0002
#constant CXS_ONTOP 0x0004
// context lock values.
#constant CXL_INSIZE 0x0001
#constant CXL_INASPECT 0x0002
#constant CXL_SENSITIVITY 0x0004
#constant CXL_MARGIN 0x0008
#constant CXL_SYSOUT 0x0010
// WT WNDPROC Message Offsets (eg. lcMsgBase + WT_PACKET).
#constant WT_PACKET 0
#constant WT_CTXOPEN 1
#constant WT_CTXCLOSE 2
#constant WT_CTXUPDATE 3
#constant WT_CTXOVERLAP 4
#constant WT_PROXIMITY 5
#constant WT_INFOCHANGE 6
#constant WT_CSRCHANGE 7 ` 1.1
#constant WT_MAX 0xF
Long Example - now includes a very basic painting mode.
#include ArgLib_Include.dba
argInit()
// basic types.
type tyPoint2d x, y endtype
type tyRect x, y, w, h endtype
type tyBound x1, y1, x2, y2 endtype
// prepare program. -------------------------------------------------------------------------------------------------------------------------------------------
type tyApp
hWnd as dword
wndNCRect as tyRect
wndCLRect as tyRect
user32DLL as byte
enumMonitor
vScr as tyBound
penPos as tyPoint2d
penPressure as float
endtype
global app as tyApp
app.hWnd = get dbpro window()
app.user32DLL = find free dll()
load dll "User32", app.user32DLL
// Set WndProc callback to receive tablet event info.
set message callback "WndProc"
// Include Wintab functions and constants. @NOTE: "Correct" way is to include under project, which I think means you'll need to wrap type declarations etc. in a gosub.
#include WT_Include.dba
// window setup.
set window on : set window layout 1,1,1
position window app.hWnd, 32, 24
set display mode 1280, 768, 32, 1
set window client size 1280, 768
set text font "courier new":set text size 14
// System Metrics values.
global SM_CYCAPTION : SM_CYCAPTION = call dll(app.user32DLL, "GetSystemMetrics", 4)
global SM_CXSIZEFRAME : SM_CXSIZEFRAME = call dll(app.user32DLL, "GetSystemMetrics", 32)
global SM_CYSIZEFRAME : SM_CYSIZEFRAME = call dll(app.user32DLL, "GetSystemMetrics", 33)
global SM_CMONITORS
// get information about monitors and virtual screen.
type tyMonitor
hMonitor as dword
Name as string
isPrimary as boolean
pos as tyBound
endtype
#constant MAXMONITORS 16
dim Monitor(MAXMONITORS) as tyMonitor
GetMonitorInfo()
app.vScr = Monitor(0).pos
// display monitor info.
print " -- Monitors --"
print SM_CMONITORS, " monitor(s) connected."
print "# origin pos extent pos is Primary?"
hMon$ = "vScrn"
for n = 0 to SM_CMONITORS
if n > 0 then hMon$ = padleft$(hex$(Monitor(n).hMonitor), 5)
print n, " - ", hMon$, ": ", padright$("[" + str$(Monitor(n).pos.x1) + "," + str$(Monitor(n).pos.y1) + "]", 12), padright$("[" + str$(Monitor(n).pos.x2) + "," + str$(Monitor(n).pos.y2) + "]", 12), " ", Monitor(n).isPrimary
next n
print
// BEGIN.
print " -- Wintab --"
print "Starting Wintab... ";
err = WT_InitWintab(app.hWnd)
// close if failed.
if err = 0
print
print "Wintab failed to start."
print "You need a compatible Wintab32.dll to run this program."
print "Press key to exit..."
nice wait key
end
endif
print "Wintab started. Version: ", WT_GetWintabVersion()
print
// PREPARE.
// some information...
nDevices = WT_GetNumDevices()
if nDevices = 0
print "Note: no tablet connected."
else
print nDevices, " tablet(s) connected."
endif
print
// Get device details.
err = WT_GetDevice()
Axis as tyWT_Axis
dvcData as dword
dvcData = WT_GetDeviceSupportedData()
print "--DEVICE--"
set text to bold : print "Supports: ", CtxPktDataString(dvcData) : set text to normal
print "Name: ", WT_Get_DvcName()
print "Hardware: ", DvcHardwareString(WT_Get_DvcHardware())
print "NCsrTypes: ", WT_Get_DvcNCsrTypes()
print "FirstCsr: ", WT_Get_DvcFirstCsr()
print "PktRate: ", WT_Get_DvcPktRate(), " hz"
print "PktData: ", CtxPktDataString(WT_Get_DvcPktData())
print "PktMode: ", CtxPktModeString(WT_Get_DvcPktMode())
print "CsrData: ", CtxPktDataString(WT_Get_DvcCsrData())
print "Margins: [", WT_Get_DvcXMargin(), ", ", WT_Get_DvcYMargin(), ", ", WT_Get_DvcZMargin(), "]"
if dvcData && PK_X
WT_Get_DvcX(Axis)
print "X: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
else : remstart print "X: n/a" remend : endif
if dvcData && PK_Y
WT_Get_DvcY(Axis)
print "Y: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
else : remstart print "Y: n/a" remend : endif
if dvcData && PK_Z
WT_Get_DvcZ(Axis)
print "Z: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
else : remstart print "Z: n/a" remend : endif
if dvcData && PK_NORMAL_PRESSURE
WT_Get_DvcNPressure(Axis)
print "NPressure: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
else : remstart print "NPressure: n/a" remend : endif
if dvcData && PK_TANGENT_PRESSURE
WT_Get_DvcTPressure(Axis)
print "TPressure: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
else : remstart print "TPressure: n/a" remend : endif
if dvcData && PK_ORIENTATION
WT_Get_DvcAzimuth(Axis)
print "Azimuth: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
WT_Get_DvcAltitude(Axis)
print "Altitude: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
WT_Get_DvcTwist(Axis)
print "Twist: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
else : remstart print "Azimuth: n/a" : print "Altitude: n/a" : print "Twist: n/a" remend : endif
if dvcData && PK_ROTATION
WT_Get_DvcPitch(Axis)
print "Pitch: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
WT_Get_DvcRoll(Axis)
print "Roll: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
WT_Get_DvcYaw(Axis)
print "Yaw: ", Axis.axMin, ", ", Axis.axMax, ", ", AxisUnitsString(Axis.axUnits), ", ", Axis.axResolution
else : remstart print "Pitch: n/a" : print "Roll: n/a" : print "Yaw: n/a" remend : endif
print "PNPId: ", WT_Get_DvcPNPId()
print
// configure context details before opening.
// give this context a name. @NOTE: seems safe and inconsequential...
WT_Set_CtxName("MyContext")
// we want the tablet to: control the windows mouse cursor; send WNDPROC messages; have a margin; and send cursor messages (this last is an i-dunno-just-in-case thing).
WT_Set_CtxOptions(CXO_SYSTEM || CXO_MESSAGES || CXO_MARGIN || CXO_MGNINSIDE || CXO_CSRMESSAGES)
// we want packets to contain all possible data, including timestamp, position and pressure information.
// @FIX: currently you'll only know about unsupported items when packet results are broken. For now you must manually ensure you don't specify items your device won't return.
WT_Set_CtxPktData(PK_CONTEXT || PK_STATUS || PK_TIME || PK_CHANGED || PK_SERIAL_NUMBER || PK_CURSOR || PK_BUTTONS || PK_X || PK_Y || PK_Z || PK_NORMAL_PRESSURE || PK_TANGENT_PRESSURE || PK_ORIENTATION || PK_ROTATION)
// limit packets to what device can support.
WT_Set_CtxPktData(WT_Get_CtxPktData() && WT_GetDeviceSupportedData())
// open context (but don't start sending packets yet).
print "Opening WT Context... ";
err = WT_OpenContext(0)
// close if failed.
if err = 0
print
print "Failed to open context."
print "Press key to exit..."
nice wait key
end
endif
// get data of new *active* state (overwriting our copy of *desired* state data), and display. may help spot discrepancies and system incompatibility for some features.
WT_GetCurrentContext()
print "Context (handle ", WT_Data.hCtx, ") opened."
print "Name: ", WT_Get_CtxName()
print "Options: ", CtxOptionsString(WT_Get_CtxOptions())
print "Status: ", CtxStatusString(WT_Get_CtxStatus())
print "Locks: ", CtxLocksString(WT_Get_CtxLocks())
print "MsgBase: ", hex$(WT_Get_CtxMsgBase())
print "Device: ", WT_Get_CtxDevice()
print "PktRate: ", WT_Get_CtxPktRate(), " hz"
print "PktData: ", CtxPktDataString(WT_Get_CtxPktData())
print "pktMode: ", CtxPktModeString(WT_Get_CtxPktMode())
print "MoveMask: ", CtxMoveMaskString(WT_Get_CtxMoveMask())
print "BtnDnMask: ", CtxBtnMaskString(WT_Get_CtxBtnDnMask())
print "BtnUpMask: ", CtxBtnMaskString(WT_Get_CtxBtnUpMask())
print "In: Origin[", WT_Get_CtxInOrgX(), ", ", WT_Get_CtxInOrgY(), ", ", WT_Get_CtxInOrgZ(), "] Extent[", WT_Get_CtxInExtX(), ", ", WT_Get_CtxInExtY(), ", ", WT_Get_CtxInExtZ(), "]"
print "Out: Origin[", WT_Get_CtxOutOrgX(), ", ", WT_Get_CtxOutOrgY(), ", ", WT_Get_CtxOutOrgZ(), "] Extent[", WT_Get_CtxOutExtX(), ", ", WT_Get_CtxOutExtY(), ", ", WT_Get_CtxOutExtZ(), "]"
print "Sens: ", WT_Get_CtxSensX(), ", ", WT_Get_CtxSensY(), ", ", WT_Get_CtxSensZ()
print "Sys: Origin[", WT_Get_CtxSysOrgX(), ", ", WT_Get_CtxSysOrgY(), "] Extent[", WT_Get_CtxSysExtX(), ", ", WT_Get_CtxSysExtY(), "]"
print "SysSens: ", WT_Get_CtxSysSensX(), ", ", WT_Get_CtxSysSensY()
print
// Inform WT of virtual screen.
WT_SetDisplay(app.vScr)
print "Ready, Press Key..."
wait 1 : nice wait key
// INTERACTIVE STAGE. -----------------------------------------------------------------------------------------------------------------------------------------
sync on : sync rate 0 : sync
create bitmap 1, screen width(), screen height() : set current bitmap 0 // for painting.
// start receiving WT packets.
WT_EnablePackets(1)
// Main Loop.
do
// update window pos/size info.
app.wndNCRect.x = get window position x()
app.wndNCRect.y = get window position y()
app.wndNCRect.w = get window width()
app.wndNCRect.h = get window height()
app.wndCLRect.x = app.wndNCRect.x + SM_CXSIZEFRAME
app.wndCLRect.y = app.wndNCRect.y + SM_CYCAPTION + SM_CYSIZEFRAME
app.wndCLRect.w = get window client width()
app.wndCLRect.h = get window client height()
// draw painted bitmap.
copy bitmap 1, 0
// get info out of a tablet packet and clean up remainder.
numPkts = WT_GetPackets(100)
`WT_FlushPackets(100)
if numPkts > 0
for iPkt = 0 to numPkts - 1
app.penPos.x = WT_Get_PktX(iPkt, 0) - app.wndCLRect.x
app.penPos.y = WT_Get_PktY(iPkt, 0) - app.wndCLRect.y
app.penPressure = WT_Get_PktNPressure(iPkt, 0)
// feedback.
line app.penPos.x-2, app.penPos.y, app.penPos.x+2, app.penPos.y
line app.penPos.x, app.penPos.y-2, app.penPos.x, app.penPos.y+2
if painting
set current bitmap 1
fill circle app.penPos.x, app.penPos.y, 64.0 * app.penPressure^2, set alpha(0xFFFFFF * (1-shiftkey()), 0xFF * app.penPressure)
set current bitmap 0
else
circle app.penPos.x, app.penPos.y, 64.0 * app.penPressure
endif
text app.penPos.x, app.penPos.y-15, str$(iPkt)
next iPkt
else
// defer to mouse.
app.penPos.x = mousex()
app.penPos.y = mousey()
app.penPressure = 0
// feedback.
line app.penPos.x-2, app.penPos.y, app.penPos.x+2, app.penPos.y
line app.penPos.x, app.penPos.y-2, app.penPos.x, app.penPos.y+2
endif
// control.
if lower$(inkey$()) = "t" then slowLoop = 1 - slowLoop : nice wait no key
if lower$(inkey$()) = "p" then painting = 1 - painting : nice wait no key
if keystate(211) then set current bitmap 1 : cls 0x000000 : set current bitmap 0 : nice wait no key
// debug.
print "T: toggle slow loop, P: toggle painting mode (hold shift: erase, del: blank)"
print "numPkts: ", numPkts
iPkt = numPkts - 1
print "Raw WT Pkt Data: pos[", WT_Get_PktX(iPkt, 1), ", ", WT_Get_PktY(iPkt, 1), "], npressure: ", WT_Get_PktNPressure(iPkt, 1)
print "Transformed WT Pkt Data: pos[", WT_Get_PktX(iPkt, 0), ", ", WT_Get_PktY(iPkt, 0), "], npressure: ", WT_Get_PktNPressure(iPkt, 0)
print "App Pen: pos[", app.penPos.x, ", ", app.penPos.y, "], npressure: ", app.penPressure
if WT_Data.dvcData && PK_ORIENTATION then print "Orientation: [", WT_Get_PktAzimuth(iPkt), ", ", WT_Get_PktAltitude(iPkt), ", ", WT_Get_PktTwist(iPkt), "]" else print "Orientation: n/a"
if WT_Data.dvcData && PK_ROTATION then print "Rotation: [", WT_Get_PktPitch(iPkt), ", ", WT_Get_PktRoll(iPkt), ", ", WT_Get_PktYaw(iPkt), "]" else print "Rotation: n/a"
print "FPS: ", screen fps()
// end of loop.
sync : cls 0 : nice wait 15 + 285*slowLoop
loop
// stop.
end
rem end
// Function block. --------------------------------------------------------------------------------------------------------------------------------------------
// display versions. @NOTE: Migrate into WT_Include, or keep optional?
function CtxOptionsString(in as dword)
local out as string
if in && CXO_SYSTEM then out = out + "CXO_SYSTEM "
if in && CXO_PEN then out = out + "CXO_PEN "
if in && CXO_MESSAGES then out = out + "CXO_MESSAGES "
if in && CXO_MARGIN then out = out + "CXO_MARGIN "
if in && CXO_MGNINSIDE then out = out + "CXO_MGNINSIDE "
if in && CXO_CSRMESSAGES then out = out + "CXO_CSRMESSAGES "
out = out + " "
endfunction out
function CtxStatusString(in as dword)
local out as string
if in && CXS_DISABLED then out = out + "CXS_DISABLED "
if in && CXS_OBSCURED then out = out + "CXS_OBSCURED "
if in && CXS_ONTOP then out = out + "CXS_ONTOP "
out = out + " "
endfunction out
function CtxLocksString(in as dword)
local out as string
if in && CXL_INSIZE then out = out + "CXL_INSIZE "
if in && CXL_INASPECT then out = out + "CXL_INASPECT "
if in && CXL_SENSITIVITY then out = out + "CXL_SENSITIVITY "
if in && CXL_MARGIN then out = out + "CXL_MARGIN "
if in && CXL_SYSOUT then out = out + "CXL_SYSOUT "
out = out + " "
endfunction out
function CtxPktDataString(in as dword)
local out as string
if in && PK_CONTEXT then out = out + "PK_CONTEXT "
if in && PK_STATUS then out = out + "PK_STATUS "
if in && PK_TIME then out = out + "PK_TIME "
if in && PK_CHANGED then out = out + "PK_CHANGED "
if in && PK_SERIAL_NUMBER then out = out + "PK_SERIAL_NUMBER "
if in && PK_CURSOR then out = out + "PK_CURSOR "
if in && PK_BUTTONS then out = out + "PK_BUTTONS "
if in && PK_X then out = out + "PK_X "
if in && PK_Y then out = out + "PK_Y "
if in && PK_Z then out = out + "PK_Z "
if in && PK_NORMAL_PRESSURE then out = out + "PK_NORMAL_PRESSURE "
if in && PK_TANGENT_PRESSURE then out = out + "PK_TANGENT_PRESSURE "
if in && PK_ORIENTATION then out = out + "PK_ORIENTATION "
if in && PK_ROTATION then out = out + "PK_ROTATION "
out = out + " "
endfunction out
function CtxPktModeString(in as dword)
local out as string
if in && PK_CONTEXT then out = out + "Rel " else out = out + "Abs "
if in && PK_STATUS then out = out + "Rel " else out = out + "Abs "
if in && PK_TIME then out = out + "Rel " else out = out + "Abs "
if in && PK_CHANGED then out = out + "Rel " else out = out + "Abs "
if in && PK_SERIAL_NUMBER then out = out + "Rel " else out = out + "Abs "
if in && PK_CURSOR then out = out + "Rel " else out = out + "Abs "
if in && PK_BUTTONS then out = out + "Rel " else out = out + "Abs "
if in && PK_X then out = out + "Rel " else out = out + "Abs "
if in && PK_Y then out = out + "Rel " else out = out + "Abs "
if in && PK_Z then out = out + "Rel " else out = out + "Abs "
if in && PK_NORMAL_PRESSURE then out = out + "Rel " else out = out + "Abs "
if in && PK_TANGENT_PRESSURE then out = out + "Rel " else out = out + "Abs "
if in && PK_ORIENTATION then out = out + "Rel " else out = out + "Abs "
if in && PK_ROTATION then out = out + "Rel " else out = out + "Abs "
endfunction out
function CtxMoveMaskString(in as dword)
local out as string
if in && PK_CONTEXT then out = out + "Y " else out = out + "N "
if in && PK_STATUS then out = out + "Y " else out = out + "N "
if in && PK_TIME then out = out + "Y " else out = out + "N "
if in && PK_CHANGED then out = out + "Y " else out = out + "N "
if in && PK_SERIAL_NUMBER then out = out + "Y " else out = out + "N "
if in && PK_CURSOR then out = out + "Y " else out = out + "N "
if in && PK_BUTTONS then out = out + "Y " else out = out + "N "
if in && PK_X then out = out + "Y " else out = out + "N "
if in && PK_Y then out = out + "Y " else out = out + "N "
if in && PK_Z then out = out + "Y " else out = out + "N "
if in && PK_NORMAL_PRESSURE then out = out + "Y " else out = out + "N "
if in && PK_TANGENT_PRESSURE then out = out + "Y " else out = out + "N "
if in && PK_ORIENTATION then out = out + "Y " else out = out + "N "
if in && PK_ROTATION then out = out + "Y " else out = out + "N "
endfunction out
function CtxBtnMaskString(in as dword)
local bin as string
local out as string
bin = right$(bin$(in), 32)
for n = 1 to 32 step 4
out = out + mid$(bin, n, 4) + " "
next n
endfunction out
function DvcHardwareString(in as dword)
local out as string = ""
if in && HWC_INTEGRATED then out = out + "HWC_INTEGRATED "
if in && HWC_TOUCH then out = out + "HWC_TOUCH "
if in && HWC_HARDPROX then out = out + "HWC_HARDPROX "
if in && HWC_PHYSID_CURSORS then out = out + "HWC_PHYSID_CURSORS "
endfunction out
function AxisUnitsString(in as dword)
local out as string = ""
out = str$(in)
if in = TU_NONE then out = "generic units"
if in = TU_INCHES then out = "inches"
if in = TU_CENTIMETERS then out = "cm"
if in = TU_CIRCLE then out = "circle units"
endfunction out
rem start
function WndProc(hWnd as dword, msg as dword, wParam as dword, lParam as dword)
`print "WndProc: ", hWnd, " - ", msg, " - ", wParam, " - ", lParam
select msg
// WM_A, WM_B, WM_C... all your standard message checks.
// WT messages do not have fixed values; will use a nested select.
case default
select msg - WT_Data.msgBase
case WT_PACKET
// packet data available.
endcase
case WT_CTXOPEN
// context opened.
endcase
case WT_CTXCLOSE
// context about to close.
endcase
case WT_CTXUPDATE
// context has changed.
endcase
case WT_CTXOVERLAP
// context has changed order.
endcase
case WT_PROXIMITY
// cursor entered/left proximity.
endcase
case WT_INFOCHANGE
// tablet plugged in or unplugged.
endcase
case WT_CSRCHANGE
// a cursor has entered context.
endcase
endselect
endcase
endselect
endfunction
// -- MONITOR FUNCTIONS --
function GetMonitorInfo()
local lpMI as dword
local flags as dword
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd144901%28v=vs.85%29.aspx
lpMI = alloc(72)
poke dword lpMI, 72
// how many monitors?
SM_CMONITORS = call dll(1, "GetSystemMetrics", 80)
// get info through user32. http://msdn.microsoft.com/en-us/library/windows/desktop/dd162610%28v=vs.85%29.aspx
app.enumMonitor = 1
err = call dll(app.user32DLL, "EnumDisplayMonitors", 0, 0, get ptr to function("MonitorEnumProc"), 0)
// fill in some additional details.
for n = 1 to SM_CMONITORS
err = call dll(1, "GetMonitorInfoA", Monitor(n).hMonitor, lpMI)
if err
flags = peek dword(lpMI + 36)
Monitor(n).isPrimary = flags && 0x1
Monitor(n).Name = peek string( lpmi + 40, 32)
endif
next n
endfunction
function MonitorEnumProc(hMonitor as dword, hdcMonitor as dword, lprcMonitor as double integer, dwData as dword)
Monitor(app.enumMonitor).hMonitor = hMonitor
Monitor(app.enumMonitor).pos.x1 = peek integer(lprcMonitor + 0 )
Monitor(app.enumMonitor).pos.y1 = peek integer(lprcMonitor + 4 )
Monitor(app.enumMonitor).pos.x2 = peek integer(lprcMonitor + 8 )
Monitor(app.enumMonitor).pos.y2 = peek integer(lprcMonitor + 12)
if Monitor(app.enumMonitor).pos.x1 < Monitor(0).pos.x1 then Monitor(0).pos.x1 = Monitor(app.enumMonitor).pos.x1
if Monitor(app.enumMonitor).pos.y1 < Monitor(0).pos.y1 then Monitor(0).pos.y1 = Monitor(app.enumMonitor).pos.y1
if Monitor(app.enumMonitor).pos.x2 > Monitor(0).pos.x2 then Monitor(0).pos.x2 = Monitor(app.enumMonitor).pos.x2
if Monitor(app.enumMonitor).pos.y2 > Monitor(0).pos.y2 then Monitor(0).pos.y2 = Monitor(app.enumMonitor).pos.y2
inc app.enumMonitor
continue = app.enumMonitor <= SM_CMONITORS
endfunction continue
rem end
Short Example
No changes, except at the top:
#include ArgLib_Include.dba
argInit()
.