From fb1282c3e4583a10fcf61a8ace5aba2576cc2cd2 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Fri, 25 Dec 2015 19:21:13 -1000 Subject: [PATCH] initial TextInput context callback --- include/boo/IWindow.hpp | 21 +++++ lib/mac/WindowCocoa.mm | 200 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 220 insertions(+), 1 deletion(-) diff --git a/include/boo/IWindow.hpp b/include/boo/IWindow.hpp index 8640741..92a04b8 100644 --- a/include/boo/IWindow.hpp +++ b/include/boo/IWindow.hpp @@ -102,6 +102,24 @@ enum class EModifierKey Command = 1<<4 }; ENABLE_BITWISE_ENUM(EModifierKey) + +struct ITextInputCallback +{ + virtual bool hasMarkedText() const=0; + virtual std::pair markedRange() const=0; + virtual std::pair selectedRange() const=0; + virtual void setMarkedText(const std::string& str, + const std::pair& selectedRange, + const std::pair& replacementRange)=0; + virtual void unmarkText()=0; + + virtual std::string substringForRange(const std::pair& range, + std::pair& actualRange) const=0; + virtual void insertText(const std::string& str, const std::pair& range)=0; + virtual int characterIndexAtPoint(const SWindowCoord& point) const=0; + virtual SWindowRect rectForCharacterRange(const std::pair& range, + std::pair& actualRange) const=0; +}; class IWindowCallback { @@ -139,7 +157,10 @@ public: virtual void modKeyDown(EModifierKey mod, bool isRepeat) {(void)mod;(void)isRepeat;} virtual void modKeyUp(EModifierKey mod) {(void)mod;} + virtual void utf8FragmentDown(const std::string& str) {(void)str;} + virtual ITextInputCallback* getTextInputCallback() {return nullptr;} + virtual void focusLost() {} virtual void focusGained() {} virtual void windowMoved(const SWindowRect& rect) diff --git a/lib/mac/WindowCocoa.mm b/lib/mac/WindowCocoa.mm index 29b40b5..1809f47 100644 --- a/lib/mac/WindowCocoa.mm +++ b/lib/mac/WindowCocoa.mm @@ -123,12 +123,13 @@ class GraphicsContextCocoaGL; class GraphicsContextCocoaMetal; } -@interface BooCocoaResponder : NSResponder +@interface BooCocoaResponder : NSResponder { @public NSUInteger lastModifiers; boo::GraphicsContextCocoa* booContext; NSView* parentView; + NSTextInputContext* textContext; } - (id)initWithBooContext:(boo::GraphicsContextCocoa*)bctx View:(NSView*)view; @end @@ -426,9 +427,174 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a lastModifiers = 0; booContext = bctx; parentView = view; + textContext = [[NSTextInputContext alloc] initWithClient: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 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 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*)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 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 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) { 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, getMod([theEvent modifierFlags])); + [textContext handleEvent:theEvent]; } - (void)mouseUp:(NSEvent*)theEvent @@ -487,6 +654,7 @@ static inline boo::EMouseButton getButton(NSEvent* event) }; booContext->m_callback->mouseUp(coord, boo::EMouseButton::Primary, getMod([theEvent modifierFlags])); + [textContext handleEvent:theEvent]; } - (void)rightMouseDown:(NSEvent*)theEvent @@ -504,6 +672,7 @@ static inline boo::EMouseButton getButton(NSEvent* event) }; booContext->m_callback->mouseDown(coord, boo::EMouseButton::Secondary, getMod([theEvent modifierFlags])); + [textContext handleEvent:theEvent]; } - (void)rightMouseUp:(NSEvent*)theEvent @@ -521,6 +690,7 @@ static inline boo::EMouseButton getButton(NSEvent* event) }; booContext->m_callback->mouseUp(coord, boo::EMouseButton::Secondary, getMod([theEvent modifierFlags])); + [textContext handleEvent: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)} }; booContext->m_callback->mouseDown(coord, button, getMod([theEvent modifierFlags])); + [textContext handleEvent: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)} }; booContext->m_callback->mouseUp(coord, button, getMod([theEvent modifierFlags])); + [textContext handleEvent:theEvent]; } - (void)mouseMoved:(NSEvent*)theEvent @@ -578,6 +750,7 @@ static inline boo::EMouseButton getButton(NSEvent* event) }; booContext->m_callback->mouseMove(coord); } + [textContext handleEvent:theEvent]; } - (void)mouseDragged:(NSEvent*)theEvent @@ -614,6 +787,7 @@ static inline boo::EMouseButton getButton(NSEvent* event) (bool)[theEvent hasPreciseScrollingDeltas] }; booContext->m_callback->scroll(coord, scroll); + [textContext handleEvent:theEvent]; } - (void)touchesBeganWithEvent:(NSEvent*)event @@ -798,6 +972,7 @@ static boo::ESpecialKey translateKeycode(short code) booContext->m_callback->charKeyDown([chars characterAtIndex:0], getMod(theEvent.modifierFlags), theEvent.isARepeat); + [textContext handleEvent:theEvent]; } - (void)keyUp:(NSEvent*)theEvent @@ -812,6 +987,7 @@ static boo::ESpecialKey translateKeycode(short code) else if ([chars length]) booContext->m_callback->charKeyUp([chars characterAtIndex:0], getMod(theEvent.modifierFlags)); + [textContext handleEvent:theEvent]; } - (void)flagsChanged:(NSEvent*)theEvent @@ -845,6 +1021,7 @@ static boo::ESpecialKey translateKeycode(short code) lastModifiers = modFlags; } + [textContext handleEvent:theEvent]; } - (BOOL)acceptsTouchEvents @@ -857,6 +1034,12 @@ static boo::ESpecialKey translateKeycode(short code) return YES; } +- (void)dealloc +{ + [textContext release]; + [super dealloc]; +} + @end @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 clipboardPaste(EClipboardType type, size_t& sz) + { + + } + ETouchType getTouchType() const { return ETouchType::Trackpad;