ebiten/internal/glfwwin/input_windows.go

515 lines
11 KiB
Go
Raw Normal View History

// SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: 2002-2006 Marcus Geelnard
// SPDX-FileCopyrightText: 2006-2019 Camilla Löwy
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
package glfwwin
import (
"fmt"
"math"
)
const stick = 3
func (w *Window) inputKey(key Key, scancode int, action Action, mods ModifierKey) {
if key >= 0 && key <= KeyLast {
var repeated bool
if action == Release && w.keys[key] == Release {
return
}
if action == Press && w.keys[key] == Press {
repeated = true
}
if action == Release && w.stickyKeys {
w.keys[key] = stick
} else {
w.keys[key] = action
}
if repeated {
action = Repeat
}
}
if !w.lockKeyMods {
mods &^= ModCapsLock | ModNumLock
}
if w.callbacks.key != nil {
w.callbacks.key(w, key, scancode, action, mods)
}
}
func (w *Window) inputChar(codepoint rune, mods ModifierKey, plain bool) {
if codepoint < 32 || (codepoint > 126 && codepoint < 160) {
return
}
if !w.lockKeyMods {
mods &^= ModCapsLock | ModNumLock
}
if w.callbacks.charmods != nil {
w.callbacks.charmods(w, codepoint, mods)
}
if plain {
if w.callbacks.character != nil {
w.callbacks.character(w, codepoint)
}
}
}
func (w *Window) inputScroll(xoffset, yoffset float64) {
if w.callbacks.scroll != nil {
w.callbacks.scroll(w, xoffset, yoffset)
}
}
func (w *Window) inputMouseClick(button MouseButton, action Action, mods ModifierKey) {
if button < 0 || button > MouseButtonLast {
return
}
if !w.lockKeyMods {
mods &^= ModCapsLock | ModNumLock
}
if action == Release && w.stickyMouseButtons {
w.mouseButtons[button] = stick
} else {
w.mouseButtons[button] = action
}
if w.callbacks.mouseButton != nil {
w.callbacks.mouseButton(w, button, action, mods)
}
}
func (w *Window) inputCursorPos(xpos float64, ypos float64) {
if w.virtualCursorPosX == xpos && w.virtualCursorPosY == ypos {
return
}
w.virtualCursorPosX = xpos
w.virtualCursorPosY = ypos
if w.callbacks.cursorPos != nil {
w.callbacks.cursorPos(w, xpos, ypos)
}
}
func (w *Window) inputCursorEnter(entered bool) {
if w.callbacks.cursorEnter != nil {
w.callbacks.cursorEnter(w, entered)
}
}
func (w *Window) inputDrop(paths []string) {
if w.callbacks.drop != nil {
w.callbacks.drop(w, paths)
}
}
func (w *Window) centerCursorInContentArea() error {
width, height, err := w.platformGetWindowSize()
if err != nil {
return err
}
if err := w.platformSetCursorPos(float64(width/2), float64(height/2)); err != nil {
return err
}
return nil
}
func (w *Window) GetInputMode(mode InputMode) (int, error) {
if !_glfw.initialized {
return 0, NotInitialized
}
switch mode {
case CursorMode:
return w.cursorMode, nil
case StickyKeysMode:
return boolToInt(w.stickyKeys), nil
case StickyMouseButtonsMode:
return boolToInt(w.stickyMouseButtons), nil
case LockKeyMods:
return boolToInt(w.lockKeyMods), nil
case RawMouseMotion:
return boolToInt(w.rawMouseMotion), nil
default:
return 0, fmt.Errorf("glfwwin: invalid input mode 0x%08X: %w", mode, InvalidEnum)
}
}
func (w *Window) SetInputMode(mode InputMode, value int) error {
if !_glfw.initialized {
return NotInitialized
}
switch mode {
case CursorMode:
if value != CursorNormal && value != CursorHidden && value != CursorDisabled {
return fmt.Errorf("glfwwin: invalid cursor mode 0x%08X: %w", value, InvalidEnum)
}
if w.cursorMode == value {
return nil
}
w.cursorMode = value
x, y, err := w.platformGetCursorPos()
if err != nil {
return err
}
w.virtualCursorPosX = x
w.virtualCursorPosY = y
if err := w.platformSetCursorMode(value); err != nil {
return err
}
return nil
case StickyKeysMode:
if w.stickyKeys == intToBool(value) {
return nil
}
if !intToBool(value) {
// Release all sticky keys
for i := Key(0); i <= KeyLast; i++ {
if w.keys[i] == stick {
w.keys[i] = Release
}
}
}
w.stickyKeys = intToBool(value)
return nil
case StickyMouseButtonsMode:
if w.stickyMouseButtons == intToBool(value) {
return nil
}
if !intToBool(value) {
// Release all sticky mouse buttons
for i := MouseButton(0); i <= MouseButtonLast; i++ {
if w.mouseButtons[i] == stick {
w.mouseButtons[i] = Release
}
}
}
w.stickyMouseButtons = intToBool(value)
return nil
case LockKeyMods:
w.lockKeyMods = intToBool(value)
return nil
case RawMouseMotion:
if !platformRawMouseMotionSupported() {
return fmt.Errorf("glfwwin: raw mouse motion is not supported on this system: %w", PlatformError)
}
if w.rawMouseMotion == intToBool(value) {
return nil
}
w.rawMouseMotion = intToBool(value)
if err := w.platformSetRawMouseMotion(intToBool(value)); err != nil {
return err
}
return nil
default:
return fmt.Errorf("glfwwin: invalid input mode 0x%08X: %w", mode, InvalidEnum)
}
}
func RawMouseMotionSupported() (bool, error) {
if !_glfw.initialized {
return false, NotInitialized
}
return platformRawMouseMotionSupported(), nil
}
func GetKeyName(key Key, scancode int) (string, error) {
if !_glfw.initialized {
return "", NotInitialized
}
if key != KeyUnknown {
if key != KeyKPEqual && (key < KeyKP0 || key > KeyKPAdd) && (key < KeyApostrophe || key > KeyWorld2) {
return "", nil
}
scancode = platformGetKeyScancode(key)
}
return platformGetScancodeName(scancode)
}
func GetKeyScancode(key Key) (int, error) {
if !_glfw.initialized {
return 0, NotInitialized
}
if key < KeySpace || key > KeyLast {
return 0, fmt.Errorf("glfwwin: invalid key %d: %w", key, InvalidEnum)
}
return platformGetKeyScancode(key), nil
}
func (w *Window) GetKey(key Key) (Action, error) {
if !_glfw.initialized {
return 0, NotInitialized
}
if key < KeySpace || key > KeyLast {
return 0, fmt.Errorf("glfwwin: invalid key %d: %w", key, InvalidEnum)
}
if w.keys[key] == stick {
// Sticky mode: release key now
w.keys[key] = Release
return Press, nil
}
return w.keys[key], nil
}
func (w *Window) GetMouseButton(button MouseButton) (Action, error) {
if !_glfw.initialized {
return 0, NotInitialized
}
if button < MouseButton1 || button > MouseButtonLast {
return 0, fmt.Errorf("glfwwin: invalid mouse button %d: %w", button, InvalidEnum)
}
if w.mouseButtons[button] == stick {
// Sticky mode: release mouse button now
w.mouseButtons[button] = Release
return Press, nil
}
return w.mouseButtons[button], nil
}
func (w *Window) GetCursorPos() (xpos, ypos float64, err error) {
if !_glfw.initialized {
return 0, 0, NotInitialized
}
if w.cursorMode == CursorDisabled {
return w.virtualCursorPosX, w.virtualCursorPosY, nil
} else {
return w.platformGetCursorPos()
}
}
func (w *Window) SetCursorPos(xpos, ypos float64) error {
if !_glfw.initialized {
return NotInitialized
}
if xpos != xpos || xpos < -math.MaxFloat64 || xpos > math.MaxFloat64 || ypos != ypos || ypos < -math.MaxFloat64 || ypos > math.MaxFloat64 {
return fmt.Errorf("glfwwin: invalid cursor position %f %f: %w", xpos, ypos, InvalidValue)
}
if !w.platformWindowFocused() {
return nil
}
if w.cursorMode == CursorDisabled {
// Only update the accumulated position if the cursor is disabled
w.virtualCursorPosX = xpos
w.virtualCursorPosY = ypos
return nil
} else {
// Update system cursor position
return w.platformSetCursorPos(xpos, ypos)
}
}
func CreateCursor(image *Image, xhot, yhot int) (*Cursor, error) {
if !_glfw.initialized {
return nil, NotInitialized
}
cursor := &Cursor{}
_glfw.cursors = append(_glfw.cursors, cursor)
if err := cursor.platformCreateCursor(image, xhot, yhot); err != nil {
_ = cursor.Destroy()
return nil, err
}
return cursor, nil
}
func CreateStandardCursor(shape StandardCursor) (*Cursor, error) {
if !_glfw.initialized {
return nil, NotInitialized
}
if shape != ArrowCursor &&
shape != IBeamCursor &&
shape != CrosshairCursor &&
shape != HandCursor &&
shape != HResizeCursor &&
shape != VResizeCursor {
return nil, fmt.Errorf("glfwwin: invalid standard cursor 0x%08X: %w", shape, InvalidEnum)
}
cursor := &Cursor{}
_glfw.cursors = append(_glfw.cursors, cursor)
if err := cursor.platformCreateStandardCursor(shape); err != nil {
_ = cursor.Destroy()
return nil, err
}
return cursor, nil
}
func (c *Cursor) Destroy() error {
if !_glfw.initialized {
return NotInitialized
}
if c == nil {
return nil
}
// Make sure the cursor is not being used by any window
for _, window := range _glfw.windows {
if window.cursor == c {
if err := window.SetCursor(nil); err != nil {
return err
}
}
}
if err := c.platformDestroyCursor(); err != nil {
return err
}
// Unlink cursor from global linked list
for i, cursor := range _glfw.cursors {
if cursor == c {
copy(_glfw.cursors[i:], _glfw.cursors[i+1:])
_glfw.cursors = _glfw.cursors[:len(_glfw.cursors)-1]
break
}
}
return nil
}
func (w *Window) SetCursor(cursor *Cursor) error {
if !_glfw.initialized {
return NotInitialized
}
w.cursor = cursor
if err := w.platformSetCursor(cursor); err != nil {
return err
}
return nil
}
func (w *Window) SetKeyCallback(cbfun KeyCallback) (KeyCallback, error) {
if !_glfw.initialized {
return nil, NotInitialized
}
old := w.callbacks.key
w.callbacks.key = cbfun
return old, nil
}
func (w *Window) SetCharCallback(cbfun CharCallback) (CharCallback, error) {
if !_glfw.initialized {
return nil, NotInitialized
}
old := w.callbacks.character
w.callbacks.character = cbfun
return old, nil
}
func (w *Window) SetCharModsCallback(cbfun CharModsCallback) (CharModsCallback, error) {
if !_glfw.initialized {
return nil, NotInitialized
}
old := w.callbacks.charmods
w.callbacks.charmods = cbfun
return old, nil
}
func (w *Window) SetMouseButtonCallback(cbfun MouseButtonCallback) (MouseButtonCallback, error) {
if !_glfw.initialized {
return nil, NotInitialized
}
old := w.callbacks.mouseButton
w.callbacks.mouseButton = cbfun
return old, nil
}
func (w *Window) SetCursorPosCallback(cbfun CursorPosCallback) (CursorPosCallback, error) {
if !_glfw.initialized {
return nil, NotInitialized
}
old := w.callbacks.cursorPos
w.callbacks.cursorPos = cbfun
return old, nil
}
func (w *Window) SetCursorEnterCallback(cbfun CursorEnterCallback) (CursorEnterCallback, error) {
if !_glfw.initialized {
return nil, NotInitialized
}
old := w.callbacks.cursorEnter
w.callbacks.cursorEnter = cbfun
return old, nil
}
func (w *Window) SetScrollCallback(cbfun ScrollCallback) (ScrollCallback, error) {
if !_glfw.initialized {
return nil, NotInitialized
}
old := w.callbacks.scroll
w.callbacks.scroll = cbfun
return old, nil
}
func (w *Window) SetDropCallback(cbfun DropCallback) (DropCallback, error) {
if !_glfw.initialized {
return nil, NotInitialized
}
old := w.callbacks.drop
w.callbacks.drop = cbfun
return old, nil
}
func (w *Window) SetClipboardString(str string) error {
if !_glfw.initialized {
return NotInitialized
}
return platformSetClipboardString(str)
}
func GetClipboardString() (string, error) {
if !_glfw.initialized {
return "", NotInitialized
}
return platformGetClipboardString()
}