Refactor input handling to unify mouse and keyboard input structures. Update key event processing to support extended key flags and improve error logging for input operations. Adjust key mappings for consistency across input types.
This commit is contained in:
@@ -409,7 +409,7 @@ func (a *Agent) handleKey(w http.ResponseWriter, r *http.Request) {
|
||||
helpers.WriteError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
helpers.Log.Printf("key: %v", err)
|
||||
helpers.Log.Printf("key %q action=%s mods=%v: %v", request.Key, action, request.Modifiers, err)
|
||||
helpers.WriteError(w, http.StatusInternalServerError, "could not send key")
|
||||
return
|
||||
}
|
||||
|
||||
+64
-30
@@ -2,6 +2,7 @@ package input
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/config"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/helpers"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -24,8 +26,11 @@ const (
|
||||
mouseAbsolute = 0x8000
|
||||
mouseVirtualDesk = 0x4000
|
||||
desktopAllAccess = 0x01FF
|
||||
|
||||
keyeventfExtended = 0x0001
|
||||
keyeventfKeyup = 0x0002
|
||||
keyeventfUnicode = 0x0004
|
||||
|
||||
smXVirtualScreen = 76
|
||||
smYVirtualScreen = 77
|
||||
smCXVirtualScreen = 78
|
||||
@@ -44,12 +49,31 @@ var (
|
||||
procSetThreadDesktop = user32.NewProc("SetThreadDesktop")
|
||||
procCloseDesktop = user32.NewProc("CloseDesktop")
|
||||
procGetSystemMetrics = user32.NewProc("GetSystemMetrics")
|
||||
|
||||
inputStructSize = int(unsafe.Sizeof(winInput{}))
|
||||
)
|
||||
|
||||
// ponytail: INPUT must be 40 bytes on amd64; wrong size yields SendInput failures.
|
||||
type mouseInput struct {
|
||||
Type uint32
|
||||
func init() {
|
||||
if inputStructSize != 40 {
|
||||
panic(fmt.Sprintf("winInput must be 40 bytes on this platform, got %d", inputStructSize))
|
||||
}
|
||||
if unsafe.Sizeof(winMouseInput{}) != 40 {
|
||||
panic(fmt.Sprintf("winMouseInput must be 40 bytes on this platform, got %d", unsafe.Sizeof(winMouseInput{})))
|
||||
}
|
||||
}
|
||||
|
||||
// winInput matches the 40-byte INPUT struct on amd64 (8-byte header + 32-byte union).
|
||||
type keyboardData struct {
|
||||
Vk uint16
|
||||
Scan uint16
|
||||
Flags uint32
|
||||
Time uint32
|
||||
_ uint32
|
||||
ExtraInfo uintptr
|
||||
_ [8]byte
|
||||
}
|
||||
|
||||
type mouseData struct {
|
||||
Dx int32
|
||||
Dy int32
|
||||
MouseData uint32
|
||||
@@ -59,15 +83,16 @@ type mouseInput struct {
|
||||
ExtraInfo uintptr
|
||||
}
|
||||
|
||||
type keybdInput struct {
|
||||
type winInput struct {
|
||||
Type uint32
|
||||
_ uint32
|
||||
Vk uint16
|
||||
Scan uint16
|
||||
Flags uint32
|
||||
Time uint32
|
||||
Ki keyboardData
|
||||
}
|
||||
|
||||
type winMouseInput struct {
|
||||
Type uint32
|
||||
_ uint32
|
||||
ExtraInfo uintptr
|
||||
Mi mouseData
|
||||
}
|
||||
|
||||
func EnableDPIAwareness() {
|
||||
@@ -87,16 +112,15 @@ func Click(x, y int, button string) error {
|
||||
}
|
||||
|
||||
absX, absY := absoluteCoords(x, y)
|
||||
inputs := []mouseInput{
|
||||
{Type: inputMouse, Dx: absX, Dy: absY, Flags: mouseMove | mouseAbsolute | mouseVirtualDesk},
|
||||
{Type: inputMouse, Flags: down},
|
||||
{Type: inputMouse, Flags: up},
|
||||
inputs := []winMouseInput{
|
||||
{Type: inputMouse, Mi: mouseData{Dx: absX, Dy: absY, Flags: mouseMove | mouseAbsolute | mouseVirtualDesk}},
|
||||
{Type: inputMouse, Mi: mouseData{Flags: down}},
|
||||
{Type: inputMouse, Mi: mouseData{Flags: up}},
|
||||
}
|
||||
if err := sendMouse(inputs); err != nil {
|
||||
if err := sendMouseInputs(inputs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ponytail: best-effort cursor sync for the local user; ignore denial after SendInput click.
|
||||
_, _, _ = procSetCursorPos.Call(uintptr(x), uintptr(y))
|
||||
return nil
|
||||
}
|
||||
@@ -135,18 +159,17 @@ func resolveKeyDelay(ms int) int {
|
||||
return ms
|
||||
}
|
||||
|
||||
// ResolveKeyDelay returns the effective per-key delay for API responses.
|
||||
func ResolveKeyDelay(ms int) int {
|
||||
return resolveKeyDelay(ms)
|
||||
}
|
||||
|
||||
func sendUnicodeRune(r rune) error {
|
||||
for _, unit := range utf16.Encode([]rune{r}) {
|
||||
inputs := []keybdInput{
|
||||
{Type: inputKeyboard, Scan: unit, Flags: keyeventfUnicode},
|
||||
{Type: inputKeyboard, Scan: unit, Flags: keyeventfUnicode | keyeventfKeyup},
|
||||
inputs := []winInput{
|
||||
{Type: inputKeyboard, Ki: keyboardData{Scan: unit, Flags: keyeventfUnicode}},
|
||||
{Type: inputKeyboard, Ki: keyboardData{Scan: unit, Flags: keyeventfUnicode | keyeventfKeyup}},
|
||||
}
|
||||
if err := sendKeys(inputs); err != nil {
|
||||
if err := sendKeyboardInputs(inputs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -193,18 +216,29 @@ func mouseFlags(button string) (down, up uint32, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func sendMouse(inputs []mouseInput) error {
|
||||
n, _, err := procSendInput.Call(uintptr(len(inputs)), uintptr(unsafe.Pointer(&inputs[0])), uintptr(unsafe.Sizeof(inputs[0])))
|
||||
if n == 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
func sendMouseInputs(inputs []winMouseInput) error {
|
||||
return sendInput(len(inputs), unsafe.Pointer(&inputs[0]), unsafe.Sizeof(inputs[0]), "mouse")
|
||||
}
|
||||
|
||||
func sendKeys(inputs []keybdInput) error {
|
||||
n, _, err := procSendInput.Call(uintptr(len(inputs)), uintptr(unsafe.Pointer(&inputs[0])), uintptr(unsafe.Sizeof(inputs[0])))
|
||||
if n == 0 {
|
||||
func sendKeyboardInputs(inputs []winInput) error {
|
||||
return sendInput(len(inputs), unsafe.Pointer(&inputs[0]), unsafe.Sizeof(inputs[0]), "keyboard")
|
||||
}
|
||||
|
||||
func sendInput(count int, ptr unsafe.Pointer, elemSize uintptr, kind string) error {
|
||||
if count == 0 {
|
||||
return nil
|
||||
}
|
||||
if int(elemSize) != inputStructSize {
|
||||
return fmt.Errorf("input struct size mismatch: %s has %d bytes, want %d", kind, elemSize, inputStructSize)
|
||||
}
|
||||
n, _, err := procSendInput.Call(uintptr(count), uintptr(ptr), elemSize)
|
||||
if n != 0 {
|
||||
return nil
|
||||
}
|
||||
if err != nil && err.Error() != "The operation completed successfully." {
|
||||
helpers.Log.Printf("SendInput %s count=%d cbSize=%d: %v", kind, count, elemSize, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
helpers.Log.Printf("SendInput %s count=%d cbSize=%d failed (n=0)", kind, count, elemSize)
|
||||
return fmt.Errorf("SendInput failed")
|
||||
}
|
||||
|
||||
+29
-24
@@ -26,43 +26,48 @@ func PressKey(key, action string, modifiers []string) error {
|
||||
modVKs = append(modVKs, modVK)
|
||||
}
|
||||
|
||||
var inputs []winInput
|
||||
for _, modVK := range modVKs {
|
||||
if err := sendKeyEvent(modVK, false); err != nil {
|
||||
return err
|
||||
}
|
||||
inputs = append(inputs, keyInput(modVK, false))
|
||||
}
|
||||
|
||||
switch strings.ToLower(strings.TrimSpace(action)) {
|
||||
case "down":
|
||||
if err := sendKeyEvent(vk, false); err != nil {
|
||||
return err
|
||||
}
|
||||
inputs = append(inputs, keyInput(vk, false))
|
||||
case "up":
|
||||
if err := sendKeyEvent(vk, true); err != nil {
|
||||
return err
|
||||
}
|
||||
inputs = append(inputs, keyInput(vk, true))
|
||||
default:
|
||||
if err := sendKeyEvent(vk, false); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := sendKeyEvent(vk, true); err != nil {
|
||||
return err
|
||||
}
|
||||
inputs = append(inputs, keyInput(vk, false), keyInput(vk, true))
|
||||
for i := len(modVKs) - 1; i >= 0; i-- {
|
||||
if err := sendKeyEvent(modVKs[i], true); err != nil {
|
||||
return err
|
||||
inputs = append(inputs, keyInput(modVKs[i], true))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
||||
return sendKeyboardInputs(inputs)
|
||||
}
|
||||
|
||||
func sendKeyEvent(vk uint16, keyUp bool) error {
|
||||
func keyInput(vk uint16, keyUp bool) winInput {
|
||||
flags := uint32(0)
|
||||
if keyUp {
|
||||
flags = keyeventfKeyup
|
||||
flags |= keyeventfKeyup
|
||||
}
|
||||
if isExtendedVK(vk) {
|
||||
flags |= keyeventfExtended
|
||||
}
|
||||
return winInput{
|
||||
Type: inputKeyboard,
|
||||
Ki: keyboardData{
|
||||
Vk: vk,
|
||||
Flags: flags,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func isExtendedVK(vk uint16) bool {
|
||||
switch vk {
|
||||
case 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x2D, 0x2E, 0x5B, 0x5C, 0x5D:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
inputs := []keybdInput{{Type: inputKeyboard, Vk: vk, Flags: flags}}
|
||||
return sendKeys(inputs)
|
||||
}
|
||||
|
||||
+4
-4
@@ -12,10 +12,10 @@ var vkNames = map[string]uint16{
|
||||
"backspace": 0x08,
|
||||
"tab": 0x09,
|
||||
"enter": 0x0D,
|
||||
"shift": 0x10,
|
||||
"ctrl": 0x11,
|
||||
"control": 0x11,
|
||||
"alt": 0x12,
|
||||
"shift": 0xA0,
|
||||
"ctrl": 0xA2,
|
||||
"control": 0xA2,
|
||||
"alt": 0xA4,
|
||||
"pause": 0x13,
|
||||
"capslock": 0x14,
|
||||
"escape": 0x1B,
|
||||
|
||||
@@ -8,7 +8,7 @@ func TestVkCode(t *testing.T) {
|
||||
"a": 0x41,
|
||||
"A": 0x41,
|
||||
"enter": 0x0D,
|
||||
"ctrl": 0x11,
|
||||
"ctrl": 0xA2,
|
||||
"win": 0x5B,
|
||||
"f5": 0x74,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user