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:
parent
41a7e3dab8
commit
6a7cb73dda
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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) \
|
||||
{ \
|
||||
|
|
6
todo.md
6
todo.md
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue