204 lines · 3.4 KB · Go
RawDownload
package draw9 import (	"fmt"	"image"	"log"	"os"	"syscall") type Cursor struct {	Offset image.Point	Clear  [2 * 16]byte	Set    [2 * 16]byte} type Menu struct {	// ???} // Mouse is a record of one event from /dev/mouse.type Mouse struct {	buttons int	xy      image.Point	msec    uint} func (m Mouse) String() string {	out := "" 	switch m.buttons {	case 1:		out += "Mb1"	case 2:		out += "Mb2"	case 4:		out += "Mb3"	case 8:		out += "SUp"	case 16:		out += "SDn"	default:		out += "nil"	} 	out += fmt.Sprintf(" %s %d", m.xy, m.msec) 	return out} // Mb1 returns true if the left mouse button was pressed.func (m *Mouse) Mb1() bool {	return m.buttons == 1} // Mb2 returns true if the middle mouse button was pressed.func (m *Mouse) Mb2() bool {	return m.buttons == 2} // Mb3 returns true if the right mouse button was pressed.func (m *Mouse) Mb3() bool {	return m.buttons == 4} // Any returns true if any mouse button is down.func (m *Mouse) Any() bool {	return m.buttons & 7 > 0} func (m *Mouse) Buttons() int {	return m.buttons} // ScrollUp returns true if the scroll wheel went up.func (m *Mouse) ScrollUp() bool {	return m.buttons == 8} // ScrollDown returns true if the scroll wheel went down.func (m *Mouse) ScrollDown() bool {	return m.buttons == 16} // Pt returns the point on the window at which the event happened.func (m *Mouse) Pt() image.Point {	return m.xy} // Ms returns the millisecond timestamp of the Mouse event.func (m *Mouse) Ms() uint {	return m.msec} type Mousectl struct {	Mouse	C      chan Mouse	Resize chan int	quit   chan bool 	// /dev/mouse	mfd *os.File	// /dev/cursor	cfd *os.File	// window/display	image *Image} func InitMouse(file string, img *Image) *Mousectl {	var err error	var ms Mousectl 	if file == "" {		file = "/dev/mouse"	} 	ms.mfd, err = os.OpenFile(file, os.O_RDWR|syscall.O_CLOEXEC, 0666)	if err != nil && file == "/dev/mouse" {		syscall.Bind("#m", "/dev", syscall.MAFTER)		ms.mfd, err = os.OpenFile(file, os.O_RDWR|syscall.O_CLOEXEC, 0666)	} 	if err != nil {		log.Fatal(err)	} 	ms.cfd, err = os.OpenFile("/dev/cursor", os.O_RDWR|syscall.O_CLOEXEC, 0666) 	ms.image = img	ms.C = make(chan Mouse)	ms.Resize = make(chan int, 2)	ms.quit = make(chan bool, 1)	go ms.readproc()	return &ms} func (ms *Mousectl) SetCursor(c *Cursor) {	if c == nil {		ms.cfd.Write([]byte{0})	} else {		buf := make([]byte, 2*4+2*2*16)		bplong(buf, uint32(c.Offset.X))		bplong(buf[4:], uint32(c.Offset.Y))		copy(buf[8:], c.Clear[:])		copy(buf[8+2*16:], c.Set[:])		ms.cfd.Write(buf)	}} func (ms *Mousectl) MoveTo(pt image.Point) {	fmt.Fprintf(ms.mfd, "m%d %d", pt.X, pt.Y)	ms.xy = pt} func (ms *Mousectl) Close() {	close(ms.quit)	ms.mfd.Close()	ms.cfd.Close()} func (ms *Mousectl) ReadMouse() Mouse {	if ms.image != nil {		ms.image.Display.flush(true)	} 	return <-ms.C} func (ms *Mousectl) readproc() {	var m Mouse	buf := make([]byte, 1+5*12) loop:	for {		select {		case <-ms.quit:			break loop		default:			n, err := ms.mfd.Read(buf)			if n != 1+4*12 {				log.Fatalf("mouse: bad count %d: %s", n, err)			} 			switch buf[0] {			// resize			case 'r':				ms.Resize <- 1				fallthrough			// mouse move			case 'm':				m.xy.X = atoi(buf[1+0*12:])				m.xy.Y = atoi(buf[1+1*12:])				m.buttons = atoi(buf[1+2*12:])				m.msec = uint(atoi(buf[1+3*12:]))				ms.C <- m			}		}	} 	close(ms.C)	close(ms.Resize)} /* TODO: setcursor */