forked from joejulian/gio
app: [macOS] remove support for key bindings
The fix for #616 went to far by attempting to support macOS key bindings through doCommandBySelector. Issue #625 is a consequence, but more fundamentally, key bindings does not work with support for key.Release events. Remove key binding translation and fix #626, and add a check whether an IME swallowed a key event, keeping #616 fixed. While here, replace the KEY_ constants with ASCII codes. Fixes: https://todo.sr.ht/~eliasnaur/gio/625 References: https://todo.sr.ht/~eliasnaur/gio/616 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+49
-49
@@ -39,12 +39,6 @@ import (
|
||||
#define MOUSE_DOWN 3
|
||||
#define MOUSE_SCROLL 4
|
||||
|
||||
#define KEY_DELETE_BACKWARD 0x7f
|
||||
#define KEY_RETURN 0xd
|
||||
#define KEY_ENTER 0x3
|
||||
#define KEY_ESCAPE 0x1b
|
||||
#define KEY_TAB 0x09
|
||||
|
||||
__attribute__ ((visibility ("hidden"))) void gio_main(void);
|
||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createView(int presentWithTrans);
|
||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef viewRef, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight);
|
||||
@@ -318,6 +312,14 @@ static void invalidateCharacterCoordinates(CFTypeRef viewRef) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void interpretKeyEvents(CFTypeRef viewRef, CFTypeRef eventRef) {
|
||||
@autoreleasepool {
|
||||
NSView *view = (__bridge NSView *)viewRef;
|
||||
NSEvent *event = (__bridge NSEvent *)eventRef;
|
||||
[view interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||
}
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
@@ -351,7 +353,10 @@ type window struct {
|
||||
scale float32
|
||||
config Config
|
||||
|
||||
cmdKeysDown map[key.Name]struct{}
|
||||
keysDown map[key.Name]struct{}
|
||||
// doCommandBySelectorCalled tracks whether a call to
|
||||
// interpretKeys resulted in a callback.
|
||||
doCommandBySelectorCalled bool
|
||||
}
|
||||
|
||||
// launched is closed when applicationDidFinishLaunching is called.
|
||||
@@ -551,25 +556,36 @@ func (w *window) runOnMain(f func()) {
|
||||
}
|
||||
|
||||
//export gio_onKeys
|
||||
func gio_onKeys(h C.uintptr_t, cstr C.CFTypeRef, ti C.double, mods C.NSUInteger, keyDown C.bool) {
|
||||
func gio_onKeys(h C.uintptr_t, event C.CFTypeRef, cstr C.CFTypeRef, ti C.double, mods C.NSUInteger, keyDown C.bool) {
|
||||
w := windowFor(h)
|
||||
str := nsstringToString(cstr)
|
||||
kmods := convertMods(mods)
|
||||
ks := key.Release
|
||||
if keyDown {
|
||||
ks = key.Press
|
||||
w.doCommandBySelectorCalled = false
|
||||
C.interpretKeyEvents(w.view, event)
|
||||
}
|
||||
w := windowFor(h)
|
||||
for _, k := range str {
|
||||
n, ok := convertKey(k)
|
||||
if !ok && ks == key.Release {
|
||||
// Key release events are not reported by onCommandBySelector.
|
||||
n, ok = convertCommandKey(k)
|
||||
if ok {
|
||||
_, ok = w.cmdKeysDown[n]
|
||||
delete(w.cmdKeysDown, n)
|
||||
if n, ok := convertKey(k); ok {
|
||||
if keyDown {
|
||||
if !w.doCommandBySelectorCalled {
|
||||
if _, isCmd := convertCommandKey(k); isCmd {
|
||||
// doCommandBySelector was not called,
|
||||
// so this event was swallowed by an IME.
|
||||
return
|
||||
}
|
||||
}
|
||||
if w.keysDown == nil {
|
||||
w.keysDown = make(map[key.Name]struct{})
|
||||
}
|
||||
w.keysDown[n] = struct{}{}
|
||||
} else {
|
||||
if _, pressed := w.keysDown[n]; !pressed {
|
||||
continue
|
||||
}
|
||||
delete(w.keysDown, n)
|
||||
}
|
||||
}
|
||||
if ok {
|
||||
w.ProcessEvent(key.Event{
|
||||
Name: n,
|
||||
Modifiers: kmods,
|
||||
@@ -580,26 +596,9 @@ func gio_onKeys(h C.uintptr_t, cstr C.CFTypeRef, ti C.double, mods C.NSUInteger,
|
||||
}
|
||||
|
||||
//export gio_onCommandBySelector
|
||||
func gio_onCommandBySelector(h C.uintptr_t, k C.int, ti C.double, mods C.NSUInteger) {
|
||||
func gio_onCommandBySelector(h C.uintptr_t) {
|
||||
w := windowFor(h)
|
||||
w.commandKey(rune(k), ti, mods)
|
||||
}
|
||||
|
||||
func (w *window) commandKey(k rune, ti C.double, mods C.NSUInteger) bool {
|
||||
n, ok := convertCommandKey(k)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if w.cmdKeysDown == nil {
|
||||
w.cmdKeysDown = make(map[key.Name]struct{})
|
||||
}
|
||||
w.cmdKeysDown[n] = struct{}{}
|
||||
w.ProcessEvent(key.Event{
|
||||
Modifiers: convertMods(mods),
|
||||
Name: n,
|
||||
State: key.Press,
|
||||
})
|
||||
return true
|
||||
w.doCommandBySelectorCalled = true
|
||||
}
|
||||
|
||||
//export gio_onFlagsChanged
|
||||
@@ -816,18 +815,16 @@ func gio_substringForProposedRange(h C.uintptr_t, crng C.NSRange, actual C.NSRan
|
||||
}
|
||||
|
||||
//export gio_insertText
|
||||
func gio_insertText(h C.uintptr_t, cstr C.CFTypeRef, crng C.NSRange, ti C.double, mods C.NSUInteger) {
|
||||
func gio_insertText(h C.uintptr_t, cstr C.CFTypeRef, crng C.NSRange) {
|
||||
w := windowFor(h)
|
||||
str := nsstringToString(cstr)
|
||||
// macOS IME in some cases calls insertText for command keys such as backspace
|
||||
// instead of doCommandBySelector.
|
||||
hadCommands := false
|
||||
for _, r := range str {
|
||||
hadCommands = w.commandKey(r, ti, mods) || hadCommands
|
||||
}
|
||||
if hadCommands {
|
||||
w.w.SetComposingRegion(key.Range{Start: -1, End: -1})
|
||||
return
|
||||
if _, ok := convertCommandKey(r); ok {
|
||||
w.w.SetComposingRegion(key.Range{Start: -1, End: -1})
|
||||
return
|
||||
}
|
||||
}
|
||||
state := w.w.EditorState()
|
||||
rng := state.compose
|
||||
@@ -1037,7 +1034,7 @@ func osMain() {
|
||||
func convertCommandKey(k rune) (key.Name, bool) {
|
||||
var n key.Name
|
||||
switch k {
|
||||
case C.KEY_ESCAPE:
|
||||
case '\x1b': // ASCII escape.
|
||||
n = key.NameEscape
|
||||
case C.NSLeftArrowFunctionKey:
|
||||
n = key.NameLeftArrow
|
||||
@@ -1047,19 +1044,19 @@ func convertCommandKey(k rune) (key.Name, bool) {
|
||||
n = key.NameUpArrow
|
||||
case C.NSDownArrowFunctionKey:
|
||||
n = key.NameDownArrow
|
||||
case C.KEY_RETURN:
|
||||
case '\r':
|
||||
n = key.NameReturn
|
||||
case C.KEY_ENTER:
|
||||
case '\x03':
|
||||
n = key.NameEnter
|
||||
case C.NSHomeFunctionKey:
|
||||
n = key.NameHome
|
||||
case C.NSEndFunctionKey:
|
||||
n = key.NameEnd
|
||||
case C.KEY_DELETE_BACKWARD, 0x08:
|
||||
case '\x7f', '\b':
|
||||
n = key.NameDeleteBackward
|
||||
case C.NSDeleteFunctionKey:
|
||||
n = key.NameDeleteForward
|
||||
case C.KEY_TAB, 0x19:
|
||||
case '\t', 0x19:
|
||||
n = key.NameTab
|
||||
case C.NSPageUpFunctionKey:
|
||||
n = key.NamePageUp
|
||||
@@ -1072,6 +1069,9 @@ func convertCommandKey(k rune) (key.Name, bool) {
|
||||
}
|
||||
|
||||
func convertKey(k rune) (key.Name, bool) {
|
||||
if n, ok := convertCommandKey(k); ok {
|
||||
return n, true
|
||||
}
|
||||
var n key.Name
|
||||
switch k {
|
||||
case C.NSF1FunctionKey:
|
||||
|
||||
+4
-53
@@ -15,7 +15,6 @@ __attribute__ ((visibility ("hidden"))) CALayer *gio_layerFactory(BOOL presentWi
|
||||
@end
|
||||
|
||||
@interface GioView : NSView <CALayerDelegate,NSTextInputClient>
|
||||
@property NSEvent *lastKeyDown;
|
||||
@property uintptr_t handle;
|
||||
@property BOOL presentWithTrans;
|
||||
@end
|
||||
@@ -133,12 +132,8 @@ static void handleMouse(GioView *view, NSEvent *event, int typ, CGFloat dx, CGFl
|
||||
handleMouse(self, event, MOUSE_SCROLL, dx, dy);
|
||||
}
|
||||
- (void)keyDown:(NSEvent *)event {
|
||||
// Stash the event for use by doCommandBySelector.
|
||||
self.lastKeyDown = event;
|
||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||
self.lastKeyDown = nil;
|
||||
NSString *keys = [event charactersIgnoringModifiers];
|
||||
gio_onKeys(self.handle, (__bridge CFTypeRef)keys, [event timestamp], [event modifierFlags], true);
|
||||
gio_onKeys(self.handle, (__bridge CFTypeRef)event, (__bridge CFTypeRef)keys, [event timestamp], [event modifierFlags], true);
|
||||
}
|
||||
- (void)flagsChanged:(NSEvent *)event {
|
||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||
@@ -146,54 +141,14 @@ static void handleMouse(GioView *view, NSEvent *event, int typ, CGFloat dx, CGFl
|
||||
}
|
||||
- (void)keyUp:(NSEvent *)event {
|
||||
NSString *keys = [event charactersIgnoringModifiers];
|
||||
gio_onKeys(self.handle, (__bridge CFTypeRef)keys, [event timestamp], [event modifierFlags], false);
|
||||
gio_onKeys(self.handle, (__bridge CFTypeRef)event, (__bridge CFTypeRef)keys, [event timestamp], [event modifierFlags], false);
|
||||
}
|
||||
- (void)insertText:(id)string {
|
||||
gio_onText(self.handle, (__bridge CFTypeRef)string);
|
||||
}
|
||||
- (void)doCommandBySelector:(SEL)action {
|
||||
NSEvent *event = self.lastKeyDown;
|
||||
if (event == nil) {
|
||||
return;
|
||||
}
|
||||
int key = 0;
|
||||
if (action == @selector(deleteBackward:)) {
|
||||
key = KEY_DELETE_BACKWARD;
|
||||
} else if (action == @selector(deleteForward:)) {
|
||||
key = NSDeleteFunctionKey;
|
||||
} else if (action == @selector(insertNewline:)) {
|
||||
NSString *keys = [event charactersIgnoringModifiers];
|
||||
if ([keys isEqualToString:@"\r"]) {
|
||||
key = KEY_RETURN;
|
||||
} else {
|
||||
key = KEY_ENTER;
|
||||
}
|
||||
} else if (action == @selector(moveUp:)) {
|
||||
key = NSUpArrowFunctionKey;
|
||||
} else if (action == @selector(moveDown:)) {
|
||||
key = NSDownArrowFunctionKey;
|
||||
} else if (action == @selector(moveLeft:)) {
|
||||
key = NSLeftArrowFunctionKey;
|
||||
} else if (action == @selector(moveRight:)) {
|
||||
key = NSRightArrowFunctionKey;
|
||||
} else if (action == @selector(cancelOperation:)) {
|
||||
key = KEY_ESCAPE;
|
||||
} else if (action == @selector(insertTab:)) {
|
||||
key = KEY_TAB;
|
||||
} else if (action == @selector(scrollToBeginningOfDocument:)) {
|
||||
key = NSHomeFunctionKey;
|
||||
} else if (action == @selector(scrollToEndOfDocument:)) {
|
||||
key = NSEndFunctionKey;
|
||||
} else if (action == @selector(scrollPageUp:)) {
|
||||
key = NSPageUpFunctionKey;
|
||||
} else if (action == @selector(scrollPageDown:)) {
|
||||
key = NSPageDownFunctionKey;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
gio_onCommandBySelector(self.handle, key, [event timestamp], [event modifierFlags]);
|
||||
gio_onCommandBySelector(self.handle);
|
||||
}
|
||||
|
||||
- (BOOL)hasMarkedText {
|
||||
int res = gio_hasMarkedText(self.handle);
|
||||
return res ? YES : NO;
|
||||
@@ -229,10 +184,6 @@ static void handleMouse(GioView *view, NSEvent *event, int typ, CGFloat dx, CGFl
|
||||
}
|
||||
- (void)insertText:(id)string
|
||||
replacementRange:(NSRange)replaceRange {
|
||||
NSEvent *event = self.lastKeyDown;
|
||||
if (event == nil) {
|
||||
return;
|
||||
}
|
||||
NSString *str;
|
||||
// string is either an NSAttributedString or an NSString.
|
||||
if ([string isKindOfClass:[NSAttributedString class]]) {
|
||||
@@ -240,7 +191,7 @@ static void handleMouse(GioView *view, NSEvent *event, int typ, CGFloat dx, CGFl
|
||||
} else {
|
||||
str = string;
|
||||
}
|
||||
gio_insertText(self.handle, (__bridge CFTypeRef)str, replaceRange, [event timestamp], [event modifierFlags]);
|
||||
gio_insertText(self.handle, (__bridge CFTypeRef)str, replaceRange);
|
||||
}
|
||||
- (NSUInteger)characterIndexForPoint:(NSPoint)p {
|
||||
return gio_characterIndexForPoint(self.handle, p);
|
||||
|
||||
Reference in New Issue
Block a user