mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
parent
e6346c01d2
commit
dd7e125d9c
@ -17,15 +17,18 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"image"
|
"image"
|
||||||
|
"image/color"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/bitmapfont/v2"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/examples/keyboard/keyboard"
|
"github.com/hajimehoshi/ebiten/v2/examples/keyboard/keyboard"
|
||||||
rkeyboard "github.com/hajimehoshi/ebiten/v2/examples/resources/images/keyboard"
|
rkeyboard "github.com/hajimehoshi/ebiten/v2/examples/resources/images/keyboard"
|
||||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/text"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -78,11 +81,17 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
|||||||
screen.DrawImage(keyboardImage.SubImage(r).(*ebiten.Image), op)
|
screen.DrawImage(keyboardImage.SubImage(r).(*ebiten.Image), op)
|
||||||
}
|
}
|
||||||
|
|
||||||
keyStrs := []string{}
|
var keyStrs []string
|
||||||
|
var keyNames []string
|
||||||
for _, k := range g.keys {
|
for _, k := range g.keys {
|
||||||
keyStrs = append(keyStrs, k.String())
|
keyStrs = append(keyStrs, k.String())
|
||||||
|
if name := ebiten.KeyName(k); name != "" {
|
||||||
|
keyNames = append(keyNames, name)
|
||||||
}
|
}
|
||||||
ebitenutil.DebugPrint(screen, strings.Join(keyStrs, ", "))
|
}
|
||||||
|
|
||||||
|
// Use bitmapfont.Face instead of ebitenutil.DebugPrint, since some key names might not be printed with DebugPrint.
|
||||||
|
text.Draw(screen, strings.Join(keyStrs, ", ")+"\n"+strings.Join(keyNames, ", "), bitmapfont.Face, 8, 12, color.White)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||||
|
13
input.go
13
input.go
@ -69,6 +69,19 @@ func IsKeyPressed(key Key) bool {
|
|||||||
return theInputState.isKeyPressed(key)
|
return theInputState.isKeyPressed(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeyName returns a key name for the current keyboard layout.
|
||||||
|
// For example, KeyName(KeyQ) returns 'q' for a QWERTY keyboard, and returns 'a' for an AZERTY keyboard.
|
||||||
|
//
|
||||||
|
// KeyName returns an empty string if 1) the key doesn't have a phisical key name, 2) the platform doesn't support KeyName,
|
||||||
|
// or 3) the main loop doesn't start yet.
|
||||||
|
//
|
||||||
|
// KeyName is supported by desktops and browsers.
|
||||||
|
//
|
||||||
|
// KeyName is concurrent-safe.
|
||||||
|
func KeyName(key Key) string {
|
||||||
|
return ui.KeyName(ui.Key(key))
|
||||||
|
}
|
||||||
|
|
||||||
// CursorPosition returns a position of a mouse cursor relative to the game screen (window). The cursor position is
|
// CursorPosition returns a position of a mouse cursor relative to the game screen (window). The cursor position is
|
||||||
// 'logical' position and this considers the scale of the screen.
|
// 'logical' position and this considers the scale of the screen.
|
||||||
//
|
//
|
||||||
|
@ -273,6 +273,10 @@ func CreateWindow(width, height int, title string, monitor *Monitor, share *Wind
|
|||||||
return theWindows.add(w), nil
|
return theWindows.add(w), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetKeyName(key Key, scancode int) string {
|
||||||
|
return glfw.GetKeyName(glfw.Key(key), scancode)
|
||||||
|
}
|
||||||
|
|
||||||
func GetMonitors() []*Monitor {
|
func GetMonitors() []*Monitor {
|
||||||
ms := []*Monitor{}
|
ms := []*Monitor{}
|
||||||
for _, m := range glfw.GetMonitors() {
|
for _, m := range glfw.GetMonitors() {
|
||||||
|
@ -306,6 +306,14 @@ func CreateWindow(width, height int, title string, monitor *Monitor, share *Wind
|
|||||||
return (*Window)(w), err
|
return (*Window)(w), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetKeyName(key Key, scancode int) string {
|
||||||
|
name, err := glfwwin.GetKeyName(glfwwin.Key(key), scancode)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
func GetMonitors() []*Monitor {
|
func GetMonitors() []*Monitor {
|
||||||
ms, err := glfwwin.GetMonitors()
|
ms, err := glfwwin.GetMonitors()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -845,6 +845,7 @@ var (
|
|||||||
procSetWindowTextW = user32.NewProc("SetWindowTextW")
|
procSetWindowTextW = user32.NewProc("SetWindowTextW")
|
||||||
procShowWindow = user32.NewProc("ShowWindow")
|
procShowWindow = user32.NewProc("ShowWindow")
|
||||||
procSystemParametersInfoW = user32.NewProc("SystemParametersInfoW")
|
procSystemParametersInfoW = user32.NewProc("SystemParametersInfoW")
|
||||||
|
procToUnicode = user32.NewProc("ToUnicode")
|
||||||
procTranslateMessage = user32.NewProc("TranslateMessage")
|
procTranslateMessage = user32.NewProc("TranslateMessage")
|
||||||
procTrackMouseEvent = user32.NewProc("TrackMouseEvent")
|
procTrackMouseEvent = user32.NewProc("TrackMouseEvent")
|
||||||
procUnregisterClassW = user32.NewProc("UnregisterClassW")
|
procUnregisterClassW = user32.NewProc("UnregisterClassW")
|
||||||
@ -1718,6 +1719,24 @@ func _TlsSetValue(dwTlsIndex uint32, lpTlsValue uintptr) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _ToUnicode(wVirtualKey uint32, wScanCode uint32, keyState []byte, buff []uint16, cchBuff int32, wFlags uint32) int32 {
|
||||||
|
var lpKeyState *byte
|
||||||
|
if len(keyState) > 0 {
|
||||||
|
lpKeyState = &keyState[0]
|
||||||
|
}
|
||||||
|
var pwszBuff *uint16
|
||||||
|
if len(buff) > 0 {
|
||||||
|
pwszBuff = &buff[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _, _ := procToUnicode.Call(uintptr(wVirtualKey), uintptr(wScanCode), uintptr(unsafe.Pointer(lpKeyState)),
|
||||||
|
uintptr(unsafe.Pointer(pwszBuff)), uintptr(cchBuff), uintptr(wFlags))
|
||||||
|
runtime.KeepAlive(lpKeyState)
|
||||||
|
runtime.KeepAlive(pwszBuff)
|
||||||
|
|
||||||
|
return int32(r)
|
||||||
|
}
|
||||||
|
|
||||||
func _TranslateMessage(lpMsg *_MSG) bool {
|
func _TranslateMessage(lpMsg *_MSG) bool {
|
||||||
r, _, _ := procTranslateMessage.Call(uintptr(unsafe.Pointer(lpMsg)))
|
r, _, _ := procTranslateMessage.Call(uintptr(unsafe.Pointer(lpMsg)))
|
||||||
return int32(r) != 0
|
return int32(r) != 0
|
||||||
|
@ -240,7 +240,20 @@ func RawMouseMotionSupported() (bool, error) {
|
|||||||
return platformRawMouseMotionSupported(), nil
|
return platformRawMouseMotionSupported(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKeyName is not implemented.
|
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) {
|
func GetKeyScancode(key Key) (int, error) {
|
||||||
if !_glfw.initialized {
|
if !_glfw.initialized {
|
||||||
|
@ -261,6 +261,7 @@ type library struct {
|
|||||||
clipboardString string
|
clipboardString string
|
||||||
keycodes [512]Key
|
keycodes [512]Key
|
||||||
scancodes [KeyLast + 1]int
|
scancodes [KeyLast + 1]int
|
||||||
|
keynames [KeyLast + 1]string
|
||||||
|
|
||||||
// Where to place the cursor when re-enabled
|
// Where to place the cursor when re-enabled
|
||||||
restoreCursorPosX float64
|
restoreCursorPosX float64
|
||||||
|
@ -151,6 +151,47 @@ func createKeyTables() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateKeyNamesWin32() {
|
||||||
|
for i := range _glfw.win32.keynames {
|
||||||
|
_glfw.win32.keynames[i] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var state [256]byte
|
||||||
|
|
||||||
|
for key := KeySpace; key <= KeyLast; key++ {
|
||||||
|
scancode := _glfw.win32.scancodes[key]
|
||||||
|
if scancode == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var vk uint32
|
||||||
|
if key >= KeyKP0 && key <= KeyKPAdd {
|
||||||
|
vks := []uint32{
|
||||||
|
_VK_NUMPAD0, _VK_NUMPAD1, _VK_NUMPAD2, _VK_NUMPAD3,
|
||||||
|
_VK_NUMPAD4, _VK_NUMPAD5, _VK_NUMPAD6, _VK_NUMPAD7,
|
||||||
|
_VK_NUMPAD8, _VK_NUMPAD9, _VK_DECIMAL, _VK_DIVIDE,
|
||||||
|
_VK_MULTIPLY, _VK_SUBTRACT, _VK_ADD,
|
||||||
|
}
|
||||||
|
vk = vks[key-KeyKP0]
|
||||||
|
} else {
|
||||||
|
vk = _MapVirtualKeyW(uint32(scancode), _MAPVK_VSC_TO_VK)
|
||||||
|
}
|
||||||
|
|
||||||
|
var chars [16]uint16
|
||||||
|
length := _ToUnicode(vk, uint32(scancode), state[:], chars[:], int32(len(chars)), 0)
|
||||||
|
if length == -1 {
|
||||||
|
// This is a dead key, so we need a second simulated key press
|
||||||
|
// to make it output its own character (usually a diacritic)
|
||||||
|
length = _ToUnicode(vk, uint32(scancode), state[:], chars[:], int32(len(chars)), 0)
|
||||||
|
}
|
||||||
|
if length < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.win32.keynames[key] = windows.UTF16ToString(chars[:length])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createHelperWindow() error {
|
func createHelperWindow() error {
|
||||||
h, err := _CreateWindowExW(_WS_EX_OVERLAPPEDWINDOW, _GLFW_WNDCLASSNAME, "GLFW message window", _WS_CLIPSIBLINGS|_WS_CLIPCHILDREN, 0, 0, 1, 1, 0, 0, _glfw.win32.instance, nil)
|
h, err := _CreateWindowExW(_WS_EX_OVERLAPPEDWINDOW, _GLFW_WNDCLASSNAME, "GLFW message window", _WS_CLIPSIBLINGS|_WS_CLIPCHILDREN, 0, 0, 1, 1, 0, 0, _glfw.win32.instance, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -238,6 +279,7 @@ func platformInit() error {
|
|||||||
_glfw.win32.instance = _HINSTANCE(m)
|
_glfw.win32.instance = _HINSTANCE(m)
|
||||||
|
|
||||||
createKeyTables()
|
createKeyTables()
|
||||||
|
updateKeyNamesWin32()
|
||||||
|
|
||||||
if isWindows10CreatorsUpdateOrGreaterWin32() {
|
if isWindows10CreatorsUpdateOrGreaterWin32() {
|
||||||
if !microsoftgdk.IsXbox() {
|
if !microsoftgdk.IsXbox() {
|
||||||
|
@ -690,7 +690,8 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
case _WM_INPUTLANGCHANGE:
|
case _WM_INPUTLANGCHANGE:
|
||||||
// Do nothing
|
updateKeyNamesWin32()
|
||||||
|
return 0
|
||||||
|
|
||||||
case _WM_CHAR, _WM_SYSCHAR:
|
case _WM_CHAR, _WM_SYSCHAR:
|
||||||
if wParam >= 0xd800 && wParam <= 0xdbff {
|
if wParam >= 0xd800 && wParam <= 0xdbff {
|
||||||
@ -2204,6 +2205,13 @@ func (w *Window) platformSetCursorMode(mode int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func platformGetScancodeName(scancode int) (string, error) {
|
||||||
|
if scancode < 0 || scancode > (_KF_EXTENDED|0xff) || _glfw.win32.keycodes[scancode] == KeyUnknown {
|
||||||
|
return "", fmt.Errorf("glwfwin: invalid scancode %d: %w", scancode, InvalidValue)
|
||||||
|
}
|
||||||
|
return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]], nil
|
||||||
|
}
|
||||||
|
|
||||||
func platformGetKeyScancode(key Key) int {
|
func platformGetKeyScancode(key Key) int {
|
||||||
return _glfw.win32.scancodes[key]
|
return _glfw.win32.scancodes[key]
|
||||||
}
|
}
|
||||||
|
@ -76,3 +76,24 @@ func (u *userInterfaceImpl) updateInputState() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func KeyName(key Key) string {
|
||||||
|
return theUI.keyName(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *userInterfaceImpl) keyName(key Key) string {
|
||||||
|
if !u.isRunning() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
gk, ok := uiKeyToGLFWKey[key]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var name string
|
||||||
|
u.t.Call(func() {
|
||||||
|
name = glfw.GetKeyName(gk, 0)
|
||||||
|
})
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
@ -167,3 +167,51 @@ func isKeyString(str string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
jsKeyboard = js.Global().Get("navigator").Get("keyboard")
|
||||||
|
jsKeyboardGetLayoutMap js.Value
|
||||||
|
jsKeyboardGetLayoutMapCh chan js.Value
|
||||||
|
jsKeyboardGetLayoutMapCallback js.Func
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if !jsKeyboard.Truthy() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jsKeyboardGetLayoutMap = jsKeyboard.Get("getLayoutMap").Call("bind", jsKeyboard)
|
||||||
|
jsKeyboardGetLayoutMapCh = make(chan js.Value, 1)
|
||||||
|
jsKeyboardGetLayoutMapCallback = js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
|
jsKeyboardGetLayoutMapCh <- args[0]
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func KeyName(key Key) string {
|
||||||
|
return theUI.keyName(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *userInterfaceImpl) keyName(key Key) string {
|
||||||
|
if !u.running {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyboardLayoutMap is reset every tick.
|
||||||
|
if u.keyboardLayoutMap.IsUndefined() {
|
||||||
|
if !jsKeyboard.Truthy() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke getLayoutMap every tick to detect the keyboard change.
|
||||||
|
// TODO: Calling this every tick might be inefficient. Is there a way to detect a keyboard change?
|
||||||
|
jsKeyboardGetLayoutMap.Invoke().Call("then", jsKeyboardGetLayoutMapCallback)
|
||||||
|
u.keyboardLayoutMap = <-jsKeyboardGetLayoutMapCh
|
||||||
|
}
|
||||||
|
|
||||||
|
n := u.keyboardLayoutMap.Call("get", uiKeyToJSKey[key])
|
||||||
|
if n.IsUndefined() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return n.String()
|
||||||
|
}
|
||||||
|
@ -51,3 +51,8 @@ func (u *userInterfaceImpl) updateInputState(keys map[Key]struct{}, runes []rune
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func KeyName(key Key) string {
|
||||||
|
// TODO: Implement this.
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
@ -37,3 +37,7 @@ func (u *userInterfaceImpl) updateInputState() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func KeyName(key Key) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
@ -91,6 +91,8 @@ type userInterfaceImpl struct {
|
|||||||
origCursorX int
|
origCursorX int
|
||||||
origCursorY int
|
origCursorY int
|
||||||
|
|
||||||
|
keyboardLayoutMap js.Value
|
||||||
|
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,6 +688,7 @@ func (u *userInterfaceImpl) readInputState(inputState *InputState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterfaceImpl) resetForTick() {
|
func (u *userInterfaceImpl) resetForTick() {
|
||||||
|
u.keyboardLayoutMap = js.Value{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterfaceImpl) Window() Window {
|
func (u *userInterfaceImpl) Window() Window {
|
||||||
|
Loading…
Reference in New Issue
Block a user