From 3508239bf7318019aff660e375fe286ecc2e8047 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 7 May 2014 17:51:04 -0400 Subject: [PATCH] Completed extending of mouse buttons to the system's limit; defined (as undefined) the mouse drag behavior for buttons >= 3; implemented all that on the GTK+ side, and decided to have MouseEvents.Held[] be sorted (documentation only for now; need to check the code to make sure it follows). Good Lord... --- area.go | 4 +++- area_unix.go | 23 ++++++++++++++--------- todo.md | 8 ++------ 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/area.go b/area.go index b39e448..d6cbf3d 100644 --- a/area.go +++ b/area.go @@ -73,6 +73,7 @@ type AreaHandler interface { // MouseEvent contains all the information for a mous event sent by Area.Mouse. // Mouse button IDs start at 1, with 1 being the left mouse button, 2 being the middle mouse button, and 3 being the right mouse button. // If additional buttons are supported, they will be returned with 4 being the first additional button. +// For example, on Unix systems where mouse buttons 4 through 7 are pseudobuttons for the scroll wheel directions, the next button, button 8, will be returned as 4, 9 as 5, etc. // The association between button numbers and physical buttons are system-defined. // For example, on Windows, buttons 4 and 5 are mapped to what are internally referred to as "XBUTTON1" and "XBUTTON2", which often correspond to the dedicated back/forward navigation buttons on the sides of many mice. // The examples here are NOT a guarantee as to how many buttons maximum will be available on a given system. @@ -103,7 +104,8 @@ type MouseEvent struct { // Held is a slice of button IDs that indicate which mouse buttons are being held during the event. // Held will not include Down and Up. - // (TODO "There is no guarantee that Held is sorted."?) + // Held will be sorted. + // Only buttons 1, 2, and 3 are guaranteed to be detected by Held properly; whether or not any others are is implementation-defined. Held []uint } diff --git a/area_unix.go b/area_unix.go index af2202a..8034a5f 100644 --- a/area_unix.go +++ b/area_unix.go @@ -108,6 +108,10 @@ func makeModifiers(state C.guint, m Modifiers) Modifiers { func finishMouseEvent(widget *C.GtkWidget, data C.gpointer, me MouseEvent, mb uint, x C.gdouble, y C.gdouble, state C.guint, gdkwindow *C.GdkWindow) { var areawidth, areaheight C.gint + // on GTK+, mouse buttons 4-7 are for scrolling; if we got here, that's a mistake (and see the TODOs on return values below) + if mb >= 4 && mb <= 7 { + return + } s := (*sysData)(unsafe.Pointer(data)) state = translateModifiers(state, gdkwindow) me.Modifiers = makeModifiers(state, 0) @@ -121,18 +125,19 @@ func finishMouseEvent(widget *C.GtkWidget, data C.gpointer, me MouseEvent, mb ui if mb != 3 && (state & C.GDK_BUTTON3_MASK) != 0 { me.Held = append(me.Held, 3) } - // TODO keep? - if mb != 4 && (state & C.GDK_BUTTON4_MASK) != 0 { - me.Held = append(me.Held, 4) - } - if mb != 5 && (state & C.GDK_BUTTON5_MASK) != 0 { - me.Held = append(me.Held, 5) - } + // don't check GDK_BUTTON4_MASK or GDK_BUTTON5_MASK because those are for the scrolling buttons mentioned above; there doesn't seem to be a way to detect higher buttons... (TODO) me.Pos = image.Pt(int(x), int(y)) C.gtk_widget_get_size_request(widget, &areawidth, &areaheight) if !me.Pos.In(image.Rect(0, 0, int(areawidth), int(areaheight))) { // outside the actual Area; no event return } + // and finally, if the button ID >= 8, continue counting from 4, as above and as in the MouseEvent spec + if me.Down >= 8 { + me.Down -= 4 + } + if me.Up >= 8 { + me.Up -= 4 + } repaint := s.handler.Mouse(me) if repaint { C.gtk_widget_queue_draw(widget) @@ -145,7 +150,7 @@ func our_area_button_press_event_callback(widget *C.GtkWidget, event *C.GdkEvent C.gtk_widget_grab_focus(widget) e := (*C.GdkEventButton)(unsafe.Pointer(event)) me := MouseEvent{ - // GDK button ID == our button ID + // GDK button ID == our button ID with some exceptions taken care of by finishMouseEvent() Down: uint(e.button), } switch e._type { @@ -166,7 +171,7 @@ var area_button_press_event_callback = C.GCallback(C.our_area_button_press_event func our_area_button_release_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean { e := (*C.GdkEventButton)(unsafe.Pointer(event)) me := MouseEvent{ - // GDK button ID == our button ID + // GDK button ID == our button ID with some exceptions taken care of by finishMouseEvent() Up: uint(e.button), } finishMouseEvent(widget, data, me, me.Up, e.x, e.y, e.state, e.window) diff --git a/todo.md b/todo.md index 440310b..4c06a24 100644 --- a/todo.md +++ b/todo.md @@ -13,12 +13,8 @@ super ultra important things: - OS X: handle Insert/Help key change in a sane and deterministic way - will need old and new Mac keyboards... - make sure MouseEvent's documentation has dragging described correctly (both Windows and GTK+ do) - - fix OS X so that it follows these rules - - native Windows (not wine) and OS X don't respond to mouse button 4 and 5 drags?! - [16:45] no, just tried, and the navigation buttons don't. - [16:45] ok, thanks a lot - [16:45] only the l, m, and r ones do. - - oh... + - figure out what to do about dragging into or out of a window; will likely need to be undefined as well... +- double-check to make sure MouseEvent.Held[] is sorted on all platforms - cap click count to 2 on all platforms - the windows build appears to be unstable: - 64-bit crashes in malloc in wine with heap corruption warnings aplenty during DLL loading; in windows 7 it works fine