
navigator.getGamepads(); return an array of joysticks, Gamepad objects.window object (namely, receiving joysticks from the navigator , and events in the window ): "gamepadconnected", "gamepaddisconnected" . window.addEventListener("gamepadconnected", function(e) {...}) e.gamepad property is the joystick that is connected or disconnected.Gamepad object itself:id contains vendor id, product id (USB) and description. Record format is not regulated;index which account is connected;mapping line in which the spelling was written and if so, which one;connected is the joystick connected ;timestamp DOMHighResTimeStamp when the joystick data was last updated;axes array of axes and values ​​from -1 to 1;buttons array of buttons, objects containing pressed (boolean) and value [0; 1] Since triggers may have a smooth change in value, this should be taken into account sometimes.id self-willed. In order to recognize the joystick yourself, you need to know the VID and PID, it means you need to parse this property, but the format is “dancing”: in the chromium, the line contains a description, and only then "Vendor: 092c Product: 12a8" , in firefox, the line begins with them, separating by minuses , for example "092c-12a8-..." , but the nastiest thing is that in the windows it turned out that prefilling with zeros is simply absent, therefore in Windows the line is transformed into "92c-12a8-..."connected ;navigator.webkitGetGamepads() to appear, the joystick must be active during a call to this function (for example, the button is pressed);maping empty although there is remapping;buttons array of values, not objects.Gamepad objects are not updated until navigator.webkitGetGamepads() or navigator.getGamepads() is called (if it is, if it is, and the old version is called, then attention will be thrown and nothing will be updated). Those. getting an object from a function is not necessary to receive it again, but it is necessary to simply call this function.GamepadMap class GamepadMap rendered separately. An object created from this class can be passed to the interface constructor."id" property. It is not safe on the one hand, but on the other parameter I could not find it better. Even the value of the mapping parameter does not give anything: in chromium, which only works with the webkit prefix, this parameter is empty, but the associations are ready, as I wrote above.gamepadconnected and gamepaddisconnected . Pressing the buttons and changes in the sticks should be obtained independently. Theoretically, this is useful, but in practice it is not always convenient. Especially if you create an alternative to "clavamyshi".navigator.getGamepads() or navigator.webkitGetGamepads() . In the firelight, everything is simpler, the state is updated automatically. Therefore, if the webkit, then pull this method every time before the survey.EventTarget interface for the elements, but you can't just create and create extends EventTarget . I had to “knee” my implementation, but observing the standard. Why not take ready Emet? There is no close compliance with the standard, but I wanted to do everything as standard where it is possible.EventTargetEmiter class: class EventTargetEmiter # implements EventTarget ###* * . * @protected * @type Object ### _subscribe: null ###* * * @public * @type EventTargetEmiter ### parent: null ###* * . * @protected * @method _checkValues * @param String|* type * @param Handler|* listener - ### _checkValues: (type, listener) -> unless isString type ERR "type not string" return false unless isFunction listener ERR "listener is not a function" return false true ###* * `list` * handler- * @constructor * @param Array list ### constructor: (list...) -> @_subscribe = _length: 0 for e in list @_subscribe[e] = [] @['on' + e] = null ###* * Add function `listener` by `type` with `useCapture` * @public * @method addEventListener * @param String type * @param Handler listener * @param Boolean useCapture = false * @return void ### addEventListener: (type, listener, useCapture = false) -> unless @_checkValues(type, listener) return useCapture = not not useCapture @_subscribe[type].push [listener, useCapture] @_subscribe._length++ return ###* * Remove function `listener` by `type` with `useCapture` * @public * @method removeEventListener * @param String type * @param Handler listener * @param Boolean useCapture = false ### removeEventListener: (type, listener, useCapture = false) -> unless @_checkValues(type, listener) return useCapture = not not useCapture return unless @_subscribe[type]? for fn, i in @_subscribe[type] if fn[0] is listener and fn[1] is useCapture @_subscribe[type].splice i, 1 @_subscribe._length-- return return ###* * Burn, baby, burn! * @public * @method dispatchEvent * @param Event evt * @return Boolean ### dispatchEvent: (evt) -> unless evt instanceof Event ERR "evt is not event." return false t = evt.type unless @_subscribe[t]? throw new EventException "UNSPECIFIED_EVENT_TYPE_ERR" return false @emet t, evt ###* * Alias for addEventListener, but return this * @public * @method on * @param String type * @param Handler listener * @param Boolean useCapture * @return this ### on: (args...) -> @addEventListener args... @ ###* * Alias for removeEventListener * @public * @method off * @param String type * @param Handler listener * @param Boolean useCapture * @return this ### off: (args...) -> @removeEventListener args... @ ###* * Emiter event by `name` and create event or use `evt` if exist * @param String name * @param Event|null evt * @return Boolean ### emet: (name, evt = null) -> # run handled-style listeners r = @['on' + name](evt) if isFunction @['on' + name] return false if r is false # run other for fn in @_subscribe[name] try r = fn[0](evt) break if fn[1] is true or r is false if evt?.bubbles is true try @parent.emet name, evt if evt? then not evt.defaultPrevented else true _subscribe property _subscribe accessible from the outside, but it doesn’t matter who rules the protective properties (with underlining) is ready to shoot himself in the foot. An object can be assigned a parent object, in which a “pop-up” event is transmitted.Event , but simply create the Event and set its properties to us is not allowed. CustomEvent comes to the CustomEvent , in which the detail property is customizable. And so that the event is called and in the parent elements, do not forget to set canBubble to true in the constructor.requestAnimationFrame used to poll the state. This is a plus and a minus:focus/blur for the window, setInterval for the scheduler, and a single requestAnimationFrame for the first run (after all, the window can load in the background). Thus, the browser itself will be engaged in the list of tasks, will execute necessary between drawings. tick = (time, fn) -> # setInterval fn, time stopTick = (tickId) -> clearInterval tickId _startShedule: (Hz = 60) -> requestAnimationFrame = top.requestAnimationFrame or top.mozRequestAnimationFrame or top.webkitRequestAnimationFrame requestAnimationFrame => # t = null startTimers = -> t is null and t = tick (1000 / Hz |0), -> # , body() return stopTimers = -> if t isnt null # , stopTick(t) t = null return window.addEventListener 'focus', -> startTimers() window.addEventListener 'blur', -> stopTimers() startTimers() return return navigator.getGamepads() returns an array, so we need an array. But we would be eventful. This is where dances with a tambourine begin: to inherit an Array you need to add a short line in the constructor: constructor: (items...) -> @splice 0, 0, items... EventTargetEmiter inherit. This could not be done directly in the cofescript. Therefore, I was helped by a simple function that passes the methods and properties to this : _implements = (mixins...) -> for mixin in mixins @::[key] = value for key, value of mixin:: @ class EventedArray extends Array # implements EventTarget _implements.call(@, EventTargetEmiter) ###* * @constructor * @param items array-style constructor without single item as length. ### constructor: (items...) -> @splice 0, 0, items... Gamepads for working with joysticks, as well as Gamepad2 and GamepadMap for manual and fine settings.Source: https://habr.com/ru/post/242835/
All Articles