event.go RawHistoryFolder
1package xturbo
2
3import "encoding/binary"
4
5// EventKind identifies a decoded event: uint16(ExtID)<<8 | code. Core events
6// use the wire code (2..34); extension events the code relative to the
7// extension's first event; XGE events 0x80|evtype.
8type EventKind uint16
9
10// KindUnknown marks an event whose code or XGE extension is not known.
11const KindUnknown EventKind = 0xFFFF
12
13const (
14 codeGenericEvent = 35
15 codeKeymapNotify = 11
16)
17
18// Event is a decoded event value. Raw is a copy and survives Dispatch; Tail
19// borrows the read buffer (XGE bytes beyond 32) and is valid only until the
20// Handler callback returns. Copy what you keep.
21type Event struct {
22 Kind EventKind
23 SendEvent bool
24 Ext ExtID
25 Seq Seq // wire sequence; Conn widens it. 0 for KeymapNotify.
26 Raw [32]byte
27 Tail []byte
28}
29
30// DecodeEvent decodes one event packet at the start of raw. n is the number
31// of bytes consumed (32, or 32+4*length for XGE). ok is false for error and
32// reply packets and for short input. Unknown codes decode with
33// Kind == KindUnknown and ok == true. A nil ext decodes core events only.
34// The returned Seq is the 16-bit wire value; Conn widens it.
35func DecodeEvent(raw []byte, ext *ExtTable) (ev Event, n int, ok bool) {
36 if len(raw) < 32 {
37 return Event{}, 0, false
38 }
39 code := raw[0] & 0x7f
40 if code < 2 {
41 return Event{}, 0, false
42 }
43 n = 32
44 if code == codeGenericEvent {
45 length := uint64(binary.LittleEndian.Uint32(raw[4:]))
46 if uint64(len(raw)-32)/4 < length {
47 return Event{}, 0, false
48 }
49 n = 32 + int(length)*4
50 ev.Tail = raw[32:n:n]
51 }
52 copy(ev.Raw[:], raw[:32])
53 ev.SendEvent = raw[0]&0x80 != 0
54 if code != codeKeymapNotify {
55 ev.Seq = Seq(binary.LittleEndian.Uint16(raw[2:]))
56 }
57 ev.Kind = KindUnknown
58 switch {
59 case code < codeGenericEvent:
60 ev.Kind = EventKind(code)
61 case code == codeGenericEvent:
62 if ext == nil {
63 break
64 }
65 evtype := binary.LittleEndian.Uint16(raw[8:])
66 if id, found := ext.ByMajor(raw[1]); found && evtype < 0x80 {
67 ev.Ext = id
68 ev.Kind = EventKind(id)<<8 | 0x80 | EventKind(evtype)
69 }
70 case code >= 64 && ext != nil:
71 if id, rel, found := ext.ByEvent(code); found {
72 ev.Ext = id
73 ev.Kind = EventKind(id)<<8 | EventKind(rel)
74 }
75 }
76 return ev, n, true
77}