diff options
| author | Pietro Gagliardi <[email protected]> | 2014-03-30 19:53:44 -0400 |
|---|---|---|
| committer | Pietro Gagliardi <[email protected]> | 2014-03-30 19:53:44 -0400 |
| commit | 6a7cb73ddaa92a87fb4df77a7a3f3c2332f8761f (patch) | |
| tree | aec15845b480cee8528f104a5685fccf54327780 | |
| parent | 41a7e3dab8193d8c19aa43eac344eb274deef5a8 (diff) | |
Added key events to Mac OS X Areas. Now Area is feature-complete (but buggy) on all platforms :D Also more TODOs.
| -rw-r--r-- | area_darwin.go | 68 | ||||
| -rw-r--r-- | bleh_darwin.m | 9 | ||||
| -rw-r--r-- | events_darwin.go | 129 | ||||
| -rw-r--r-- | objc_darwin.h | 2 | ||||
| -rw-r--r-- | todo.md | 6 |
5 files changed, 214 insertions, 0 deletions
diff --git a/area_darwin.go b/area_darwin.go index c5c3845..2f93614 100644 --- a/area_darwin.go +++ b/area_darwin.go @@ -17,6 +17,9 @@ import ( // extern void areaView_mouseMoved(id, SEL, id); // extern void areaView_mouseDown_mouseDragged(id, SEL, id); // extern void areaView_mouseUp(id, SEL, id); +// extern void areaView_keyDown(id, SEL, id); +// extern void areaView_keyUp(id, SEL, id); +// extern void areaView_flagsChanged(id, SEL, id); import "C" const ( @@ -47,6 +50,9 @@ var eventMethods = []eventMethod{ eventMethod{"otherMouseDown:", uintptr(C.areaView_mouseDown_mouseDragged)}, eventMethod{"otherMouseDragged:", uintptr(C.areaView_mouseDown_mouseDragged)}, eventMethod{"otherMouseUp:", uintptr(C.areaView_mouseUp)}, + eventMethod{"keyDown:", uintptr(C.areaView_keyDown)}, + eventMethod{"keyUp:", uintptr(C.areaView_keyUp)}, + eventMethod{"flagsChanged:", uintptr(C.areaView_flagsChanged)}, } func mkAreaClass() error { @@ -202,6 +208,68 @@ func areaView_mouseUp(self C.id, sel C.SEL, e C.id) { areaMouseEvent(self, e, true, true) } +var ( + _keyCode = sel_getUid("keyCode") +) + +func handleKeyEvent(self C.id) { + // TODO +} + +func sendKeyEvent(self C.id, ke KeyEvent) { + s := getSysData(self) + handled, repaint := s.handler.Key(ke) + if repaint { + C.objc_msgSend_noargs(self, _display) + } + if !handled { + handleKeyEvent(self) + } +} + +func areaKeyEvent(self C.id, e C.id, up bool) { + var ke KeyEvent + + keyCode := uintptr(C.objc_msgSend_ushortret_noargs(e, _keyCode)) + ke, ok := fromKeycode(keyCode) + if !ok { + // no such key; modifiers by themselves are handled by -[self flagsChanged:] + handleKeyEvent(self) + return + } + // either ke.Key or ke.ExtKey will be set at this point + ke.Modifiers = parseModifiers(e) + ke.Up = up + sendKeyEvent(self, ke) +} + +//export areaView_keyDown +func areaView_keyDown(self C.id, sel C.SEL, e C.id) { + areaKeyEvent(self, e, false) +} + +//export areaView_keyUp +func areaView_keyUp(self C.id, sel C.SEL, e C.id) { + areaKeyEvent(self, e, true) +} + +//export areaView_flagsChanged +func areaView_flagsChanged(self C.id, sel C.SEL, e C.id) { + var ke KeyEvent + + // Mac OS X sends this event on both key up and key down. + // Fortunately -[e keyCode] IS valid here, so we can simply map from key code to Modifiers, get the value of [e modifierFlags], the respective bit is set or not — that will give us the up/down state + keyCode := uintptr(C.objc_msgSend_ushortret_noargs(e, _keyCode)) + mod, ok := keycodeModifiers[keyCode] // comma-ok form to avoid adding entries + if !ok { // unknown modifier; ignore + handleKeyEvent(self) + return + } + ke.Modifiers = parseModifiers(e) + ke.Up = (ke.Modifiers & mod) == 0 + sendKeyEvent(self, ke) +} + // TODO combine these with the listbox functions? func newAreaScrollView(area C.id) C.id { diff --git a/bleh_darwin.m b/bleh_darwin.m index 48f0ae7..720da0f 100644 --- a/bleh_darwin.m +++ b/bleh_darwin.m @@ -67,6 +67,15 @@ id objc_msgSend_id_int(id obj, SEL sel, id a, intptr_t b) } /* +same as above, but for unsigned short +*/ + +uintptr_t objc_msgSend_ushortret_noargs(id obj, SEL sel) +{ + return (uintptr_t) ((unsigned short) objc_msgSend(obj, sel)); +} + +/* These are the objc_msgSend() wrappers around NSRect. The problem is that while on 32-bit systems, NSRect is a concrete structure, on 64-bit systems it's just a typedef to CGRect. While in practice just using CGRect everywhere seems to work, better to be safe than sorry. I use int64_t for maximum safety, as my coordinates are stored as Go ints and Go int -> C int (which is what is documented as happening) isn't reliable. diff --git a/events_darwin.go b/events_darwin.go new file mode 100644 index 0000000..27f479d --- /dev/null +++ b/events_darwin.go @@ -0,0 +1,129 @@ +// 30 march 2014 + +package ui + +/* +Mac OS X uses its own set of hardware key codes that are different from PC keyboard scancodes, but are positional (like PC keyboard scancodes). These are defined in <HIToolbox/Events.h>, a Carbon header. As far as I can tell, there's no way to include this header without either using an absolute path or linking Carbon into the program, so the constant values are used here instead. + +The Cocoa docs do guarantee that -[NSEvent keyCode] results in key codes that are the same as those returned by Carbon; that is, these codes. +*/ + +// use uintptr to be safe +var keycodeKeys = map[uintptr]byte{ + 0x00: 'a', + 0x01: 's', + 0x02: 'd', + 0x03: 'f', + 0x04: 'h', + 0x05: 'g', + 0x06: 'z', + 0x07: 'x', + 0x08: 'c', + 0x09: 'v', + 0x0B: 'b', + 0x0C: 'q', + 0x0D: 'w', + 0x0E: 'e', + 0x0F: 'r', + 0x10: 'y', + 0x11: 't', + 0x12: '1', + 0x13: '2', + 0x14: '3', + 0x15: '4', + 0x16: '6', + 0x17: '5', + 0x18: '=', + 0x19: '9', + 0x1A: '7', + 0x1B: '-', + 0x1C: '8', + 0x1D: '0', + 0x1E: ']', + 0x1F: 'o', + 0x20: 'u', + 0x21: '[', + 0x22: 'i', + 0x23: 'p', + 0x25: 'l', + 0x26: 'j', + 0x27: '\'', + 0x28: 'k', + 0x29: ';', + 0x2A: '\\', + 0x2B: ',', + 0x2C: '/', + 0x2D: 'n', + 0x2E: 'm', + 0x2F: '.', + 0x32: '`', + 0x24: '\n', + 0x30: '\t', + 0x31: ' ', + 0x33: '\b', +} + +var keycodeExtKeys = map[uintptr]ExtKey{ + 0x41: NDot, + 0x43: NMultiply, + 0x45: NAdd, +// 0x47: kVK_ANSI_KeypadClear, + 0x4B: NDivide, + 0x4C: NEnter, + 0x4E: NSubtract, + 0x52: N0, + 0x53: N1, + 0x54: N2, + 0x55: N3, + 0x56: N4, + 0x57: N5, + 0x58: N6, + 0x59: N7, + 0x5B: N8, + 0x5C: N9, + 0x35: Escape, + 0x60: F5, + 0x61: F6, + 0x62: F7, + 0x63: F3, + 0x64: F8, + 0x65: F9, + 0x67: F11, + 0x6D: F10, + 0x6F: F12, +// 0x72: kVK_Help, + 0x73: Home, + 0x74: PageUp, + 0x75: Delete, + 0x76: F4, + 0x77: End, + 0x78: F2, + 0x79: PageDown, + 0x7A: F1, + 0x7B: Left, + 0x7C: Right, + 0x7D: Down, + 0x7E: Up, +} + +var keycodeModifiers = map[uintptr]Modifiers{ + 0x37: Ctrl, // left command (TODO both commands?) + 0x38: Shift, // left shift + 0x3A: Alt, // left option +// 0x3B: kVK_Control, + 0x3C: Shift, // right shift + 0x3D: Alt, // right alt +// 0x3E: kVK_RightControl, +} + +func fromKeycode(keycode uintptr) (ke KeyEvent, ok bool) { + if key, ok := keycodeKeys[keycode]; ok { + ke.Key = key + return ke, true + } + if extkey, ok := keycodeExtKeys[keycode]; ok { + ke.ExtKey = extkey + return ke, true + } + return ke, false +} diff --git a/objc_darwin.h b/objc_darwin.h index 2807d93..0583d37 100644 --- a/objc_darwin.h +++ b/objc_darwin.h @@ -56,6 +56,8 @@ extern uintptr_t objc_msgSend_uintret_noargs(id objc, SEL sel); extern intptr_t objc_msgSend_intret_noargs(id obj, SEL sel); +extern uintptr_t objc_msgSend_ushortret_noargs(id objc, SEL sel); + #define m1(name, type1) \ static inline id objc_msgSend_ ## name (id obj, SEL sel, type1 a) \ { \ @@ -51,6 +51,12 @@ important things: - make sure mouse events don't trigger if the control size is larger than the Area size and the mouse event happens outside the Area range on all platforms super ultra important things: +- formalize what happens if Modifiers by themselves are held + - OS X: find out if multiple DIFFERENT modifiers released at once produces multiple events + - in general, figure out what to do on multiple events, period +- OS X: handle Insert/Help key change in a sane and deterministic way + - will need old and new Mac keyboards... +- should pressing modifier+key in the keyboard test mark the key alone as pressed as well? I'm leaning toward no, in which case make sure this behavior exists on all platforms - formalize dragging - implement dragging on windows - may need to drop Held depending on weirdness I see in OS X |
