mirror of https://github.com/AxioDL/boo.git
initial TextInput context callback
This commit is contained in:
parent
92c47a5e77
commit
fb1282c3e4
|
@ -103,6 +103,24 @@ enum class EModifierKey
|
||||||
};
|
};
|
||||||
ENABLE_BITWISE_ENUM(EModifierKey)
|
ENABLE_BITWISE_ENUM(EModifierKey)
|
||||||
|
|
||||||
|
struct ITextInputCallback
|
||||||
|
{
|
||||||
|
virtual bool hasMarkedText() const=0;
|
||||||
|
virtual std::pair<int,int> markedRange() const=0;
|
||||||
|
virtual std::pair<int,int> selectedRange() const=0;
|
||||||
|
virtual void setMarkedText(const std::string& str,
|
||||||
|
const std::pair<int,int>& selectedRange,
|
||||||
|
const std::pair<int,int>& replacementRange)=0;
|
||||||
|
virtual void unmarkText()=0;
|
||||||
|
|
||||||
|
virtual std::string substringForRange(const std::pair<int,int>& range,
|
||||||
|
std::pair<int,int>& actualRange) const=0;
|
||||||
|
virtual void insertText(const std::string& str, const std::pair<int,int>& range)=0;
|
||||||
|
virtual int characterIndexAtPoint(const SWindowCoord& point) const=0;
|
||||||
|
virtual SWindowRect rectForCharacterRange(const std::pair<int,int>& range,
|
||||||
|
std::pair<int,int>& actualRange) const=0;
|
||||||
|
};
|
||||||
|
|
||||||
class IWindowCallback
|
class IWindowCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -139,7 +157,10 @@ public:
|
||||||
virtual void modKeyDown(EModifierKey mod, bool isRepeat)
|
virtual void modKeyDown(EModifierKey mod, bool isRepeat)
|
||||||
{(void)mod;(void)isRepeat;}
|
{(void)mod;(void)isRepeat;}
|
||||||
virtual void modKeyUp(EModifierKey mod) {(void)mod;}
|
virtual void modKeyUp(EModifierKey mod) {(void)mod;}
|
||||||
|
|
||||||
virtual void utf8FragmentDown(const std::string& str) {(void)str;}
|
virtual void utf8FragmentDown(const std::string& str) {(void)str;}
|
||||||
|
virtual ITextInputCallback* getTextInputCallback() {return nullptr;}
|
||||||
|
|
||||||
virtual void focusLost() {}
|
virtual void focusLost() {}
|
||||||
virtual void focusGained() {}
|
virtual void focusGained() {}
|
||||||
virtual void windowMoved(const SWindowRect& rect)
|
virtual void windowMoved(const SWindowRect& rect)
|
||||||
|
|
|
@ -123,12 +123,13 @@ class GraphicsContextCocoaGL;
|
||||||
class GraphicsContextCocoaMetal;
|
class GraphicsContextCocoaMetal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface BooCocoaResponder : NSResponder
|
@interface BooCocoaResponder : NSResponder <NSTextInputClient>
|
||||||
{
|
{
|
||||||
@public
|
@public
|
||||||
NSUInteger lastModifiers;
|
NSUInteger lastModifiers;
|
||||||
boo::GraphicsContextCocoa* booContext;
|
boo::GraphicsContextCocoa* booContext;
|
||||||
NSView* parentView;
|
NSView* parentView;
|
||||||
|
NSTextInputContext* textContext;
|
||||||
}
|
}
|
||||||
- (id)initWithBooContext:(boo::GraphicsContextCocoa*)bctx View:(NSView*)view;
|
- (id)initWithBooContext:(boo::GraphicsContextCocoa*)bctx View:(NSView*)view;
|
||||||
@end
|
@end
|
||||||
|
@ -426,9 +427,174 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a
|
||||||
lastModifiers = 0;
|
lastModifiers = 0;
|
||||||
booContext = bctx;
|
booContext = bctx;
|
||||||
parentView = view;
|
parentView = view;
|
||||||
|
textContext = [[NSTextInputContext alloc] initWithClient:self];
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasMarkedText
|
||||||
|
{
|
||||||
|
if (booContext->m_callback)
|
||||||
|
{
|
||||||
|
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
|
||||||
|
if (textCb)
|
||||||
|
return textCb->hasMarkedText();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSRange)markedRange
|
||||||
|
{
|
||||||
|
if (booContext->m_callback)
|
||||||
|
{
|
||||||
|
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
|
||||||
|
if (textCb)
|
||||||
|
{
|
||||||
|
std::pair<int,int> rng = textCb->markedRange();
|
||||||
|
return NSMakeRange(rng.first < 0 ? NSNotFound : rng.first, rng.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NSMakeRange(NSNotFound, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSRange)selectedRange
|
||||||
|
{
|
||||||
|
if (booContext->m_callback)
|
||||||
|
{
|
||||||
|
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
|
||||||
|
if (textCb)
|
||||||
|
{
|
||||||
|
std::pair<int,int> rng = textCb->selectedRange();
|
||||||
|
return NSMakeRange(rng.first < 0 ? NSNotFound : rng.first, rng.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NSMakeRange(NSNotFound, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
|
||||||
|
{
|
||||||
|
if (booContext->m_callback)
|
||||||
|
{
|
||||||
|
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
|
||||||
|
if (textCb)
|
||||||
|
{
|
||||||
|
NSString* plainStr;
|
||||||
|
if ([aString isKindOfClass:[NSAttributedString class]])
|
||||||
|
plainStr = ((NSAttributedString*)aString).string;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plainStr = aString;
|
||||||
|
[plainStr retain];
|
||||||
|
}
|
||||||
|
textCb->setMarkedText([plainStr UTF8String],
|
||||||
|
std::make_pair(selectedRange.location, selectedRange.length),
|
||||||
|
std::make_pair(replacementRange.location, replacementRange.length));
|
||||||
|
[plainStr release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)unmarkText
|
||||||
|
{
|
||||||
|
if (booContext->m_callback)
|
||||||
|
{
|
||||||
|
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
|
||||||
|
if (textCb)
|
||||||
|
textCb->unmarkText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray<NSString*>*)validAttributesForMarkedText
|
||||||
|
{
|
||||||
|
return [NSArray array];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
|
||||||
|
{
|
||||||
|
if (booContext->m_callback)
|
||||||
|
{
|
||||||
|
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
|
||||||
|
if (textCb)
|
||||||
|
{
|
||||||
|
std::pair<int,int> actualRng;
|
||||||
|
std::string str = textCb->substringForRange(std::make_pair(aRange.location, aRange.length), actualRng);
|
||||||
|
if (str.empty())
|
||||||
|
return nil;
|
||||||
|
actualRange->location = actualRng.first;
|
||||||
|
actualRange->length = actualRng.second;
|
||||||
|
NSString* nsStr = [NSString stringWithUTF8String:str.c_str()];
|
||||||
|
NSAttributedString* ret = [[NSAttributedString alloc] initWithString:nsStr];
|
||||||
|
[nsStr release];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
|
||||||
|
{
|
||||||
|
if (booContext->m_callback)
|
||||||
|
{
|
||||||
|
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
|
||||||
|
if (textCb)
|
||||||
|
{
|
||||||
|
NSString* plainStr;
|
||||||
|
if ([aString isKindOfClass:[NSAttributedString class]])
|
||||||
|
plainStr = ((NSAttributedString*)aString).string;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plainStr = aString;
|
||||||
|
[plainStr retain];
|
||||||
|
}
|
||||||
|
textCb->insertText([plainStr UTF8String],
|
||||||
|
std::make_pair(replacementRange.location, replacementRange.length));
|
||||||
|
[plainStr release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
|
||||||
|
{
|
||||||
|
if (booContext->m_callback)
|
||||||
|
{
|
||||||
|
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
|
||||||
|
if (textCb)
|
||||||
|
{
|
||||||
|
NSPoint backingPoint = [parentView convertPointToBacking:aPoint];
|
||||||
|
boo::SWindowCoord coord = {{int(backingPoint.x), int(backingPoint.y)}, {int(aPoint.x), int(aPoint.y)}};
|
||||||
|
int idx = textCb->characterIndexAtPoint(coord);
|
||||||
|
if (idx < 0)
|
||||||
|
return NSNotFound;
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NSNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
|
||||||
|
{
|
||||||
|
if (booContext->m_callback)
|
||||||
|
{
|
||||||
|
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
|
||||||
|
if (textCb)
|
||||||
|
{
|
||||||
|
std::pair<int,int> actualRng;
|
||||||
|
boo::SWindowRect rect =
|
||||||
|
textCb->rectForCharacterRange(std::make_pair(aRange.location, aRange.length), actualRng);
|
||||||
|
actualRange->location = actualRng.first;
|
||||||
|
actualRange->length = actualRng.second;
|
||||||
|
return [[parentView window] convertRectToScreen:
|
||||||
|
[parentView convertRectFromBacking:NSMakeRect(rect.location[0], rect.location[1],
|
||||||
|
rect.size[0], rect.size[1])]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NSMakeRect(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)doCommandBySelector:(SEL)aSelector
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static inline boo::EModifierKey getMod(NSUInteger flags)
|
static inline boo::EModifierKey getMod(NSUInteger flags)
|
||||||
{
|
{
|
||||||
boo::EModifierKey ret = boo::EModifierKey::None;
|
boo::EModifierKey ret = boo::EModifierKey::None;
|
||||||
|
@ -470,6 +636,7 @@ static inline boo::EMouseButton getButton(NSEvent* event)
|
||||||
};
|
};
|
||||||
booContext->m_callback->mouseDown(coord, boo::EMouseButton::Primary,
|
booContext->m_callback->mouseDown(coord, boo::EMouseButton::Primary,
|
||||||
getMod([theEvent modifierFlags]));
|
getMod([theEvent modifierFlags]));
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseUp:(NSEvent*)theEvent
|
- (void)mouseUp:(NSEvent*)theEvent
|
||||||
|
@ -487,6 +654,7 @@ static inline boo::EMouseButton getButton(NSEvent* event)
|
||||||
};
|
};
|
||||||
booContext->m_callback->mouseUp(coord, boo::EMouseButton::Primary,
|
booContext->m_callback->mouseUp(coord, boo::EMouseButton::Primary,
|
||||||
getMod([theEvent modifierFlags]));
|
getMod([theEvent modifierFlags]));
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)rightMouseDown:(NSEvent*)theEvent
|
- (void)rightMouseDown:(NSEvent*)theEvent
|
||||||
|
@ -504,6 +672,7 @@ static inline boo::EMouseButton getButton(NSEvent* event)
|
||||||
};
|
};
|
||||||
booContext->m_callback->mouseDown(coord, boo::EMouseButton::Secondary,
|
booContext->m_callback->mouseDown(coord, boo::EMouseButton::Secondary,
|
||||||
getMod([theEvent modifierFlags]));
|
getMod([theEvent modifierFlags]));
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)rightMouseUp:(NSEvent*)theEvent
|
- (void)rightMouseUp:(NSEvent*)theEvent
|
||||||
|
@ -521,6 +690,7 @@ static inline boo::EMouseButton getButton(NSEvent* event)
|
||||||
};
|
};
|
||||||
booContext->m_callback->mouseUp(coord, boo::EMouseButton::Secondary,
|
booContext->m_callback->mouseUp(coord, boo::EMouseButton::Secondary,
|
||||||
getMod([theEvent modifierFlags]));
|
getMod([theEvent modifierFlags]));
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)otherMouseDown:(NSEvent*)theEvent
|
- (void)otherMouseDown:(NSEvent*)theEvent
|
||||||
|
@ -540,6 +710,7 @@ static inline boo::EMouseButton getButton(NSEvent* event)
|
||||||
{float(liw.x / frame.size.width), float(liw.y / frame.size.height)}
|
{float(liw.x / frame.size.width), float(liw.y / frame.size.height)}
|
||||||
};
|
};
|
||||||
booContext->m_callback->mouseDown(coord, button, getMod([theEvent modifierFlags]));
|
booContext->m_callback->mouseDown(coord, button, getMod([theEvent modifierFlags]));
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)otherMouseUp:(NSEvent*)theEvent
|
- (void)otherMouseUp:(NSEvent*)theEvent
|
||||||
|
@ -559,6 +730,7 @@ static inline boo::EMouseButton getButton(NSEvent* event)
|
||||||
{float(liw.x / frame.size.width), float(liw.y / frame.size.height)}
|
{float(liw.x / frame.size.width), float(liw.y / frame.size.height)}
|
||||||
};
|
};
|
||||||
booContext->m_callback->mouseUp(coord, button, getMod([theEvent modifierFlags]));
|
booContext->m_callback->mouseUp(coord, button, getMod([theEvent modifierFlags]));
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseMoved:(NSEvent*)theEvent
|
- (void)mouseMoved:(NSEvent*)theEvent
|
||||||
|
@ -578,6 +750,7 @@ static inline boo::EMouseButton getButton(NSEvent* event)
|
||||||
};
|
};
|
||||||
booContext->m_callback->mouseMove(coord);
|
booContext->m_callback->mouseMove(coord);
|
||||||
}
|
}
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDragged:(NSEvent*)theEvent
|
- (void)mouseDragged:(NSEvent*)theEvent
|
||||||
|
@ -614,6 +787,7 @@ static inline boo::EMouseButton getButton(NSEvent* event)
|
||||||
(bool)[theEvent hasPreciseScrollingDeltas]
|
(bool)[theEvent hasPreciseScrollingDeltas]
|
||||||
};
|
};
|
||||||
booContext->m_callback->scroll(coord, scroll);
|
booContext->m_callback->scroll(coord, scroll);
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)touchesBeganWithEvent:(NSEvent*)event
|
- (void)touchesBeganWithEvent:(NSEvent*)event
|
||||||
|
@ -798,6 +972,7 @@ static boo::ESpecialKey translateKeycode(short code)
|
||||||
booContext->m_callback->charKeyDown([chars characterAtIndex:0],
|
booContext->m_callback->charKeyDown([chars characterAtIndex:0],
|
||||||
getMod(theEvent.modifierFlags),
|
getMod(theEvent.modifierFlags),
|
||||||
theEvent.isARepeat);
|
theEvent.isARepeat);
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)keyUp:(NSEvent*)theEvent
|
- (void)keyUp:(NSEvent*)theEvent
|
||||||
|
@ -812,6 +987,7 @@ static boo::ESpecialKey translateKeycode(short code)
|
||||||
else if ([chars length])
|
else if ([chars length])
|
||||||
booContext->m_callback->charKeyUp([chars characterAtIndex:0],
|
booContext->m_callback->charKeyUp([chars characterAtIndex:0],
|
||||||
getMod(theEvent.modifierFlags));
|
getMod(theEvent.modifierFlags));
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)flagsChanged:(NSEvent*)theEvent
|
- (void)flagsChanged:(NSEvent*)theEvent
|
||||||
|
@ -845,6 +1021,7 @@ static boo::ESpecialKey translateKeycode(short code)
|
||||||
|
|
||||||
lastModifiers = modFlags;
|
lastModifiers = modFlags;
|
||||||
}
|
}
|
||||||
|
[textContext handleEvent:theEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)acceptsTouchEvents
|
- (BOOL)acceptsTouchEvents
|
||||||
|
@ -857,6 +1034,12 @@ static boo::ESpecialKey translateKeycode(short code)
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[textContext release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation GraphicsContextCocoaGLInternal
|
@implementation GraphicsContextCocoaGLInternal
|
||||||
|
@ -1152,6 +1335,21 @@ public:
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void claimKeyboardFocus(const int coord[2])
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<uint8_t[]> clipboardPaste(EClipboardType type, size_t& sz)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ETouchType getTouchType() const
|
ETouchType getTouchType() const
|
||||||
{
|
{
|
||||||
return ETouchType::Trackpad;
|
return ETouchType::Trackpad;
|
||||||
|
|
Loading…
Reference in New Issue