diff --git a/cmd/mosh-wasm/main.go b/cmd/mosh-wasm/main.go index dec3e82..9c4c34c 100644 --- a/cmd/mosh-wasm/main.go +++ b/cmd/mosh-wasm/main.go @@ -85,13 +85,28 @@ func newSession(url, key string) (*session, error) { func (s *session) jsObject() js.Value { obj := js.Global().Get("Object").New() + // Batch keystrokes: queue actions, flush once per animation frame. + // This prevents cumulative state from creating new sequence numbers + // for every keystroke, which causes duplicates on high-latency paths. + var pendingFlush bool + flushFn := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + pendingFlush = false + s.client.Tick() + return nil + }) + scheduleFlush := func() { + if !pendingFlush { + pendingFlush = true + js.Global().Call("requestAnimationFrame", flushFn) + } + } + obj.Set("send", js.FuncOf(func(this js.Value, args []js.Value) interface{} { if len(args) < 1 { return nil } - data := args[0].String() - s.client.Send([]byte(data)) - s.client.Tick() + s.client.Send([]byte(args[0].String())) + scheduleFlush() return nil })) @@ -99,10 +114,8 @@ func (s *session) jsObject() js.Value { if len(args) < 2 { return nil } - cols := args[0].Int() - rows := args[1].Int() - s.client.Resize(uint16(cols), uint16(rows)) - s.client.Tick() + s.client.Resize(uint16(args[0].Int()), uint16(args[1].Int())) + scheduleFlush() return nil }))