This repository has been archived by the owner on Jul 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathindex.html
838 lines (796 loc) · 48.6 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
<!DOCTYPE html>
<html lang="en">
<head>
<title>Touch Events - Level 2</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta content="width=device-width" name="viewport"><!--
=== NOTA BENE ===
For the three scripts below, if your spec resides on dev.w3 you can check them
out in the same tree and use relative links so that they'll work offline,
-->
<script class="remove" defer src="https://www.w3.org/Tools/respec/respec-w3c">
</script>
<script class="remove">
var respecConfig = {
// specification status (e.g. WD, LC, NOTE, etc.). If in doubt use ED.
specStatus: "CG-FINAL",
// the specification's short name, as in http://www.w3.org/TR/short-name/
shortName: "touch-events",
// if your specification has a subtitle that goes below the main
// formal title, define it here
// subtitle : "an excellent document",
// if you wish the publication date to be other than today, set this
publishDate: "2024-07-04",
// if the specification's copyright date is a range of years, specify
// the start date here:
// copyrightStart: "2005"
// if there is a previously published draft, uncomment this and set its YYYY-MM-DD date
// and its maturity status
previousPublishDate: "2013-10-10",
previousMaturity: "REC",
// if there a publicly available Editor's Draft, this is the link
edDraftURI: "https://w3c.github.io/touch-events/",
license: "w3c-software-doc",
// latest version for CG Final
latestVersion: "https://www.w3.org/community/reports/touchevents/CG-FINAL-touch-events-20240704/",
// if this is a LCWD, uncomment and set the end of its review period
// lcEnd: "2013-02-14",
// prEnd: "2013-06-06",
// editors, add as many as you like
// only "name" is required
editors: [
{ name: "Doug Schepers", url: "http://schepers.cc/",
company: "W3C", companyURL: "https://w3.org/" },
{ name: "Sangwhan Moon",
company: "Opera Software ASA", companyURL: "https://www.opera.com/" },
{ name: "Matt Brubeck", url: "https://limpet.net/mbrubeck/",
company: "Mozilla", companyURL: "https://www.mozilla.org/" },
{ name: "Arthur Barstow",
company: "Invited Expert", companyURL: "https://twitter.com/afbarstow" },
{ name: "Rick Byers", url: "https://rbyers.net/",
company: "Google", companyURL: "https://www.google.com/" },
{ name: "Patrick H. Lauke",
company: "TetraLogical", companyURL: "https://tetralogical.com/" },
],
otherLinks: [{
key: 'Repository',
data: [{
value: 'We are on Github.',
href: 'https://github.com/w3c/touch-events'
}, {
value: 'File a bug.',
href: 'https://github.com/w3c/touch-events/issues'
}, {
value: 'Commit history.',
href: 'https://github.com/w3c/touch-events/commits/gh-pages'
}, {
value: 'Mailing list.',
href: 'https://lists.w3.org/Archives/Public/public-touchevents/'
}]
}],
// authors, add as many as you like.
// This is optional, uncomment if you have authors as well as editors.
// only "name" is required. Same format as editors.
//authors: [
// { name: "Your Name", url: "http://example.org/",
// company: "Your Company", companyURL: "http://example.com/" },
//],
// Name of the group
group: "touchevents",
// URI of the patent status for this WG, for Rec-track documents
// !!!! IMPORTANT !!!!
// This is important for Rec-track documents, do not copy a patent URI from a random
// document unless you know what you're doing. If in doubt ask your friendly neighbourhood
// Team Contact.
// wgPatentURI: "http://www.w3.org/2004/01/pp-impl/45559/status",
// Enables automatic linking
xref: ["html", "dom", "infra", "uievents"]
};
</script>
<script id="fixuphook">
(function () {
// Hacky fix-up hook to patch up return types generated by respec.js, as special
// operations like the ones in specialOps are not officially supported.
var specialOps = ['getter ', 'setter ', 'creator ', 'deleter ', 'caller ', 'omittable '];
var fixUpCaller = window.setInterval(function() {
// Check if respec.js is done.
var respecJS = document.querySelectorAll(".remove");
if (respecJS.length > 0) return;
else
{
// Performance-wise, this is a stupid idea. For long specs it's probably
// going to take a *extremely* long time to finish. You have been warned.
var tags = document.getElementsByTagName('a');
for (var i = 0; i < tags.length; i++)
for (var j = 0; j < specialOps.length; j++)
if (tags[i].textContent.indexOf(specialOps[j]) === 0 &&
tags[i].parentNode.previousSibling.textContent.indexOf('Return type:') !== -1)
tags[i].textContent = tags[i].textContent.substring(specialOps[j].length - 1);
// Clean-up script element and interval caller
var fixUpEl = document.getElementById('fixuphook');
fixUpEl.parentNode.removeChild(fixUpEl);
window.clearInterval(fixUpCaller);
}
}, 100);
})();
</script>
<style>
.event {
font-family: monospace;
color: #459900;
}
pre.idl {
white-space: pre-wrap;
}
.simple th[scope=row] a { color: inherit;}
</style>
</head>
<body>
<section id="sotd">
<p>This specification was published by the <a href="https://www.w3.org/community/touchevents/">Touch Events Community Group</a>. It is not a W3C Standard nor is it on the W3C Standards Track.</p>
<p>Please note that under the <a href="https://www.w3.org/community/about/process/final/">W3C Community Final Specification Agreement (FSA)</a> other conditions apply.</p>
<p>This version of the specification includes fixes and improvements to <a href="https://www.w3.org/TR/touch-events/">Touch Events Level 1</a>, and incorporates the features previously published as <a href="https://www.w3.org/TR/touch-events-extensions/">Touch Event Extensions</a>.</p>
<p class="note">There is currently no intention to carry on further work on the Touch Events specification. This document has been maintained up to this point to reflect additions and changes made in user agents since the release of the original <a href="https://www.w3.org/TR/touch-events/">Touch Events Level 1</a> specification. The Community Group considers Touch Events a legacy API – authors are strongly encouraged to adopt <a href="https://www.w3.org/TR/pointerevents/">Pointer Events</a> instead.</p>
</section>
<section id="abstract">
<p>The Touch Events specification defines a set of low-level events that represent one or more points of contact with a touch-sensitive surface, and changes of those points with respect to the surface and any DOM elements displayed upon it (e.g. for touch screens) or associated with it (e.g. for drawing tablets without displays). It also addresses pen-tablet devices, such as drawing tablets, with consideration toward stylus capabilities.</p>
</section>
<section class="informative" id="introduction">
<h2>Introduction</h2>
<p>User Agents that run on terminals which provide touch input to use web applications typically use interpreted mouse events to allow users to access interactive web applications. However, these interpreted events, being normalized data based on the physical touch input, tend to have limitations on delivering the intended user experience. Additionally, it is not possible to handle concurrent input regardless of device capability, due to constraints of mouse events: both system level limitations and legacy compatibility.</p>
<p>Meanwhile, native applications are capable of handling both cases with the provided system APIs.</p>
<p>The Touch Events specification provides a solution to this problem by specifying interfaces to allow web applications to directly handle touch events, and multiple touch points for capable devices.</p>
</section>
<section id="conformance">
<p>This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.</p>
<p>WindowProxy is defined in [[!HTML5]].</p>
<h3 id="webidl-conform">WebIDL Conformance</h3>
<p>The IDL blocks in this specification are conforming IDL fragments as defined by the WebIDL specification [[!WEBIDL]].</p>
<p>A conforming user agent must also be a <a href="https://webidl.spec.whatwg.org/#dfn-conforming-javascript-implementation">conforming JavaScript implementation</a> of this IDL fragments in this specification, with the following exception:</p>
<ul>
<li>
<a href="https://www.w3.org/TR/WebIDL/#es-attributes">section 4.4.6 of Web IDL</a> requires that IDL attributes are reflected as accessor properties on interface prototype objects. Instead of this, the user agent may reflect IDL attributes as data properties on the platform objects that implement the relevant interface. These data properties must have the same behavior when getting and setting as would be exhibited when invoking the getter and setter of the accessor properties on the platform object.
</li>
</ul>
<p><strong>Note:</strong> Both ways of reflecting IDL attributes allow for simply getting and setting the property on the platform object to work. For example, given a <code>Touch</code> object <code>aTouch</code>, evaluating <code>aTouch.target</code> would return the <code>EventTarget</code> for the <code>Touch</code> object. If the user agent implements IDL attributes as accessor properties, then the property access invokes the getter which returns the <code>EventTarget</code>. If the user agent implements IDL attributes as data properties on the platform object with the same behavior as would be found with the accessor properties, then the object would appear to have an own property named <code>target</code> whose value is an <code>EventTarget</code> object, and the property access would return this value.</p>
</section>
<section>
<h2><dfn>Touch</dfn> Interface</h2>
<p>This interface describes an individual <a>touch point</a> for a touch event. <a><code>Touch</code></a> objects are immutable; after one is created, its attributes must not change.</p>
<pre class="idl">
enum TouchType {
"direct",
"stylus"
};
dictionary TouchInit {
required long identifier;
required EventTarget target;
double clientX = 0;
double clientY = 0;
double screenX = 0;
double screenY = 0;
double pageX = 0;
double pageY = 0;
float radiusX = 0;
float radiusY = 0;
float rotationAngle = 0;
float force = 0;
double altitudeAngle = 0;
double azimuthAngle = 0;
TouchType touchType = "direct";
};
[Exposed=Window]
interface Touch {
constructor(TouchInit touchInitDict);
readonly attribute long identifier;
readonly attribute EventTarget target;
readonly attribute double screenX;
readonly attribute double screenY;
readonly attribute double clientX;
readonly attribute double clientY;
readonly attribute double pageX;
readonly attribute double pageY;
readonly attribute float radiusX;
readonly attribute float radiusY;
readonly attribute float rotationAngle;
readonly attribute float force;
readonly attribute float altitudeAngle;
readonly attribute float azimuthAngle;
readonly attribute TouchType touchType;
};
</pre>
<dl data-dfn-for="Touch" data-link-for="Touch">
<dt><dfn>identifier</dfn></dt>
<dd>
<p>An identification number for each <a>touch point</a>.</p>
<p>When a touch point becomes active, it must be assigned an <a>identifier</a> that is distinct from any other <a>active touch point</a>. While the touch point remains active, all events that refer to it must assign it the same <a>identifier</a>.</p>
</dd>
<dt><dfn>target</dfn></dt>
<dd>
<p>The <code>EventTarget</code> on which the <a>touch point</a> started when it was first placed on the surface, even if the <a>touch point</a> has since moved outside the interactive area of that element.</p>
<p class="note">Some implementations alter the target element to correct for the imprecision of coarse input. Therefore, the target element may not necessarily be the element directly at the coordinates of the event. The methods used to target/disambiguate coarse input are out of scope for this specification.</p>
</dd>
<dt><dfn>screenX</dfn></dt>
<dd>
<p>The horizontal coordinate of point relative to the screen in pixels</p>
</dd>
<dt><dfn>screenY</dfn></dt>
<dd>
<p>The vertical coordinate of point relative to the screen in pixels</p>
</dd>
<dt><dfn>clientX</dfn></dt>
<dd>
<p>The horizontal coordinate of point relative to the viewport in pixels, excluding any scroll offset</p>
</dd>
<dt><dfn>clientY</dfn></dt>
<dd>
<p>The vertical coordinate of point relative to the viewport in pixels, excluding any scroll offset</p>
</dd>
<dt><dfn>pageX</dfn></dt>
<dd>
<p>The horizontal coordinate of point relative to the viewport in pixels, including any scroll offset</p>
</dd>
<dt><dfn>pageY</dfn></dt>
<dd>
<p>The vertical coordinate of point relative to the viewport in pixels, including any scroll offset</p>
</dd>
<dt><dfn>radiusX</dfn></dt>
<dd>
<p>The radius of the ellipse which most closely circumscribes the touching area (e.g. finger, stylus) along the axis indicated by rotationAngle, in CSS pixels (as defined by [[!CSS-VALUES]]) of the same scale as screenX; <code>0</code> if no value is known. The value must not be negative.</p>
</dd>
<dt><dfn>radiusY</dfn></dt>
<dd>
<p>The radius of the ellipse which most closely circumscribes the touching area (e.g. finger, stylus) along the axis perpendicular to that indicated by rotationAngle, in CSS pixels (as defined by [[!CSS-VALUES]]) of the same scale as screenY; <code>0</code> if no value is known. The value must not be negative.</p>
</dd>
<dt><dfn>rotationAngle</dfn></dt>
<dd>
<p>The angle (in degrees) that the ellipse described by radiusX and radiusY is rotated clockwise about its center; <code>0</code> if no value is known. The value must be greater than or equal to <code>0</code> and less than <code>90</code>.</p>
<p>If the ellipse described by radiusX and radiusY is circular, then rotationAngle has no effect. The user agent may use <code>0</code> as the value in this case, or it may use any other value in the allowed range. (For example, the user agent may use the rotationAngle value from the previous touch event, to avoid sudden changes.)</p>
</dd>
<dt><dfn>force</dfn></dt>
<dd>
<p>A relative value of pressure applied, in the range <code>0</code> to <code>1</code>, where <code>0</code> is no pressure, and <code>1</code> is the highest level of pressure the touch device is capable of sensing; <code>0</code> if no value is known. In environments where force is known, the absolute pressure represented by the force attribute, and the sensitivity in levels of pressure, may vary.</p>
</dd>
<dt><dfn>altitudeAngle</dfn></dt>
<dd>
<p>The altitude (in radians) of the transducer (e.g. pen/stylus), in the range [0,π/2] — where 0 is parallel to the surface (X-Y plane), and π/2 is perpendicular to the surface. For hardware and platforms that do not report tilt or angle, the value MUST be 0.</p>
<div class="note">
The default value defined here for <code>altitudeAngle</code> is 0. This differs from the <a href="https://w3c.github.io/pointerevents/">Pointer Events - Level 3</a> [[POINTEREVENTS]] specification's definition for the <code>altitudeAngle</code> property, which has a default value of π/2, which positions the transducer as being perpendicular to the surface.
</div>
<figure id="figure_altitudeAngle">
<img alt="altitudeAngle explanation diagram" src="images/altitudeAngle.png">
<figcaption>
Example <code>altitudeAngle</code> of π/4 (45 degrees from the X-Y plane).
</figcaption>
</figure>
</dd>
<dt><dfn>azimuthAngle</dfn></dt>
<dd>
<p>The azimuth angle (in radians) of the transducer (e.g. pen/stylus), in the range [0, 2π] — where 0 represents a transducer whose cap is pointing in the direction of increasing X values (point to "3 o'clock" if looking straight down) on the X-Y plane, and the values progressively increase when going clockwise (π/2 at "6 o'clock", π at "9 o'clock", 3π/2 at "12 o'clock"). When the transducer is perfectly perpendicular to the surface (<code>altitudeAngle</code> of π/2), the value MUST be 0. For hardware and platforms that do not report tilt or angle, the value MUST be 0.</p>
<figure id="figure_azimuthAngle">
<img alt="azimuthAngle explanation diagram" src="images/azimuthAngle.png">
<figcaption>
Example <code>azimuthAngle</code> of π/6 ("4 o'clock").
</figcaption>
</figure>
</dd>
<dt><dfn>touchType</dfn></dt>
<dd>
<p>The type of device used to trigger the touch.</p>
</dd>
</dl>
<dl>
<dt><dfn>TouchType</dfn></dt>
<dd>
<p>An enumeration representing the different types of possible touch input.</p>
</dd>
</dl>
<dl data-dfn-for="TouchType" data-link-for="TouchType">
<dt><dfn>direct</dfn></dt>
<dd>
<p>A direct touch from a finger on the screen.</p>
</dd>
<dt><dfn>stylus</dfn></dt>
<dd>
<p>A touch from a stylus or pen device.</p>
</dd>
</dl>
</section>
<section>
<h2><dfn>TouchList</dfn> Interface</h2>
<p>This interface defines a list of individual points of contact for a touch event. <a><code>TouchList</code></a> objects are immutable; after one is created, its contents must not change.</p>
<p>A <code>TouchList</code> object's <em>supported property indices</em> ([[!WEBIDL]]) are the numbers in the range 0 to one less than the length of the list.</p>
<pre class="idl">
[Exposed=Window]
interface TouchList {
readonly attribute unsigned long length;
getter Touch? item (unsigned long index);
};
</pre>
<dl data-dfn-for="TouchList" data-link-for="TouchList">
<dt><dfn>length</dfn></dt>
<dd>
<p>Returns the number of <a><code>Touch</code></a> objects in the list</p>
</dd>
<dt><dfn>item</dfn></dt>
<dd>
<p>Returns the <a><code>Touch</code></a> at the specified index in the list or null if the index is not less than the length of the list.</p>
</dd>
</dl>
</section>
<section>
<h2><dfn>TouchEvent</dfn> Interface</h2>
<p>This interface defines the <a><code>touchstart</code></a>, <a><code>touchend</code></a>, <a><code>touchmove</code></a>, and <a><code>touchcancel</code></a> event types. <a><code>TouchEvent</code></a> objects are immutable; after one is created and initialized, its attributes must not change. <code>TouchEvent</code> inherits from the <code>UIEvent</code> interface defined in [[!DOM-LEVEL-3-EVENTS]].</p>
<p>The <dfn>TouchEventInit</dfn> dictionary is used by the <code>TouchEvent</code> interface's constructor to provide a mechanism by which to construct untrusted (synthetic) touch events. It inherits from the <code>EventModifierInit</code> dictionary defined in [[!DOM-LEVEL-3-EVENTS]]. The steps for constructing an event are defined in [[!DOM4]]. See the <a href="#firing-a-synthetic-touchevent-from-script" title="examples">example</a> for sample code demonstrating how to fire an untrusted touch event.</p>
<pre class="idl">
dictionary TouchEventInit : EventModifierInit {
sequence<Touch> touches = [];
sequence<Touch> targetTouches = [];
sequence<Touch> changedTouches = [];
};
[Exposed=Window]
interface TouchEvent : UIEvent {
constructor(DOMString type, optional TouchEventInit eventInitDict = {});
readonly attribute TouchList touches;
readonly attribute TouchList targetTouches;
readonly attribute TouchList changedTouches;
readonly attribute boolean altKey;
readonly attribute boolean metaKey;
readonly attribute boolean ctrlKey;
readonly attribute boolean shiftKey;
getter boolean getModifierState (DOMString keyArg);
};
</pre>
<dl data-dfn-for="TouchEvent" data-link-for="TouchEvent">
<dt><dfn>touches</dfn></dt>
<dd>
<p>A list of <a><code>Touch</code></a> objects for every point of contact currently touching the surface.</p>
</dd>
<dt><dfn>targetTouches</dfn></dt>
<dd>
<p>A list of <a><code>Touch</code></a> objects for every point of contact that is touching the surface <em>and</em> started on the element that is the target of the current event.</p>
</dd>
<dt><dfn>changedTouches</dfn></dt>
<dd>
<p>A list of <a><code>Touch</code></a> objects for every point of contact which contributed to the event.</p>
<p>For the <a><code>touchstart</code></a> event this must be a list of the touch points that just became active with the current event. For the <a><code>touchmove</code></a> event this must be a list of the touch points that have moved since the last event. For the <a><code>touchend</code></a> and <a><code>touchcancel</code></a> events this must be a list of the touch points that have just been removed from the surface, with the last known coordinates of the touch points before they were removed.</p>
</dd>
<dt><dfn>altKey</dfn></dt>
<dd>
<p><code>true</code> if the alt (Alternate) key modifier is activated; otherwise <code>false</code></p>
</dd>
<dt><dfn>metaKey</dfn></dt>
<dd>
<p><code>true</code> if the meta (Meta) key modifier is activated; otherwise <code>false</code>. On some platforms this attribute may map to a differently-named key modifier.</p>
</dd>
<dt><dfn>ctrlKey</dfn></dt>
<dd>
<p><code>true</code> if the ctrl (Control) key modifier is activated; otherwise <code>false</code></p>
</dd>
<dt><dfn>shiftKey</dfn></dt>
<dd>
<p><code>true</code> if the shift (Shift) key modifier is activated; otherwise <code>false</code></p>
</dd>
<dt><dfn>getModifierState</dfn>(keyArg)</dt>
<dd>
<p>Queries the state of a modifier using a key value. Returns <code>true</code> if it is a modifier key and the modifier is activated, <code>false</code> otherwise.</p>
</dd>
</dl>
<section class="informative">
<h2>TouchEvent Implementer's Note</h2>
<div class="note">
<p>User agents should ensure that all <a><code>Touch</code></a> objects available from a given <a><code>TouchEvent</code></a> are all associated to the same document that the <a><code>TouchEvent</code></a> was dispatched to. To implement this, user agents should maintain a notion of the current <em>touch-active</em> document. On first touch, this is set to the target document where the touch was created. When all active touch points are released, the <em>touch-active</em> document is cleared. All <a><code>TouchEvent</code></a>s are dispatched to the current <em>touch-active</em> document, and each <a><code>Touch</code></a> object it contains refers only to DOM elements (and co-ordinates) in that document. If a touch starts entirely outside the currently <em>touch-active</em> document, then it is ignored entirely.</p>
</div>
</section>
<section class="informative">
<h2>Usage Examples</h2>
<p>The examples below demonstrate the relations between the different <a><code>TouchList</code></a> members defined in a <a><code>TouchEvent</code></a>.</p>
<section>
<h3><code>touches</code> and <code>targetTouches</code> of a <a><code>TouchEvent</code></a></h3>
<p>This example demonstrates the utility and relations between the <code>touches</code> and <code>targetTouches</code> members defined in the <a><code>TouchEvent</code></a> interface. The following code will generate different output based on the number of touch points on the touchable element and the document:</p>
<pre class="example">
<div id="touchable">This element is touchable.</div>
<script>
document.getElementById('touchable').addEventListener('touchstart', function(ev) {
if (ev.touches.item(0) == ev.targetTouches.item(0))
{
/**
* If the first touch on the surface is also targeting the
* "touchable" element, the code below should execute.
* Since targetTouches is a subset of touches which covers the
* entire surface, TouchEvent.touches >= TouchEvents.targetTouches
* is always true.
*/
document.write('Hello Touch Events!');
}
if (ev.touches.length == ev.targetTouches.length)
{
/**
* If all of the active touch points are on the "touchable"
* element, the length properties should be the same.
*/
document.write('All points are on target element')
}
if (ev.touches.length > 1)
{
/**
* On a single touch input device, there can only be one point
* of contact on the surface, so the following code can only
* execute when the terminal supports multiple touches.
*/
document.write('Hello Multiple Touch!');
}
}, false);
</script>
</pre>
</section>
<section>
<h3><code>changedTouches</code> of a <a><code>TouchEvent</code></a></h3>
<p>This example demonstrates the utility of <code>changedTouches</code> and it's relation with the other <a><code>TouchList</code></a> members of the <a><code>TouchEvent</code></a> interface. The code is a example which triggers whenever a touch point is removed from the defined touchable element:</p>
<pre class="example">
<div id="touchable">This element is touchable.</div>
<script>
document.getElementById('touchable').addEventListener('touchend', function(ev) {
/**
* Example output when three touch points are on the surface,
* two of them being on the "touchable" element and one point
* in the "touchable" element is lifted from the surface:
*
* Touch points removed: 1
* Touch points left on element: 1
* Touch points left on document: 2
*/
document.write('Touch points removed: ' + ev.changedTouches.length);
document.write('Touch points left on element: ' + ev.targetTouches.length);
document.write('Touch points left on document: ' + ev.touches.length);
}, false);
</script>
</pre>
</section>
<section>
<h3>Firing a synthetic <a><code>TouchEvent</code></a> from script</h3>
<p>This example demonstrates how to create and fire a <a><code>TouchEvent</code></a> from script.</p>
<pre class="example">
if (Touch.length < 1 || TouchEvent.length < 1)
throw "TouchEvent constructors not supported";
var touch = new Touch({
identifier: 42,
target: document.body,
clientX: 200,
clientY: 200,
screenX: 300,
screenY: 300,
pageX: 200,
pageY: 200,
radiusX: 5,
radiusY: 5
});
var touchEvent = new TouchEvent("touchstart", {
cancelable: true,
bubbles: true,
composed: true,
touches: [touch],
targetTouches: [touch],
changedTouches: [touch]
});
document.body.dispatchEvent(touchEvent);
</pre>
</section>
</section>
<section class="informative">
<h2>List of <a><code>TouchEvent</code></a> types</h2>
<p>The following table provides a summary of the <a><code>TouchEvent</code></a> event types defined in this specification. All events should accomplish the bubbling phase. All events should be composed [[WHATWG-DOM]] events.</p><!--
// FIXME: As of the time of writing, respec.js doesn't have support for
// tables like this - we're just piggybacking on a existing class, with
// raw markup as a quick and dirty workaround.
-->
<table class="simple" id="table-event-summary">
<thead>
<tr>
<th>Event Type</th>
<th>Sync / Async</th>
<th>Bubbling phase</th>
<th>Composed</th>
<th>Trusted proximal event target types</th>
<th>Interface</th>
<th>Cancelable</th>
<th>Default Action</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
<a><code>touchstart</code></a>
</th>
<td>Sync</td>
<td>Yes</td>
<td>Yes</td>
<td><code>Document</code>, <code>Element</code></td>
<td>
<a><code>TouchEvent</code></a>
</td>
<td>
<a href="#cancelability">Varies</a>
</td>
<td>undefined</td>
</tr>
<tr>
<th scope="row">
<a><code>touchend</code></a>
</th>
<td>Sync</td>
<td>Yes</td>
<td>Yes</td>
<td><code>Document</code>, <code>Element</code></td>
<td>
<a><code>TouchEvent</code></a>
</td>
<td>
<a href="#cancelability">Varies</a>
</td>
<td>
Varies: user agents may dispatch <a href="#mouse-events">mouse and click events</a>
</td>
</tr>
<tr>
<th scope="row">
<a><code>touchmove</code></a>
</th>
<td>Sync</td>
<td>Yes</td>
<td>Yes</td>
<td><code>Document</code>, <code>Element</code></td>
<td>
<a><code>TouchEvent</code></a>
</td>
<td>
<a href="#cancelability">Varies</a>
</td>
<td>undefined</td>
</tr>
<tr>
<th scope="row">
<a><code>touchcancel</code></a>
</th>
<td>Sync</td>
<td>Yes</td>
<td>Yes</td>
<td><code>Document</code>, <code>Element</code></td>
<td>
<a><code>TouchEvent</code></a>
</td>
<td>No</td>
<td>none</td>
</tr>
</tbody>
</table>
</section>
<section>
<h3 id="cancelability">Cancelability of touch events</h3>
<p><a href="#dfn-canceled-event">Canceling</a> a touch event can prevent or otherwise interrupt scrolling (which could be happening in parallel with script execution). For maximum scroll performance, a user agent may not wait for each touch event associated with the scroll to be processed to see if it will be canceled. In such cases the user agent should generate touch events whose <code>cancelable</code> property is <code>false</code>, indicating that <code>preventDefault</code> cannot be used to prevent or interrupt scrolling. Otherwise <code>cancelable</code> will be <code>true</code>.</p>
<p>In particular, a user agent should generate only uncancelable touch events when it <a href="https://dom.spec.whatwg.org/#observing-event-listeners">observes that there are no non-passive listeners</a> for the event.</p>
</section>
<section>
<h3 id="event-touchstart">The <dfn class="event"><code>touchstart</code></dfn> event</h3>
<p>A user agent must dispatch this event type to indicate when the user places a <a>touch point</a> on the touch surface.</p>
<p>The target of this event must be an <code>Element</code>. If the touch point is within a frame, the event should be dispatched to an element in the child browsing context of that frame.</p>
<p>If this event is <a href="#dfn-canceled-event">canceled</a>, it should prevent any default actions caused by any touch events associated with the same <a>active touch point</a>, including mouse events or scrolling.</p>
</section>
<section data-link-for="TouchEvent">
<h3 id="event-touchend">The <dfn class="event"><code>touchend</code></dfn> event</h3>
<p>A user agent must dispatch this event type to indicate when the user removes a <a>touch point</a> from the touch surface, also including cases where the touch point physically leaves the touch surface, such as being dragged off of the screen.</p>
<p>The target of this event must be the same <code>Element</code> on which the <a>touch point</a> started when it was first placed on the surface, even if the <a>touch point</a> has since moved outside the interactive area of the target element.</p>
<p>The <a>touch point</a> or points that were removed must be included in the <a><code>changedTouches</code></a> attribute of the <a><code>TouchEvent</code></a>, and must not be included in the <a><code>touches</code></a> and <a><code>targetTouches</code></a> attributes.</p>
<p>If this event is <a href="#dfn-canceled-event">canceled</a>, any sequence of touch events that includes this event must not be <a href="#click-events">interpreted as a click</a>.</p>
</section>
<section>
<h3 id="event-touchmove">The <dfn class="event"><code>touchmove</code></dfn> event</h3>
<p>A user agent must dispatch this event type to indicate when the user moves a <a>touch point</a> along the touch surface.</p>
<p>The target of this event must be the same <code>Element</code> on which the <a>touch point</a> started when it was first placed on the surface, even if the <a>touch point</a> has since moved outside the interactive area of the target element.</p>
<p>Note that the rate at which the user agent sends <a><code>touchmove</code></a> events is implementation-defined, and may depend on hardware capabilities and other implementation details.</p>
<p>A user agent should suppress the default action caused by any <a><code>touchmove</code></a> event until at least one <a><code>touchmove</code></a> event associated with the same <a>active touch point</a> is not <a href="#dfn-canceled-event">canceled</a>. Whether the default action is suppressed for <a><code>touchmove</code></a> events after at least one <a><code>touchmove</code></a> event associated with the same <a>active touch point</a> is not <a href="#dfn-canceled-event">canceled</a> is implementation dependent.</p>
</section>
<section data-link-for="TouchEvent">
<h3 id="event-touchcancel">The <dfn class="event"><code>touchcancel</code></dfn> event</h3>
<p>A user agent must dispatch this event type to indicate when a touch point has been disrupted in an implementation-specific manner, such as a synchronous event or action originating from the UA canceling the touch, or the touch point leaving the document window into a non-document area which is capable of handling user interactions (e.g. the UA's native user interface, or an area of the document which is managed by a plug-in). A user agent may also dispatch this event type when the user places more <a>touch point</a>s on the touch surface than the device or implementation is configured to store, in which case the earliest <a><code>Touch</code></a> object in the <a><code>TouchList</code></a> should be removed.</p>
<p>The target of this event must be the same <code>Element</code> on which the <a>touch point</a> started when it was first placed on the surface, even if the <a>touch point</a> has since moved outside the interactive area of the target element.</p>
<p>The <a>touch point</a> or points that were removed must be included in the <a><code>changedTouches</code></a> attribute of the <a><code>TouchEvent</code></a>, and must not be included in the <a><code>touches</code></a> and <a><code>targetTouches</code></a> attributes.</p>
</section>
</section>
<section>
<h2>Retargeting</h2>
<p>The following section describes <a href="https://dom.spec.whatwg.org/#retarget">retargeting steps</a>, defined in [[!WHATWG-DOM]].</p>
<p><code>Touch</code> object has an associated <dfn>unadjustedTarget</dfn> (null or <code>EventTarget</code>). Unless stated otherwise it is null.</p>
<p><code>TouchEvent</code>'s <a href="https://dom.spec.whatwg.org/#retarget">retargeting steps</a>, given a <var>touchEvent</var>, must run these steps:</p>
<ol>
<li>
<p>For each <a><code>Touch</code></a> <var>touch</var> in <var>touchEvent</var>'s <code>touches</code>, <code>targetTouches</code>, and <code>changedTouches</code> members:</p>
<ol>
<li>Set <var>touch</var>'s <a><code>unadjustedTarget</code></a> to <var>touch</var>'s <code>target</code> if <var>touch</var>'s <a><code>unadjustedTarget</code></a> is null.
</li>
<li>Set <var>touch</var>'s <code>target</code> to the result of invoking <a href="https://dom.spec.whatwg.org/#retarget">retargeting</a> <var>touch</var>'s <a><code>unadjustedTarget</code></a> against <var>touchEvent</var>'s <code>target</code>.
</li>
</ol>
</li>
</ol>
</section>
<section>
<h2>Conditionally exposing legacy touch event APIs</h2>
<p>User agents have an associated boolean <dfn data-export="">expose legacy touch event APIs</dfn> whose value is <a>implementation-defined</a>.</p>
<p class="note">Existing web content often use the existence of these APIs as a signal that the user agent is a touch-enabled "mobile" device, and therefore exposing these APIs on non-mobile devices, even if they are touch-enabled, could lead to a suboptimal user experience for such web content.</p>
</section>
<section>
<h2>Extensions to the <code>GlobalEventHandlers</code> mixin</h2>
<p>The following section describes extensions to the existing <dfn data-cite="HTML5#globaleventhandlers">GlobalEventHandlers</dfn> mixin, defined in [[!HTML5]], to facilitate the event handler registration. For user agents where <a>expose legacy touch event APIs</a> is false, this mixin must not be implemented.</p>
<pre class="idl">
partial interface mixin GlobalEventHandlers {
attribute EventHandler ontouchstart;
attribute EventHandler ontouchend;
attribute EventHandler ontouchmove;
attribute EventHandler ontouchcancel;
};
</pre>
<dl data-dfn-for="GlobalEventHandlers" data-link-for="GlobalEventHandlers">
<dt><dfn>ontouchstart</dfn></dt>
<dd>
<p>The event handler IDL attribute (see [[!HTML5]]) for the <code>touchstart</code> event type.</p>
</dd>
<dt><dfn>ontouchend</dfn></dt>
<dd>
<p>The event handler IDL attribute (see [[!HTML5]]) for the <code>touchend</code> event type.</p>
</dd>
<dt><dfn>ontouchmove</dfn></dt>
<dd>
<p>The event handler IDL attribute (see [[!HTML5]]) for the <code>touchmove</code> event type.</p>
</dd>
<dt><dfn>ontouchcancel</dfn></dt>
<dd>
<p>The event handler IDL attribute (see [[!HTML5]]) for the <code>touchcancel</code> event type.</p>
</dd>
</dl>
</section>
<section id="mouse-events">
<h2>Interaction with Mouse Events and <code>click</code></h2>
<p>The user agent may dispatch both touch events and (for compatibility with web content not designed for touch) mouse events [[!DOM-LEVEL-2-EVENTS]] in response to the same user input. If the user agent dispatches both touch events and mouse events in response to a single user action, then the <a><code>touchstart</code></a> event type must be dispatched before any mouse event types for that action. If <a><code>touchstart</code></a>, <a><code>touchmove</code></a>, or <a><code>touchend</code></a> are <a href="#dfn-canceled-event">canceled</a>, the user agent should not dispatch any mouse event that would be a consequential result of the prevented touch event.</p>
<p class="note">If a Web application can process touch events, it can <a href="#dfn-canceled-event">cancel</a> the events, and no corresponding mouse events would need to be dispatched by the user agent. If the Web application is not specifically written for touch input devices, it will react to the subsequent mouse events instead.</p>
<p class="note">User agents will typically dispatch mouse and click events only for single-finger activation gestures (like tap and long press). Gestures involving movement of the touch point or multi-touch interactions – with two or more <a href="#dfn-active-touch-point">active touch points</a> – will usually only generate touch events.</p>
<p id="click-events">If the user agent interprets a sequence of touch events as a tap gesture, then it should dispatch <code>mousemove</code>, <code>mousedown</code>, <code>mouseup</code>, and <code>click</code> events (in that order) at the location of the <a><code>touchend</code></a> event for the corresponding touch input. If the contents of the document have changed during processing of the touch events, then the user agent may dispatch the mouse events to a different target than the touch events.</p>
<p>The default actions and ordering of any further touch and mouse events are implementation-defined, except as specified elsewhere.</p>
<div class="note">
<p>The activation of an element (e.g., in some implementations, a tap) would typically produce the following event sequence (though this may vary slightly, depending on specific user agent behavior):</p>
<ol data-class="note-list">
<li><code>touchstart</code></li>
<li>Zero or more <code>touchmove</code> events, depending on movement of the finger</li>
<li><code>touchend</code></li>
<li><code>mousemove</code> <small>(for compatibility with legacy mouse-specific code)</small></li>
<li><code>mousedown</code></li>
<li><code>mouseup</code></li>
<li><code>click</code></li>
</ol>
<p>If, however, either the <code>touchstart</code>, <code>touchmove</code> or <code>touchend</code> event has been <a href="#dfn-canceled-event">canceled</a> during this interaction, no mouse or click events will be fired, and the resulting sequence of events would simply be:</p>
<ol data-class="note-list">
<li><code>touchstart</code></li>
<li>Zero or more <code>touchmove</code> events, depending on movement of the finger</li>
<li><code>touchend</code></li>
</ol>
</div>
<div class="note">
<p>Even if a user agent supports Touch Events, this does not necessarily mean that a touchscreen is the only input mechanism available to users. Particularly in the case of touch-enabled laptops, or traditional "touch only" devices (such as phones and tablets) with paired external input devices, users may use the touchscreen in conjunction with a trackpad, mouse or keyboard. For this reason, developers should avoid binding event listeners with "either touch or mouse/keyboard" conditional code, as this results in sites/application that become touch-exclusive, preventing users from being able to use any other input mechanism.</p>
<pre class="example"><code>
// conditional "touch OR mouse/keyboard" event binding
// DON'T DO THIS, as it makes interactions touch-exclusive
// on devices that have both touch and mouse/keyboard
if ('ontouchstart' in window) {
// set up event listeners for touch
target.addEventListener('touchend', ...);
...
} else {
// set up event listeners for mouse/keyboard
target.addEventListener('click', ...);
...
}
</code></pre>
<p>Instead, developers should handle different forms of input concurrently.</p>
<pre class="example"><code>
// concurrent "touch AND mouse/keyboard" event binding
// set up event listeners for touch
target.addEventListener('touchend', function(e) {
// prevent compatibility mouse events and click
e.preventDefault();
...
});
...
// set up event listeners for mouse/keyboard
target.addEventListener('click', ...);
...
</code></pre>
<p>To avoid processing the same interaction twice for touch (once for the touch event, and once for the compatibility mouse events), developers should make sure to <a href="#dfn-canceled-event">cancel</a> the touch event, suppressing the generation of any further mouse or click events. Alternatively, see the <a href="https://wicg.github.io/input-device-capabilities/">InputDeviceCapabilities API</a> for a way to detect mouse events that were generated as a result of touch events.</p>
</div>
</section>
<section>
<h2>Glossary</h2>
<dl>
<dt><dfn>active touch point</dfn></dt>
<dd>
A <a>touch point</a> which is currently on the screen and is being tracked by the user agent. The touch point becomes active when the user agent first dispatches a <a><code>touchstart</code></a> event indicating its appearance. It ceases to be active after the user agent dispatches a <a><code>touchend</code></a> or <a><code>touchcancel</code></a> event indicating that the touch point is removed from the surface or no longer tracked.
</dd>
<dt><dfn>touch point</dfn></dt>
<dd>The coordinate point at which a pointer (e.g finger or stylus) intersects the target surface of an interface. This may apply to a finger touching a touch-screen, or an digital pen writing on a piece of paper.</dd>
<dt><dfn>canceled event</dfn></dt>
<dd>An event whose default action was prevented by means of <code>preventDefault()</code>, returning <code>false</code> in an event handler, or other means as defined by [[!DOM-LEVEL-3-EVENTS]] and [[!HTML5]].</dd>
</dl>
</section>
<section class="appendix informative">
<h2>Acknowledgements</h2>
<p>Many thanks to the WebKit engineers for developing the model used as a basis for this spec, Neil Roberts (SitePen) for his summary of WebKit touch events, Peter-Paul Koch (PPK) for his write-ups and suggestions, Robin Berjon for developing the <a href="https://dev.w3.org/2009/dap/ReSpec.js/documentation.html">ReSpec.js spec authoring tool</a>, and the WebEvents WG for their many contributions.</p>
<p>Many others have made additional comments as the spec developed, which have led to steady improvements. Among them are Matthew Schinckel, Andrew Grieve, Cathy Chan, Boris Zbarsky, Patrick H. Lauke, and Simon Pieters. If we inadvertently omitted your name, please let me know.</p>
<p>The group acknowledges the following contributors to this specification's test suite: Matt Brubeck, Olli Pettay, Art Barstow, Cathy Chan and Rick Byers.</p>
</section>
<section class="appendix informative">
<h2>Changes Since Last Publication</h2>
<p>This is a summary of the major changes made since the <a href="https://www.w3.org/TR/touch-events/">10 October 2013 Recommendation</a> was published. <a href="https://github.com/w3c/touch-events/compare/v1...gh-pages">Full commit history</a> is also available.</p>
<ul>
<li>
<a href="https://github.com/w3c/touch-events/pull/125">Reword altitudeAngle/azimuthAngle descriptions in line with PointerEvents, add illustrations</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/120">Add getModifierState definition</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/commit/303b36e1d188a380f9bc0861b175438e596a34b1">Added force attribute to Touch</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/commit/6d222fb7f106273bef847ad1d1d7a23569841954">Added radiusX and radiusY attributes to Touch</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/commit/487f6815a9590b72779d4820ff43c2b58d798f92">Added rotationAngle attribute to Touch</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/commit/006274ffada14de504f731afdb5ec1581ff327ca">Upgraded co-ordinates to double type instead of long</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/commit/df620100e48111cf7a30592f344606f8c8b7fe22">Update touchmove behavior on preventDefault</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/commit/54a3d1668c4f727d9c6f6d729b28a036041e301f">Clarify effect of canceling touchend event</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/commit/219546b80cd148543a5ece656d81ba3c901d2106">Add constructor for TouchEvent and Touch</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/commit/50f51ccacb0d5ad06f9cf6ed44f853d6a3616d10">Added legacy event initializer initTouchEvent</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/59">Added support for uncancelable touch events and described scroll performance implications</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/67">Indicate that all events should be "composed".</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/72">Note about avoiding conditional "touch OR mouse/keyboard" event handling</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/73">Added TouchEvent's retargeting steps</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/81">Add touchType, altitudeAngle, azimuthAngle (Safari iOS 10.3 extensions for stylus)</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/88">Add [Exposed=Window] to Constructor</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/95">Add note to mention UA might adjusting touch target</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/96">Remove Legacy Event Initializers (createTouch and createTouchList)</a> and the <a href="https://github.com/w3c/touch-events/pull/100">note about initTouchEvent / createTouchList</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/111">Conditionally expose legacy touch events API</a>
</li>
<li>
<a href="https://github.com/w3c/touch-events/pull/91">Add getModifierState definition to TouchEvent</a>
</li>
</ul>
</section>
</body>
</html>