70 lines
2.1 KiB
Go
70 lines
2.1 KiB
Go
package device
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// Touch immediately forwards an event on the persistent scrcpy connection.
|
|
// It never launches an adb shell or waits for a complete gesture.
|
|
func (s *Service) Touch(req TouchRequest) error {
|
|
if req.Action < 0 || req.Action > 3 || req.Width < 1 || req.Height < 1 || req.Width > 65535 || req.Height > 65535 || req.X < 0 || req.Y < 0 || req.X >= req.Width || req.Y >= req.Height {
|
|
return fmt.Errorf("触摸事件或画面坐标无效")
|
|
}
|
|
st := s.ensureStream()
|
|
st.mu.Lock()
|
|
defer st.mu.Unlock()
|
|
if !st.running || st.serial != req.DeviceID || st.controlConn == nil {
|
|
return fmt.Errorf("控制通道未连接,请重新开始预览")
|
|
}
|
|
if req.Action != 0 && !st.touchDown {
|
|
return nil
|
|
}
|
|
if req.Action == 0 && st.touchDown {
|
|
cancel := st.lastTouch
|
|
cancel.Action = 3
|
|
if err := st.writeTouchLocked(cancel); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := st.writeTouchLocked(req); err != nil {
|
|
return fmt.Errorf("发送触摸事件失败,请重新开始预览: %w", err)
|
|
}
|
|
st.lastTouch = req
|
|
st.touchDown = req.Action == 0 || req.Action == 2
|
|
return nil
|
|
}
|
|
|
|
// scrcpy 5 INJECT_TOUCH_EVENT: 32 bytes, big endian. Generic finger id=-2.
|
|
func encodeTouch(req TouchRequest) []byte {
|
|
packet := make([]byte, 32)
|
|
packet[0] = 2
|
|
packet[1] = byte(req.Action)
|
|
binary.BigEndian.PutUint64(packet[2:10], ^uint64(1))
|
|
binary.BigEndian.PutUint32(packet[10:14], uint32(req.X))
|
|
binary.BigEndian.PutUint32(packet[14:18], uint32(req.Y))
|
|
binary.BigEndian.PutUint16(packet[18:20], uint16(req.Width))
|
|
binary.BigEndian.PutUint16(packet[20:22], uint16(req.Height))
|
|
if req.Action == 0 || req.Action == 2 {
|
|
binary.BigEndian.PutUint16(packet[22:24], 65535)
|
|
}
|
|
return packet
|
|
}
|
|
|
|
func (st *previewStream) writeTouchLocked(req TouchRequest) error {
|
|
_ = st.controlConn.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
|
|
data := encodeTouch(req)
|
|
for len(data) > 0 {
|
|
n, err := st.controlConn.Write(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n == 0 {
|
|
return fmt.Errorf("控制通道写入中断")
|
|
}
|
|
data = data[n:]
|
|
}
|
|
return nil
|
|
}
|