Code : Tout sélectionner
; purebasic survival guide
; touch_tablet - 11.11.2003 ejn (blueznl)
; http://www.xs4all.nl/~bluez/datatalk/pure1.htm
;
; - using a touch tablet in purebasic
; - references to pages / tables refer to a word document by lcs/telegraphics:
;
; wintab interface specification 1.0
; 16- and 32-bit api reference by Rick Poyner
; revised december 13, 1994
;
; - use google, the doc above is NOT part of the wintab sdk (duh!) but is on their site
; - to do: disable tablet context when window is not in focus
; - to do: handle pen vs. lmb issues (pen can generate lmb message at pressure 0, timing is all...)
; - to do: tilt detection (wacom) etc.
;
;
;
;
; wanna' have a message to notify the mouse leaving the window? use the trackmouseevent_() function
; here's the structure and the constants we might need later (uncomment when needed)
;
; Structure tagTRACKMOUSEEVENT
; cbSize.l
; dwFlags.l
; hwndTrack.l
; dwHoverTime.l
; EndStructure
; #TME_LEAVE = 2
;
#WM_MOUSELEAVE = $2A3
;
;
; *** wintab constants and structures
;
; device configuration constants (ch5.7.1 p21)
;
#WTDC_NONE = 0
#WTDC_CANCEL = 1
#WTDC_OK = 2
#WTDC_RESTART = 3
;
; message constants (ch6 p34)
;
#WT_DEFBASE = $7FF0
#WT_MAXOFFSET = $F
#WT_MAX = $7FFF ; aka wt_defbase + wt_maxoffset
Enumeration #WT_DEFBASE
#WT_PACKET
#WT_CTXOPEN
#WT_CTXCLOSE
#WT_CTXUPDATE
#WT_CTXOVERLAP
#WT_PROXIMITY
#WT_INFOCHANGE
#WT_CSRCHANGE
EndEnumeration
;
; packet constants (t7.1 p38)
;
#PK_CONTEXT = $1 ; context
#PK_STATUS = $2 ; status bits
#PK_TIME = $4 ; time stamp
#PK_CHANGED = $8 ; change bit vector
#PK_SERIAL_NUMBER = $10 ; packet serial number
#PK_CURSOR = $20 ; reporting cursor
#PK_BUTTONS = $40 ; button information
#PK_X = $80 ; x-axis
#PK_Y = $100 ; y-axis
#PK_Z = $200 ; z-axis
#PK_NORMAL_PRESSURE = $400 ; normal or tip pressure
#PK_TANGENT_PRESSURE = $800 ; tangential or barrel pressure
#PK_ORIENTATION = $1000 ; orientation info / tilts
#PK_ROTATION = $2000
;
; unit specifiers (t7.2)
;
#TU_NONE = 0
#TU_INCHES = 1
#TU_CENTIMETERS = 2
#TU_CIRCLE = 3
;
; wti category definitions (t7.3)
;
#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
;
; wti_interface index definitions (t7.4)
;
#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
#IFC_MAX = 10
;
; wti_status index definitions (t7.5)
;
#STA_CONTEXTS = 1
#STA_SYSCTXS = 2
#STA_PKTRATE = 3
#STA_PKTDATA = 4
#STA_MANAGERS = 5
#STA_SYSTEM = 6
#STA_BUTTONUSE = 7
#STA_SYSBTNUSE = 8
#STA_MAX = 8
;
; wti_defcontext / wti_defsysctx index definitions (t7.6)
;
#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
#CTX_MAX = 34
;
; wti_devices index definitions (t7.7)
;
#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
#DVC_MAX = 19
;
; dvc_hardware hardware capabilities (t7.7)
;
#HWC_INTEGRATED = $1
#HWC_TOUCH = $2
#HWC_HARDPROX = $4
#HWC_PHYSID_CURSORS = $8
;
; wti_cursors (t7.8)
;
#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_MAX = 19
;
; wti_extensions (t7.9)
;
#EXT_NAME = 1
#EXT_TAG = 2
#EXT_MASK = 3
#EXT_SIZE = 4
#EXT_AXES = 5
#EXT_DEFAULT = 6
#EXT_DEFCONTEXT = 7
#EXT_DEFSYSCTX = 8
#EXT_CURSORS = 9
#EXT_MAX = 109
;
; system button assignment values (t7.10)
;
#SBN_NONE = $0
#SBN_LCLICK = $1
#SBN_LDBLCLICK = $2
#SBN_LDRAG = $3
#SBN_RCLICK = $4
#SBN_RDBLCLICK = $5
#SBN_RDRAG = $6
#SBN_MCLICK = $7
#SBN_MDBLCLICK = $8
#SBN_MDRAG = $9
;
; pen windows assignments (t7.10)
;
#SBN_PTCLICK = $10
#SBN_PTDBLCLICK = $20
#SBN_PTDRAG = $30
#SBN_PNCLICK = $40
#SBN_PNDBLCLICK = $50
#SBN_PNDRAG = $60
#SBN_P1CLICK = $70
#SBN_P1DBLCLICK = $80
#SBN_P1DRAG = $90
#SBN_P2CLICK = $A0
#SBN_P2DBLCLICK = $B0
#SBN_P2DRAG = $C0
#SBN_P3CLICK = $D0
#SBN_P3DBLCLICK = $E0
#SBN_P3DRAG = $F0
;
; context option values (t7.11)
;
#CXO_SYSTEM = $1
#CXO_PEN = $2
#CXO_MESSAGES = $4
#CXO_MARGIN = $8000
#CXO_MGNINSIDE = $4000
;
; context status values (t.12)
;
#CXS_DISABLED = $1
#CXS_OBSCURED = $2
#CXS_ONTOP = $4
;
; context lock condition values (t7.13)
;
#CXL_INSIZE = $1
#CXL_INASPECT = $2
#CXL_SENSITIVITY = $4
#CXL_MARGIN = $8
#CXL_SYSOUT = $10
;
; relative buttons (t7.13)
;
#TBN_NONE = 0
#TBN_UP = 1
#TBN_DOWN = 2
;
; packet status values (t7.14)
;
#TPS_PROXIMITY = $1
#TPS_QUEUE_ERR = $2
#TPS_MARGIN = $4
#TPS_GRAB = $8
#TPS_INVERT = $10
;
; hook constants
;
#WTH_PLAYBACK = 1
#WTH_RECORD = 2
#WTHC_GETLPLPFN = (-3)
#WTHC_LPLPFNNEXT = (-2)
#WTHC_LPFNNEXT = (-1)
#WTHC_ACTION = 0
#WTHC_GETNEXT = 1
#WTHC_SKIP = 2
;
; cursor capabilities
;
#CRC_MULTIMODE = $1
#CRC_AGGREGATE = $2
#CRC_INVERT = $4
;
Structure tagLOGCONTEXT ; (ch7.3.1 p47)
lcName.b[40] ; name
lcOptions.l ; options (see t7.11)
lcStatus.l ; current status (see t7.12)
lcLocks.l ; locked conditions (see t7.13)
lcMsgBase.l ; range of message numbers (see ch6)
lcDevice.l ; device
lcPktRate.l ; packet report rate in hz (n per sec)
lcPktData.l ; optional data to report (?)
lcPktMode.l ; bit per option, 1 = relative, 0 = absolute
lcMoveMask.l ; specify packet data items that generate move events
lcBtnDnMask.l ; specify buttons that generate button events
lcBtnUpMask.l ; (p48)
lcInOrgX.l ; xyz origin on input (tablet)
lcInOrgY.l
lcInOrgZ.l
lcInExtX.l ; xyz range on input (tablet)
lcInExtY.l
lcInExtZ.l
lcOutOrgX.l ; xyz origin on output (dc?)
lcOutOrgY.l
lcOutOrgZ.l
lcOutExtX.l ; xyz range on output
lcOutExtY.l
lcOutExtZ.l
lcSensX.l ; sensitivity in relative mode
lcSensY.l
lcSensZ.l
lcSysMode.l ; system cursor tracking mode (0 = absolute) (p49)
lcSysOrgX.l ; origin of screen mapping are for system cursor tracking in screen coordinates
lcSysOrgY.l
lcSysExtX.l
lcSysExtY.l
lcSysSensX.l ; system cursor relative mode sensitivity
lcSysSensY.l
EndStructure
;
Structure tagAXIS
axMin.l
axMax.l
axUnits.l
axResolution.l ; fix32, float = fix32 / 65536
EndStructure
;
;
; enough declarations that are not used... now, let's open a window and do some stuff
;
InitSprite()
main_nr.l = 777
main_whnd.l = OpenWindow(main_nr,300,350,400,200,"Test", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget)
;
;OpenWindowedScreen(WindowID(main_nr),0,0, 640, 480, 1, 0, 0)
;CreateSprite(0,640,480)
Global Texte$= "Hello"
;UseBuffer(0)
wt_nr.l = 778
OpenLibrary(wt_nr,"WINTAB32.dll")
;
;
; the following is nice if you want to list all the stuff in a library
; (has nothing to do with this example though :-))
;
; Debug ExamineLibraryFunctions(wt_nr)
; While NextLibraryFunction()<>0
; Debug LibraryFunctionName()
; Debug LibraryFunctionAddress()
; Wend
;
;
; find functions in the wintab32 dll (there's a lot more but i haven't declared all)
;
WTInfo = GetFunction(wt_nr,"WTInfoA")
WTOpen = GetFunction(wt_nr,"WTOpenA")
WTPacketsGet = GetFunction(wt_nr,"WTPacketsGet")
WTClose = GetFunction(wt_nr,"WTClose")
;
; get size of the largest possible reply from WTInfo, can also be used to check existence of a tablet
;
; buffer_l.l = CallFunctionFast(WTInfo,0,0,0)
;
; set up a context for wt_WTOpen
;
; notes:
;
; still gotta' play a little with this, there are some interesting things possible
; and some things don't behave as i would expect :-(
; the context is not automatically updated after screen resizes
; as far as i can tell, this tablet / driver only supports ONE context at a time
; opening up multiple programs with tablet support does not go well
; setting up coords / corner points in the LOGCONTEXT might solve this if all programs do so (fat chance)
;
tablet_lc.tagLOGCONTEXT ; create context
;
; CallFunctionFast(WTInfo,#WTI_DEFCONTEXT,0,@tablet_lc) ; fill it with default values
CallFunctionFast(WTInfo,#WTI_DEFSYSCTX,0,@tablet_lc) ; fill it with default values
;
PokeS(@tablet_lc\lcName,"TEST_TABLET",39)
tablet_lc\lcOptions = tablet_lc\lcOptions | #CXO_MESSAGES ; options (see t7.11)
tablet_lc\lcMsgBase = #WT_DEFBASE ; base for message numbers (see ch6)
tablet_lc\lcPktData = #PK_X|#PK_Y|#PK_NORMAL_PRESSURE|#PK_BUTTONS ; data to report
tablet_lc\lcPktMode = 0 ; bit per option, 1 = relative, 0 = absolute
tablet_lc\lcMoveMask = tablet_lc\lcPktData ; specify packet data items that generate move events
tablet_lc\lcBtnDnMask = #SBN_LCLICK|#SBN_RCLICK|#SBN_LDBLCLICK ; specify buttons that generate button events
tablet_lc\lcBtnUpMask = tablet_lc\lcBtnDnMask ; (p48)
tablet_hctx = CallFunctionFast(WTOpen,main_whnd,@tablet_lc,1) ; open and enable it
;
Structure WT_PACKET ; (see p52) size and length of and fields in packet struct depend on options set
pkButtons.l
pkX.l
pkY.l
pkNormalPressure.l
EndStructure
;
packet.WT_PACKET
;
mouselmb.l = #False
done.l = #False
Repeat
;
; processing windows messages using waitevent() instead of callback
;
Event.l = WaitWindowEvent() ; wait for an event
Window.l = EventWindow() ; on which window?
;
Select Event
Case #WM_KEYDOWN
Debug "256 #WM_KEYDOWN key pressed"
event_parameter.l = EventwParam() ; undocumented / deprecated / windows only
Select event_parameter ; eventwparam() gets additional info on event
Case #VK_ESCAPE
done=#True
EndSelect
Case #PB_Event_CloseWindow
; Debug "16 #PB_Event_CloseWindow close window"
done = #True
Case #WM_MOUSEMOVE
; Debug "512 $200 #WM_MOUSEMOVE mouse moved over window"
;
; EventwParam() contains info on variuos virtual keys
; EventlParam() contains the cursor coords
;
; the implementation of mousecoordinates is somewhat fuzzy in purebasic, they are
; reported in relation to the upper left corner of the window, not of the client area
; using the EventlParam() field an accurate position can be retrieved
;
mousex.l = EventlParam() % 65536
mousey.l = EventlParam() / 65536
;
; if you want to use the build in commands, you have to compensate for the size
; of window borders etc.
;
; mousex.l = WindowMouseX()-GetSystemMetrics_(#SM_CYSIZEFRAME)
; mousey.l = WindowMouseY()-GetSystemMetrics_(#SM_CYCAPTION)-GetSystemMetrics_(#SM_CYSIZEFRAME)
;
; if you want To detect when the mouse leaves the window, you could set a TrackMouseEvent_()
;
; mouseleave.tagTRACKMOUSEEVENT
; mouseleave\cbSize = SizeOf(tagTRACKMOUSEEVENT)
; mouseleave\dwFlags = #TME_LEAVE
; mouseleave\hwndTrack = main_whnd
; TrackMouseEvent_(@mouseleave)
;
; when using SetCapture_() windows 'prefilters' messages, that is you won't receive
; messages unless another condition is met (virtual keys, mousebuttons, etc.)
; so you can't use SetCapture() to see if the cursor left the area with no button
; pressed
;
Case #WM_LBUTTONDOWN
;
; Debug "513 $201 #WM_LBUTTONDOWN lmb down"
;
mouselmb = #True
;
; if a mousebutton is pressed, and the cursor is moved outside the window client area
; no more messages will be received, including the WM_LBUTTONUP message
; to make sure such a message is received grab all messages until we got what we
; want
;
SetCapture_(main_whnd)
;
Case #WM_LBUTTONUP
;
; Debug "514 $202 #WM_LBUTTONUP lmb up"
;
mouselmb = #False
;
ReleaseCapture_()
;
Case #WM_MOUSELEAVE
;
Debug "675 $2A3WM_MOUSELEAVE mouse left window (after a trackmouseevent was used)"
;
; only generated after calling TrackMouseEvent_(), see #WM_MOUSEMOVE above
;
Default
;
; all other events
;
If Event >= #WT_DEFBASE And Event <= #WT_MAX
CallFunctionFast(WTPacketsGet,tablet_hctx,1,@packet)
;
; there's more information that can be retrieved from the tablet, depending on type etc.
; here i only look for pressure
;
pressure.l = packet\pkNormalPressure
EndIf
EndSelect
;
; only draw if something has changed
; moves a circle over the window, size depending on pressure, erased when moving
;
If mousex<>mousex_old Or mousey<>mousey_old Or pressure <> pressure_old
; StartDrawing(SpriteOutput(0))
; Box(0,0,640,480,RGB(125,125,125))
; DrawingMode(#PB_2DDrawing_Transparent)
; DrawText(mousex_old,mousey_old, "yooooooooooooooooooooooooooooooooooooooooooooo", #Red)
; mousex_old = mousex
; mousey_old = mousey
; StopDrawing()
StartDrawing(WindowOutput(main_nr))
DrawingMode(2)
If pressure_old > 0 ; erase old circle
Circle(mousex_old,mousey_old,pressure_old/10,RGB(0,0,0))
EndIf
If pressure > 0 ; tablet was used
Circle(mousex,mousey,pressure/10,RGB(0,0,0))
EndIf
mousex_old = mousex
mousey_old = mousey
pressure_old = pressure
StopDrawing()
EndIf
;FlipBuffers()
Until done = #True
;
CallFunctionFast(WTClose,tablet_hctx) ; close and destroy
CloseLibrary(wintab_nr)
.