change(tracker): add more events to input, fix typo and timestamp calc

This commit is contained in:
nick-delirium 2023-02-13 11:23:18 +01:00
parent e9848bf335
commit 9628bcdfad
15 changed files with 213 additions and 157 deletions

View file

@ -2,7 +2,7 @@
package messages package messages
func IsReplayerType(id int) bool { func IsReplayerType(id int) bool {
return 1 != id && 3 != id && 17 != id && 23 != id && 24 != id && 25 != id && 26 != id && 27 != id && 28 != id && 29 != id && 30 != id && 31 != id && 32 != id && 33 != id && 35 != id && 42 != id && 52 != id && 56 != id && 62 != id && 63 != id && 64 != id && 66 != id && 78 != id && 80 != id && 81 != id && 82 != id && 83 != id && 125 != id && 126 != id && 127 != id && 107 != id && 91 != id && 92 != id && 94 != id && 95 != id && 97 != id && 98 != id && 99 != id && 101 != id && 104 != id && 110 != id && 111 != id return 1 != id && 3 != id && 17 != id && 23 != id && 24 != id && 25 != id && 26 != id && 27 != id && 28 != id && 29 != id && 30 != id && 31 != id && 32 != id && 33 != id && 35 != id && 42 != id && 52 != id && 56 != id && 62 != id && 63 != id && 64 != id && 66 != id && 78 != id && 80 != id && 81 != id && 82 != id && 125 != id && 126 != id && 127 != id && 112 != id && 107 != id && 91 != id && 92 != id && 94 != id && 95 != id && 97 != id && 98 != id && 99 != id && 101 != id && 104 != id && 110 != id && 111 != id
} }
func IsIOSType(id int) bool { func IsIOSType(id int) bool {
@ -10,5 +10,5 @@ func IsIOSType(id int) bool {
} }
func IsDOMType(id int) bool { func IsDOMType(id int) bool {
return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 84 == id || 90 == id || 93 == id || 96 == id || 100 == id || 102 == id || 103 == id || 105 == id return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 113 == id || 90 == id || 93 == id || 96 == id || 100 == id || 102 == id || 103 == id || 105 == id
} }

View file

@ -79,11 +79,11 @@ const (
MsgBatchMeta = 80 MsgBatchMeta = 80
MsgBatchMetadata = 81 MsgBatchMetadata = 81
MsgPartitionedMessage = 82 MsgPartitionedMessage = 82
MsgInputChange = 83
MsgSelectionChange = 84
MsgIssueEvent = 125 MsgIssueEvent = 125
MsgSessionEnd = 126 MsgSessionEnd = 126
MsgSessionSearch = 127 MsgSessionSearch = 127
MsgInputChange = 112
MsgSelectionChange = 113
MsgIOSBatchMeta = 107 MsgIOSBatchMeta = 107
MsgIOSSessionStart = 90 MsgIOSSessionStart = 90
MsgIOSSessionEnd = 91 MsgIOSSessionEnd = 91
@ -2119,56 +2119,6 @@ func (msg *PartitionedMessage) TypeID() int {
return 82 return 82
} }
type InputChange struct {
message
ID uint64
Label string
HesitationTime int64
}
func (msg *InputChange) Encode() []byte {
buf := make([]byte, 31+len(msg.Label))
buf[0] = 83
p := 1
p = WriteUint(msg.ID, buf, p)
p = WriteString(msg.Label, buf, p)
p = WriteInt(msg.HesitationTime, buf, p)
return buf[:p]
}
func (msg *InputChange) Decode() Message {
return msg
}
func (msg *InputChange) TypeID() int {
return 83
}
type SelectionChange struct {
message
SelectionStart uint64
SelectionEnd uint64
Selection string
}
func (msg *SelectionChange) Encode() []byte {
buf := make([]byte, 31+len(msg.Selection))
buf[0] = 84
p := 1
p = WriteUint(msg.SelectionStart, buf, p)
p = WriteUint(msg.SelectionEnd, buf, p)
p = WriteString(msg.Selection, buf, p)
return buf[:p]
}
func (msg *SelectionChange) Decode() Message {
return msg
}
func (msg *SelectionChange) TypeID() int {
return 84
}
type IssueEvent struct { type IssueEvent struct {
message message
MessageID uint64 MessageID uint64
@ -2248,6 +2198,62 @@ func (msg *SessionSearch) TypeID() int {
return 127 return 127
} }
type InputChange struct {
message
ID uint64
Value string
ValueMasked bool
Label string
HesitationTime int64
InputDuration int64
}
func (msg *InputChange) Encode() []byte {
buf := make([]byte, 61+len(msg.Value)+len(msg.Label))
buf[0] = 112
p := 1
p = WriteUint(msg.ID, buf, p)
p = WriteString(msg.Value, buf, p)
p = WriteBoolean(msg.ValueMasked, buf, p)
p = WriteString(msg.Label, buf, p)
p = WriteInt(msg.HesitationTime, buf, p)
p = WriteInt(msg.InputDuration, buf, p)
return buf[:p]
}
func (msg *InputChange) Decode() Message {
return msg
}
func (msg *InputChange) TypeID() int {
return 112
}
type SelectionChange struct {
message
SelectionStart uint64
SelectionEnd uint64
Selection string
}
func (msg *SelectionChange) Encode() []byte {
buf := make([]byte, 31+len(msg.Selection))
buf[0] = 113
p := 1
p = WriteUint(msg.SelectionStart, buf, p)
p = WriteUint(msg.SelectionEnd, buf, p)
p = WriteString(msg.Selection, buf, p)
return buf[:p]
}
func (msg *SelectionChange) Decode() Message {
return msg
}
func (msg *SelectionChange) TypeID() int {
return 113
}
type IOSBatchMeta struct { type IOSBatchMeta struct {
message message
Timestamp uint64 Timestamp uint64

View file

@ -1293,36 +1293,6 @@ func DecodePartitionedMessage(reader BytesReader) (Message, error) {
return msg, err return msg, err
} }
func DecodeInputChange(reader BytesReader) (Message, error) {
var err error = nil
msg := &InputChange{}
if msg.ID, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.Label, err = reader.ReadString(); err != nil {
return nil, err
}
if msg.HesitationTime, err = reader.ReadInt(); err != nil {
return nil, err
}
return msg, err
}
func DecodeSelectionChange(reader BytesReader) (Message, error) {
var err error = nil
msg := &SelectionChange{}
if msg.SelectionStart, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.SelectionEnd, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.Selection, err = reader.ReadString(); err != nil {
return nil, err
}
return msg, err
}
func DecodeIssueEvent(reader BytesReader) (Message, error) { func DecodeIssueEvent(reader BytesReader) (Message, error) {
var err error = nil var err error = nil
msg := &IssueEvent{} msg := &IssueEvent{}
@ -1374,6 +1344,45 @@ func DecodeSessionSearch(reader BytesReader) (Message, error) {
return msg, err return msg, err
} }
func DecodeInputChange(reader BytesReader) (Message, error) {
var err error = nil
msg := &InputChange{}
if msg.ID, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.Value, err = reader.ReadString(); err != nil {
return nil, err
}
if msg.ValueMasked, err = reader.ReadBoolean(); err != nil {
return nil, err
}
if msg.Label, err = reader.ReadString(); err != nil {
return nil, err
}
if msg.HesitationTime, err = reader.ReadInt(); err != nil {
return nil, err
}
if msg.InputDuration, err = reader.ReadInt(); err != nil {
return nil, err
}
return msg, err
}
func DecodeSelectionChange(reader BytesReader) (Message, error) {
var err error = nil
msg := &SelectionChange{}
if msg.SelectionStart, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.SelectionEnd, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.Selection, err = reader.ReadString(); err != nil {
return nil, err
}
return msg, err
}
func DecodeIOSBatchMeta(reader BytesReader) (Message, error) { func DecodeIOSBatchMeta(reader BytesReader) (Message, error) {
var err error = nil var err error = nil
msg := &IOSBatchMeta{} msg := &IOSBatchMeta{}
@ -1932,16 +1941,16 @@ func ReadMessage(t uint64, reader BytesReader) (Message, error) {
return DecodeBatchMetadata(reader) return DecodeBatchMetadata(reader)
case 82: case 82:
return DecodePartitionedMessage(reader) return DecodePartitionedMessage(reader)
case 83:
return DecodeInputChange(reader)
case 84:
return DecodeSelectionChange(reader)
case 125: case 125:
return DecodeIssueEvent(reader) return DecodeIssueEvent(reader)
case 126: case 126:
return DecodeSessionEnd(reader) return DecodeSessionEnd(reader)
case 127: case 127:
return DecodeSessionSearch(reader) return DecodeSessionSearch(reader)
case 112:
return DecodeInputChange(reader)
case 113:
return DecodeSelectionChange(reader)
case 107: case 107:
return DecodeIOSBatchMeta(reader) return DecodeIOSBatchMeta(reader)
case 90: case 90:

View file

@ -744,24 +744,6 @@ class PartitionedMessage(Message):
self.part_total = part_total self.part_total = part_total
class InputChange(Message):
__id__ = 83
def __init__(self, id, label, hesitation_time):
self.id = id
self.label = label
self.hesitation_time = hesitation_time
class SelectionChange(Message):
__id__ = 84
def __init__(self, selection_start, selection_end, selection):
self.selection_start = selection_start
self.selection_end = selection_end
self.selection = selection
class IssueEvent(Message): class IssueEvent(Message):
__id__ = 125 __id__ = 125
@ -791,6 +773,27 @@ class SessionSearch(Message):
self.partition = partition self.partition = partition
class InputChange(Message):
__id__ = 112
def __init__(self, id, value, value_masked, label, hesitation_time, input_duration):
self.id = id
self.value = value
self.value_masked = value_masked
self.label = label
self.hesitation_time = hesitation_time
self.input_duration = input_duration
class SelectionChange(Message):
__id__ = 113
def __init__(self, selection_start, selection_end, selection):
self.selection_start = selection_start
self.selection_end = selection_end
self.selection = selection
class IOSBatchMeta(Message): class IOSBatchMeta(Message):
__id__ = 107 __id__ = 107

View file

@ -660,20 +660,6 @@ class MessageCodec(Codec):
part_total=self.read_uint(reader) part_total=self.read_uint(reader)
) )
if message_id == 83:
return InputChange(
id=self.read_uint(reader),
label=self.read_string(reader),
hesitation_time=self.read_int(reader)
)
if message_id == 84:
return SelectionChange(
selection_start=self.read_uint(reader),
selection_end=self.read_uint(reader),
selection=self.read_string(reader)
)
if message_id == 125: if message_id == 125:
return IssueEvent( return IssueEvent(
message_id=self.read_uint(reader), message_id=self.read_uint(reader),
@ -697,6 +683,23 @@ class MessageCodec(Codec):
partition=self.read_uint(reader) partition=self.read_uint(reader)
) )
if message_id == 112:
return InputChange(
id=self.read_uint(reader),
value=self.read_string(reader),
value_masked=self.read_boolean(reader),
label=self.read_string(reader),
hesitation_time=self.read_int(reader),
input_duration=self.read_int(reader)
)
if message_id == 113:
return SelectionChange(
selection_start=self.read_uint(reader),
selection_end=self.read_uint(reader),
selection=self.read_string(reader)
)
if message_id == 107: if message_id == 107:
return IOSBatchMeta( return IOSBatchMeta(
timestamp=self.read_uint(reader), timestamp=self.read_uint(reader),

View file

@ -627,7 +627,7 @@ export default class RawMessageReader extends PrimitiveReader {
}; };
} }
case 84: { case 113: {
const selectionStart = this.readUint(); if (selectionStart === null) { return resetPointer() } const selectionStart = this.readUint(); if (selectionStart === null) { return resetPointer() }
const selectionEnd = this.readUint(); if (selectionEnd === null) { return resetPointer() } const selectionEnd = this.readUint(); if (selectionEnd === null) { return resetPointer() }
const selection = this.readString(); if (selection === null) { return resetPointer() } const selection = this.readString(); if (selection === null) { return resetPointer() }

View file

@ -3,7 +3,7 @@
import { MType } from './raw.gen' import { MType } from './raw.gen'
const DOM_TYPES = [0,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,37,38,49,50,51,54,55,57,58,59,60,61,67,69,70,71,72,73,74,75,76,77,84,90,93,96,100,102,103,105] const DOM_TYPES = [0,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,37,38,49,50,51,54,55,57,58,59,60,61,67,69,70,71,72,73,74,75,76,77,113,90,93,96,100,102,103,105]
export function isDOMType(t: MType) { export function isDOMType(t: MType) {
return DOM_TYPES.includes(t) return DOM_TYPES.includes(t)
} }

View file

@ -53,7 +53,7 @@ export const enum MType {
AdoptedSsAddOwner = 76, AdoptedSsAddOwner = 76,
AdoptedSsRemoveOwner = 77, AdoptedSsRemoveOwner = 77,
Zustand = 79, Zustand = 79,
SelectionChange = 84, SelectionChange = 113,
IosSessionStart = 90, IosSessionStart = 90,
IosCustomEvent = 93, IosCustomEvent = 93,
IosScreenChanges = 96, IosScreenChanges = 96,

View file

@ -54,7 +54,7 @@ export const TP_MAP = {
76: MType.AdoptedSsAddOwner, 76: MType.AdoptedSsAddOwner,
77: MType.AdoptedSsRemoveOwner, 77: MType.AdoptedSsRemoveOwner,
79: MType.Zustand, 79: MType.Zustand,
84: MType.SelectionChange, 113: MType.SelectionChange,
90: MType.IosSessionStart, 90: MType.IosSessionStart,
93: MType.IosCustomEvent, 93: MType.IosCustomEvent,
96: MType.IosScreenChanges, 96: MType.IosScreenChanges,

View file

@ -430,14 +430,17 @@ type TrPartitionedMessage = [
] ]
type TrInputChange = [ type TrInputChange = [
type: 83, type: 112,
id: number, id: number,
value: string,
valueMasked: boolean,
label: string, label: string,
hesitationTime: number, hesitationTime: number,
inputDuration: number,
] ]
type TrSelectionChange = [ type TrSelectionChange = [
type: 84, type: 113,
selectionStart: number, selectionStart: number,
selectionEnd: number, selectionEnd: number,
selection: string, selection: string,
@ -881,7 +884,7 @@ export default function translate(tMsg: TrackerMessage): RawMessage | null {
} }
} }
case 84: { case 113: {
return { return {
tp: MType.SelectionChange, tp: MType.SelectionChange,
selectionStart: tMsg[1], selectionStart: tMsg[1],

View file

@ -475,17 +475,7 @@ message 82, 'PartitionedMessage', :replayer => false do
uint 'PartTotal' uint 'PartTotal'
end end
message 83, 'InputChange', :replayer => false do # 90-111 reserved iOS
uint 'ID'
string 'Label'
int 'HesitationTime'
end
message 84, 'SelectionChange' do
uint 'SelectionStart'
uint 'SelectionEnd'
string 'Selection'
end
## Backend-only ## Backend-only
message 125, 'IssueEvent', :replayer => false, :tracker => false do message 125, 'IssueEvent', :replayer => false, :tracker => false do
@ -505,3 +495,20 @@ message 127, 'SessionSearch', :tracker => false, :replayer => false do
uint 'Timestamp' uint 'Timestamp'
uint 'Partition' uint 'Partition'
end end
# since tracker 4.1.10
message 112, 'InputChange', :replayer => false do
uint 'ID'
string 'Value'
boolean 'ValueMasked'
string 'Label'
int 'HesitationTime'
int 'InputDuration'
end
message 113, 'SelectionChange' do
uint 'SelectionStart'
uint 'SelectionEnd'
string 'Selection'
end

View file

@ -63,8 +63,8 @@ export declare const enum Type {
Zustand = 79, Zustand = 79,
BatchMetadata = 81, BatchMetadata = 81,
PartitionedMessage = 82, PartitionedMessage = 82,
InputChange = 83, InputChange = 112,
SelectionChange = 84, SelectionChange = 113,
} }
@ -495,8 +495,11 @@ export type PartitionedMessage = [
export type InputChange = [ export type InputChange = [
/*type:*/ Type.InputChange, /*type:*/ Type.InputChange,
/*id:*/ number, /*id:*/ number,
/*value:*/ string,
/*valueMasked:*/ boolean,
/*label:*/ string, /*label:*/ string,
/*hesitationTime:*/ number, /*hesitationTime:*/ number,
/*inputDuration:*/ number,
] ]
export type SelectionChange = [ export type SelectionChange = [

View file

@ -794,14 +794,20 @@ export function PartitionedMessage(
export function InputChange( export function InputChange(
id: number, id: number,
value: string,
valueMasked: boolean,
label: string, label: string,
hesitationTime: number, hesitationTime: number,
inputDuration: number,
): Messages.InputChange { ): Messages.InputChange {
return [ return [
Messages.Type.InputChange, Messages.Type.InputChange,
id, id,
value,
valueMasked,
label, label,
hesitationTime, hesitationTime,
inputDuration,
] ]
} }

View file

@ -6,9 +6,9 @@ import { InputChange, SetInputValue, SetInputChecked } from '../app/messages.gen
const INPUT_TYPES = ['text', 'password', 'email', 'search', 'number', 'range', 'date', 'tel'] const INPUT_TYPES = ['text', 'password', 'email', 'search', 'number', 'range', 'date', 'tel']
// TODO: take into consideration "contenteditable" attribute // TODO: take into consideration "contenteditable" attribute
type TextFeildElement = HTMLInputElement | HTMLTextAreaElement type TextFieldElement = HTMLInputElement | HTMLTextAreaElement
function isTextFeildElement(node: Node): node is TextFeildElement { function isTextFieldElement(node: Node): node is TextFieldElement {
if (hasTag(node, 'textarea')) { if (hasTag(node, 'textarea')) {
return true return true
} }
@ -27,7 +27,7 @@ function isCheckbox(node: Node): node is HTMLInputElement & { type: 'checkbox' |
return type === 'checkbox' || type === 'radio' return type === 'checkbox' || type === 'radio'
} }
const labelElementFor: (element: TextFeildElement) => HTMLLabelElement | undefined = const labelElementFor: (element: TextFieldElement) => HTMLLabelElement | undefined =
IN_BROWSER && 'labels' in HTMLInputElement.prototype IN_BROWSER && 'labels' in HTMLInputElement.prototype
? (node) => { ? (node) => {
let p: Node | null = node let p: Node | null = node
@ -57,7 +57,7 @@ const labelElementFor: (element: TextFeildElement) => HTMLLabelElement | undefin
} }
} }
export function getInputLabel(node: TextFeildElement): string { export function getInputLabel(node: TextFieldElement): string {
let label = getLabelAttribute(node) let label = getLabelAttribute(node)
if (label === null) { if (label === null) {
const labelElement = labelElementFor(node) const labelElement = labelElementFor(node)
@ -96,7 +96,7 @@ export default function (app: App, opts: Partial<Options>): void {
opts, opts,
) )
function sendInputValue(id: number, node: TextFeildElement | HTMLSelectElement): void { function getInputValue(id: number, node: TextFieldElement | HTMLSelectElement) {
let value = node.value let value = node.value
let inputMode: InputMode = options.defaultInputMode let inputMode: InputMode = options.defaultInputMode
@ -123,6 +123,11 @@ export default function (app: App, opts: Partial<Options>): void {
break break
} }
return { value, mask }
}
function sendInputValue(id: number, node: TextFieldElement | HTMLSelectElement): void {
const { value, mask } = getInputValue(id, node)
app.send(SetInputValue(id, value, mask)) app.send(SetInputValue(id, value, mask))
} }
@ -134,7 +139,7 @@ export default function (app: App, opts: Partial<Options>): void {
checkboxValues.clear() checkboxValues.clear()
}) })
function trackInputValue(id: number, node: TextFeildElement) { function trackInputValue(id: number, node: TextFieldElement) {
if (inputValues.get(id) === node.value) { if (inputValues.get(id) === node.value) {
return return
} }
@ -150,7 +155,7 @@ export default function (app: App, opts: Partial<Options>): void {
app.send(SetInputChecked(id, value)) app.send(SetInputChecked(id, value))
} }
// The only way (to our knowladge) to track all kinds of input changes, including those made by JS // The only way (to our knowledge) to track all kinds of input changes, including those made by JS
app.ticker.attach(() => { app.ticker.attach(() => {
inputValues.forEach((value, id) => { inputValues.forEach((value, id) => {
const node = app.nodes.getNode(id) as HTMLInputElement const node = app.nodes.getNode(id) as HTMLInputElement
@ -162,12 +167,18 @@ export default function (app: App, opts: Partial<Options>): void {
if (!node) return checkboxValues.delete(id) if (!node) return checkboxValues.delete(id)
trackCheckboxValue(id, node.checked) trackCheckboxValue(id, node.checked)
}) })
}, 5) }, 3)
function sendInputChange(id: number, node: TextFeildElement, hesitationTime: number) { function sendInputChange(
trackInputValue(id, node) id: number,
node: TextFieldElement,
hesitationTime: number,
inputTime: number,
) {
const { value, mask } = getInputValue(id, node)
const label = getInputLabel(node) const label = getInputLabel(node)
app.send(InputChange(id, label, hesitationTime))
app.send(InputChange(id, value, mask !== 0, label, hesitationTime, inputTime))
} }
app.nodes.attachNodeCallback( app.nodes.attachNodeCallback(
@ -183,22 +194,27 @@ export default function (app: App, opts: Partial<Options>): void {
app.nodes.attachNodeListener(node, 'change', () => sendInputValue(id, node)) app.nodes.attachNodeListener(node, 'change', () => sendInputValue(id, node))
} }
if (isTextFeildElement(node)) { if (isTextFieldElement(node)) {
trackInputValue(id, node) trackInputValue(id, node)
let nodeFocusTime = 0 let nodeFocusTime = 0
let nodeHesitationTime = 0 let nodeHesitationTime = 0
let inputTime = 0
const onFocus = () => { const onFocus = () => {
nodeFocusTime = now() nodeFocusTime = now()
} }
const onInput = () => { const onInput = () => {
const value = node.value
if (nodeHesitationTime === 0) { if (nodeHesitationTime === 0) {
nodeHesitationTime = nodeFocusTime - now() nodeHesitationTime = now() - nodeFocusTime
} }
} }
const onChange = () => { const onChange = () => {
sendInputChange(id, node, nodeHesitationTime) inputTime = now() - nodeFocusTime
sendInputChange(id, node, nodeHesitationTime, inputTime)
nodeHesitationTime = 0 nodeHesitationTime = 0
inputTime = 0
} }
app.nodes.attachNodeListener(node, 'focus', onFocus) app.nodes.attachNodeListener(node, 'focus', onFocus)
app.nodes.attachNodeListener(node, 'input', onInput) app.nodes.attachNodeListener(node, 'input', onInput)
@ -208,7 +224,7 @@ export default function (app: App, opts: Partial<Options>): void {
if (isCheckbox(node)) { if (isCheckbox(node)) {
trackCheckboxValue(id, node.checked) trackCheckboxValue(id, node.checked)
app.nodes.attachNodeListener(node, 'change', (e) => trackCheckboxValue(id, node.checked)) app.nodes.attachNodeListener(node, 'change', () => trackCheckboxValue(id, node.checked))
return return
} }
}), }),

View file

@ -255,7 +255,7 @@ export default class MessageEncoder extends PrimitiveEncoder {
break break
case Messages.Type.InputChange: case Messages.Type.InputChange:
return this.uint(msg[1]) && this.string(msg[2]) && this.int(msg[3]) return this.uint(msg[1]) && this.string(msg[2]) && this.boolean(msg[3]) && this.string(msg[4]) && this.int(msg[5]) && this.int(msg[6])
break break
case Messages.Type.SelectionChange: case Messages.Type.SelectionChange: