1window.whatInput = (function() { 2 3 'use strict'; 4 5 /* 6 --------------- 7 variables 8 --------------- 9 */ 10 11 // array of actively pressed keys 12 var activeKeys = []; 13 14 // cache document.body 15 var body; 16 17 // boolean: true if touch buffer timer is running 18 var buffer = false; 19 20 // the last used input type 21 var currentInput = null; 22 23 // `input` types that don't accept text 24 var nonTypingInputs = [ 25 'button', 26 'checkbox', 27 'file', 28 'image', 29 'radio', 30 'reset', 31 'submit' 32 ]; 33 34 // detect version of mouse wheel event to use 35 // via https://developer.mozilla.org/en-US/docs/Web/Events/wheel 36 var mouseWheel = detectWheel(); 37 38 // list of modifier keys commonly used with the mouse and 39 // can be safely ignored to prevent false keyboard detection 40 var ignoreMap = [ 41 16, // shift 42 17, // control 43 18, // alt 44 91, // Windows key / left Apple cmd 45 93 // Windows menu / right Apple cmd 46 ]; 47 48 // mapping of events to input types 49 var inputMap = { 50 'keydown': 'keyboard', 51 'keyup': 'keyboard', 52 'mousedown': 'mouse', 53 'mousemove': 'mouse', 54 'MSPointerDown': 'pointer', 55 'MSPointerMove': 'pointer', 56 'pointerdown': 'pointer', 57 'pointermove': 'pointer', 58 'touchstart': 'touch' 59 }; 60 61 // add correct mouse wheel event mapping to `inputMap` 62 inputMap[detectWheel()] = 'mouse'; 63 64 // array of all used input types 65 var inputTypes = []; 66 67 // mapping of key codes to a common name 68 var keyMap = { 69 9: 'tab', 70 13: 'enter', 71 16: 'shift', 72 27: 'esc', 73 32: 'space', 74 37: 'left', 75 38: 'up', 76 39: 'right', 77 40: 'down' 78 }; 79 80 // map of IE 10 pointer events 81 var pointerMap = { 82 2: 'touch', 83 3: 'touch', // treat pen like touch 84 4: 'mouse' 85 }; 86 87 // touch buffer timer 88 var timer; 89 90 91 /* 92 --------------- 93 functions 94 --------------- 95 */ 96 97 // allows events that are also triggered to be filtered out for `touchstart` 98 function eventBuffer() { 99 clearTimer(); 100 setInput(event); 101 102 buffer = true; 103 timer = window.setTimeout(function() { 104 buffer = false; 105 }, 650); 106 } 107 108 function bufferedEvent(event) { 109 if (!buffer) setInput(event); 110 } 111 112 function unBufferedEvent(event) { 113 clearTimer(); 114 setInput(event); 115 } 116 117 function clearTimer() { 118 window.clearTimeout(timer); 119 } 120 121 function setInput(event) { 122 var eventKey = key(event); 123 var value = inputMap[event.type]; 124 if (value === 'pointer') value = pointerType(event); 125 126 // don't do anything if the value matches the input type already set 127 if (currentInput !== value) { 128 var eventTarget = target(event); 129 var eventTargetNode = eventTarget.nodeName.toLowerCase(); 130 var eventTargetType = (eventTargetNode === 'input') ? eventTarget.getAttribute('type') : null; 131 132 if ( 133 (// only if the user flag to allow typing in form fields isn't set 134 !body.hasAttribute('data-whatinput-formtyping') && 135 136 // only if currentInput has a value 137 currentInput && 138 139 // only if the input is `keyboard` 140 value === 'keyboard' && 141 142 // not if the key is `TAB` 143 keyMap[eventKey] !== 'tab' && 144 145 // only if the target is a form input that accepts text 146 ( 147 eventTargetNode === 'textarea' || 148 eventTargetNode === 'select' || 149 (eventTargetNode === 'input' && nonTypingInputs.indexOf(eventTargetType) < 0) 150 )) || ( 151 // ignore modifier keys 152 ignoreMap.indexOf(eventKey) > -1 153 ) 154 ) { 155 // ignore keyboard typing 156 } else { 157 switchInput(value); 158 } 159 } 160 161 if (value === 'keyboard') logKeys(eventKey); 162 } 163 164 function switchInput(string) { 165 currentInput = string; 166 body.setAttribute('data-whatinput', currentInput); 167 168 if (inputTypes.indexOf(currentInput) === -1) inputTypes.push(currentInput); 169 } 170 171 function key(event) { 172 return (event.keyCode) ? event.keyCode : event.which; 173 } 174 175 function target(event) { 176 return event.target || event.srcElement; 177 } 178 179 function pointerType(event) { 180 if (typeof event.pointerType === 'number') { 181 return pointerMap[event.pointerType]; 182 } else { 183 return (event.pointerType === 'pen') ? 'touch' : event.pointerType; // treat pen like touch 184 } 185 } 186 187 // keyboard logging 188 function logKeys(eventKey) { 189 if (activeKeys.indexOf(keyMap[eventKey]) === -1 && keyMap[eventKey]) activeKeys.push(keyMap[eventKey]); 190 } 191 192 function unLogKeys(event) { 193 var eventKey = key(event); 194 var arrayPos = activeKeys.indexOf(keyMap[eventKey]); 195 196 if (arrayPos !== -1) activeKeys.splice(arrayPos, 1); 197 } 198 199 function bindEvents() { 200 body = document.body; 201 202 // pointer events (mouse, pen, touch) 203 if (window.PointerEvent) { 204 body.addEventListener('pointerdown', bufferedEvent); 205 body.addEventListener('pointermove', bufferedEvent); 206 } else if (window.MSPointerEvent) { 207 body.addEventListener('MSPointerDown', bufferedEvent); 208 body.addEventListener('MSPointerMove', bufferedEvent); 209 } else { 210 211 // mouse events 212 body.addEventListener('mousedown', bufferedEvent); 213 body.addEventListener('mousemove', bufferedEvent); 214 215 // touch events 216 if ('ontouchstart' in window) { 217 body.addEventListener('touchstart', eventBuffer); 218 } 219 } 220 221 // mouse wheel 222 body.addEventListener(mouseWheel, bufferedEvent); 223 224 // keyboard events 225 body.addEventListener('keydown', unBufferedEvent); 226 body.addEventListener('keyup', unBufferedEvent); 227 document.addEventListener('keyup', unLogKeys); 228 } 229 230 231 /* 232 --------------- 233 utilities 234 --------------- 235 */ 236 237 // detect version of mouse wheel event to use 238 // via https://developer.mozilla.org/en-US/docs/Web/Events/wheel 239 function detectWheel() { 240 return mouseWheel = 'onwheel' in document.createElement('div') ? 241 'wheel' : // Modern browsers support "wheel" 242 243 document.onmousewheel !== undefined ? 244 'mousewheel' : // Webkit and IE support at least "mousewheel" 245 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox 246 } 247 248 249 /* 250 --------------- 251 init 252 253 don't start script unless browser cuts the mustard, 254 also passes if polyfills are used 255 --------------- 256 */ 257 258 if ( 259 'addEventListener' in window && 260 Array.prototype.indexOf 261 ) { 262 263 // if the dom is already ready already (script was placed at bottom of <body>
263) 264 if (document.body) { 265 bindEvents(); 266 267 // otherwise wait for the dom to load (script was placed in the <head>) 268 } else { 269 document.addEventListener('DOMContentLoaded', bindEvents); 270 } 271 } 272 273 274 /* 275 --------------- 276 api 277 --------------- 278 */ 279 280 return { 281 282 // returns string: the current input type 283 ask: function() { return currentInput; }, 284 285 // returns array: currently pressed keys 286 keys: function() { return activeKeys; }, 287 288 // returns array: all the detected input types 289 types: function() { return inputTypes; }, 290 291 // accepts string: manually set the input type 292 set: switchInput 293 }; 294 295}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.