Merge pull request #268 from zonble/master
Various bug fixes for the inputting and marking states
This commit is contained in:
commit
063164d0ab
|
@ -11,8 +11,6 @@
|
||||||
6A0D4F0915FC0DA600ABF4B3 /* Bopomofo@2x.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4EF015FC0DA600ABF4B3 /* Bopomofo@2x.tiff */; };
|
6A0D4F0915FC0DA600ABF4B3 /* Bopomofo@2x.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4EF015FC0DA600ABF4B3 /* Bopomofo@2x.tiff */; };
|
||||||
6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F2015FC0EB100ABF4B3 /* Mandarin.cpp */; };
|
6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F2015FC0EB100ABF4B3 /* Mandarin.cpp */; };
|
||||||
6A0D4F5315FC0EE100ABF4B3 /* preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4F4E15FC0EE100ABF4B3 /* preferences.xib */; };
|
6A0D4F5315FC0EE100ABF4B3 /* preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4F4E15FC0EE100ABF4B3 /* preferences.xib */; };
|
||||||
6A0D4F5715FC0EF900ABF4B3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4F4815FC0EE100ABF4B3 /* InfoPlist.strings */; };
|
|
||||||
6A0D4F5815FC0EF900ABF4B3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4F4A15FC0EE100ABF4B3 /* Localizable.strings */; };
|
|
||||||
6A187E2616004C5900466B2E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A187E2816004C5900466B2E /* MainMenu.xib */; };
|
6A187E2616004C5900466B2E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A187E2816004C5900466B2E /* MainMenu.xib */; };
|
||||||
6A225A1F23679F2600F685C6 /* NotarizedArchives in Resources */ = {isa = PBXBuildFile; fileRef = 6A225A1E23679F2600F685C6 /* NotarizedArchives */; };
|
6A225A1F23679F2600F685C6 /* NotarizedArchives in Resources */ = {isa = PBXBuildFile; fileRef = 6A225A1E23679F2600F685C6 /* NotarizedArchives */; };
|
||||||
6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */; };
|
6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */; };
|
||||||
|
@ -48,19 +46,22 @@
|
||||||
D44FB74A2791B829003C80A6 /* VXHanConvert in Frameworks */ = {isa = PBXBuildFile; productRef = D44FB7492791B829003C80A6 /* VXHanConvert */; };
|
D44FB74A2791B829003C80A6 /* VXHanConvert in Frameworks */ = {isa = PBXBuildFile; productRef = D44FB7492791B829003C80A6 /* VXHanConvert */; };
|
||||||
D44FB74D2792189A003C80A6 /* PhraseReplacementMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44FB74B2792189A003C80A6 /* PhraseReplacementMap.cpp */; };
|
D44FB74D2792189A003C80A6 /* PhraseReplacementMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44FB74B2792189A003C80A6 /* PhraseReplacementMap.cpp */; };
|
||||||
D456576E279E4F7B00DF6BC9 /* KeyHandlerInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = D456576D279E4F7B00DF6BC9 /* KeyHandlerInput.swift */; };
|
D456576E279E4F7B00DF6BC9 /* KeyHandlerInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = D456576D279E4F7B00DF6BC9 /* KeyHandlerInput.swift */; };
|
||||||
|
D45EB5C127A9894C00E28B17 /* StringUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45EB5BF27A9890C00E28B17 /* StringUtils.swift */; };
|
||||||
D461B792279DAC010070E734 /* InputState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D461B791279DAC010070E734 /* InputState.swift */; };
|
D461B792279DAC010070E734 /* InputState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D461B791279DAC010070E734 /* InputState.swift */; };
|
||||||
D47B92C027972AD100458394 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47B92BF27972AC800458394 /* main.swift */; };
|
D47B92C027972AD100458394 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47B92BF27972AC800458394 /* main.swift */; };
|
||||||
D47D73A427A5D43900255A50 /* KeyHandlerBopomofoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47D73A327A5D43900255A50 /* KeyHandlerBopomofoTests.swift */; };
|
D47D73A427A5D43900255A50 /* KeyHandlerBopomofoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47D73A327A5D43900255A50 /* KeyHandlerBopomofoTests.swift */; };
|
||||||
D47D73C327A7200500255A50 /* FSEventStreamHelper in Frameworks */ = {isa = PBXBuildFile; productRef = D47D73C227A7200500255A50 /* FSEventStreamHelper */; };
|
|
||||||
D47D73A827A6C84F00255A50 /* associated-phrases.cin in Resources */ = {isa = PBXBuildFile; fileRef = D47D73A727A6C84F00255A50 /* associated-phrases.cin */; };
|
D47D73A827A6C84F00255A50 /* associated-phrases.cin in Resources */ = {isa = PBXBuildFile; fileRef = D47D73A727A6C84F00255A50 /* associated-phrases.cin */; };
|
||||||
D47D73A927A6C84F00255A50 /* associated-phrases.cin in Resources */ = {isa = PBXBuildFile; fileRef = D47D73A727A6C84F00255A50 /* associated-phrases.cin */; };
|
D47D73A927A6C84F00255A50 /* associated-phrases.cin in Resources */ = {isa = PBXBuildFile; fileRef = D47D73A727A6C84F00255A50 /* associated-phrases.cin */; };
|
||||||
D47D73AC27A6CAE600255A50 /* AssociatedPhrases.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D47D73AA27A6CAE600255A50 /* AssociatedPhrases.cpp */; };
|
D47D73AC27A6CAE600255A50 /* AssociatedPhrases.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D47D73AA27A6CAE600255A50 /* AssociatedPhrases.cpp */; };
|
||||||
|
D47D73C327A7200500255A50 /* FSEventStreamHelper in Frameworks */ = {isa = PBXBuildFile; productRef = D47D73C227A7200500255A50 /* FSEventStreamHelper */; };
|
||||||
D47F7DCE278BFB57002F9DD7 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */; };
|
D47F7DCE278BFB57002F9DD7 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */; };
|
||||||
D47F7DD0278C0897002F9DD7 /* NonModalAlertWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */; };
|
D47F7DD0278C0897002F9DD7 /* NonModalAlertWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */; };
|
||||||
D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */; };
|
D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */; };
|
||||||
D485D3B92796A8A000657FF3 /* PreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D485D3B82796A8A000657FF3 /* PreferencesTests.swift */; };
|
D485D3B92796A8A000657FF3 /* PreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D485D3B82796A8A000657FF3 /* PreferencesTests.swift */; };
|
||||||
D485D3C02796CE3200657FF3 /* VersionUpdateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D485D3BF2796CE3200657FF3 /* VersionUpdateTests.swift */; };
|
D485D3C02796CE3200657FF3 /* VersionUpdateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D485D3BF2796CE3200657FF3 /* VersionUpdateTests.swift */; };
|
||||||
D4A13D5A27A59F0B003BE359 /* InputMethodController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A13D5927A59D5C003BE359 /* InputMethodController.swift */; };
|
D4A13D5A27A59F0B003BE359 /* InputMethodController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A13D5927A59D5C003BE359 /* InputMethodController.swift */; };
|
||||||
|
D4E33D8A27A838CF006DB1CF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D4E33D8827A838CF006DB1CF /* Localizable.strings */; };
|
||||||
|
D4E33D8F27A838F0006DB1CF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D4E33D8D27A838F0006DB1CF /* InfoPlist.strings */; };
|
||||||
D4E569DC27A34D0E00AC2CEF /* KeyHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = D4E569DB27A34CC100AC2CEF /* KeyHandler.mm */; };
|
D4E569DC27A34D0E00AC2CEF /* KeyHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = D4E569DB27A34CC100AC2CEF /* KeyHandler.mm */; };
|
||||||
D4E569E427A414CB00AC2CEF /* data-plain-bpmf.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6AD7CBC715FE555000691B5B /* data-plain-bpmf.txt */; };
|
D4E569E427A414CB00AC2CEF /* data-plain-bpmf.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6AD7CBC715FE555000691B5B /* data-plain-bpmf.txt */; };
|
||||||
D4E569E527A414CB00AC2CEF /* data.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6A38BBF615FC117A00A8A51F /* data.txt */; };
|
D4E569E527A414CB00AC2CEF /* data.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6A38BBF615FC117A00A8A51F /* data.txt */; };
|
||||||
|
@ -145,10 +146,6 @@
|
||||||
6A0D4F4015FC0EB100ABF4B3 /* OVTextBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVTextBuffer.h; sourceTree = "<group>"; };
|
6A0D4F4015FC0EB100ABF4B3 /* OVTextBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVTextBuffer.h; sourceTree = "<group>"; };
|
||||||
6A0D4F4115FC0EB100ABF4B3 /* OVUTF8Helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVUTF8Helper.h; sourceTree = "<group>"; };
|
6A0D4F4115FC0EB100ABF4B3 /* OVUTF8Helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVUTF8Helper.h; sourceTree = "<group>"; };
|
||||||
6A0D4F4215FC0EB100ABF4B3 /* OVWildcard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVWildcard.h; sourceTree = "<group>"; };
|
6A0D4F4215FC0EB100ABF4B3 /* OVWildcard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OVWildcard.h; sourceTree = "<group>"; };
|
||||||
6A0D4F4915FC0EE100ABF4B3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Source/en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
|
||||||
6A0D4F4B15FC0EE100ABF4B3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Source/en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
|
||||||
6A0D4F5415FC0EF900ABF4B3 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "Source/zh-Hant.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
|
||||||
6A0D4F5515FC0EF900ABF4B3 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "Source/zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
|
||||||
6A0D4F5615FC0EF900ABF4B3 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "zh-Hant"; path = "Source/zh-Hant.lproj/preferences.xib"; sourceTree = "<group>"; };
|
6A0D4F5615FC0EF900ABF4B3 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "zh-Hant"; path = "Source/zh-Hant.lproj/preferences.xib"; sourceTree = "<group>"; };
|
||||||
6A15B32421A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
6A15B32421A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
6A15B32521A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
6A15B32521A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
|
@ -204,13 +201,14 @@
|
||||||
D44FB74B2792189A003C80A6 /* PhraseReplacementMap.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PhraseReplacementMap.cpp; sourceTree = "<group>"; };
|
D44FB74B2792189A003C80A6 /* PhraseReplacementMap.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PhraseReplacementMap.cpp; sourceTree = "<group>"; };
|
||||||
D44FB74C2792189A003C80A6 /* PhraseReplacementMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PhraseReplacementMap.h; sourceTree = "<group>"; };
|
D44FB74C2792189A003C80A6 /* PhraseReplacementMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PhraseReplacementMap.h; sourceTree = "<group>"; };
|
||||||
D456576D279E4F7B00DF6BC9 /* KeyHandlerInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyHandlerInput.swift; sourceTree = "<group>"; };
|
D456576D279E4F7B00DF6BC9 /* KeyHandlerInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyHandlerInput.swift; sourceTree = "<group>"; };
|
||||||
|
D45EB5BF27A9890C00E28B17 /* StringUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringUtils.swift; sourceTree = "<group>"; };
|
||||||
D461B791279DAC010070E734 /* InputState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputState.swift; sourceTree = "<group>"; };
|
D461B791279DAC010070E734 /* InputState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputState.swift; sourceTree = "<group>"; };
|
||||||
D47B92BF27972AC800458394 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
D47B92BF27972AC800458394 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
|
||||||
D47D73A327A5D43900255A50 /* KeyHandlerBopomofoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyHandlerBopomofoTests.swift; sourceTree = "<group>"; };
|
D47D73A327A5D43900255A50 /* KeyHandlerBopomofoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyHandlerBopomofoTests.swift; sourceTree = "<group>"; };
|
||||||
D47D73C027A71FFA00255A50 /* FSEventStreamHelper */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FSEventStreamHelper; path = Packages/FSEventStreamHelper; sourceTree = "<group>"; };
|
|
||||||
D47D73A727A6C84F00255A50 /* associated-phrases.cin */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "associated-phrases.cin"; sourceTree = "<group>"; };
|
D47D73A727A6C84F00255A50 /* associated-phrases.cin */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "associated-phrases.cin"; sourceTree = "<group>"; };
|
||||||
D47D73AA27A6CAE600255A50 /* AssociatedPhrases.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AssociatedPhrases.cpp; sourceTree = "<group>"; };
|
D47D73AA27A6CAE600255A50 /* AssociatedPhrases.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AssociatedPhrases.cpp; sourceTree = "<group>"; };
|
||||||
D47D73AB27A6CAE600255A50 /* AssociatedPhrases.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AssociatedPhrases.h; sourceTree = "<group>"; };
|
D47D73AB27A6CAE600255A50 /* AssociatedPhrases.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AssociatedPhrases.h; sourceTree = "<group>"; };
|
||||||
|
D47D73C027A71FFA00255A50 /* FSEventStreamHelper */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FSEventStreamHelper; path = Packages/FSEventStreamHelper; sourceTree = "<group>"; };
|
||||||
D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
|
D47F7DCD278BFB57002F9DD7 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
|
||||||
D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonModalAlertWindowController.swift; sourceTree = "<group>"; };
|
D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonModalAlertWindowController.swift; sourceTree = "<group>"; };
|
||||||
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserOverrideModel.h; sourceTree = "<group>"; };
|
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserOverrideModel.h; sourceTree = "<group>"; };
|
||||||
|
@ -220,6 +218,12 @@
|
||||||
D485D3BF2796CE3200657FF3 /* VersionUpdateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionUpdateTests.swift; sourceTree = "<group>"; };
|
D485D3BF2796CE3200657FF3 /* VersionUpdateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionUpdateTests.swift; sourceTree = "<group>"; };
|
||||||
D495583A27A5C6C4006ADE1C /* LanguageModelManager+Privates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LanguageModelManager+Privates.h"; sourceTree = "<group>"; };
|
D495583A27A5C6C4006ADE1C /* LanguageModelManager+Privates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LanguageModelManager+Privates.h"; sourceTree = "<group>"; };
|
||||||
D4A13D5927A59D5C003BE359 /* InputMethodController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputMethodController.swift; sourceTree = "<group>"; };
|
D4A13D5927A59D5C003BE359 /* InputMethodController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputMethodController.swift; sourceTree = "<group>"; };
|
||||||
|
D4E33D8927A838CF006DB1CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
D4E33D8B27A838D5006DB1CF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
D4E33D8C27A838D8006DB1CF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||||
|
D4E33D8E27A838F0006DB1CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
|
D4E33D9027A838F4006DB1CF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
|
D4E33D9127A838F7006DB1CF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||||
D4E569DA27A34CC100AC2CEF /* KeyHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyHandler.h; sourceTree = "<group>"; };
|
D4E569DA27A34CC100AC2CEF /* KeyHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyHandler.h; sourceTree = "<group>"; };
|
||||||
D4E569DB27A34CC100AC2CEF /* KeyHandler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyHandler.mm; sourceTree = "<group>"; };
|
D4E569DB27A34CC100AC2CEF /* KeyHandler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyHandler.mm; sourceTree = "<group>"; };
|
||||||
D4F0BBDE279AF1AF0071253C /* ArchiveUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveUtil.swift; sourceTree = "<group>"; };
|
D4F0BBDE279AF1AF0071253C /* ArchiveUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArchiveUtil.swift; sourceTree = "<group>"; };
|
||||||
|
@ -300,6 +304,7 @@
|
||||||
D4E569DB27A34CC100AC2CEF /* KeyHandler.mm */,
|
D4E569DB27A34CC100AC2CEF /* KeyHandler.mm */,
|
||||||
D456576D279E4F7B00DF6BC9 /* KeyHandlerInput.swift */,
|
D456576D279E4F7B00DF6BC9 /* KeyHandlerInput.swift */,
|
||||||
D461B791279DAC010070E734 /* InputState.swift */,
|
D461B791279DAC010070E734 /* InputState.swift */,
|
||||||
|
D45EB5BF27A9890C00E28B17 /* StringUtils.swift */,
|
||||||
D427F76B278CA1BA004A2160 /* AppDelegate.swift */,
|
D427F76B278CA1BA004A2160 /* AppDelegate.swift */,
|
||||||
D44FB74427915555003C80A6 /* Preferences.swift */,
|
D44FB74427915555003C80A6 /* Preferences.swift */,
|
||||||
D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */,
|
D47F7DCF278C0897002F9DD7 /* NonModalAlertWindowController.swift */,
|
||||||
|
@ -423,8 +428,8 @@
|
||||||
6AFF97F0253B299E007F1C49 /* NonModalAlertWindowController.xib */,
|
6AFF97F0253B299E007F1C49 /* NonModalAlertWindowController.xib */,
|
||||||
6A0D4EEE15FC0DA600ABF4B3 /* Images */,
|
6A0D4EEE15FC0DA600ABF4B3 /* Images */,
|
||||||
6A0D4EF515FC0DA600ABF4B3 /* McBopomofo-Info.plist */,
|
6A0D4EF515FC0DA600ABF4B3 /* McBopomofo-Info.plist */,
|
||||||
6A0D4F4815FC0EE100ABF4B3 /* InfoPlist.strings */,
|
D4E33D8D27A838F0006DB1CF /* InfoPlist.strings */,
|
||||||
6A0D4F4A15FC0EE100ABF4B3 /* Localizable.strings */,
|
D4E33D8827A838CF006DB1CF /* Localizable.strings */,
|
||||||
6A187E2816004C5900466B2E /* MainMenu.xib */,
|
6A187E2816004C5900466B2E /* MainMenu.xib */,
|
||||||
6A0D4F4E15FC0EE100ABF4B3 /* preferences.xib */,
|
6A0D4F4E15FC0EE100ABF4B3 /* preferences.xib */,
|
||||||
);
|
);
|
||||||
|
@ -640,14 +645,14 @@
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D4E33D8A27A838CF006DB1CF /* Localizable.strings in Resources */,
|
||||||
6A6ED16E2797650A0012872E /* template-exclude-phrases.txt in Resources */,
|
6A6ED16E2797650A0012872E /* template-exclude-phrases.txt in Resources */,
|
||||||
6A0D4F0815FC0DA600ABF4B3 /* Bopomofo.tiff in Resources */,
|
6A0D4F0815FC0DA600ABF4B3 /* Bopomofo.tiff in Resources */,
|
||||||
6A0D4F0915FC0DA600ABF4B3 /* Bopomofo@2x.tiff in Resources */,
|
6A0D4F0915FC0DA600ABF4B3 /* Bopomofo@2x.tiff in Resources */,
|
||||||
6A6ED16D2797650A0012872E /* template-exclude-phrases-plain-bpmf.txt in Resources */,
|
6A6ED16D2797650A0012872E /* template-exclude-phrases-plain-bpmf.txt in Resources */,
|
||||||
6A0D4F5315FC0EE100ABF4B3 /* preferences.xib in Resources */,
|
6A0D4F5315FC0EE100ABF4B3 /* preferences.xib in Resources */,
|
||||||
6A0D4F5715FC0EF900ABF4B3 /* InfoPlist.strings in Resources */,
|
|
||||||
6A0D4F5815FC0EF900ABF4B3 /* Localizable.strings in Resources */,
|
|
||||||
6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */,
|
6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */,
|
||||||
|
D4E33D8F27A838F0006DB1CF /* InfoPlist.strings in Resources */,
|
||||||
6A38BC1515FC117A00A8A51F /* data.txt in Resources */,
|
6A38BC1515FC117A00A8A51F /* data.txt in Resources */,
|
||||||
6A6ED16B2797650A0012872E /* template-phrases-replacement.txt in Resources */,
|
6A6ED16B2797650A0012872E /* template-phrases-replacement.txt in Resources */,
|
||||||
6AFF97F2253B299E007F1C49 /* NonModalAlertWindowController.xib in Resources */,
|
6AFF97F2253B299E007F1C49 /* NonModalAlertWindowController.xib in Resources */,
|
||||||
|
@ -728,6 +733,7 @@
|
||||||
D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */,
|
D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */,
|
||||||
6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */,
|
6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */,
|
||||||
6ACC3D452793701600F1B140 /* ParselessLM.cpp in Sources */,
|
6ACC3D452793701600F1B140 /* ParselessLM.cpp in Sources */,
|
||||||
|
D45EB5C127A9894C00E28B17 /* StringUtils.swift in Sources */,
|
||||||
D41355DE278EA3ED005E5CBD /* UserPhrasesLM.cpp in Sources */,
|
D41355DE278EA3ED005E5CBD /* UserPhrasesLM.cpp in Sources */,
|
||||||
6ACC3D3F27914F2400F1B140 /* KeyValueBlobReader.cpp in Sources */,
|
6ACC3D3F27914F2400F1B140 /* KeyValueBlobReader.cpp in Sources */,
|
||||||
D41355D8278D74B5005E5CBD /* LanguageModelManager.mm in Sources */,
|
D41355D8278D74B5005E5CBD /* LanguageModelManager.mm in Sources */,
|
||||||
|
@ -775,26 +781,6 @@
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
6A0D4F4815FC0EE100ABF4B3 /* InfoPlist.strings */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
6A0D4F4915FC0EE100ABF4B3 /* en */,
|
|
||||||
6A0D4F5415FC0EF900ABF4B3 /* zh-Hant */,
|
|
||||||
);
|
|
||||||
name = InfoPlist.strings;
|
|
||||||
path = ..;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
6A0D4F4A15FC0EE100ABF4B3 /* Localizable.strings */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
6A0D4F4B15FC0EE100ABF4B3 /* en */,
|
|
||||||
6A0D4F5515FC0EF900ABF4B3 /* zh-Hant */,
|
|
||||||
);
|
|
||||||
name = Localizable.strings;
|
|
||||||
path = ..;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
6A0D4F4E15FC0EE100ABF4B3 /* preferences.xib */ = {
|
6A0D4F4E15FC0EE100ABF4B3 /* preferences.xib */ = {
|
||||||
isa = PBXVariantGroup;
|
isa = PBXVariantGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -890,6 +876,26 @@
|
||||||
path = Source/Installer;
|
path = Source/Installer;
|
||||||
sourceTree = SOURCE_ROOT;
|
sourceTree = SOURCE_ROOT;
|
||||||
};
|
};
|
||||||
|
D4E33D8827A838CF006DB1CF /* Localizable.strings */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
D4E33D8927A838CF006DB1CF /* Base */,
|
||||||
|
D4E33D8B27A838D5006DB1CF /* en */,
|
||||||
|
D4E33D8C27A838D8006DB1CF /* zh-Hant */,
|
||||||
|
);
|
||||||
|
name = Localizable.strings;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D4E33D8D27A838F0006DB1CF /* InfoPlist.strings */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
D4E33D8E27A838F0006DB1CF /* Base */,
|
||||||
|
D4E33D9027A838F4006DB1CF /* en */,
|
||||||
|
D4E33D9127A838F7006DB1CF /* zh-Hant */,
|
||||||
|
);
|
||||||
|
name = InfoPlist.strings;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D4F0BBE9279B14C20071253C /* Credits.rtf */ = {
|
D4F0BBE9279B14C20071253C /* Credits.rtf */ = {
|
||||||
isa = PBXVariantGroup;
|
isa = PBXVariantGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
CFBundleName = "McBopomofo";
|
||||||
|
CFBundleDisplayName = "McBopomofo";
|
||||||
|
NSHumanReadableCopyright = "Copyright © 2011-2022 Mengjuei Hsieh et al.\nAll Rights Reserved.";
|
||||||
|
"org.openvanilla.inputmethod.McBopomofo.Bopomofo" = "Bopomofo";
|
||||||
|
"org.openvanilla.inputmethod.McBopomofo.PlainBopomofo" = "Plain Bopomofo";
|
|
@ -0,0 +1,92 @@
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"About McBopomofo…" = "About McBopomofo…";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"McBopomofo Preferences" = "McBopomofo Preferences";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"Check for Updates…" = "Check for Updates…";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"Update Check Failed" = "Update Check Failed";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"There may be no internet connection or the server failed to respond.\n\nError message: %@" = "There may be no internet connection or the server failed to respond.\n\nError message: %@";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"OK" = "OK";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"Dismiss" = "Dismiss";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"New Version Available" = "New Version Available";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"Not Now" = "Not Now";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"Visit Website" = "Visit Website";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"You're currently using McBopomofo %@ (%@), a new version %@ (%@) is now available. Do you want to visit McBopomofo's website to download the version?%@" = "You're currently using McBopomofo %@ (%@), a new version %@ (%@) is now available. Do you want to visit McBopomofo's website to download the version?%@";
|
||||||
|
|
||||||
|
"Chinese Conversion" = "Convert to Simplified Chinese";
|
||||||
|
|
||||||
|
"User Phrases" = "User Phrases";
|
||||||
|
|
||||||
|
"Edit User Phrases" = "Edit User Phrases";
|
||||||
|
|
||||||
|
"Reload User Phrases" = "Reload User Phrases";
|
||||||
|
|
||||||
|
"Unable to create the user phrase file." = "Unable to create the user phrase file.";
|
||||||
|
|
||||||
|
"Please check the permission of at \"%@\"." = "Please check the permission of at \"%@\".";
|
||||||
|
|
||||||
|
"Edit Excluded Phrases" = "Edit Excluded Phrases";
|
||||||
|
|
||||||
|
"Use Half-Width Punctuations" = "Use Half-Width Punctuations";
|
||||||
|
|
||||||
|
"You are now selecting \"%@\". You can add a phrase with two or more characters." = "You are now selecting \"%@\". You can add a phrase with two or more characters.";
|
||||||
|
|
||||||
|
"You are now selecting \"%@\". Press enter to add a new phrase." = "You are now selecting \"%@\". Press enter to add a new phrase.";
|
||||||
|
|
||||||
|
"You are now selecting \"%@\". A phrase cannot be longer than %d characters." = "You are now selecting \"%@\". A phrase cannot be longer than %d characters.";
|
||||||
|
|
||||||
|
"Chinese conversion on" = "Chinese conversion on";
|
||||||
|
|
||||||
|
"Chinese conversion off" = "Chinese conversion off";
|
||||||
|
|
||||||
|
"Edit Phrase Replacement Table" = "Edit Phrase Replacement Table";
|
||||||
|
|
||||||
|
"Use Phrase Replacement" = "Use Phrase Replacement";
|
||||||
|
|
||||||
|
"Candidates keys cannot be empty." = "Candidates keys cannot be empty.";
|
||||||
|
|
||||||
|
"Candidate keys can only contain latin characters and numbers." = "Candidate keys can only contain latin characters and numbers.";
|
||||||
|
|
||||||
|
"Candidate keys cannot contain space." = "Candidate keys cannot contain space.";
|
||||||
|
|
||||||
|
"There should not be duplicated keys." = "There should not be duplicated keys.";
|
||||||
|
|
||||||
|
"The length of your candidate keys can not be less than 4 characters." = "The length of your candidate keys can not be less than 4 characters.";
|
||||||
|
|
||||||
|
"The length of your candidate keys can not be larger than 15 characters." = "The length of your candidate keys can not be larger than 15 characters.";
|
||||||
|
|
||||||
|
"Phrase replacement mode is on. Not suggested to add phrase in the mode." = "Phrase replacement mode is on. Not suggested to add phrase in the mode.";
|
||||||
|
|
||||||
|
"Model based Chinese conversion is on. Not suggested to add phrase in the mode." = "Model based Chinese conversion is on. Not suggested to add phrase in the mode.";
|
||||||
|
|
||||||
|
"Half-width punctuation on" = "Half-width punctuation on";
|
||||||
|
|
||||||
|
"Half-width punctuation off" = "Half-width punctuation off";
|
||||||
|
|
||||||
|
"Associated Phrases" = "Associated Phrases";
|
||||||
|
|
||||||
|
"There are special phrases in your text. We don't support adding new phrases in this case." = "There are special phrases in your text. We don't support adding new phrases in this case.";
|
||||||
|
|
||||||
|
"Cursor is before \"%@\"." = "Cursor is before \"%@\".";
|
||||||
|
|
||||||
|
"Cursor is after \"%@\"." = "Cursor is after \"%@\".";
|
||||||
|
|
||||||
|
"Cursor is between \"%@\" and \"%@\"." = "Cursor is between \"%@\" and \"%@\".";
|
|
@ -180,6 +180,7 @@ class McBopomofoInputMethodController: IMKInputController {
|
||||||
}
|
}
|
||||||
|
|
||||||
let input = KeyHandlerInput(event: event, isVerticalMode: useVerticalMode)
|
let input = KeyHandlerInput(event: event, isVerticalMode: useVerticalMode)
|
||||||
|
|
||||||
let result = keyHandler.handle(input, state: state) { newState in
|
let result = keyHandler.handle(input, state: state) { newState in
|
||||||
self.handle(state: newState, client: client)
|
self.handle(state: newState, client: client)
|
||||||
} candidateSelectionCallback: {
|
} candidateSelectionCallback: {
|
||||||
|
@ -388,6 +389,9 @@ extension McBopomofoInputMethodController {
|
||||||
// the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound,
|
// the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound,
|
||||||
// i.e. the client app needs to take care of where to put this composing buffer
|
// i.e. the client app needs to take care of where to put this composing buffer
|
||||||
client.setMarkedText(state.attributedString, selectionRange: NSMakeRange(Int(state.cursorIndex), 0), replacementRange: NSMakeRange(NSNotFound, NSNotFound))
|
client.setMarkedText(state.attributedString, selectionRange: NSMakeRange(Int(state.cursorIndex), 0), replacementRange: NSMakeRange(NSNotFound, NSNotFound))
|
||||||
|
if !state.tooltip.isEmpty {
|
||||||
|
show(tooltip: state.tooltip, composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex, client: client)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handle(state: InputState.Marking, previous: InputState, client: Any?) {
|
private func handle(state: InputState.Marking, previous: InputState, client: Any?) {
|
||||||
|
@ -482,16 +486,19 @@ extension McBopomofoInputMethodController {
|
||||||
gCurrentCandidateController?.visible = true
|
gCurrentCandidateController?.visible = true
|
||||||
|
|
||||||
var lineHeightRect = NSMakeRect(0.0, 0.0, 16.0, 16.0)
|
var lineHeightRect = NSMakeRect(0.0, 0.0, 16.0, 16.0)
|
||||||
var cursor: UInt = 0
|
var cursor: Int = 0
|
||||||
|
|
||||||
if let state = state as? InputState.ChoosingCandidate {
|
if let state = state as? InputState.ChoosingCandidate {
|
||||||
cursor = state.cursorIndex
|
cursor = Int(state.cursorIndex)
|
||||||
if cursor == state.composingBuffer.count && cursor != 0 {
|
if cursor == state.composingBuffer.count && cursor != 0 {
|
||||||
cursor -= 1
|
cursor -= 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(client as? IMKTextInput)?.attributes(forCharacterIndex: Int(cursor), lineHeightRectangle: &lineHeightRect)
|
while lineHeightRect.origin.x == 0 && lineHeightRect.origin.y == 0 && cursor >= 0 {
|
||||||
|
(client as? IMKTextInput)?.attributes(forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect)
|
||||||
|
cursor -= 1
|
||||||
|
}
|
||||||
|
|
||||||
if useVerticalMode {
|
if useVerticalMode {
|
||||||
gCurrentCandidateController?.set(windowTopLeftPoint: NSMakePoint(lineHeightRect.origin.x + lineHeightRect.size.width + 4.0, lineHeightRect.origin.y - 4.0), bottomOutOfScreenAdjustmentHeight: lineHeightRect.size.height + 4.0)
|
gCurrentCandidateController?.set(windowTopLeftPoint: NSMakePoint(lineHeightRect.origin.x + lineHeightRect.size.width + 4.0, lineHeightRect.origin.y - 4.0), bottomOutOfScreenAdjustmentHeight: lineHeightRect.size.height + 4.0)
|
||||||
|
@ -502,11 +509,14 @@ extension McBopomofoInputMethodController {
|
||||||
|
|
||||||
private func show(tooltip: String, composingBuffer: String, cursorIndex: UInt, client: Any!) {
|
private func show(tooltip: String, composingBuffer: String, cursorIndex: UInt, client: Any!) {
|
||||||
var lineHeightRect = NSMakeRect(0.0, 0.0, 16.0, 16.0)
|
var lineHeightRect = NSMakeRect(0.0, 0.0, 16.0, 16.0)
|
||||||
var cursor = cursorIndex
|
var cursor: Int = Int(cursorIndex)
|
||||||
if cursor == composingBuffer.count && cursor != 0 {
|
if cursor == composingBuffer.count && cursor != 0 {
|
||||||
cursor -= 1
|
cursor -= 1
|
||||||
}
|
}
|
||||||
(client as? IMKTextInput)?.attributes(forCharacterIndex: Int(cursor), lineHeightRectangle: &lineHeightRect)
|
while lineHeightRect.origin.x == 0 && lineHeightRect.origin.y == 0 && cursor >= 0 {
|
||||||
|
(client as? IMKTextInput)?.attributes(forCharacterIndex: cursor, lineHeightRectangle: &lineHeightRect)
|
||||||
|
cursor -= 1
|
||||||
|
}
|
||||||
McBopomofoInputMethodController.tooltipController.show(tooltip: tooltip, at: lineHeightRect.origin)
|
McBopomofoInputMethodController.tooltipController.show(tooltip: tooltip, at: lineHeightRect.origin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,8 @@ class InputState: NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
/// Represents that the composing buffer is empty.
|
/// Represents that the composing buffer is empty.
|
||||||
@objc (InputStateEmpty)
|
@objc (InputStateEmpty)
|
||||||
class Empty: InputState {
|
class Empty: InputState {
|
||||||
|
@ -76,6 +78,8 @@ class InputState: NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
/// Represents that the composing buffer is empty.
|
/// Represents that the composing buffer is empty.
|
||||||
@objc (InputStateEmptyIgnoringPreviousState)
|
@objc (InputStateEmptyIgnoringPreviousState)
|
||||||
class EmptyIgnoringPreviousState: InputState {
|
class EmptyIgnoringPreviousState: InputState {
|
||||||
|
@ -87,6 +91,8 @@ class InputState: NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
/// Represents that the input controller is committing text into client app.
|
/// Represents that the input controller is committing text into client app.
|
||||||
@objc (InputStateCommitting)
|
@objc (InputStateCommitting)
|
||||||
class Committing: InputState {
|
class Committing: InputState {
|
||||||
|
@ -101,11 +107,14 @@ class InputState: NSObject {
|
||||||
"<InputState.Committing poppedText:\(poppedText)>"
|
"<InputState.Committing poppedText:\(poppedText)>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
/// Represents that the composing buffer is not empty.
|
/// Represents that the composing buffer is not empty.
|
||||||
@objc (InputStateNotEmpty)
|
@objc (InputStateNotEmpty)
|
||||||
class NotEmpty: InputState {
|
class NotEmpty: InputState {
|
||||||
@objc private(set) var composingBuffer: String = ""
|
@objc private(set) var composingBuffer: String
|
||||||
@objc private(set) var cursorIndex: UInt = 0
|
@objc private(set) var cursorIndex: UInt
|
||||||
|
|
||||||
@objc init(composingBuffer: String, cursorIndex: UInt) {
|
@objc init(composingBuffer: String, cursorIndex: UInt) {
|
||||||
self.composingBuffer = composingBuffer
|
self.composingBuffer = composingBuffer
|
||||||
|
@ -117,12 +126,13 @@ class InputState: NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
/// Represents that the user is inputting text.
|
/// Represents that the user is inputting text.
|
||||||
@objc (InputStateInputting)
|
@objc (InputStateInputting)
|
||||||
class Inputting: NotEmpty {
|
class Inputting: NotEmpty {
|
||||||
@objc var bpmfReading: String = ""
|
|
||||||
@objc var bpmfReadingCursorIndex: UInt8 = 0
|
|
||||||
@objc var poppedText: String = ""
|
@objc var poppedText: String = ""
|
||||||
|
@objc var tooltip: String = ""
|
||||||
|
|
||||||
@objc override init(composingBuffer: String, cursorIndex: UInt) {
|
@objc override init(composingBuffer: String, cursorIndex: UInt) {
|
||||||
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
|
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
|
||||||
|
@ -137,20 +147,27 @@ class InputState: NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
override var description: String {
|
override var description: String {
|
||||||
"<InputState.Inputting, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex), poppedText:\(poppedText)>"
|
"<InputState.Inputting, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>, poppedText:\(poppedText)>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
private let kMinMarkRangeLength = 2
|
private let kMinMarkRangeLength = 2
|
||||||
private let kMaxMarkRangeLength = 6
|
private let kMaxMarkRangeLength = 6
|
||||||
|
|
||||||
/// Represents that the user is marking a range in the composing buffer.
|
/// Represents that the user is marking a range in the composing buffer.
|
||||||
@objc (InputStateMarking)
|
@objc (InputStateMarking)
|
||||||
class Marking: NotEmpty {
|
class Marking: NotEmpty {
|
||||||
|
|
||||||
@objc private(set) var markerIndex: UInt
|
@objc private(set) var markerIndex: UInt
|
||||||
@objc private(set) var markedRange: NSRange
|
@objc private(set) var markedRange: NSRange
|
||||||
@objc var tooltip: String {
|
@objc var tooltip: String {
|
||||||
|
|
||||||
|
if composingBuffer.count != readings.count {
|
||||||
|
return NSLocalizedString("There are special phrases in your text. We don't support adding new phrases in this case.", comment: "")
|
||||||
|
}
|
||||||
|
|
||||||
if Preferences.phraseReplacementEnabled {
|
if Preferences.phraseReplacementEnabled {
|
||||||
return NSLocalizedString("Phrase replacement mode is on. Not suggested to add phrase in the mode.", comment: "")
|
return NSLocalizedString("Phrase replacement mode is on. Not suggested to add phrase in the mode.", comment: "")
|
||||||
}
|
}
|
||||||
|
@ -170,6 +187,7 @@ class InputState: NSObject {
|
||||||
return String(format: NSLocalizedString("You are now selecting \"%@\". Press enter to add a new phrase.", comment: ""), text)
|
return String(format: NSLocalizedString("You are now selecting \"%@\". Press enter to add a new phrase.", comment: ""), text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc var tooltipForInputting: String = ""
|
||||||
@objc private(set) var readings: [String]
|
@objc private(set) var readings: [String]
|
||||||
|
|
||||||
@objc init(composingBuffer: String, cursorIndex: UInt, markerIndex: UInt, readings: [String]) {
|
@objc init(composingBuffer: String, cursorIndex: UInt, markerIndex: UInt, readings: [String]) {
|
||||||
|
@ -197,32 +215,45 @@ class InputState: NSObject {
|
||||||
.underlineStyle: NSUnderlineStyle.single.rawValue,
|
.underlineStyle: NSUnderlineStyle.single.rawValue,
|
||||||
.markedClauseSegment: 2
|
.markedClauseSegment: 2
|
||||||
], range: NSRange(location: end,
|
], range: NSRange(location: end,
|
||||||
length: composingBuffer.count - end))
|
length: (composingBuffer as NSString).length - end))
|
||||||
return attributedSting
|
return attributedSting
|
||||||
}
|
}
|
||||||
|
|
||||||
override var description: String {
|
override var description: String {
|
||||||
"<InputState.Marking, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex), markedRange:\(markedRange), readings:\(readings)>"
|
"<InputState.Marking, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex), markedRange:\(markedRange)>"
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func convertToInputting() -> Inputting {
|
@objc func convertToInputting() -> Inputting {
|
||||||
let state = Inputting(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
|
let state = Inputting(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
|
||||||
|
state.tooltip = tooltipForInputting
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc var validToWrite: Bool {
|
@objc var validToWrite: Bool {
|
||||||
markedRange.length >= kMinMarkRangeLength && markedRange.length <= kMaxMarkRangeLength
|
/// McBopomofo allows users to input a string whose length differs
|
||||||
|
/// from the amount of Bopomofo readings. In this case, the range
|
||||||
|
/// in the composing buffer and the readings could not match, so
|
||||||
|
/// we disable the function to write user phrases in this case.
|
||||||
|
if composingBuffer.count != readings.count {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return markedRange.length >= kMinMarkRangeLength &&
|
||||||
|
markedRange.length <= kMaxMarkRangeLength
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc var userPhrase: String {
|
@objc var userPhrase: String {
|
||||||
let text = (composingBuffer as NSString).substring(with: markedRange)
|
let text = (composingBuffer as NSString).substring(with: markedRange)
|
||||||
let end = markedRange.location + markedRange.length
|
let exactBegin = StringUtils.convertToCharIndex(from: markedRange.location, in: composingBuffer)
|
||||||
let readings = readings[markedRange.location..<end]
|
let exactEnd = StringUtils.convertToCharIndex(from: markedRange.location + markedRange.length, in: composingBuffer)
|
||||||
|
let readings = readings[exactBegin..<exactEnd]
|
||||||
let joined = readings.joined(separator: "-")
|
let joined = readings.joined(separator: "-")
|
||||||
return "\(text) \(joined)"
|
return "\(text) \(joined)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
/// Represents that the user is choosing in a candidates list.
|
/// Represents that the user is choosing in a candidates list.
|
||||||
@objc (InputStateChoosingCandidate)
|
@objc (InputStateChoosingCandidate)
|
||||||
class ChoosingCandidate: NotEmpty {
|
class ChoosingCandidate: NotEmpty {
|
||||||
|
@ -244,10 +275,12 @@ class InputState: NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
override var description: String {
|
override var description: String {
|
||||||
"<InputState.ChoosingCandidate, candidates:\(candidates), useVerticalMode:\(useVerticalMode), composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
|
"<InputState.ChoosingCandidate, candidates:\(candidates), useVerticalMode:\(useVerticalMode), composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
/// Represents that the user is choosing in a candidates list
|
/// Represents that the user is choosing in a candidates list
|
||||||
/// in the associated phrases mode.
|
/// in the associated phrases mode.
|
||||||
@objc (InputStateAssociatedPhrases)
|
@objc (InputStateAssociatedPhrases)
|
||||||
|
@ -264,5 +297,4 @@ class InputState: NSObject {
|
||||||
"<InputState.AssociatedPhrases, candidates:\(candidates), useVerticalMode:\(useVerticalMode)>"
|
"<InputState.AssociatedPhrases, candidates:\(candidates), useVerticalMode:\(useVerticalMode)>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,12 +226,12 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
McBopomofoEmacsKey emacsKey = input.emacsKey;
|
McBopomofoEmacsKey emacsKey = input.emacsKey;
|
||||||
|
|
||||||
// if the inputText is empty, it's a function key combination, we ignore it
|
// if the inputText is empty, it's a function key combination, we ignore it
|
||||||
if (![input.inputText length]) {
|
if (!input.inputText.length) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the composing buffer is empty and there's no reading, and there is some function key combination, we ignore it
|
// if the composing buffer is empty and there's no reading, and there is some function key combination, we ignore it
|
||||||
BOOL isFunctionKey = ([input isCommandHold] || [input isControlHold] || [input isOptionHold] || [input isNumericPad]);
|
BOOL isFunctionKey = ([input isCommandHold] || [input isOptionHold] || [input isNumericPad]) || [input isControlHotKey];
|
||||||
if (![state isKindOfClass:[InputStateNotEmpty class]] &&
|
if (![state isKindOfClass:[InputStateNotEmpty class]] &&
|
||||||
![state isKindOfClass:[InputStateAssociatedPhrases class]] &&
|
![state isKindOfClass:[InputStateAssociatedPhrases class]] &&
|
||||||
isFunctionKey) {
|
isFunctionKey) {
|
||||||
|
@ -302,10 +302,12 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
}
|
}
|
||||||
|
|
||||||
bool composeReading = false;
|
bool composeReading = false;
|
||||||
|
BOOL skipBpmfHandling = [input isReservedKey] || [input isControlHold];
|
||||||
|
|
||||||
// MARK: Handle BPMF Keys
|
// MARK: Handle BPMF Keys
|
||||||
|
|
||||||
// see if it's valid BPMF reading
|
// see if it's valid BPMF reading
|
||||||
if (_bpmfReadingBuffer->isValidKey((char) charCode)) {
|
if (!skipBpmfHandling && _bpmfReadingBuffer->isValidKey((char) charCode)) {
|
||||||
_bpmfReadingBuffer->combineKey((char) charCode);
|
_bpmfReadingBuffer->combineKey((char) charCode);
|
||||||
|
|
||||||
// if we have a tone marker, we have to insert the reading to the
|
// if we have a tone marker, we have to insert the reading to the
|
||||||
|
@ -348,7 +350,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
size_t cursorIndex = [self _actualCandidateCursorIndex];
|
size_t cursorIndex = [self _actualCandidateCursorIndex];
|
||||||
vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
|
vector<NodeAnchor> nodes = _builder->grid().nodesCrossingOrEndingAt(cursorIndex);
|
||||||
double highestScore = FindHighestScore(nodes, kEpsilon);
|
double highestScore = FindHighestScore(nodes, kEpsilon);
|
||||||
_builder->grid().overrideNodeScoreForSelectedCandidate(cursorIndex, overrideValue, highestScore);
|
_builder->grid().overrideNodeScoreForSelectedCandidate(cursorIndex, overrideValue, static_cast<float>(highestScore));
|
||||||
}
|
}
|
||||||
|
|
||||||
// then update the text
|
// then update the text
|
||||||
|
@ -397,12 +399,10 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
// if the spacebar is NOT set to be a selection key
|
// if the spacebar is NOT set to be a selection key
|
||||||
if ([input isShiftHold] || !Preferences.chooseCandidateUsingSpace) {
|
if ([input isShiftHold] || !Preferences.chooseCandidateUsingSpace) {
|
||||||
if (_builder->cursorIndex() >= _builder->length()) {
|
if (_builder->cursorIndex() >= _builder->length()) {
|
||||||
if ([state isKindOfClass:[InputStateNotEmpty class]]) {
|
NSString *composingBuffer = [(InputStateNotEmpty*) state composingBuffer];
|
||||||
NSString *composingBuffer = [(InputStateNotEmpty *)state composingBuffer];
|
if (composingBuffer.length) {
|
||||||
if ([composingBuffer length]) {
|
InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:composingBuffer];
|
||||||
InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:composingBuffer];
|
stateCallback (committing);
|
||||||
stateCallback(committing);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
[self clear];
|
[self clear];
|
||||||
InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:@" "];
|
InputStateCommitting *committing = [[InputStateCommitting alloc] initWithPoppedText:@" "];
|
||||||
|
@ -490,8 +490,16 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
|
|
||||||
// MARK: Punctuation
|
// MARK: Punctuation
|
||||||
// if nothing is matched, see if it's a punctuation key for current layout.
|
// if nothing is matched, see if it's a punctuation key for current layout.
|
||||||
|
|
||||||
|
string punctuationNamePrefix;
|
||||||
|
if ([input isControlHold]) {
|
||||||
|
punctuationNamePrefix = string("_ctrl_punctuation_");
|
||||||
|
} else if (Preferences.halfWidthPunctuationEnabled) {
|
||||||
|
punctuationNamePrefix = string("_half_punctuation_");
|
||||||
|
} else {
|
||||||
|
punctuationNamePrefix = string("_punctuation_");
|
||||||
|
}
|
||||||
string layout = [self _currentLayout];
|
string layout = [self _currentLayout];
|
||||||
string punctuationNamePrefix = Preferences.halfWidthPunctuationEnabled ? string("_half_punctuation_") : string("_punctuation_");
|
|
||||||
string customPunctuation = punctuationNamePrefix + layout + string(1, (char) charCode);
|
string customPunctuation = punctuationNamePrefix + layout + string(1, (char) charCode);
|
||||||
if ([self _handlePunctuation:customPunctuation state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) {
|
if ([self _handlePunctuation:customPunctuation state:state usingVerticalMode:input.useVerticalMode stateCallback:stateCallback errorCallback:errorCallback]) {
|
||||||
return YES;
|
return YES;
|
||||||
|
@ -540,7 +548,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
// other platforms
|
// other platforms
|
||||||
|
|
||||||
if (_bpmfReadingBuffer->isEmpty()) {
|
if (_bpmfReadingBuffer->isEmpty()) {
|
||||||
// no nee to beep since the event is deliberately triggered by user
|
// no need to beep since the event is deliberately triggered by user
|
||||||
if (![state isKindOfClass:[InputStateInputting class]]) {
|
if (![state isKindOfClass:[InputStateInputting class]]) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
@ -569,8 +577,10 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
|
|
||||||
if ([input isShiftHold]) {
|
if ([input isShiftHold]) {
|
||||||
// Shift + left
|
// Shift + left
|
||||||
if (_builder->cursorIndex() > 0) {
|
if (currentState.cursorIndex > 0) {
|
||||||
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:currentState.cursorIndex - 1 readings: [self _currentReadings]];
|
NSInteger previousPosition = [StringUtils previousUtf16PositionForIndex:currentState.cursorIndex in:currentState.composingBuffer];
|
||||||
|
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:previousPosition readings:[self _currentReadings]];
|
||||||
|
marking.tooltipForInputting = currentState.tooltip;
|
||||||
stateCallback(marking);
|
stateCallback(marking);
|
||||||
} else {
|
} else {
|
||||||
errorCallback();
|
errorCallback();
|
||||||
|
@ -605,8 +615,10 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
|
|
||||||
if ([input isShiftHold]) {
|
if ([input isShiftHold]) {
|
||||||
// Shift + Right
|
// Shift + Right
|
||||||
if (_builder->cursorIndex() < _builder->length()) {
|
if (currentState.cursorIndex < currentState.composingBuffer.length) {
|
||||||
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:currentState.cursorIndex + 1 readings: [self _currentReadings]];
|
NSInteger nextPosition = [StringUtils nextUtf16PositionForIndex:currentState.cursorIndex in:currentState.composingBuffer];
|
||||||
|
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:currentState.composingBuffer cursorIndex:currentState.cursorIndex markerIndex:nextPosition readings:[self _currentReadings]];
|
||||||
|
marking.tooltipForInputting = currentState.tooltip;
|
||||||
stateCallback(marking);
|
stateCallback(marking);
|
||||||
} else {
|
} else {
|
||||||
errorCallback();
|
errorCallback();
|
||||||
|
@ -832,8 +844,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
&& ([input isShiftHold])) {
|
&& ([input isShiftHold])) {
|
||||||
NSUInteger index = state.markerIndex;
|
NSUInteger index = state.markerIndex;
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
index -= 1;
|
index = [StringUtils previousUtf16PositionForIndex:index in:state.composingBuffer];
|
||||||
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index readings:state.readings];
|
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index readings:state.readings];
|
||||||
|
marking.tooltipForInputting = state.tooltipForInputting;
|
||||||
stateCallback(marking);
|
stateCallback(marking);
|
||||||
} else {
|
} else {
|
||||||
errorCallback();
|
errorCallback();
|
||||||
|
@ -847,8 +860,9 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
&& ([input isShiftHold])) {
|
&& ([input isShiftHold])) {
|
||||||
NSUInteger index = state.markerIndex;
|
NSUInteger index = state.markerIndex;
|
||||||
if (index < state.composingBuffer.length) {
|
if (index < state.composingBuffer.length) {
|
||||||
index += 1;
|
index = [StringUtils nextUtf16PositionForIndex:index in:state.composingBuffer];
|
||||||
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index readings:state.readings];
|
InputStateMarking *marking = [[InputStateMarking alloc] initWithComposingBuffer:state.composingBuffer cursorIndex:state.cursorIndex markerIndex:index readings:state.readings];
|
||||||
|
marking.tooltipForInputting = state.tooltipForInputting;
|
||||||
stateCallback(marking);
|
stateCallback(marking);
|
||||||
} else {
|
} else {
|
||||||
errorCallback();
|
errorCallback();
|
||||||
|
@ -1070,7 +1084,14 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
|
|
||||||
if (_inputMode == InputModePlainBopomofo) {
|
if (_inputMode == InputModePlainBopomofo) {
|
||||||
string layout = [self _currentLayout];
|
string layout = [self _currentLayout];
|
||||||
string punctuationNamePrefix = Preferences.halfWidthPunctuationEnabled ? string("_half_punctuation_") : string("_punctuation_");
|
string punctuationNamePrefix;
|
||||||
|
if ([input isControlHold]) {
|
||||||
|
punctuationNamePrefix = string("_ctrl_punctuation_");
|
||||||
|
} else if (Preferences.halfWidthPunctuationEnabled) {
|
||||||
|
punctuationNamePrefix = string("_half_punctuation_");
|
||||||
|
} else {
|
||||||
|
punctuationNamePrefix = string("_punctuation_");
|
||||||
|
}
|
||||||
string customPunctuation = punctuationNamePrefix + layout + string(1, (char) charCode);
|
string customPunctuation = punctuationNamePrefix + layout + string(1, (char) charCode);
|
||||||
string punctuation = punctuationNamePrefix + string(1, (char) charCode);
|
string punctuation = punctuationNamePrefix + string(1, (char) charCode);
|
||||||
|
|
||||||
|
@ -1114,6 +1135,8 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
size_t readingCursorIndex = 0;
|
size_t readingCursorIndex = 0;
|
||||||
size_t builderCursorIndex = _builder->cursorIndex();
|
size_t builderCursorIndex = _builder->cursorIndex();
|
||||||
|
|
||||||
|
NSString *tooltip = @"";
|
||||||
|
|
||||||
// we must do some Unicode codepoint counting to find the actual cursor location for the client
|
// we must do some Unicode codepoint counting to find the actual cursor location for the client
|
||||||
// i.e. we need to take UTF-16 into consideration, for which a surrogate pair takes 2 UniChars
|
// i.e. we need to take UTF-16 into consideration, for which a surrogate pair takes 2 UniChars
|
||||||
// locations
|
// locations
|
||||||
|
@ -1137,9 +1160,30 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
composedStringCursorIndex += [valueString length];
|
composedStringCursorIndex += [valueString length];
|
||||||
readingCursorIndex += spanningLength;
|
readingCursorIndex += spanningLength;
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < codepointCount && readingCursorIndex < builderCursorIndex; i++) {
|
if (codepointCount == spanningLength) {
|
||||||
composedStringCursorIndex += [[NSString stringWithUTF8String:codepoints[i].c_str()] length];
|
for (size_t i = 0; i < codepointCount && readingCursorIndex < builderCursorIndex; i++) {
|
||||||
readingCursorIndex++;
|
composedStringCursorIndex += [[NSString stringWithUTF8String:codepoints[i].c_str()] length];
|
||||||
|
readingCursorIndex++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (readingCursorIndex < builderCursorIndex) {
|
||||||
|
composedStringCursorIndex += [valueString length];
|
||||||
|
readingCursorIndex += spanningLength;
|
||||||
|
if (readingCursorIndex > builderCursorIndex) {
|
||||||
|
readingCursorIndex = builderCursorIndex;
|
||||||
|
}
|
||||||
|
if (builderCursorIndex == 0) {
|
||||||
|
tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is before \"%@\".", @""),
|
||||||
|
[NSString stringWithUTF8String:_builder->readings()[builderCursorIndex].c_str()]];
|
||||||
|
} else if (builderCursorIndex >= _builder->readings().size()) {
|
||||||
|
tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is after \"%@\".", @""),
|
||||||
|
[NSString stringWithUTF8String:_builder->readings()[_builder->readings().size() - 1].c_str()]];
|
||||||
|
} else {
|
||||||
|
tooltip = [NSString stringWithFormat:NSLocalizedString(@"Cursor is between \"%@\" and \"%@\".", @""),
|
||||||
|
[NSString stringWithUTF8String:_builder->readings()[builderCursorIndex - 1].c_str()],
|
||||||
|
[NSString stringWithUTF8String:_builder->readings()[builderCursorIndex].c_str()]];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1155,6 +1199,7 @@ static NSString *const kGraphVizOutputfile = @"/tmp/McBopomofo-visualization.dot
|
||||||
NSInteger cursorIndex = composedStringCursorIndex + [reading length];
|
NSInteger cursorIndex = composedStringCursorIndex + [reading length];
|
||||||
|
|
||||||
InputStateInputting *newState = [[InputStateInputting alloc] initWithComposingBuffer:composedText cursorIndex:cursorIndex];
|
InputStateInputting *newState = [[InputStateInputting alloc] initWithComposingBuffer:composedText cursorIndex:cursorIndex];
|
||||||
|
newState.tooltip = tooltip;
|
||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,10 @@ class KeyHandlerInput: NSObject {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override var description: String {
|
||||||
|
return "<\(super.description) inputText:\(String(describing: inputText)), inputTextIgnoringModifiers:\(String(describing: inputTextIgnoringModifiers)) charCode:\(charCode), keyCode:\(keyCode), flags:\(flags), cursorForwardKey:\(cursorForwardKey), cursorBackwardKey:\(cursorBackwardKey), extraChooseCandidateKey:\(extraChooseCandidateKey), absorbedArrowKey:\(absorbedArrowKey), verticalModeOnlyChooseCandidateKey:\(verticalModeOnlyChooseCandidateKey), emacsKey:\(emacsKey), useVerticalMode:\(useVerticalMode)>"
|
||||||
|
}
|
||||||
|
|
||||||
@objc var isShiftHold: Bool {
|
@objc var isShiftHold: Bool {
|
||||||
flags.contains([.shift])
|
flags.contains([.shift])
|
||||||
}
|
}
|
||||||
|
@ -102,6 +106,10 @@ class KeyHandlerInput: NSObject {
|
||||||
flags.contains([.control])
|
flags.contains([.control])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc var isControlHotKey: Bool {
|
||||||
|
flags.contains([.control]) && inputText?.first?.isLetter ?? false
|
||||||
|
}
|
||||||
|
|
||||||
@objc var isOptionHold: Bool {
|
@objc var isOptionHold: Bool {
|
||||||
flags.contains([.option])
|
flags.contains([.option])
|
||||||
}
|
}
|
||||||
|
@ -114,6 +122,13 @@ class KeyHandlerInput: NSObject {
|
||||||
flags.contains([.numericPad])
|
flags.contains([.numericPad])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc var isReservedKey: Bool {
|
||||||
|
guard let code = KeyCode(rawValue: keyCode) else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return code.rawValue != KeyCode.none.rawValue
|
||||||
|
}
|
||||||
|
|
||||||
@objc var isEnter: Bool {
|
@objc var isEnter: Bool {
|
||||||
KeyCode(rawValue: keyCode) == KeyCode.enter
|
KeyCode(rawValue: keyCode) == KeyCode.enter
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,7 +219,6 @@ class Preferences: NSObject {
|
||||||
defaults.removeObject(forKey: kChineseConversionEngineKey)
|
defaults.removeObject(forKey: kChineseConversionEngineKey)
|
||||||
defaults.removeObject(forKey: kChineseConversionStyle)
|
defaults.removeObject(forKey: kChineseConversionStyle)
|
||||||
defaults.removeObject(forKey: kAssociatedPhrasesEnabledKey)
|
defaults.removeObject(forKey: kAssociatedPhrasesEnabledKey)
|
||||||
// defaults.removeObject(forKey: kAssociatedPhrasesKeys)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UserDefault(key: kKeyboardLayoutPreferenceKey, defaultValue: 0)
|
@UserDefault(key: kKeyboardLayoutPreferenceKey, defaultValue: 0)
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright (c) 2022 and onwards The McBopomofo Authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person
|
||||||
|
// obtaining a copy of this software and associated documentation
|
||||||
|
// files (the "Software"), to deal in the Software without
|
||||||
|
// restriction, including without limitation the rights to use,
|
||||||
|
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following
|
||||||
|
// conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be
|
||||||
|
// included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
// OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Utilities to convert the length of an NSString and a Swift string.
|
||||||
|
class StringUtils: NSObject {
|
||||||
|
|
||||||
|
/// Converts the index in an NSString to the index in a Swift string.
|
||||||
|
///
|
||||||
|
/// An Emoji might be compose by more than one UTF-16 code points, however
|
||||||
|
/// the length of an NSString is only the sum of the UTF-16 code points. It
|
||||||
|
/// causes that the NSString and Swift string representation of the same
|
||||||
|
/// string have different lengths once the string contains such Emoji. The
|
||||||
|
/// method helps to find the index in a Swift string by passing the index
|
||||||
|
/// in an NSString.
|
||||||
|
static func convertToCharIndex(from utf16Index: Int, in string: String) -> Int {
|
||||||
|
var length = 0
|
||||||
|
for (i, character) in string.enumerated() {
|
||||||
|
if length >= utf16Index {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
length += character.utf16.count
|
||||||
|
}
|
||||||
|
return string.count
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc (nextUtf16PositionForIndex:in:)
|
||||||
|
static func nextUtf16Position(for index: Int, in string: String) -> Int {
|
||||||
|
var index = convertToCharIndex(from: index, in: string)
|
||||||
|
if index < string.count {
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
let count = string[..<string.index(string.startIndex, offsetBy: index)].utf16.count
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc (previousUtf16PositionForIndex:in:)
|
||||||
|
static func previousUtf16Position(for index: Int, in string: String) -> Int {
|
||||||
|
var index = convertToCharIndex(from: index, in: string)
|
||||||
|
if index > 0 {
|
||||||
|
index -= 1
|
||||||
|
}
|
||||||
|
let count = string[..<string.index(string.startIndex, offsetBy: index)].utf16.count
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NSString {
|
||||||
|
@objc var count: Int {
|
||||||
|
(self as String).count
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +1,12 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"About McBopomofo…" = "About McBopomofo…";
|
"About McBopomofo…" = "About McBopomofo…";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Clear Learning Dictionary (%ju Items)" = "Clear Learning Dictionary (%ju Items)";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Dump Learning Data to Console" = "Dump Learning Data to Console";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Enable Selection Learning" = "Enable Selection Learning";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"McBopomofo Preferences" = "McBopomofo Preferences";
|
"McBopomofo Preferences" = "McBopomofo Preferences";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Check Later" = "Check Later";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Check for Updates…" = "Check for Updates…";
|
"Check for Updates…" = "Check for Updates…";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Check for Update Completed" = "Check for Update Completed";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"You are already using the latest version of McBopomofo." = "You are already using the latest version of McBopomofo.";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Update Check Failed" = "Update Check Failed";
|
"Update Check Failed" = "Update Check Failed";
|
||||||
|
|
||||||
|
@ -100,3 +82,11 @@
|
||||||
"Half-width punctuation off" = "Half-width punctuation off";
|
"Half-width punctuation off" = "Half-width punctuation off";
|
||||||
|
|
||||||
"Associated Phrases" = "Associated Phrases";
|
"Associated Phrases" = "Associated Phrases";
|
||||||
|
|
||||||
|
"There are special phrases in your text. We don't support adding new phrases in this case." = "There are special phrases in your text. We don't support adding new phrases in this case.";
|
||||||
|
|
||||||
|
"Cursor is before \"%@\"." = "Cursor is before \"%@\".";
|
||||||
|
|
||||||
|
"Cursor is after \"%@\"." = "Cursor is after \"%@\".";
|
||||||
|
|
||||||
|
"Cursor is between \"%@\" and \"%@\"." = "Cursor is between \"%@\" and \"%@\".";
|
||||||
|
|
|
@ -1,30 +1,12 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"About McBopomofo…" = "關於小麥注音…";
|
"About McBopomofo…" = "關於小麥注音…";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Clear Learning Dictionary (%ju Items)" = "清除學習辭典 (%ju 個項目)";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Dump Learning Data to Console" = "將學習辭典內容輸出到 Console 上";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Enable Selection Learning" = "使用自動學習功能";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"McBopomofo Preferences" = "小麥注音偏好設定";
|
"McBopomofo Preferences" = "小麥注音偏好設定";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Check Later" = "晚點再通知我";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Check for Updates…" = "檢查是否有新版…";
|
"Check for Updates…" = "檢查是否有新版…";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Check for Update Completed" = "新版檢查完畢";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"You are already using the latest version of McBopomofo." = "目前使用的已經是最新版本。";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Update Check Failed" = "無法檢查新版";
|
"Update Check Failed" = "無法檢查新版";
|
||||||
|
|
||||||
|
@ -100,3 +82,11 @@
|
||||||
"Half-width punctuation off" = "已經切回到全型標點模式";
|
"Half-width punctuation off" = "已經切回到全型標點模式";
|
||||||
|
|
||||||
"Associated Phrases" = "聯想詞";
|
"Associated Phrases" = "聯想詞";
|
||||||
|
|
||||||
|
"There are special phrases in your text. We don't support adding new phrases in this case." = "您輸入了特殊符號,我們還無法支援在這種狀況下手動加詞。";
|
||||||
|
|
||||||
|
"Cursor is before \"%@\"." = "游標正在「%@」前方";
|
||||||
|
|
||||||
|
"Cursor is after \"%@\"." = "游標正在「%@」後方";
|
||||||
|
|
||||||
|
"Cursor is between \"%@\" and \"%@\"." = "游標正在「%@」與「%@」之間";
|
||||||
|
|
Loading…
Reference in New Issue