Tk Source Code

Check-in [c1ca811f]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Use virtual events for touch. Removed <Touch>
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | pspjuth-touch
Files: files | file ages | folders
SHA1: c1ca811fbdb0fa949d4b1b6df57055d2428d1e5e
User & Date: pspjuth 2016-08-25 19:37:17
Context
2016-09-05
22:22
Merge from trunk check-in: 8a8fac1e user: pspjuth tags: pspjuth-touch
2016-08-25
19:37
Use virtual events for touch. Removed <Touch> check-in: c1ca811f user: pspjuth tags: pspjuth-touch
2016-08-13
19:53
Suppore pan options and pan inertia. Remade script API. check-in: bec7c299 user: pspjuth tags: pspjuth-touch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tk.h.

647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
 *----------------------------------------------------------------------
 */

#define VirtualEvent	    (MappingNotify + 1)
#define ActivateNotify	    (MappingNotify + 2)
#define DeactivateNotify    (MappingNotify + 3)
#define MouseWheelEvent     (MappingNotify + 4)
#define TouchEvent          (MappingNotify + 5)
#define TK_LASTEVENT	    (MappingNotify + 6)

#define MouseWheelMask	    (1L << 28)
#define ActivateMask	    (1L << 29)
#define VirtualEventMask    (1L << 30)
#define TouchEventMask      (1L << 31)

/*
 * A virtual event shares most of its fields with the XKeyEvent and
 * XButtonEvent structures. 99% of the time a virtual event will be an
 * abstraction of a key or button event, so this structure provides the most
 * information to the user. The only difference is the changing of the detail
 * field for a virtual event so that it holds the name of the virtual event







<
|




<







647
648
649
650
651
652
653

654
655
656
657
658

659
660
661
662
663
664
665
 *----------------------------------------------------------------------
 */

#define VirtualEvent	    (MappingNotify + 1)
#define ActivateNotify	    (MappingNotify + 2)
#define DeactivateNotify    (MappingNotify + 3)
#define MouseWheelEvent     (MappingNotify + 4)

#define TK_LASTEVENT	    (MappingNotify + 5)

#define MouseWheelMask	    (1L << 28)
#define ActivateMask	    (1L << 29)
#define VirtualEventMask    (1L << 30)


/*
 * A virtual event shares most of its fields with the XKeyEvent and
 * XButtonEvent structures. 99% of the time a virtual event will be an
 * abstraction of a key or button event, so this structure provides the most
 * information to the user. The only difference is the changing of the detail
 * field for a virtual event so that it holds the name of the virtual event

Changes to generic/tkBind.c.

439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
    {"Gravity",		GravityNotify,		StructureNotifyMask},
    {"Circulate",	CirculateNotify,	StructureNotifyMask},
    {"Property",	PropertyNotify,		PropertyChangeMask},
    {"Colormap",	ColormapNotify,		ColormapChangeMask},
    {"Activate",	ActivateNotify,		ActivateMask},
    {"Deactivate",	DeactivateNotify,	ActivateMask},
    {"MouseWheel",	MouseWheelEvent,	MouseWheelMask},
    {"Touch",		TouchEvent,		TouchEventMask},
    {"CirculateRequest", CirculateRequest,	SubstructureRedirectMask},
    {"ConfigureRequest", ConfigureRequest,	SubstructureRedirectMask},
    {"Create",		CreateNotify,		SubstructureNotifyMask},
    {"MapRequest",	MapRequest,		SubstructureRedirectMask},
    {"ResizeRequest",	ResizeRequest,		ResizeRedirectMask},
    {NULL,		0,			0}
};







<







439
440
441
442
443
444
445

446
447
448
449
450
451
452
    {"Gravity",		GravityNotify,		StructureNotifyMask},
    {"Circulate",	CirculateNotify,	StructureNotifyMask},
    {"Property",	PropertyNotify,		PropertyChangeMask},
    {"Colormap",	ColormapNotify,		ColormapChangeMask},
    {"Activate",	ActivateNotify,		ActivateMask},
    {"Deactivate",	DeactivateNotify,	ActivateMask},
    {"MouseWheel",	MouseWheelEvent,	MouseWheelMask},

    {"CirculateRequest", CirculateRequest,	SubstructureRedirectMask},
    {"ConfigureRequest", ConfigureRequest,	SubstructureRedirectMask},
    {"Create",		CreateNotify,		SubstructureNotifyMask},
    {"MapRequest",	MapRequest,		SubstructureRedirectMask},
    {"ResizeRequest",	ResizeRequest,		ResizeRedirectMask},
    {NULL,		0,			0}
};
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
   /* SelectionNotify */	0,
   /* ColormapNotify */		COLORMAP,
   /* ClientMessage */		0,
   /* MappingNotify */		0,
   /* VirtualEvent */		VIRTUAL,
   /* Activate */		ACTIVATE,
   /* Deactivate */		ACTIVATE,
   /* MouseWheel */		KEY,
   /* Touch */		        VIRTUAL
};

/*
 * The following table is used to map between the location where an generated
 * event should be queued and the string used to specify the location.
 */








|
<







522
523
524
525
526
527
528
529

530
531
532
533
534
535
536
   /* SelectionNotify */	0,
   /* ColormapNotify */		COLORMAP,
   /* ClientMessage */		0,
   /* MappingNotify */		0,
   /* VirtualEvent */		VIRTUAL,
   /* Activate */		ACTIVATE,
   /* Deactivate */		ACTIVATE,
   /* MouseWheel */		KEY

};

/*
 * The following table is used to map between the location where an generated
 * event should be queued and the string used to specify the location.
 */

Changes to generic/tkEvent.c.

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    0					/* Mapping Notify */
};

static const unsigned long virtualEventMasks[TK_LASTEVENT-VirtualEvent] = {
    VirtualEventMask,			/* VirtualEvents */
    ActivateMask,			/* ActivateNotify */
    ActivateMask,			/* DeactivateNotify */
    MouseWheelMask,			/* MouseWheelEvent */
    TouchEventMask			/* TouchEvent */
};

/*
 * For each exit handler created with a call to TkCreateExitHandler or
 * TkCreateThreadExitHandler there is a structure of the following type:
 */








|
<







114
115
116
117
118
119
120
121

122
123
124
125
126
127
128
    0					/* Mapping Notify */
};

static const unsigned long virtualEventMasks[TK_LASTEVENT-VirtualEvent] = {
    VirtualEventMask,			/* VirtualEvents */
    ActivateMask,			/* ActivateNotify */
    ActivateMask,			/* DeactivateNotify */
    MouseWheelMask			/* MouseWheelEvent */

};

/*
 * For each exit handler created with a call to TkCreateExitHandler or
 * TkCreateThreadExitHandler there is a structure of the following type:
 */

1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
	    ckfree(kePtr->charValuePtr);
	    kePtr->charValuePtr = NULL;
	    kePtr->charValueLen = 0;
	}
	break;
    }

    case TouchEvent:
    case VirtualEvent: {
	XVirtualEvent *vePtr = (XVirtualEvent *) eventPtr;

	if (vePtr->user_data != NULL) {
	    Tcl_DecrRefCount(vePtr->user_data);
	    vePtr->user_data = NULL;
	}







<







1787
1788
1789
1790
1791
1792
1793

1794
1795
1796
1797
1798
1799
1800
	    ckfree(kePtr->charValuePtr);
	    kePtr->charValuePtr = NULL;
	    kePtr->charValueLen = 0;
	}
	break;
    }


    case VirtualEvent: {
	XVirtualEvent *vePtr = (XVirtualEvent *) eventPtr;

	if (vePtr->user_data != NULL) {
	    Tcl_DecrRefCount(vePtr->user_data);
	    vePtr->user_data = NULL;
	}

Changes to win/tkWinX.c.

883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
    sInput.y = rooty;
    cInput = sInput;
    ScreenToClient(hwnd, &cInput);

    tkwin = Tk_HWNDToWindow(hwnd);
    winPtr = (TkWindow *)tkwin;
    memset(event, 0, sizeof(*event));
    event->xany.type = TouchEvent;
    event->xany.serial =
	LastKnownRequestProcessed(winPtr->display);
    event->xany.send_event = False;
    event->xany.window = Tk_WindowId(tkwin);
    event->xany.display = winPtr->display;
    event->xkey.root =
	RootWindow(winPtr->display,winPtr->screenNum);







|







883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
    sInput.y = rooty;
    cInput = sInput;
    ScreenToClient(hwnd, &cInput);

    tkwin = Tk_HWNDToWindow(hwnd);
    winPtr = (TkWindow *)tkwin;
    memset(event, 0, sizeof(*event));
    event->xany.type = VirtualEvent;
    event->xany.serial =
	LastKnownRequestProcessed(winPtr->display);
    event->xany.send_event = False;
    event->xany.window = Tk_WindowId(tkwin);
    event->xany.display = winPtr->display;
    event->xkey.root =
	RootWindow(winPtr->display,winPtr->screenNum);
952
953
954
955
956
957
958

959
960
961

962
963
964

965
966
967
968
969
970
971
		/* Touch ID */
		ADD_DICT_INT(dictPtr, "id", ti.dwID);
		/* Raw flags value */
		ADD_DICT_INT(dictPtr, "flags", ti.dwFlags);
		/* Decode known flags */
		if (ti.dwFlags & TOUCHEVENTF_MOVE) {
		    ADD_DICT_INT(dictPtr, "move", 1);

		}
		if (ti.dwFlags & TOUCHEVENTF_DOWN) {
		    ADD_DICT_INT(dictPtr, "down", 1);

		}
		if (ti.dwFlags & TOUCHEVENTF_UP) {
		    ADD_DICT_INT(dictPtr, "up", 1);

		}
		if (ti.dwFlags & TOUCHEVENTF_INRANGE) {
		    ADD_DICT_INT(dictPtr, "inrange", 1);
		}
		if (ti.dwFlags & TOUCHEVENTF_PRIMARY) {
		    ADD_DICT_INT(dictPtr, "primary", 1);
		}







>



>



>







952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
		/* Touch ID */
		ADD_DICT_INT(dictPtr, "id", ti.dwID);
		/* Raw flags value */
		ADD_DICT_INT(dictPtr, "flags", ti.dwFlags);
		/* Decode known flags */
		if (ti.dwFlags & TOUCHEVENTF_MOVE) {
		    ADD_DICT_INT(dictPtr, "move", 1);
		    event.virtual.name = Tk_GetUid("FingerMotion");
		}
		if (ti.dwFlags & TOUCHEVENTF_DOWN) {
		    ADD_DICT_INT(dictPtr, "down", 1);
		    event.virtual.name = Tk_GetUid("FingerDown");
		}
		if (ti.dwFlags & TOUCHEVENTF_UP) {
		    ADD_DICT_INT(dictPtr, "up", 1);
		    event.virtual.name = Tk_GetUid("FingerUp");
		}
		if (ti.dwFlags & TOUCHEVENTF_INRANGE) {
		    ADD_DICT_INT(dictPtr, "inrange", 1);
		}
		if (ti.dwFlags & TOUCHEVENTF_PRIMARY) {
		    ADD_DICT_INT(dictPtr, "primary", 1);
		}
1042
1043
1044
1045
1046
1047
1048

1049
1050
1051
1052
1053
1054
1055
	/* A gesture was not recognized */
	return 0;
    }

    POINTSTOPOINT(sLoc, gi.ptsLocation);
    
    InitTouchEvent(&event.general, hwnd, sLoc.x, sLoc.y);

    dictPtr = Tcl_NewDictObj();
    Tcl_IncrRefCount(dictPtr);
    /* Identify as a gesture event */
    ADD_DICT_STR(dictPtr, "event", "gesture");
    /* Raw flags value */
    ADD_DICT_INT(dictPtr, "flags", gi.dwFlags);
    /* Decode known flags */







>







1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
	/* A gesture was not recognized */
	return 0;
    }

    POINTSTOPOINT(sLoc, gi.ptsLocation);
    
    InitTouchEvent(&event.general, hwnd, sLoc.x, sLoc.y);
    event.virtual.name = Tk_GetUid("Gesture");
    dictPtr = Tcl_NewDictObj();
    Tcl_IncrRefCount(dictPtr);
    /* Identify as a gesture event */
    ADD_DICT_STR(dictPtr, "event", "gesture");
    /* Raw flags value */
    ADD_DICT_INT(dictPtr, "flags", gi.dwFlags);
    /* Decode known flags */
1065
1066
1067
1068
1069
1070
1071

1072
1073
1074
1075
1076
1077
1078
    
    LInt = (UINT) (gi.ullArguments & 0xFFFFFFFF);
    HInt = (UINT) (gi.ullArguments >> 32);
    switch (gi.dwID){
    case GID_ZOOM:
	ADD_DICT_STR(dictPtr, "gesture", "zoom");
	ADD_DICT_WIDE(dictPtr, "distance", gi.ullArguments);

	break;
    case GID_PAN:
	ADD_DICT_STR(dictPtr, "gesture", "pan");
	ADD_DICT_WIDE(dictPtr, "distance", LInt);
	if (gi.dwFlags & GF_INERTIA) {
	    pts = MAKEPOINTS(HInt);
	    ADD_DICT_INT(dictPtr, "inertiax", pts.x);







>







1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
    
    LInt = (UINT) (gi.ullArguments & 0xFFFFFFFF);
    HInt = (UINT) (gi.ullArguments >> 32);
    switch (gi.dwID){
    case GID_ZOOM:
	ADD_DICT_STR(dictPtr, "gesture", "zoom");
	ADD_DICT_WIDE(dictPtr, "distance", gi.ullArguments);
	event.virtual.name = Tk_GetUid("PinchToZoom");
	break;
    case GID_PAN:
	ADD_DICT_STR(dictPtr, "gesture", "pan");
	ADD_DICT_WIDE(dictPtr, "distance", LInt);
	if (gi.dwFlags & GF_INERTIA) {
	    pts = MAKEPOINTS(HInt);
	    ADD_DICT_INT(dictPtr, "inertiax", pts.x);

Changes to win/touch.tcl.

25
26
27
28
29
30
31
32
33
34



35
36
37
38
39
40
41
    To get raw touch events:
    If any of the flags -touch, -fine or -wantpalm is given,
    the window is registered to receive raw touch event.
    It will no longer receive any gesture events.
    The flags -fine/-wantpalm corresponds to the Windows API
    RegisterTouchWindow.

    Events are received as <Touch> events.
    These events support at least base %W %x %y %X %Y fields.
    All extra information is given in a dictionary in the %d field.




    Any boolean field in the dictionary is either present with
    the value 1 or not present. Below they are written without a value.

    Touch fields:
    event = touch : Identify event as a touch. (i.e. not a gesture)
    id <val> : Id to know what events belong to the same touch.







|


>
>
>







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    To get raw touch events:
    If any of the flags -touch, -fine or -wantpalm is given,
    the window is registered to receive raw touch event.
    It will no longer receive any gesture events.
    The flags -fine/-wantpalm corresponds to the Windows API
    RegisterTouchWindow.

    Events are received as virtual events.
    These events support at least base %W %x %y %X %Y fields.
    All extra information is given in a dictionary in the %d field.
    <<FingerDown>> <<FingerUp>> <<FingerMotion>> : Raw touch events
    <<PinchToZoom>> : Zoom gesture
    <<Gesture>>     : Other gestures

    Any boolean field in the dictionary is either present with
    the value 1 or not present. Below they are written without a value.

    Touch fields:
    event = touch : Identify event as a touch. (i.e. not a gesture)
    id <val> : Id to know what events belong to the same touch.
65
66
67
68
69
70
71

72
73
74
75
76
77
78
    
    distance <i> : For zoom/pan/twofingertap: Distance between fingers.
    angle <r> : For rotate: Rotation angle in radians.
    deltax <i> : For pressandtap: Locates second finger. Valid with begin.
    deltay <i> : For pressandtap: Locates second finger. Valid with begin.
    inertiax <i> : For pan: Inertia vector. Valid with inertia flag.
    inertiay <i> : For pan: Inertia vector. Valid with inertia flag.

}

namespace import tcl::mathop::*

proc rndCol {} {
    set lst {orange yellow green cyan blue purple violet pink}
    set i [expr {int(rand()*[llength $lst])}]







>







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    
    distance <i> : For zoom/pan/twofingertap: Distance between fingers.
    angle <r> : For rotate: Rotation angle in radians.
    deltax <i> : For pressandtap: Locates second finger. Valid with begin.
    deltay <i> : For pressandtap: Locates second finger. Valid with begin.
    inertiax <i> : For pan: Inertia vector. Valid with inertia flag.
    inertiay <i> : For pan: Inertia vector. Valid with inertia flag.

}

namespace import tcl::mathop::*

proc rndCol {} {
    set lst {orange yellow green cyan blue purple violet pink}
    set i [expr {int(rand()*[llength $lst])}]
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

200

201

202


                    -fill orange -outline black -width 2 -tags rotate \
                    -start $a -extent 40
        }
    }
    Log $W $d
}

#console show
set ::size [expr {[winfo screenwidth .] / 4}]
canvas .c1 -width $::size -height $::size -bd 3 -relief solid
canvas .c2 -width $::size -height $::size -bd 3 -relief solid
canvas .c3 -width $::size -height $::size -bd 3 -relief solid
.c1 create text [expr {$::size /2}] [expr {$::size /2}] -text Touch
lappend ::messages "Gesture"
.c2 create text [expr {$::size / 2}] [expr {$::size / 2}] -text GestureAll -tags gesture
.c3 create text [expr {$::size / 2}] [expr {$::size / 2}] -text Gesture -tags gesture

grid .c1 -   -sticky news
grid .c2 .c3 -sticky news
grid columnconfigure . all -weight 1
grid rowconfigure . all -weight 1
wm touch .c1 -touch
wm touch .c2 -all
wm touch .c3 -pan 1 -pansfv 0 -pansfh 0 -pangutter 0 -paninertia 0

bind .c1 <Touch> "Touch1 %W %d %x %y %X %Y"

bind .c2 <Touch> "Touch2 %W %d %x %y %X %Y"

bind .c3 <Touch> "Touch2 %W %d %x %y %X %Y"









|
















>
|
>
|
>
|
>
>
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
                    -fill orange -outline black -width 2 -tags rotate \
                    -start $a -extent 40
        }
    }
    Log $W $d
}

console show
set ::size [expr {[winfo screenwidth .] / 4}]
canvas .c1 -width $::size -height $::size -bd 3 -relief solid
canvas .c2 -width $::size -height $::size -bd 3 -relief solid
canvas .c3 -width $::size -height $::size -bd 3 -relief solid
.c1 create text [expr {$::size /2}] [expr {$::size /2}] -text Touch
lappend ::messages "Gesture"
.c2 create text [expr {$::size / 2}] [expr {$::size / 2}] -text GestureAll -tags gesture
.c3 create text [expr {$::size / 2}] [expr {$::size / 2}] -text Gesture -tags gesture

grid .c1 -   -sticky news
grid .c2 .c3 -sticky news
grid columnconfigure . all -weight 1
grid rowconfigure . all -weight 1
wm touch .c1 -touch
wm touch .c2 -all
wm touch .c3 -pan 1 -pansfv 0 -pansfh 0 -pangutter 0 -paninertia 0
bind .c1 <<FingerDown>> "Touch1 %W %d %x %y %X %Y"
bind .c1 <<FingerUp>> "Touch1 %W %d %x %y %X %Y"
bind .c1 <<FingerMotion>> "Touch1 %W %d %x %y %X %Y"
bind .c2 <<Gesture>> "Touch2 %W %d %x %y %X %Y"
bind .c2 <<PinchToZoom>> "Touch2 %W %d %x %y %X %Y"
bind .c3 <<Gesture>> "Touch2 %W %d %x %y %X %Y"
bind .c3 <<PinchToZoom>> "Touch2 %W %d %x %y %X %Y"