Skip to content

Commit

Permalink
XIM working, users can now type composed letters
Browse files Browse the repository at this point in the history
  • Loading branch information
LubosD committed Mar 2, 2021
1 parent 879571d commit 479dd38
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 22 deletions.
5 changes: 5 additions & 0 deletions AppKit/X11.backend/X11Display.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#import <AppKit/NSDisplay.h>
#import <X11/Xlib.h>
#import <X11/Xresource.h>
#import <X11/Xlocale.h>

#ifdef DARLING
#import <CoreFoundation/CFRunLoop.h>
Expand Down Expand Up @@ -36,6 +38,9 @@
X11Cursor *_blankCursor, *_defaultCursor;
BOOL _cursorGrabbed;
KeySym _lastKeySym;

@public
XIM _xim;
}

- (Display *) display;
Expand Down
56 changes: 35 additions & 21 deletions AppKit/X11.backend/X11Display.m
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ this software and associated documentation files (the "Software"), to deal in
#import <X11/Xutil.h>
#import <X11/extensions/XKBrules.h>
#import <X11/extensions/Xrandr.h>
#import <X11/keysym.h>
#import <fcntl.h>
#import <fontconfig/fontconfig.h>
#import <stddef.h>
Expand Down Expand Up @@ -119,6 +120,16 @@ static void socketCallback(CFSocketRef s, CFSocketCallBackType type,
_windowsByID = [NSMutableDictionary new];
[self _enableDetectableAutoRepeat];

XSetLocaleModifiers("");
_xim = XOpenIM(_display, NULL, NULL, NULL);

if (!_xim) {
NSLog(@"Failed to open XIM, falling back to im=none\n");

XSetLocaleModifiers("@im=none");
_xim = XOpenIM(_display, NULL, NULL, NULL);
}

lastFocusedWindow = nil;
lastClickTimeStamp = 0.0;
clickCount = 0;
Expand All @@ -130,6 +141,8 @@ - (void) dealloc {
[_blankCursor release];
[_defaultCursor release];

XCloseIM(_xim);

if (_display)
XCloseDisplay(_display);
#ifdef DARLING
Expand Down Expand Up @@ -902,39 +915,38 @@ - (NSArray *) orderedWindowNumbers {
- (void) postXEvent: (XEvent *) ev {
id event = nil;
NSEventType type;
id window = [self windowForID: ev->xany.window];
X11Window* window = (X11Window*) [self windowForID: ev->xany.window];

id delegate = [window delegate];

switch (ev->type) {
case KeyPress:
case KeyRelease:;
NSEventModifierFlags modifierFlags =
[self modifierFlagsForState: ev->xkey.state];
char buf[4] = {0};

NSEventModifierFlags modifierFlags = [self modifierFlagsForState: ev->xkey.state];
char buf[20] = {0};
KeySym keySym;
int strLen;

if (XFilterEvent(ev, None)) // XIM processing
break;

if (ev->type == KeyPress) {
strLen = Xutf8LookupString(window->_xic, (XKeyPressedEvent *) ev, buf, sizeof(buf) - 1, &keySym, NULL);
buf[strLen] = 0;
} else {
// Xutf8LookupString() may not be used with KeyRelease
strLen = XLookupString((XKeyEvent*) ev, buf, sizeof(buf) - 1, &keySym, NULL);
buf[strLen] = 0;
}

XLookupString((XKeyEvent *) ev, buf, 4, &keySym, NULL);
id str = [[NSString alloc] initWithCString: buf
encoding: NSISOLatin1StringEncoding];
encoding: NSUTF8StringEncoding];
NSPoint pos =
[window transformPoint: NSMakePoint(ev->xkey.x, ev->xkey.y)];

id strIg;
if ([str length] != 0 && [str characterAtIndex: 0] != 0x7f /* backspace */) {
strIg = [str lowercaseString];
if (ev->xkey.state) {
ev->xkey.state = 0;
XLookupString((XKeyEvent *) ev, buf, 4, NULL, NULL);
strIg = [[NSString alloc]
initWithCString: buf
encoding: NSISOLatin1StringEncoding];
}
} else {
// It was a function key of some sort
uint16_t ucsCode = (uint16_t) X11KeySymToUCS(keySym); // All defined codes in the table fit into 16 bits
strIg = [NSString stringWithCharacters: &ucsCode length: 1];
}
uint16_t ucsCode = (uint16_t) X11KeySymToUCS(keySym); // All defined codes in the table fit into 16 bits
NSString* strIg = [NSString stringWithCharacters: &ucsCode length: 1];

// If there's an app that uses constants from HIToolbox/Events.h (e.g.
// kVK_ANSI_A), this gives it a chance to work.
Expand Down Expand Up @@ -1135,6 +1147,7 @@ - (void) postXEvent: (XEvent *) ev {
}
[delegate platformWindowActivated: window displayIfNeeded: YES];
lastFocusedWindow = delegate;
XSetICFocus(window->_xic);
break;

case FocusOut:
Expand All @@ -1144,6 +1157,7 @@ - (void) postXEvent: (XEvent *) ev {
lastFocusedWindow = nil;
if (_cursorGrabbed)
[self grabMouse: NO];
XUnsetICFocus(window->_xic);
break;

case KeymapNotify:
Expand Down
5 changes: 5 additions & 0 deletions AppKit/X11.backend/X11Window.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#import <Onyx2D/O2Geometry.h>
#import <OpenGL/CGLInternal.h>
#import <X11/Xlib.h>
#import <X11/Xresource.h>
#import <X11/Xlocale.h>

@class X11Display, CAWindowOpenGLContext, NSWindow, O2Context;

Expand All @@ -45,6 +47,9 @@
BOOL _mapped;
CGPoint _lastMotionPos;
BOOL _isModal;

@public
XIC _xic;
}

+ (void) removeDecorationForWindow: (Window) w onDisplay: (Display *) dpy;
Expand Down
13 changes: 12 additions & 1 deletion AppKit/X11.backend/X11Window.m
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ - (instancetype) initWithDelegate: (NSWindow *) delegate {
_styleMask = [delegate styleMask];
_backingType = (CGSBackingStoreType)[delegate backingType];
_deviceDictionary = [NSMutableDictionary new];
_display = [(X11Display *) [NSDisplay currentDisplay] display];

X11Display* x11disp = (X11Display *) [NSDisplay currentDisplay];
_display = [x11disp display];

_frame = [self transformFrame: [delegate frame]];
BOOL isPanel = [delegate isKindOfClass: [NSPanel class]];
if (isPanel && _styleMask & NSDocModalWindowMask)
Expand Down Expand Up @@ -245,6 +248,12 @@ - (instancetype) initWithDelegate: (NSWindow *) delegate {
XSetTransientForHint(_display, _window, [mainWindow windowHandle]);
}

_xic = XCreateIC(x11disp->_xim,
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, _window,
XNFocusWindow, _window,
NULL);

_cglWindow = CGLGetWindow((void *) _window);

[(X11Display *) [NSDisplay currentDisplay] setWindow: self forID: _window];
Expand Down Expand Up @@ -403,6 +412,8 @@ - (void) invalidate {
}

if (_window) {
XDestroyIC(_xic);

[(X11Display *) [NSDisplay currentDisplay] setWindow: nil
forID: _window];
XDestroyWindow(_display, _window);
Expand Down

0 comments on commit 479dd38

Please sign in to comment.