summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--area_unix.go151
-rw-r--r--test/main.go4
2 files changed, 135 insertions, 20 deletions
diff --git a/area_unix.go b/area_unix.go
index 333f268..3362861 100644
--- a/area_unix.go
+++ b/area_unix.go
@@ -76,22 +76,32 @@ func our_area_draw_callback(widget *C.GtkWidget, cr *C.cairo_t, data C.gpointer)
var area_draw_callback = C.GCallback(C.our_area_draw_callback)
-// shared code for finishing up and sending a mouse event
-func finishMouseEvent(data C.gpointer, me MouseEvent, mb uint, x C.gdouble, y C.gdouble, state C.guint, gdkwindow *C.GdkWindow) {
- s := (*sysData)(unsafe.Pointer(data))
+func translateModifiers(state C.guint, window *C.GdkWindow) C.guint {
// GDK doesn't initialize the modifier flags fully; we have to explicitly tell it to (thanks to Daniel_S and daniels (two different people) in irc.gimp.net/#gtk+)
C.gdk_keymap_add_virtual_modifiers(
- C.gdk_keymap_get_for_display(C.gdk_window_get_display(gdkwindow)),
+ C.gdk_keymap_get_for_display(C.gdk_window_get_display(window)),
(*C.GdkModifierType)(unsafe.Pointer(&state)))
+ return state
+}
+
+func makeModifiers(state C.guint) (m Modifiers) {
if (state & C.GDK_CONTROL_MASK) != 0 {
- me.Modifiers |= Ctrl
+ m |= Ctrl
}
if (state & C.GDK_META_MASK) != 0 {
- me.Modifiers |= Alt
+ m |= Alt
}
if (state & C.GDK_SHIFT_MASK) != 0 {
- me.Modifiers |= Shift
+ m |= Shift
}
+ return m
+}
+
+// shared code for finishing up and sending a mouse event
+func finishMouseEvent(data C.gpointer, me MouseEvent, mb uint, x C.gdouble, y C.gdouble, state C.guint, gdkwindow *C.GdkWindow) {
+ s := (*sysData)(unsafe.Pointer(data))
+ state = translateModifiers(state, gdkwindow)
+ me.Modifiers = makeModifiers(state)
// the mb != # checks exclude the Up/Down button from Held
if mb != 1 && (state & C.GDK_BUTTON1_MASK) != 0 {
me.Held = append(me.Held, 1)
@@ -157,9 +167,38 @@ func our_area_motion_notify_event_callback(widget *C.GtkWidget, event *C.GdkEven
var area_motion_notify_event_callback = C.GCallback(C.our_area_motion_notify_event_callback)
+// shared code for doing a key event
+func doKeyEvent(event *C.GdkEvent, data C.gpointer, up bool) bool {
+ var ke KeyEvent
+
+ e := (*C.GdkEventKey)(unsafe.Pointer(event))
+ s := (*sysData)(unsafe.Pointer(data))
+ keyval := e.keyval
+ if extkey, ok := extkeys[keyval]; ok {
+ ke.ExtKey = extkey
+ } else if predef, ok := predefkeys[keyval]; ok {
+ ke.ASCII = predef
+ } else if _, ok := modonlykeys[keyval]; !ok { // use ok form here to save memory/avoid racy map write
+ cp := C.gdk_keyval_to_unicode(keyval)
+ // GDK keycodes in GDK 3.4 the ASCII plane map to their ASCII values
+ // (proof: https://git.gnome.org/browse/gtk+/tree/gdk/gdkkeysyms.h?h=gtk-3-4)
+ // this also handles the numeric keypad keys (proof: https://git.gnome.org/browse/gtk+/tree/gdk/gdkkeyuni.c?h=gtk-3-4#n846)
+ // the cp < 0x20 will also handle the case where the key is totally unknown to us (gdk_keyval_to_unicode() returns 0) and the space key
+ if cp < 0x20 || cp >= 0x7F {
+ // TODO really stop here? or should we handle modifiers?
+ return false // pretend unhandled
+ }
+ ke.ASCII = byte(cp)
+ }
+ state := translateModifiers(e.state, e.window)
+ ke.Modifiers = makeModifiers(state)
+ ke.Up = up
+ return s.handler.Key(ke)
+}
+
//export our_area_key_press_event_callback
func our_area_key_press_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
- e := (*C.GdkEventKey)(unsafe.Pointer(event))
+/*
fmt.Printf("PRESS %#v\n", e)
fmt.Printf("this (%d/GDK_KEY_%s):\n", e.keyval,
C.GoString((*C.char)(unsafe.Pointer(
@@ -169,28 +208,24 @@ func our_area_key_press_event_callback(widget *C.GtkWidget, event *C.GdkEvent, d
pk(C.GDK_KEY_A, e.window)
fmt.Printf("%d/GDK_KEY_a:\n", C.GDK_KEY_a)
pk(C.GDK_KEY_a, e.window)
- return C.FALSE // TODO really false?
+*/
+ ret := doKeyEvent(event, data, false)
+ _ = ret
+ return C.FALSE // TODO really false? should probably return !ret (since true indicates stop processing)
}
var area_key_press_event_callback = C.GCallback(C.our_area_key_press_event_callback)
//export our_area_key_release_event_callback
func our_area_key_release_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
- e := (*C.GdkEventKey)(unsafe.Pointer(event))
- fmt.Printf("RELEASE %#v\n", e)
- fmt.Printf("this (%d/GDK_KEY_%s):\n", e.keyval,
- C.GoString((*C.char)(unsafe.Pointer(
- C.gdk_keyval_name(e.keyval)))))
- pk(e.keyval, e.window)
- fmt.Printf("%d/GDK_KEY_A:\n", C.GDK_KEY_A)
- pk(C.GDK_KEY_A, e.window)
- fmt.Printf("%d/GDK_KEY_a:\n", C.GDK_KEY_a)
- pk(C.GDK_KEY_a, e.window)
- return C.FALSE // TODO really false?
+ ret := doKeyEvent(event, data, true)
+ _ = ret
+ return C.FALSE // TODO really false? should probably return !ret (since true indicates stop processing)
}
var area_key_release_event_callback = C.GCallback(C.our_area_key_release_event_callback)
+/*
func pk(keyval C.guint, window *C.GdkWindow) {
var kk *C.GdkKeymapKey
var nk C.gint
@@ -210,3 +245,79 @@ func pk(keyval C.guint, window *C.GdkWindow) {
}
C.g_free(C.gpointer(unsafe.Pointer(ok)))
}
+*/
+
+var extkeys = map[C.guint]ExtKey{
+ C.GDK_KEY_Escape: Escape,
+ C.GDK_KEY_Insert: Insert,
+ C.GDK_KEY_Delete: Delete,
+ C.GDK_KEY_Home: Home,
+ C.GDK_KEY_End: End,
+ C.GDK_KEY_Page_Up: PageUp,
+ C.GDK_KEY_Page_Down: PageDown,
+ C.GDK_KEY_Up: Up,
+ C.GDK_KEY_Down: Down,
+ C.GDK_KEY_Left: Left,
+ C.GDK_KEY_Right: Right,
+ C.GDK_KEY_F1: F1,
+ C.GDK_KEY_F2: F2,
+ C.GDK_KEY_F3: F3,
+ C.GDK_KEY_F4: F4,
+ C.GDK_KEY_F5: F5,
+ C.GDK_KEY_F6: F6,
+ C.GDK_KEY_F7: F7,
+ C.GDK_KEY_F8: F8,
+ C.GDK_KEY_F9: F9,
+ C.GDK_KEY_F10: F10,
+ C.GDK_KEY_F11: F11,
+ C.GDK_KEY_F12: F12,
+ // numeric keypad equivalents:
+ C.GDK_KEY_KP_Insert: Insert,
+ C.GDK_KEY_KP_Delete: Delete,
+ C.GDK_KEY_KP_Home: Home,
+ C.GDK_KEY_KP_End: End,
+ C.GDK_KEY_KP_Page_Up: PageUp,
+ C.GDK_KEY_KP_Page_Down: PageDown,
+ C.GDK_KEY_KP_Up: Up,
+ C.GDK_KEY_KP_Down: Down,
+ C.GDK_KEY_KP_Left: Left,
+ C.GDK_KEY_KP_Right: Right,
+}
+
+// sanity check
+func init() {
+ included := make([]bool, _nextkeys)
+ for _, v := range extkeys {
+ included[v] = true
+ }
+ for i := 1; i < int(_nextkeys); i++ {
+ if !included[i] {
+ panic(fmt.Errorf("error: not all ExtKeys defined on Unix (missing %d)", i))
+ }
+ }
+}
+
+var predefkeys = map[C.guint]byte{
+ C.GDK_KEY_Return: '\n',
+ // TODO C.GDK_KEY_Linefeed too? What key is this?
+ C.GDK_KEY_Tab: '\t',
+ C.GDK_KEY_BackSpace: '\b',
+ // tests indicate that this is sent on Shift+Tab
+ C.GDK_KEY_ISO_Left_Tab: '\t',
+ // numeric keypad equivalents:
+ C.GDK_KEY_KP_Enter: '\n',
+ // all other numeric keypad equivalents are handled by gdk_keymap_to_unicode() as mentioned above
+ // no space; handled by the code above
+}
+
+var modonlykeys = map[C.guint]bool{
+ C.GDK_KEY_Shift_L: true,
+ C.GDK_KEY_Shift_R: true,
+ C.GDK_KEY_Control_L: true,
+ C.GDK_KEY_Control_R: true,
+ C.GDK_KEY_Meta_L: true,
+ C.GDK_KEY_Meta_R: true,
+ // TODO GDK_KEY_Alt_L/R too?
+ C.GDK_KEY_Super_L: true,
+ C.GDK_KEY_Super_R: true,
+}
diff --git a/test/main.go b/test/main.go
index d4a94e3..b2d6a6d 100644
--- a/test/main.go
+++ b/test/main.go
@@ -133,6 +133,10 @@ func (a *areaHandler) Paint(rect image.Rectangle) *image.NRGBA {
func (a *areaHandler) Mouse(e MouseEvent) {
// fmt.Printf("%#v\n", e)
}
+func (a *areaHandler) Key(e KeyEvent) bool {
+ fmt.Printf("%#v\n", e)
+ return false
+}
var doArea = flag.Bool("area", false, "run area test instead")
func areaTest() {