diff --git a/Source/InputMethodController.mm b/Source/InputMethodController.mm index ee830be2..3ed9987f 100644 --- a/Source/InputMethodController.mm +++ b/Source/InputMethodController.mm @@ -241,7 +241,6 @@ static double FindHighestScore(const vector& nodes, double epsilon) _languageModel->setExternalConverterEnabled(Preferences.chineseConversionStyle == 1); [(AppDelegate *)[NSApp delegate] checkForUpdate]; - } - (void)deactivateServer:(id)client @@ -669,7 +668,8 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; } // see if we have a unigram for this if (!_languageModel->hasUnigramsForKey(reading)) { [self beep]; - [self handleState:_state client:client]; + InputStateInputting *inputting = [self buildInputingState]; + [self handleState:inputting client:client]; return YES; } diff --git a/Source/InputState.swift b/Source/InputState.swift index 7b9f6b22..80e61e8c 100644 --- a/Source/InputState.swift +++ b/Source/InputState.swift @@ -1,4 +1,4 @@ -import Foundation +import Cocoa class InputState: NSObject { } @@ -27,6 +27,15 @@ class InputStateInputting: InputState { self.composingBuffer = composingBuffer self.cursorIndex = cursorIndex } + + @objc var attributedSting: NSAttributedString { + let attrs: [NSAttributedString.Key : Any] = [ + .underlineStyle: NSUnderlineStyle.single, + .markedClauseSegment: 0 + ] + let attributedSting = NSAttributedString(string: composingBuffer, attributes: attrs) + return attributedSting + } } class InputStateMarking: InputStateInputting { @@ -41,7 +50,25 @@ class InputStateMarking: InputStateInputting { self.markerIndex = markerIndex let begin = min(cursorIndex, markerIndex) let end = max(cursorIndex, markerIndex) - self.markedRange = NSMakeRange(Int(begin), Int( end - begin)) + self.markedRange = NSMakeRange(Int(begin), Int(end - begin)) + } + + @objc override var attributedSting: NSAttributedString { + let attributedSting = NSMutableAttributedString(string: composingBuffer) + attributedSting.setAttributes([ + NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single, + NSAttributedString.Key.markedClauseSegment: 0 + ], range: NSRange(location: 0, length: markedRange.location)) + attributedSting.setAttributes([ + NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single, + NSAttributedString.Key.markedClauseSegment: 1 + ], range: markedRange) + attributedSting.setAttributes([ + NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single, + NSAttributedString.Key.markedClauseSegment: 2 + ], range: NSRange(location: markedRange.location + markedRange.length, + length: composingBuffer.count - (markedRange.location + markedRange.length) )) + return attributedSting } } diff --git a/Source/KeyHandler.swift b/Source/KeyHandler.swift index b15818ed..c10c4d27 100644 --- a/Source/KeyHandler.swift +++ b/Source/KeyHandler.swift @@ -18,11 +18,11 @@ class KeyHandlerInput: NSObject { private (set) var event: NSEvent private (set) var useVerticalMode: Bool - var inputText: String? { + @objc var inputText: String? { event.characters } - var charCode: UInt16 { + @objc var charCode: UInt16 { guard let inputText = inputText, inputText.count > 0 else { return 0 } @@ -30,31 +30,31 @@ class KeyHandlerInput: NSObject { return first } - var keyCode: UInt16 { + @objc var keyCode: UInt16 { event.keyCode } - var flags: NSEvent.ModifierFlags { + @objc var flags: NSEvent.ModifierFlags { event.modifierFlags } - var cursorForwardKey: KeyCode { + @objc var cursorForwardKey: KeyCode { useVerticalMode ? .down : .right } - var cursorBackwardKey: KeyCode { + @objc var cursorBackwardKey: KeyCode { useVerticalMode ? .up : .left } - var extraChooseCandidateKey: KeyCode { + @objc var extraChooseCandidateKey: KeyCode { useVerticalMode ? .left : .down } - var absorbedArrowKey: KeyCode { + @objc var absorbedArrowKey: KeyCode { useVerticalMode ? .right : .up } - var verticalModeOnlyChooseCandidateKey: KeyCode { + @objc var verticalModeOnlyChooseCandidateKey: KeyCode { useVerticalMode ? absorbedArrowKey : .none } @@ -63,138 +63,3 @@ class KeyHandlerInput: NSObject { self.useVerticalMode = isVerticalMode } } - -typealias KeyHandlerStateCallback = (InputState) -> () -typealias KeyHandlerErrorCallback = () -> () - -@objc protocol KeyHandlerDelegate: AnyObject { - func keyHandlerRequestCurrentInputtingState(_ handler: KeyHandler) -> InputStateInputting - func keyHandler(_ handler: KeyHandler, requestWriteUserPhrase state: InputStateMarking ) -> Bool - - func keyHandler(_ handler: KeyHandler, isCharCodeValidBmpfReading charCode:UInt16 ) -> Bool - func keyHandler(_ handler: KeyHandler, insertCharCodeToBmpfReading charCode:UInt16 ) -> Void - -} - - -class KeyHandler: NSObject { - var delegate: KeyHandlerDelegate? - - @objc func handle(_ input: KeyHandlerInput, - currentState: InputState, - stateCallback: @escaping KeyHandlerStateCallback, - errorCallback: @escaping KeyHandlerErrorCallback - ) -> Bool { - guard let delegate = delegate else { - return false - } - - // if the inputText is empty, it's a function key combination, we ignore it - guard let inputText = input.inputText else { - return false - } - if inputText.isEmpty { - return false - } - - let flags = input.flags - let charCode = input.charCode - let keyCode = input.keyCode - let emacsKey = EmacsKeyHelper.detect(charCode: charCode, flags: flags) - - // if the composing buffer is empty and there's no reading, and there is some function key combination, we ignore it - let isFunctionKey = flags.contains(.command) || flags.contains(.control) || flags.contains(.option) || flags.contains(.numericPad) - if currentState is InputStateInputting == false && isFunctionKey { - return false - } - - // Caps Lock processing : if Caps Lock is on, temporarily disable bopomofo. - if charCode == 8 || - charCode == 13 || - keyCode == input.absorbedArrowKey.rawValue || - keyCode == input.cursorForwardKey.rawValue || - keyCode == input.cursorBackwardKey.rawValue { - // do nothing if backspace is pressed -- we ignore the key - } else if flags.contains(.capsLock) { - // process all possible combination, we hope. - stateCallback(InputStateEmpty()) - - // first commit everything in the buffer. - if flags.contains(.shift) { - return false - } - - // if ASCII but not printable, don't use insertText:replacementRange: as many apps don't handle non-ASCII char insertions. - if charCode < 0x80 && isprint(Int32(charCode)) == 0 { - return false - } - stateCallback(InputStateCommitting(poppedText: inputText.lowercased())) - stateCallback(InputStateEmpty()) - return true - } - - if flags.contains(.numericPad) { - if keyCode != KeyCode.left.rawValue && - keyCode != KeyCode.right.rawValue && - keyCode != KeyCode.down.rawValue && - keyCode != KeyCode.up.rawValue && - charCode != 32 && - isprint(Int32(charCode)) != 0 { - stateCallback(InputStateEmpty()) - stateCallback(InputStateCommitting(poppedText: inputText.lowercased())) - stateCallback(InputStateEmpty()) - return true - } - } - - // candidates? - - if let state = currentState as? InputStateMarking { - // ESC - if charCode == 27 { - let inputting = InputStateInputting(composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex) - stateCallback(inputting) - return true - } - // Enter - if charCode == 13 { - if delegate.keyHandler(self, requestWriteUserPhrase: state) == false { - errorCallback() - return true - } - let inputting = InputStateInputting(composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex) - stateCallback(inputting) - return true - } - // Shift + left - if (keyCode == input.cursorBackwardKey.rawValue || emacsKey == .backward) && flags.contains(.shift) { - var index = state.markerIndex - if index > 0 { - index -= 1 - let marking = InputStateMarking(composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex, markerIndex: state.markerIndex) - stateCallback(marking) - } else { - errorCallback() - } - return true - } - if (keyCode == input.cursorForwardKey.rawValue || emacsKey == .forward) && flags.contains(.shift) { - var index = state.markerIndex - if index < state.composingBuffer.count { - index += 1 - let marking = InputStateMarking(composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex, markerIndex: state.markerIndex) - stateCallback(marking) - } else { - errorCallback() - } - return true - } - } - - - - - return false - } - -}