forked from toolshed/abra
		
	
		
			
				
	
	
		
			487 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			487 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package coninput
 | |
| 
 | |
| import (
 | |
| 	"encoding/binary"
 | |
| 	"fmt"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	maxEventSize     = 16
 | |
| 	wordPaddingBytes = 2
 | |
| )
 | |
| 
 | |
| // EventType denots the type of an event
 | |
| type EventType uint16
 | |
| 
 | |
| // EventUnion is the union data type that contains the data for any event.
 | |
| type EventUnion [maxEventSize]byte
 | |
| 
 | |
| // InputRecord corresponds to the INPUT_RECORD structure from the Windows
 | |
| // console API (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/input-record-str).
 | |
| type InputRecord struct {
 | |
| 	// EventType specifies the type of event that helt in Event.
 | |
| 	EventType EventType
 | |
| 
 | |
| 	// Padding of the 16-bit EventType to a whole 32-bit dword.
 | |
| 	_ [wordPaddingBytes]byte
 | |
| 
 | |
| 	// Event holds the actual event data. Use Unrap to access it as its
 | |
| 	// respective event type.
 | |
| 	Event EventUnion
 | |
| }
 | |
| 
 | |
| // String implements fmt.Stringer for InputRecord.
 | |
| func (ir InputRecord) String() string {
 | |
| 	return ir.Unwrap().String()
 | |
| }
 | |
| 
 | |
| // Unwrap parses the event data into an EventRecord of the respective event
 | |
| // type. The data in the returned EventRecord does not contain any references to
 | |
| // the passed InputRecord.
 | |
| func (ir InputRecord) Unwrap() EventRecord {
 | |
| 	switch ir.EventType {
 | |
| 	case FocusEventType:
 | |
| 		return FocusEventRecord{SetFocus: ir.Event[0] > 0}
 | |
| 	case KeyEventType:
 | |
| 		return KeyEventRecord{
 | |
| 			KeyDown:         binary.LittleEndian.Uint32(ir.Event[0:4]) > 0,
 | |
| 			RepeatCount:     binary.LittleEndian.Uint16(ir.Event[4:6]),
 | |
| 			VirtualKeyCode:  VirtualKeyCode(binary.LittleEndian.Uint16(ir.Event[6:8])),
 | |
| 			VirtualScanCode: VirtualKeyCode(binary.LittleEndian.Uint16(ir.Event[8:10])),
 | |
| 			Char:            rune(binary.LittleEndian.Uint16(ir.Event[10:12])),
 | |
| 			ControlKeyState: ControlKeyState(binary.LittleEndian.Uint32(ir.Event[12:16])),
 | |
| 		}
 | |
| 	case MouseEventType:
 | |
| 		m := MouseEventRecord{
 | |
| 			MousePositon: Coord{
 | |
| 				X: binary.LittleEndian.Uint16(ir.Event[0:2]),
 | |
| 				Y: binary.LittleEndian.Uint16(ir.Event[2:4]),
 | |
| 			},
 | |
| 			ButtonState:     ButtonState(binary.LittleEndian.Uint32(ir.Event[4:8])),
 | |
| 			ControlKeyState: ControlKeyState(binary.LittleEndian.Uint32(ir.Event[8:12])),
 | |
| 			EventFlags:      EventFlags(binary.LittleEndian.Uint32(ir.Event[12:16])),
 | |
| 		}
 | |
| 
 | |
| 		if (m.EventFlags&MOUSE_WHEELED > 0) || (m.EventFlags&MOUSE_HWHEELED > 0) {
 | |
| 			if int16(highWord(uint32(m.ButtonState))) > 0 {
 | |
| 				m.WheelDirection = 1
 | |
| 			} else {
 | |
| 				m.WheelDirection = -1
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return m
 | |
| 	case WindowBufferSizeEventType:
 | |
| 		return WindowBufferSizeEventRecord{
 | |
| 			Size: Coord{
 | |
| 				X: binary.LittleEndian.Uint16(ir.Event[0:2]),
 | |
| 				Y: binary.LittleEndian.Uint16(ir.Event[2:4]),
 | |
| 			},
 | |
| 		}
 | |
| 	case MenuEventType:
 | |
| 		return MenuEventRecord{
 | |
| 			CommandID: binary.LittleEndian.Uint32(ir.Event[0:4]),
 | |
| 		}
 | |
| 	default:
 | |
| 		return &UnknownEvent{InputRecord: ir}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // EventRecord represents one of the following event types:
 | |
| // TypeFocusEventRecord, TypeKeyEventRecord, TypeMouseEventRecord,
 | |
| // TypeWindowBufferSizeEvent, TypeMenuEventRecord and UnknownEvent.
 | |
| type EventRecord interface {
 | |
| 	Type() string
 | |
| 	fmt.Stringer
 | |
| }
 | |
| 
 | |
| // FocusEventType is the event type for a FocusEventRecord (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/input-record-str).
 | |
| const FocusEventType EventType = 0x0010
 | |
| 
 | |
| // FocusEventRecord represent the FOCUS_EVENT_RECORD structure from the Windows
 | |
| // console API (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/focus-event-record-str).
 | |
| // These events are used internally by the Windows console API and should be
 | |
| // ignored.
 | |
| type FocusEventRecord struct {
 | |
| 	// SetFocus is reserved and should not be used.
 | |
| 	SetFocus bool
 | |
| }
 | |
| 
 | |
| // Ensure that FocusEventRecord satisfies EventRecord interface.
 | |
| var _ EventRecord = FocusEventRecord{}
 | |
| 
 | |
| // Type ensures that FocusEventRecord satisfies EventRecord interface.
 | |
| func (e FocusEventRecord) Type() string { return "FocusEvent" }
 | |
| 
 | |
| // String ensures that FocusEventRecord satisfies EventRecord and fmt.Stringer
 | |
| // interfaces.
 | |
| func (e FocusEventRecord) String() string { return fmt.Sprintf("%s[%v]", e.Type(), e.SetFocus) }
 | |
| 
 | |
| // KeyEventType is the event type for a KeyEventRecord (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/input-record-str).
 | |
| const KeyEventType EventType = 0x0001
 | |
| 
 | |
| // KeyEventRecord represent the KEY_EVENT_RECORD structure from the Windows
 | |
| // console API (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/key-event-record-str).
 | |
| type KeyEventRecord struct {
 | |
| 	// KeyDown specified whether the key is pressed or released.
 | |
| 	KeyDown bool
 | |
| 
 | |
| 	//  RepeatCount indicates that a key is being held down. For example, when a
 | |
| 	//  key is held down, five events with RepeatCount equal to 1 may be
 | |
| 	//  generated, one event with RepeatCount equal to 5, or multiple events
 | |
| 	//  with RepeatCount greater than or equal to 1.
 | |
| 	RepeatCount uint16
 | |
| 
 | |
| 	// VirtualKeyCode identifies the given key in a device-independent manner
 | |
| 	// (see
 | |
| 	// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes).
 | |
| 	VirtualKeyCode VirtualKeyCode
 | |
| 
 | |
| 	//  VirtualScanCode represents the device-dependent value generated by the
 | |
| 	//  keyboard hardware.
 | |
| 	VirtualScanCode VirtualKeyCode
 | |
| 
 | |
| 	// Char is the character that corresponds to the pressed key. Char can be
 | |
| 	// zero for some keys.
 | |
| 	Char rune
 | |
| 
 | |
| 	//ControlKeyState holds the state of the control keys.
 | |
| 	ControlKeyState ControlKeyState
 | |
| }
 | |
| 
 | |
| // Ensure that KeyEventRecord satisfies EventRecord interface.
 | |
| var _ EventRecord = KeyEventRecord{}
 | |
| 
 | |
| // Type ensures that KeyEventRecord satisfies EventRecord interface.
 | |
| func (e KeyEventRecord) Type() string { return "KeyEvent" }
 | |
| 
 | |
| // String ensures that KeyEventRecord satisfies EventRecord and fmt.Stringer
 | |
| // interfaces.
 | |
| func (e KeyEventRecord) String() string {
 | |
| 	infos := []string{}
 | |
| 
 | |
| 	repeat := ""
 | |
| 	if e.RepeatCount > 1 {
 | |
| 		repeat = "x" + strconv.Itoa(int(e.RepeatCount))
 | |
| 	}
 | |
| 
 | |
| 	infos = append(infos, fmt.Sprintf("%q%s", e.Char, repeat))
 | |
| 
 | |
| 	direction := "up"
 | |
| 	if e.KeyDown {
 | |
| 		direction = "down"
 | |
| 	}
 | |
| 
 | |
| 	infos = append(infos, direction)
 | |
| 
 | |
| 	if e.ControlKeyState != NO_CONTROL_KEY {
 | |
| 		infos = append(infos, e.ControlKeyState.String())
 | |
| 	}
 | |
| 
 | |
| 	infos = append(infos, fmt.Sprintf("KeyCode: %d", e.VirtualKeyCode))
 | |
| 	infos = append(infos, fmt.Sprintf("ScanCode: %d", e.VirtualScanCode))
 | |
| 
 | |
| 	return fmt.Sprintf("%s[%s]", e.Type(), strings.Join(infos, ", "))
 | |
| }
 | |
| 
 | |
| // MenuEventType is the event type for a MenuEventRecord (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/input-record-str).
 | |
| const MenuEventType EventType = 0x0008
 | |
| 
 | |
| // MenuEventRecord represent the MENU_EVENT_RECORD structure from the Windows
 | |
| // console API (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/menu-event-record-str).
 | |
| // These events are deprecated by the Windows console API and should be ignored.
 | |
| type MenuEventRecord struct {
 | |
| 	CommandID uint32
 | |
| }
 | |
| 
 | |
| // Ensure that MenuEventRecord satisfies EventRecord interface.
 | |
| var _ EventRecord = MenuEventRecord{}
 | |
| 
 | |
| // Type ensures that MenuEventRecord satisfies EventRecord interface.
 | |
| func (e MenuEventRecord) Type() string { return "MenuEvent" }
 | |
| 
 | |
| // String ensures that MenuEventRecord satisfies EventRecord and fmt.Stringer
 | |
| // interfaces.
 | |
| func (e MenuEventRecord) String() string { return fmt.Sprintf("MenuEvent[%d]", e.CommandID) }
 | |
| 
 | |
| // MouseEventType is the event type for a MouseEventRecord (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/input-record-str).
 | |
| const MouseEventType EventType = 0x0002
 | |
| 
 | |
| // MouseEventRecord represent the MOUSE_EVENT_RECORD structure from the Windows
 | |
| // console API (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str).
 | |
| type MouseEventRecord struct {
 | |
| 	// MousePosition contains the location of the cursor, in terms of the
 | |
| 	// console screen buffer's character-cell coordinates.
 | |
| 	MousePositon Coord
 | |
| 
 | |
| 	// ButtonState holds the status of the mouse buttons.
 | |
| 	ButtonState ButtonState
 | |
| 
 | |
| 	// ControlKeyState holds the state of the control keys.
 | |
| 	ControlKeyState ControlKeyState
 | |
| 
 | |
| 	// EventFlags specify tge type of mouse event.
 | |
| 	EventFlags EventFlags
 | |
| 
 | |
| 	// WheelDirection specified the direction in which the mouse wheel is
 | |
| 	// spinning when EventFlags contains MOUSE_HWHEELED or MOUSE_WHEELED. When
 | |
| 	// the event flags specify MOUSE_WHEELED it is 1 if the wheel rotated
 | |
| 	// forward (away from the user) or -1 when it rotates backwards. When
 | |
| 	// MOUSE_HWHEELED is specified it is 1 when the wheel rotates right and -1
 | |
| 	// when it rotates left. When the EventFlags do not indicate a mouse wheel
 | |
| 	// event it is 0.
 | |
| 	WheelDirection int
 | |
| }
 | |
| 
 | |
| // Ensure that MouseEventRecord satisfies EventRecord interface.
 | |
| var _ EventRecord = MouseEventRecord{}
 | |
| 
 | |
| func (e MouseEventRecord) WheelDirectionName() string {
 | |
| 	if e.EventFlags&MOUSE_WHEELED > 0 {
 | |
| 		if e.WheelDirection > 0 {
 | |
| 			return "Forward"
 | |
| 		}
 | |
| 
 | |
| 		return "Backward"
 | |
| 	} else if e.EventFlags&MOUSE_HWHEELED > 0 {
 | |
| 		if e.WheelDirection > 0 {
 | |
| 			return "Right"
 | |
| 		}
 | |
| 
 | |
| 		return "Left"
 | |
| 	}
 | |
| 
 | |
| 	return ""
 | |
| }
 | |
| 
 | |
| // Type ensures that MouseEventRecord satisfies EventRecord interface.
 | |
| func (e MouseEventRecord) Type() string { return "MouseEvent" }
 | |
| 
 | |
| // String ensures that MouseEventRecord satisfies EventRecord and fmt.Stringer
 | |
| // interfaces.
 | |
| func (e MouseEventRecord) String() string {
 | |
| 	infos := []string{e.MousePositon.String()}
 | |
| 
 | |
| 	if e.ButtonState&0xFF != 0 {
 | |
| 		infos = append(infos, e.ButtonState.String())
 | |
| 	}
 | |
| 
 | |
| 	eventDescription := e.EventFlags.String()
 | |
| 
 | |
| 	wheelDirection := e.WheelDirectionName()
 | |
| 	if wheelDirection != "" {
 | |
| 		eventDescription += "(" + wheelDirection + ")"
 | |
| 	}
 | |
| 
 | |
| 	infos = append(infos, eventDescription)
 | |
| 
 | |
| 	if e.ControlKeyState != NO_CONTROL_KEY {
 | |
| 		infos = append(infos, e.ControlKeyState.String())
 | |
| 	}
 | |
| 
 | |
| 	return fmt.Sprintf("%s[%s]", e.Type(), strings.Join(infos, ", "))
 | |
| }
 | |
| 
 | |
| // WindowBufferSizeEventType is the event type for a WindowBufferSizeEventRecord
 | |
| // (see https://docs.microsoft.com/en-us/windows/console/input-record-str).
 | |
| const WindowBufferSizeEventType EventType = 0x0004
 | |
| 
 | |
| // WindowBufferSizeEventRecord represent the WINDOW_BUFFER_SIZE_RECORD structure
 | |
| // from the Windows console API (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/window-buffer-size-record-str).
 | |
| type WindowBufferSizeEventRecord struct {
 | |
| 	// Size contains the size of the console screen buffer, in character cell columns and rows.
 | |
| 	Size Coord
 | |
| }
 | |
| 
 | |
| // Ensure that WindowBufferSizeEventRecord satisfies EventRecord interface.
 | |
| var _ EventRecord = WindowBufferSizeEventRecord{}
 | |
| 
 | |
| // Type ensures that WindowBufferSizeEventRecord satisfies EventRecord interface.
 | |
| func (e WindowBufferSizeEventRecord) Type() string { return "WindowBufferSizeEvent" }
 | |
| 
 | |
| // String ensures that WindowBufferSizeEventRecord satisfies EventRecord and fmt.Stringer
 | |
| // interfaces.
 | |
| func (e WindowBufferSizeEventRecord) String() string {
 | |
| 	return fmt.Sprintf("WindowBufferSizeEvent[%s]", e.Size)
 | |
| }
 | |
| 
 | |
| // UnknownEvent is generated when the event type does not match one of the
 | |
| // following types: TypeFocusEventRecord, TypeKeyEventRecord,
 | |
| // TypeMouseEventRecord, TypeWindowBufferSizeEvent, TypeMenuEventRecord and
 | |
| // UnknownEvent.
 | |
| type UnknownEvent struct {
 | |
| 	InputRecord
 | |
| }
 | |
| 
 | |
| // Ensure that UnknownEvent satisfies EventRecord interface.
 | |
| var _ EventRecord = UnknownEvent{}
 | |
| 
 | |
| // Type ensures that UnknownEvent satisfies EventRecord interface.
 | |
| func (e UnknownEvent) Type() string { return "UnknownEvent" }
 | |
| 
 | |
| // String ensures that UnknownEvent satisfies EventRecord and fmt.Stringer
 | |
| // interfaces.
 | |
| func (e UnknownEvent) String() string {
 | |
| 	return fmt.Sprintf("%s[Type: %d, Data: %v]", e.Type(), e.InputRecord.EventType, e.InputRecord.Event[:])
 | |
| }
 | |
| 
 | |
| // Coord represent the COORD structure from the Windows
 | |
| // console API (see https://docs.microsoft.com/en-us/windows/console/coord-str).
 | |
| type Coord struct {
 | |
| 	// X is the horizontal coordinate or column value. The units depend on the function call.
 | |
| 	X uint16
 | |
| 	// Y is the vertical coordinate or row value. The units depend on the function call.
 | |
| 	Y uint16
 | |
| }
 | |
| 
 | |
| // String ensures that Coord satisfies the fmt.Stringer interface.
 | |
| func (c Coord) String() string {
 | |
| 	return fmt.Sprintf("(%d, %d)", c.X, c.Y)
 | |
| }
 | |
| 
 | |
| // ButtonState holds the state of the mouse buttons (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str).
 | |
| type ButtonState uint32
 | |
| 
 | |
| func (bs ButtonState) Contains(state ButtonState) bool {
 | |
| 	return bs&state > 0
 | |
| }
 | |
| 
 | |
| // String ensures that ButtonState satisfies the fmt.Stringer interface.
 | |
| func (bs ButtonState) String() string {
 | |
| 	switch {
 | |
| 	case bs&FROM_LEFT_1ST_BUTTON_PRESSED > 0:
 | |
| 		return "Left"
 | |
| 	case bs&FROM_LEFT_2ND_BUTTON_PRESSED > 0:
 | |
| 		return "2"
 | |
| 	case bs&FROM_LEFT_3RD_BUTTON_PRESSED > 0:
 | |
| 		return "3"
 | |
| 	case bs&FROM_LEFT_4TH_BUTTON_PRESSED > 0:
 | |
| 		return "4"
 | |
| 	case bs&RIGHTMOST_BUTTON_PRESSED > 0:
 | |
| 		return "Right"
 | |
| 	case bs&0xFF == 0:
 | |
| 		return "No Button"
 | |
| 	default:
 | |
| 		return fmt.Sprintf("Unknown(%d)", bs)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (bs ButtonState) IsReleased() bool {
 | |
| 	return bs&0xff > 0
 | |
| }
 | |
| 
 | |
| // Valid values for ButtonState.
 | |
| const (
 | |
| 	FROM_LEFT_1ST_BUTTON_PRESSED ButtonState = 0x0001
 | |
| 	RIGHTMOST_BUTTON_PRESSED     ButtonState = 0x0002
 | |
| 	FROM_LEFT_2ND_BUTTON_PRESSED ButtonState = 0x0004
 | |
| 	FROM_LEFT_3RD_BUTTON_PRESSED ButtonState = 0x0008
 | |
| 	FROM_LEFT_4TH_BUTTON_PRESSED ButtonState = 0x0010
 | |
| )
 | |
| 
 | |
| // ControlKeyState holds the state of the control keys for key and mouse events
 | |
| // (see https://docs.microsoft.com/en-us/windows/console/key-event-record-str
 | |
| // and https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str).
 | |
| type ControlKeyState uint32
 | |
| 
 | |
| func (cks ControlKeyState) Contains(state ControlKeyState) bool {
 | |
| 	return cks&state > 0
 | |
| }
 | |
| 
 | |
| // Valid values for ControlKeyState.
 | |
| const (
 | |
| 	CAPSLOCK_ON        ControlKeyState = 0x0080
 | |
| 	ENHANCED_KEY       ControlKeyState = 0x0100
 | |
| 	LEFT_ALT_PRESSED   ControlKeyState = 0x0002
 | |
| 	LEFT_CTRL_PRESSED  ControlKeyState = 0x0008
 | |
| 	NUMLOCK_ON         ControlKeyState = 0x0020
 | |
| 	RIGHT_ALT_PRESSED  ControlKeyState = 0x0001
 | |
| 	RIGHT_CTRL_PRESSED ControlKeyState = 0x0004
 | |
| 	SCROLLLOCK_ON      ControlKeyState = 0x0040
 | |
| 	SHIFT_PRESSED      ControlKeyState = 0x0010
 | |
| 	NO_CONTROL_KEY     ControlKeyState = 0x0000
 | |
| )
 | |
| 
 | |
| // String ensures that ControlKeyState satisfies the fmt.Stringer interface.
 | |
| func (cks ControlKeyState) String() string {
 | |
| 	controlKeys := []string{}
 | |
| 
 | |
| 	switch {
 | |
| 	case cks&CAPSLOCK_ON > 0:
 | |
| 		controlKeys = append(controlKeys, "CapsLock")
 | |
| 	case cks&ENHANCED_KEY > 0:
 | |
| 		controlKeys = append(controlKeys, "Enhanced")
 | |
| 	case cks&LEFT_ALT_PRESSED > 0:
 | |
| 		controlKeys = append(controlKeys, "Alt")
 | |
| 	case cks&LEFT_CTRL_PRESSED > 0:
 | |
| 		controlKeys = append(controlKeys, "CTRL")
 | |
| 	case cks&NUMLOCK_ON > 0:
 | |
| 		controlKeys = append(controlKeys, "NumLock")
 | |
| 	case cks&RIGHT_ALT_PRESSED > 0:
 | |
| 		controlKeys = append(controlKeys, "RightAlt")
 | |
| 	case cks&RIGHT_CTRL_PRESSED > 0:
 | |
| 		controlKeys = append(controlKeys, "RightCTRL")
 | |
| 	case cks&SCROLLLOCK_ON > 0:
 | |
| 		controlKeys = append(controlKeys, "ScrollLock")
 | |
| 	case cks&SHIFT_PRESSED > 0:
 | |
| 		controlKeys = append(controlKeys, "Shift")
 | |
| 	case cks == NO_CONTROL_KEY:
 | |
| 	default:
 | |
| 		return fmt.Sprintf("Unknown(%d)", cks)
 | |
| 	}
 | |
| 
 | |
| 	return strings.Join(controlKeys, ",")
 | |
| }
 | |
| 
 | |
| // EventFlags specifies the type of a mouse event (see
 | |
| // https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str).
 | |
| type EventFlags uint32
 | |
| 
 | |
| // String ensures that EventFlags satisfies the fmt.Stringer interface.
 | |
| func (ef EventFlags) String() string {
 | |
| 	switch {
 | |
| 	case ef&DOUBLE_CLICK > 0:
 | |
| 		return "DoubleClick"
 | |
| 	case ef&MOUSE_WHEELED > 0:
 | |
| 		return "Wheeled"
 | |
| 	case ef&MOUSE_MOVED > 0:
 | |
| 		return "Moved"
 | |
| 	case ef&MOUSE_HWHEELED > 0:
 | |
| 		return "HWheeld"
 | |
| 	case ef == CLICK:
 | |
| 		return "Click"
 | |
| 	default:
 | |
| 		return fmt.Sprintf("Unknown(%d)", ef)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (ef EventFlags) Contains(flag EventFlags) bool {
 | |
| 	return ef&flag > 0
 | |
| }
 | |
| 
 | |
| // Valid values for EventFlags.
 | |
| const (
 | |
| 	CLICK          EventFlags = 0x0000
 | |
| 	MOUSE_MOVED    EventFlags = 0x0001
 | |
| 	DOUBLE_CLICK   EventFlags = 0x0002
 | |
| 	MOUSE_WHEELED  EventFlags = 0x0004
 | |
| 	MOUSE_HWHEELED EventFlags = 0x0008
 | |
| )
 | |
| 
 | |
| func highWord(data uint32) uint16 {
 | |
| 	return uint16((data & 0xFFFF0000) >> 16)
 | |
| }
 |