twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

input_js.go (8745B)


      1 // Copyright 2015 Hajime Hoshi
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package js
     16 
     17 import (
     18 	"encoding/hex"
     19 	"syscall/js"
     20 	"unicode"
     21 
     22 	"github.com/hajimehoshi/ebiten/v2/internal/driver"
     23 	"github.com/hajimehoshi/ebiten/v2/internal/jsutil"
     24 )
     25 
     26 type pos struct {
     27 	X int
     28 	Y int
     29 }
     30 
     31 type gamePad struct {
     32 	valid         bool
     33 	name          string
     34 	axisNum       int
     35 	axes          [16]float64
     36 	buttonNum     int
     37 	buttonPressed [256]bool
     38 }
     39 
     40 type Input struct {
     41 	keyPressed         map[string]bool
     42 	keyPressedEdge     map[int]bool
     43 	mouseButtonPressed map[int]bool
     44 	cursorX            int
     45 	cursorY            int
     46 	wheelX             float64
     47 	wheelY             float64
     48 	gamepads           [16]gamePad
     49 	touches            map[driver.TouchID]pos
     50 	runeBuffer         []rune
     51 	ui                 *UserInterface
     52 }
     53 
     54 func (i *Input) CursorPosition() (x, y int) {
     55 	xf, yf := i.ui.context.AdjustPosition(float64(i.cursorX), float64(i.cursorY))
     56 	return int(xf), int(yf)
     57 }
     58 
     59 func (i *Input) GamepadSDLID(id driver.GamepadID) string {
     60 	// This emulates the implementation of EMSCRIPTEN_JoystickGetDeviceGUID.
     61 	// https://hg.libsdl.org/SDL/file/bc90ce38f1e2/src/joystick/emscripten/SDL_sysjoystick.c#l385
     62 	if len(i.gamepads) <= int(id) {
     63 		return ""
     64 	}
     65 	var sdlid [16]byte
     66 	copy(sdlid[:], []byte(i.gamepads[id].name))
     67 	return hex.EncodeToString(sdlid[:])
     68 }
     69 
     70 // GamepadName returns a string containing some information about the controller.
     71 // A PS2 controller returned "810-3-USB Gamepad" on Firefox
     72 // A Xbox 360 controller returned "xinput" on Firefox and "Xbox 360 Controller (XInput STANDARD GAMEPAD)" on Chrome
     73 func (i *Input) GamepadName(id driver.GamepadID) string {
     74 	if len(i.gamepads) <= int(id) {
     75 		return ""
     76 	}
     77 	return i.gamepads[id].name
     78 }
     79 
     80 func (i *Input) GamepadIDs() []driver.GamepadID {
     81 	if len(i.gamepads) == 0 {
     82 		return nil
     83 	}
     84 	var r []driver.GamepadID
     85 	for id, g := range i.gamepads {
     86 		if g.valid {
     87 			r = append(r, driver.GamepadID(id))
     88 		}
     89 	}
     90 	return r
     91 }
     92 
     93 func (i *Input) GamepadAxisNum(id driver.GamepadID) int {
     94 	if len(i.gamepads) <= int(id) {
     95 		return 0
     96 	}
     97 	return i.gamepads[id].axisNum
     98 }
     99 
    100 func (i *Input) GamepadAxis(id driver.GamepadID, axis int) float64 {
    101 	if len(i.gamepads) <= int(id) {
    102 		return 0
    103 	}
    104 	return i.gamepads[id].axes[axis]
    105 }
    106 
    107 func (i *Input) GamepadButtonNum(id driver.GamepadID) int {
    108 	if len(i.gamepads) <= int(id) {
    109 		return 0
    110 	}
    111 	return i.gamepads[id].buttonNum
    112 }
    113 
    114 func (i *Input) IsGamepadButtonPressed(id driver.GamepadID, button driver.GamepadButton) bool {
    115 	if len(i.gamepads) <= int(id) {
    116 		return false
    117 	}
    118 	return i.gamepads[id].buttonPressed[button]
    119 }
    120 
    121 func (i *Input) TouchIDs() []driver.TouchID {
    122 	if len(i.touches) == 0 {
    123 		return nil
    124 	}
    125 
    126 	var ids []driver.TouchID
    127 	for id := range i.touches {
    128 		ids = append(ids, id)
    129 	}
    130 	return ids
    131 }
    132 
    133 func (i *Input) TouchPosition(id driver.TouchID) (x, y int) {
    134 	for tid, pos := range i.touches {
    135 		if id == tid {
    136 			x, y := i.ui.context.AdjustPosition(float64(pos.X), float64(pos.Y))
    137 			return int(x), int(y)
    138 		}
    139 	}
    140 	return 0, 0
    141 }
    142 
    143 func (i *Input) RuneBuffer() []rune {
    144 	return i.runeBuffer
    145 }
    146 
    147 func (i *Input) resetForFrame() {
    148 	i.runeBuffer = nil
    149 	i.wheelX = 0
    150 	i.wheelY = 0
    151 }
    152 
    153 func (i *Input) IsKeyPressed(key driver.Key) bool {
    154 	if i.keyPressed != nil {
    155 		if i.keyPressed[driverKeyToJSKey[key]] {
    156 			return true
    157 		}
    158 	}
    159 	if i.keyPressedEdge != nil {
    160 		for c, k := range edgeKeyCodeToDriverKey {
    161 			if k != key {
    162 				continue
    163 			}
    164 			if i.keyPressedEdge[c] {
    165 				return true
    166 			}
    167 		}
    168 	}
    169 	return false
    170 }
    171 
    172 var codeToMouseButton = map[int]driver.MouseButton{
    173 	0: driver.MouseButtonLeft,
    174 	1: driver.MouseButtonMiddle,
    175 	2: driver.MouseButtonRight,
    176 }
    177 
    178 func (i *Input) IsMouseButtonPressed(button driver.MouseButton) bool {
    179 	if i.mouseButtonPressed == nil {
    180 		i.mouseButtonPressed = map[int]bool{}
    181 	}
    182 	for c, b := range codeToMouseButton {
    183 		if b != button {
    184 			continue
    185 		}
    186 		if i.mouseButtonPressed[c] {
    187 			return true
    188 		}
    189 	}
    190 	return false
    191 }
    192 
    193 func (i *Input) Wheel() (xoff, yoff float64) {
    194 	return i.wheelX, i.wheelY
    195 }
    196 
    197 func (i *Input) keyDown(code string) {
    198 	if i.keyPressed == nil {
    199 		i.keyPressed = map[string]bool{}
    200 	}
    201 	i.keyPressed[code] = true
    202 }
    203 
    204 func (i *Input) keyUp(code string) {
    205 	if i.keyPressed == nil {
    206 		i.keyPressed = map[string]bool{}
    207 	}
    208 	i.keyPressed[code] = false
    209 }
    210 
    211 func (i *Input) keyDownEdge(code int) {
    212 	if i.keyPressedEdge == nil {
    213 		i.keyPressedEdge = map[int]bool{}
    214 	}
    215 	i.keyPressedEdge[code] = true
    216 }
    217 
    218 func (i *Input) keyUpEdge(code int) {
    219 	if i.keyPressedEdge == nil {
    220 		i.keyPressedEdge = map[int]bool{}
    221 	}
    222 	i.keyPressedEdge[code] = false
    223 }
    224 
    225 func (i *Input) mouseDown(code int) {
    226 	if i.mouseButtonPressed == nil {
    227 		i.mouseButtonPressed = map[int]bool{}
    228 	}
    229 	i.mouseButtonPressed[code] = true
    230 }
    231 
    232 func (i *Input) mouseUp(code int) {
    233 	if i.mouseButtonPressed == nil {
    234 		i.mouseButtonPressed = map[int]bool{}
    235 	}
    236 	i.mouseButtonPressed[code] = false
    237 }
    238 
    239 func (i *Input) setMouseCursor(x, y int) {
    240 	i.cursorX, i.cursorY = x, y
    241 }
    242 
    243 func (i *Input) UpdateGamepads() {
    244 	nav := js.Global().Get("navigator")
    245 	if jsutil.Equal(nav.Get("getGamepads"), js.Undefined()) {
    246 		return
    247 	}
    248 	gamepads := nav.Call("getGamepads")
    249 	l := gamepads.Get("length").Int()
    250 	for id := 0; id < l; id++ {
    251 		i.gamepads[id].valid = false
    252 		gamepad := gamepads.Index(id)
    253 		if jsutil.Equal(gamepad, js.Undefined()) || jsutil.Equal(gamepad, js.Null()) {
    254 			continue
    255 		}
    256 		i.gamepads[id].valid = true
    257 		i.gamepads[id].name = gamepad.Get("id").String()
    258 
    259 		axes := gamepad.Get("axes")
    260 		axesNum := axes.Get("length").Int()
    261 		i.gamepads[id].axisNum = axesNum
    262 		for a := 0; a < len(i.gamepads[id].axes); a++ {
    263 			if axesNum <= a {
    264 				i.gamepads[id].axes[a] = 0
    265 				continue
    266 			}
    267 			i.gamepads[id].axes[a] = axes.Index(a).Float()
    268 		}
    269 
    270 		buttons := gamepad.Get("buttons")
    271 		buttonsNum := buttons.Get("length").Int()
    272 		i.gamepads[id].buttonNum = buttonsNum
    273 		for b := 0; b < len(i.gamepads[id].buttonPressed); b++ {
    274 			if buttonsNum <= b {
    275 				i.gamepads[id].buttonPressed[b] = false
    276 				continue
    277 			}
    278 			i.gamepads[id].buttonPressed[b] = buttons.Index(b).Get("pressed").Bool()
    279 		}
    280 	}
    281 }
    282 
    283 func (i *Input) Update(e js.Value) {
    284 	switch e.Get("type").String() {
    285 	case "keydown":
    286 		c := e.Get("code")
    287 		if jsutil.Equal(c, js.Undefined()) {
    288 			code := e.Get("keyCode").Int()
    289 			if edgeKeyCodeToDriverKey[code] == driver.KeyUp ||
    290 				edgeKeyCodeToDriverKey[code] == driver.KeyDown ||
    291 				edgeKeyCodeToDriverKey[code] == driver.KeyLeft ||
    292 				edgeKeyCodeToDriverKey[code] == driver.KeyRight ||
    293 				edgeKeyCodeToDriverKey[code] == driver.KeyBackspace ||
    294 				edgeKeyCodeToDriverKey[code] == driver.KeyTab {
    295 				e.Call("preventDefault")
    296 			}
    297 			i.keyDownEdge(code)
    298 			return
    299 		}
    300 		cs := c.String()
    301 		if cs == driverKeyToJSKey[driver.KeyUp] ||
    302 			cs == driverKeyToJSKey[driver.KeyDown] ||
    303 			cs == driverKeyToJSKey[driver.KeyLeft] ||
    304 			cs == driverKeyToJSKey[driver.KeyRight] ||
    305 			cs == driverKeyToJSKey[driver.KeyBackspace] ||
    306 			cs == driverKeyToJSKey[driver.KeyTab] {
    307 			e.Call("preventDefault")
    308 		}
    309 		i.keyDown(cs)
    310 	case "keypress":
    311 		if r := rune(e.Get("charCode").Int()); unicode.IsPrint(r) {
    312 			i.runeBuffer = append(i.runeBuffer, r)
    313 		}
    314 	case "keyup":
    315 		if jsutil.Equal(e.Get("code"), js.Undefined()) {
    316 			// Assume that UA is Edge.
    317 			code := e.Get("keyCode").Int()
    318 			i.keyUpEdge(code)
    319 			return
    320 		}
    321 		code := e.Get("code").String()
    322 		i.keyUp(code)
    323 	case "mousedown":
    324 		button := e.Get("button").Int()
    325 		i.mouseDown(button)
    326 		i.setMouseCursorFromEvent(e)
    327 	case "mouseup":
    328 		button := e.Get("button").Int()
    329 		i.mouseUp(button)
    330 		i.setMouseCursorFromEvent(e)
    331 	case "mousemove":
    332 		i.setMouseCursorFromEvent(e)
    333 	case "wheel":
    334 		// TODO: What if e.deltaMode is not DOM_DELTA_PIXEL?
    335 		i.wheelX = -e.Get("deltaX").Float()
    336 		i.wheelY = -e.Get("deltaY").Float()
    337 	case "touchstart", "touchend", "touchmove":
    338 		i.updateTouches(e)
    339 	}
    340 }
    341 
    342 func (i *Input) setMouseCursorFromEvent(e js.Value) {
    343 	x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
    344 	i.setMouseCursor(x, y)
    345 }
    346 
    347 func (i *Input) updateTouches(e js.Value) {
    348 	j := e.Get("targetTouches")
    349 	ts := map[driver.TouchID]pos{}
    350 	for i := 0; i < j.Length(); i++ {
    351 		jj := j.Call("item", i)
    352 		id := driver.TouchID(jj.Get("identifier").Int())
    353 		ts[id] = pos{
    354 			X: jj.Get("clientX").Int(),
    355 			Y: jj.Get("clientY").Int(),
    356 		}
    357 	}
    358 	i.touches = ts
    359 }