Added key events to Mac OS X Areas. Now Area is feature-complete (but buggy) on all platforms :D Also more TODOs.

This commit is contained in:
Pietro Gagliardi 2014-03-30 19:53:44 -04:00
parent 41a7e3dab8
commit 6a7cb73dda
5 changed files with 214 additions and 0 deletions

View File

@ -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 {

View File

@ -66,6 +66,15 @@ id objc_msgSend_id_int(id obj, SEL sel, id a, intptr_t b)
return objc_msgSend(obj, sel, a, (NSInteger) 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.

129
events_darwin.go Normal file
View File

@ -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
}

View File

@ -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) \
{ \

View File

@ -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