-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathreader_keypress.go
93 lines (81 loc) · 1.61 KB
/
reader_keypress.go
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
package reader
import (
"context"
"os"
"sync"
"time"
"github.com/projectdiscovery/utils/reader/rawmode"
)
type KeyPressReader struct {
originalMode interface{}
Timeout time.Duration
datachan chan []byte
Once *sync.Once
Raw bool
BufferSize int
}
func (reader *KeyPressReader) Start() error {
reader.Once.Do(func() {
go reader.read()
reader.originalMode, _ = rawmode.GetMode(os.Stdin)
if reader.Raw {
reader.BufferSize = 1
} else {
reader.BufferSize = 512
}
})
// set raw mode
if reader.Raw {
mode, _ := rawmode.GetMode(os.Stdin)
return rawmode.SetRawMode(os.Stdin, mode)
}
// proceed with buffered input - only new lines are detected
return nil
}
func (reader *KeyPressReader) Stop() error {
// disable raw mode
if reader.Raw {
return rawmode.SetMode(os.Stdin, reader.originalMode)
}
// nop
return nil
}
func (reader *KeyPressReader) read() {
if reader.datachan == nil {
reader.datachan = make(chan []byte)
}
for {
var (
n int
err error
r = make([]byte, reader.BufferSize)
)
if reader.Raw {
n, err = rawmode.Read(os.Stdin, r)
} else {
n, err = os.Stdin.Read(r)
}
if n > 0 && err == nil {
reader.datachan <- r
}
}
}
// Read into the buffer
func (reader KeyPressReader) Read(p []byte) (n int, err error) {
var (
ctx context.Context
cancel context.CancelFunc
)
if reader.Timeout > 0 {
ctx, cancel = context.WithTimeout(context.Background(), time.Duration(reader.Timeout))
defer cancel()
}
select {
case <-ctx.Done():
err = ErrTimeout
return
case data := <-reader.datachan:
n = copy(p, data)
return
}
}