touch tablet

Share your advanced PureBasic knowledge/code with the community.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

touch tablet

Post by blueznl »

Code: Select all

; 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.
;
;
; 
IncludeFile("x_lib.pb")
;
x_init()
;
; 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
;
main_nr.l = x_nr()
main_whnd.l = OpenWindow(main_nr,300,350,400,200,#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget,"Test")
;
wt_nr.l = x_nr()
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 = IsFunction(wt_nr,"WTInfoA")
WTOpen = IsFunction(wt_nr,"WTOpenA")
WTPacketsGet = IsFunction(wt_nr,"WTPacketsGet")
WTClose = IsFunction(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 = EventWindowID()                    ; 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(WindowOutput())
    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
  ;
Until done = #True
;
CallFunctionFast(WTClose,tablet_hctx)                      ; close and destroy
CloseLibrary(wintab_nr)
;
x_hidedebugger()
x_end()

( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Karbon
PureBasic Expert
PureBasic Expert
Posts: 2010
Joined: Mon Jun 02, 2003 1:42 am
Location: Ashland, KY
Contact:

Post by Karbon »

Very nice!
-Mitchell
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
Skipsy
User
User
Posts: 98
Joined: Wed Apr 30, 2003 12:26 pm
Location: France

Post by Skipsy »

Oups...

Problem when compiling...
It says "Only a litteral string can be put after'includefile' "
at line : IncludeFile("x_lib.pb")

Where am I supposed to find "x_lib.pb" ?

WW
Beware of the man who has the solution before he understands the problem...
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

oooooooops

well, you can take it from the survival guide (it's part of the zip file on my page), or take all calls to the lib out

i only use x_nr iirc, and that function just returns some unique numbers
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Skipsy
User
User
Posts: 98
Joined: Wed Apr 30, 2003 12:26 pm
Location: France

Post by Skipsy »

Hi,

I have had to download PB 3.8 upgrade.
Now compiling is OK but application crashes :
"PureBasic6992985 has encounter a problem and must close"
" Do you want to send report to Microsoft bla, bla..."

I have also tried with debug ON... same message.... sorry

Tested on Dell C640 Windows XP SP1 256 MO ram
marvin
User
User
Posts: 35
Joined: Sun Jul 18, 2004 1:43 am

[quote]I've just discovered this and I like it's potential[/

Post by marvin »

[/quote] ;
; 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
;SetFrameRate(100)
StartDrawing(WindowOutput())

;Changed this
DrawingMode(1)
;If pressure_old > 0 ; erase old circle
;Circle(mousex_old+mousex,mousey_old+mousey,pressure_old/10,RGB(0,0,0))
;EndIf
;If pressure > 0 ; tablet was used
Circle(mousex,mousey,pressure/60,RGB(255,255,0))
;EndIf
;mousex_old = mousex
;mousey_old = mousey
;pressure_old = pressure
;StopDrawing()
;EndIf

I changed the drawing mode and made it able to leave a drawing trail.
I need help in making a continous line with it. Like what it is suppose to do, instead I only got it to draw dots that don't connect when I move the pen too fast.

Can someone help me here?

Thanks
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

did you ever get it working?
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
marvin
User
User
Posts: 35
Joined: Sun Jul 18, 2004 1:43 am

Post by marvin »

blueznl, not sure if this question is for me but, If you are asking me, the answer is yes! I searched and found this procedure. Added it to your code to get a continuous line along with pressure line thickness control.

Procedure Lin(x,y,x1,y1,Gros,Color)
hDC=GetDC_(WindowID())
pen=CreatePen_(#Ps_Solid,GROS,color)
hPenOld=SelectObject_(hDC,pen)
MoveToEx_(hDC,x,y,0):LineTo_(hDC,x1,y1)
DeleteObject_(pen)
DeleteObject_(hPenOld)
EndProcedure
It was implemented here.
If mousex<>mousex_old Or mousey<>mousey_old Or pressure <> pressure_old
;SetFrameRate(100)
StartDrawing(WindowOutput())
DrawingMode(0)

If pressure > 0 ; tablet was used

lin(mousex_old,mousey_old,mousex,mousey,pressure/30,RGB(Random(25),Random(5),#red))

EndIf
mousex_old = mousex
mousey_old = mousey
pressure_old = pressure
StopDrawing()
EndIf
haven't yet work out the bugs but it works like intended.

Thanks bluenl, even if you weren't pertaining to my issue.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

no prob, it was indeed your message i was refering to
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
zxtunes.com
Enthusiast
Enthusiast
Posts: 375
Joined: Wed Apr 23, 2008 7:51 am
Location: Saint-Petersburg, Russia
Contact:

Re: touch tablet

Post by zxtunes.com »

Update for PB 4.5 and remove x_lib , i tested this, it work fine.
Thank you blueznl!! :D

WINTAB32.dll: http://zenratai.com/software/stereopain ... NTAB32.dll

Code: Select all

; 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
;
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)
;
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(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
  ;
Until done = #True
;
CallFunctionFast(WTClose,tablet_hctx)                      ; close and destroy
CloseLibrary(wintab_nr)

Post Reply