-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkeycharactermap.go
More file actions
130 lines (115 loc) · 3.48 KB
/
keycharactermap.go
File metadata and controls
130 lines (115 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package view
import (
"fmt"
"github.com/AndroidGoLab/binder/parcel"
)
// KeyCharacterMap is a native C++ parcelable whose wire format is defined
// by JNI (android_view_KeyCharacterMap.cpp) and libinput (KeyCharacterMap.cpp).
//
// JNI envelope (nativeWriteToParcel):
//
// int32 deviceId
// bool hasMap (int32: 0 or 1)
//
// If hasMap, KeyCharacterMap::writeToParcel follows:
//
// CString loadFileName (null-terminated, no length prefix)
// int32 type
// bool layoutOverlayApplied
// int32 numKeys
// per key:
// int32 keyCode
// int32 label
// int32 number
// repeated {int32(1), metaState, character, fallbackKeyCode, replacementKeyCode}
// int32(0) sentinel
// int32 numKeyRemapping, pairs of (from, to) int32
// int32 numKeysByScanCode, pairs of (scanCode, keyCode) int32
// int32 numKeysByUsageCode, pairs of (usageCode, keyCode) int32
type KeyCharacterMap struct {
DeviceId int32
}
const maxKeyCharMapKeys = 8192
var _ parcel.Parcelable = (*KeyCharacterMap)(nil)
func (s *KeyCharacterMap) MarshalParcel(
p *parcel.Parcel,
) error {
p.WriteInt32(s.DeviceId)
p.WriteBool(false) // hasMap = false
return nil
}
func (s *KeyCharacterMap) UnmarshalParcel(
p *parcel.Parcel,
) error {
var err error
s.DeviceId, err = p.ReadInt32()
if err != nil {
return fmt.Errorf("KeyCharacterMap: reading deviceId: %w", err)
}
hasMap, err := p.ReadBool()
if err != nil {
return fmt.Errorf("KeyCharacterMap: reading hasMap: %w", err)
}
if !hasMap {
return nil
}
// CString loadFileName (null-terminated, no length prefix).
if _, err = p.ReadCString(); err != nil {
return fmt.Errorf("KeyCharacterMap: reading loadFileName: %w", err)
}
// int32 type
if _, err = p.ReadInt32(); err != nil {
return fmt.Errorf("KeyCharacterMap: reading type: %w", err)
}
// bool layoutOverlayApplied
if _, err = p.ReadBool(); err != nil {
return fmt.Errorf("KeyCharacterMap: reading layoutOverlayApplied: %w", err)
}
// int32 numKeys
numKeys, err := p.ReadInt32()
if err != nil {
return fmt.Errorf("KeyCharacterMap: reading numKeys: %w", err)
}
if numKeys < 0 || numKeys > maxKeyCharMapKeys {
return fmt.Errorf("KeyCharacterMap: numKeys %d out of range", numKeys)
}
for i := int32(0); i < numKeys; i++ {
// keyCode, label, number
for _, field := range []string{"keyCode", "label", "number"} {
if _, err = p.ReadInt32(); err != nil {
return fmt.Errorf("KeyCharacterMap: key[%d] %s: %w", i, field, err)
}
}
// Sentinel-terminated behavior list.
for {
sentinel, serr := p.ReadInt32()
if serr != nil {
return fmt.Errorf("KeyCharacterMap: key[%d] behavior sentinel: %w", i, serr)
}
if sentinel == 0 {
break
}
for _, field := range []string{"metaState", "character", "fallbackKeyCode", "replacementKeyCode"} {
if _, err = p.ReadInt32(); err != nil {
return fmt.Errorf("KeyCharacterMap: key[%d] behavior %s: %w", i, field, err)
}
}
}
}
// Three mapping tables: keyRemapping, keysByScanCode, keysByUsageCode.
for _, tableName := range []string{"keyRemapping", "keysByScanCode", "keysByUsageCode"} {
count, cerr := p.ReadInt32()
if cerr != nil {
return fmt.Errorf("KeyCharacterMap: reading %s count: %w", tableName, cerr)
}
for j := int32(0); j < count; j++ {
if _, err = p.ReadInt32(); err != nil {
return fmt.Errorf("KeyCharacterMap: %s[%d] key: %w", tableName, j, err)
}
if _, err = p.ReadInt32(); err != nil {
return fmt.Errorf("KeyCharacterMap: %s[%d] value: %w", tableName, j, err)
}
}
}
return nil
}