Use termios via CGO
Signed-off-by: Yohei Ueda <yohei@jp.ibm.com>
This commit is contained in:
parent
bfe8d7af74
commit
92251ceb7b
6 changed files with 75 additions and 6 deletions
10
term/term.go
10
term/term.go
|
@ -47,8 +47,7 @@ func SetWinsize(fd uintptr, ws *Winsize) error {
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
func IsTerminal(fd uintptr) bool {
|
func IsTerminal(fd uintptr) bool {
|
||||||
var termios Termios
|
var termios Termios
|
||||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&termios)))
|
return tcget(fd, &termios) == 0
|
||||||
return err == 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore restores the terminal connected to the given file descriptor to a
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||||
|
@ -57,8 +56,7 @@ func RestoreTerminal(fd uintptr, state *State) error {
|
||||||
if state == nil {
|
if state == nil {
|
||||||
return ErrInvalidState
|
return ErrInvalidState
|
||||||
}
|
}
|
||||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)))
|
if err := tcset(fd, &state.termios); err != 0 {
|
||||||
if err != 0 {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -66,7 +64,7 @@ func RestoreTerminal(fd uintptr, state *State) error {
|
||||||
|
|
||||||
func SaveState(fd uintptr) (*State, error) {
|
func SaveState(fd uintptr) (*State, error) {
|
||||||
var oldState State
|
var oldState State
|
||||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, getTermios, uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
|
if err := tcget(fd, &oldState.termios); err != 0 {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +75,7 @@ func DisableEcho(fd uintptr, state *State) error {
|
||||||
newState := state.termios
|
newState := state.termios
|
||||||
newState.Lflag &^= syscall.ECHO
|
newState.Lflag &^= syscall.ECHO
|
||||||
|
|
||||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(&newState))); err != 0 {
|
if err := tcset(fd, &newState); err != 0 {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
handleInterrupt(fd, state)
|
handleInterrupt(fd, state)
|
||||||
|
|
47
term/term_cgo.go
Normal file
47
term/term_cgo.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// +build !windows,cgo
|
||||||
|
|
||||||
|
package term
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include <termios.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
||||||
|
|
||||||
|
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||||
|
// mode and returns the previous state of the terminal so that it can be
|
||||||
|
// restored.
|
||||||
|
func MakeRaw(fd uintptr) (*State, error) {
|
||||||
|
var oldState State
|
||||||
|
if err := tcget(fd, &oldState.termios); err != 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newState := oldState.termios
|
||||||
|
|
||||||
|
C.cfmakeraw((*C.struct_termios)(unsafe.Pointer(&newState)))
|
||||||
|
if err := tcset(fd, &newState); err != 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &oldState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func tcget(fd uintptr, p *Termios) syscall.Errno {
|
||||||
|
ret, err := C.tcgetattr(C.int(fd), (*C.struct_termios)(unsafe.Pointer(p)))
|
||||||
|
if ret != 0 {
|
||||||
|
return err.(syscall.Errno)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func tcset(fd uintptr, p *Termios) syscall.Errno {
|
||||||
|
ret, err := C.tcsetattr(C.int(fd), C.TCSANOW, (*C.struct_termios)(unsafe.Pointer(p)))
|
||||||
|
if ret != 0 {
|
||||||
|
return err.(syscall.Errno)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
18
term/term_nocgo.go
Normal file
18
term/term_nocgo.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// +build !windows,!cgo
|
||||||
|
|
||||||
|
package term
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func tcget(fd uintptr, p *Termios) syscall.Errno {
|
||||||
|
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(p)))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func tcset(fd uintptr, p *Termios) syscall.Errno {
|
||||||
|
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(p)))
|
||||||
|
return err
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !cgo
|
||||||
|
|
||||||
package term
|
package term
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !cgo
|
||||||
|
|
||||||
package term
|
package term
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build !cgo
|
||||||
|
|
||||||
package term
|
package term
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
Loading…
Reference in a new issue