From 6ac6b8e7c02b50b02f63f50ad918f31e00dbca81 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Thu, 24 Mar 2016 23:51:20 +0900 Subject: [PATCH] input: Make functions goroutine-safe (#192) --- input.go | 28 +++++++--- internal/ui/input.go | 105 +++++++++++++++++++++++--------------- internal/ui/input_glfw.go | 9 ++-- internal/ui/input_js.go | 28 ++++++---- internal/ui/ui_glfw.go | 2 +- 5 files changed, 108 insertions(+), 64 deletions(-) diff --git a/input.go b/input.go index 17b5e81bc..703fb5bb0 100644 --- a/input.go +++ b/input.go @@ -19,48 +19,62 @@ import ( ) // IsKeyPressed returns a boolean indicating whether key is pressed. +// +// This function is goroutine-safe. func IsKeyPressed(key Key) bool { - return ui.IsKeyPressed(ui.Key(key)) + return ui.CurrentInput().IsKeyPressed(ui.Key(key)) } // CursorPosition returns a position of a mouse cursor. +// +// This function is goroutine-safe. func CursorPosition() (x, y int) { - return ui.CursorPosition() + return ui.CurrentInput().CursorPosition() } // IsMouseButtonPressed returns a boolean indicating whether mouseButton is pressed. +// +// This function is goroutine-safe. func IsMouseButtonPressed(mouseButton MouseButton) bool { - return ui.IsMouseButtonPressed(ui.MouseButton(mouseButton)) + return ui.CurrentInput().IsMouseButtonPressed(ui.MouseButton(mouseButton)) } // GamepadAxisNum returns the number of axes of the gamepad. // +// This function is goroutine-safe. +// // NOTE: Gamepad API is available only on desktops, Chrome and Firefox. // To use this API, browsers might require rebooting the browser. func GamepadAxisNum(id int) int { - return ui.GamepadAxisNum(id) + return ui.CurrentInput().GamepadAxisNum(id) } // GamepadAxis returns the float value [-1.0 - 1.0] of the axis. // +// This function is goroutine-safe. +// // NOTE: Gamepad API is available only on desktops, Chrome and Firefox. // To use this API, browsers might require rebooting the browser. func GamepadAxis(id int, axis int) float64 { - return ui.GamepadAxis(id, axis) + return ui.CurrentInput().GamepadAxis(id, axis) } // GamepadButtonNum returns the number of the buttons of the gamepad. // +// This function is goroutine-safe. +// // NOTE: Gamepad API is available only on desktops, Chrome and Firefox. // To use this API, browsers might require rebooting the browser. func GamepadButtonNum(id int) int { - return ui.GamepadButtonNum(id) + return ui.CurrentInput().GamepadButtonNum(id) } // IsGamepadButtonPressed returns the boolean indicating the buttons is pressed or not. // +// This function is goroutine-safe. +// // NOTE: Gamepad API is available only on desktops, Chrome and Firefox. // To use this API, browsers might require rebooting the browser. func IsGamepadButtonPressed(id int, button GamepadButton) bool { - return ui.IsGamepadButtonPressed(id, ui.GamepadButton(button)) + return ui.CurrentInput().IsGamepadButtonPressed(id, ui.GamepadButton(button)) } diff --git a/internal/ui/input.go b/internal/ui/input.go index 69ca66c69..cbb263ffc 100644 --- a/internal/ui/input.go +++ b/internal/ui/input.go @@ -14,54 +14,19 @@ package ui -func IsKeyPressed(key Key) bool { - return currentInput.keyPressed[key] -} +import ( + "sync" +) -func CursorPosition() (x, y int) { - return currentInput.cursorX, currentInput.cursorY -} +var currentInput = &Input{} -func IsMouseButtonPressed(button MouseButton) bool { - return currentInput.mouseButtonPressed[button] -} - -func GamepadAxisNum(id int) int { - if len(currentInput.gamepads) <= id { - return 0 - } - return currentInput.gamepads[id].axisNum -} - -func GamepadAxis(id int, axis int) float64 { - if len(currentInput.gamepads) <= id { - return 0 - } - return currentInput.gamepads[id].axes[axis] -} - -func GamepadButtonNum(id int) int { - if len(currentInput.gamepads) <= id { - return 0 - } - return currentInput.gamepads[id].buttonNum -} - -func IsGamepadButtonPressed(id int, button GamepadButton) bool { - if len(currentInput.gamepads) <= id { - return false - } - return currentInput.gamepads[id].buttonPressed[button] -} - -var currentInput input - -type input struct { +type Input struct { keyPressed [256]bool mouseButtonPressed [256]bool cursorX int cursorY int gamepads [16]gamePad + m sync.RWMutex } type gamePad struct { @@ -70,3 +35,61 @@ type gamePad struct { buttonNum int buttonPressed [256]bool } + +func CurrentInput() *Input { + return currentInput +} + +func (i *Input) IsKeyPressed(key Key) bool { + i.m.RLock() + defer i.m.RUnlock() + return i.keyPressed[key] +} + +func (i *Input) CursorPosition() (x, y int) { + i.m.RLock() + defer i.m.RUnlock() + return i.cursorX, currentInput.cursorY +} + +func (i *Input) IsMouseButtonPressed(button MouseButton) bool { + i.m.RLock() + defer i.m.RUnlock() + return i.mouseButtonPressed[button] +} + +func (i *Input) GamepadAxisNum(id int) int { + i.m.RLock() + defer i.m.RUnlock() + if len(i.gamepads) <= id { + return 0 + } + return i.gamepads[id].axisNum +} + +func (i *Input) GamepadAxis(id int, axis int) float64 { + i.m.RLock() + defer i.m.RUnlock() + if len(i.gamepads) <= id { + return 0 + } + return i.gamepads[id].axes[axis] +} + +func (i *Input) GamepadButtonNum(id int) int { + i.m.RLock() + defer i.m.RUnlock() + if len(i.gamepads) <= id { + return 0 + } + return i.gamepads[id].buttonNum +} + +func (i *Input) IsGamepadButtonPressed(id int, button GamepadButton) bool { + i.m.RLock() + defer i.m.RUnlock() + if len(i.gamepads) <= id { + return false + } + return i.gamepads[id].buttonPressed[button] +} diff --git a/internal/ui/input_glfw.go b/internal/ui/input_glfw.go index 5e2fb3fad..2ea15a5f3 100644 --- a/internal/ui/input_glfw.go +++ b/internal/ui/input_glfw.go @@ -21,17 +21,16 @@ import ( "math" ) -func updateInput(window *glfw.Window, scale int) error { - return currentInput.update(window, scale) -} - var glfwMouseButtonToMouseButton = map[glfw.MouseButton]MouseButton{ glfw.MouseButtonLeft: MouseButtonLeft, glfw.MouseButtonRight: MouseButtonRight, glfw.MouseButtonMiddle: MouseButtonMiddle, } -func (i *input) update(window *glfw.Window, scale int) error { +func (i *Input) update(window *glfw.Window, scale int) error { + i.m.Lock() + defer i.m.Unlock() + for g, e := range glfwKeyCodeToKey { i.keyPressed[e] = window.GetKey(g) == glfw.Press } diff --git a/internal/ui/input_js.go b/internal/ui/input_js.go index aa0306ed0..7d7a4604d 100644 --- a/internal/ui/input_js.go +++ b/internal/ui/input_js.go @@ -20,11 +20,9 @@ import ( "github.com/gopherjs/gopherjs/js" ) -func CurrentInput() *input { - return ¤tInput -} - -func (i *input) KeyDown(key int) { +func (i *Input) KeyDown(key int) { + i.m.Lock() + defer i.m.Unlock() k, ok := keyCodeToKey[key] if !ok { return @@ -32,7 +30,9 @@ func (i *input) KeyDown(key int) { i.keyPressed[k] = true } -func (i *input) KeyUp(key int) { +func (i *Input) KeyUp(key int) { + i.m.Lock() + defer i.m.Unlock() k, ok := keyCodeToKey[key] if !ok { return @@ -40,7 +40,9 @@ func (i *input) KeyUp(key int) { i.keyPressed[k] = false } -func (i *input) MouseDown(button int) { +func (i *Input) MouseDown(button int) { + i.m.Lock() + defer i.m.Unlock() p := &i.mouseButtonPressed switch button { case 0: @@ -52,7 +54,9 @@ func (i *input) MouseDown(button int) { } } -func (i *input) MouseUp(button int) { +func (i *Input) MouseUp(button int) { + i.m.Lock() + defer i.m.Unlock() p := &i.mouseButtonPressed switch button { case 0: @@ -64,11 +68,15 @@ func (i *input) MouseUp(button int) { } } -func (i *input) SetMouseCursor(x, y int) { +func (i *Input) SetMouseCursor(x, y int) { + i.m.Lock() + defer i.m.Unlock() i.cursorX, i.cursorY = x, y } -func (i *input) UpdateGamepads() { +func (i *Input) UpdateGamepads() { + i.m.Lock() + defer i.m.Unlock() nav := js.Global.Get("navigator") if nav.Get("getGamepads") == js.Undefined { return diff --git a/internal/ui/ui_glfw.go b/internal/ui/ui_glfw.go index d453e960c..8f61ec5af 100644 --- a/internal/ui/ui_glfw.go +++ b/internal/ui/ui_glfw.go @@ -153,7 +153,7 @@ func (u *userInterface) actualScreenScale() int { func (u *userInterface) pollEvents() error { glfw.PollEvents() - return updateInput(u.window, u.windowScale()) + return currentInput.update(u.window, u.windowScale()) } func (u *userInterface) doEvents() error {