diff --git a/Source/Base.lproj/preferences.xib b/Source/Base.lproj/preferences.xib index e62722b8..5d28fd0c 100644 --- a/Source/Base.lproj/preferences.xib +++ b/Source/Base.lproj/preferences.xib @@ -1,7 +1,6 @@ - @@ -218,17 +217,17 @@ + - - - - - - + + + + + + + + + diff --git a/Source/Beep.aif b/Source/Beep.aif new file mode 100644 index 00000000..ba0f9895 Binary files /dev/null and b/Source/Beep.aif differ diff --git a/Source/Engine/SFX/clsSFX.swift b/Source/Engine/SFX/clsSFX.swift new file mode 100644 index 00000000..1b184f76 --- /dev/null +++ b/Source/Engine/SFX/clsSFX.swift @@ -0,0 +1,74 @@ +// +// clsSFX.swift +// +// Copyright (c) 2021-2022 The vChewing Project. +// +// Contributors: +// Shiki Suen (@ShikiSuen) @ vChewing +// Isaac Xen a.k.a. ix4n33 (@IsaacXen) @ no affiliation +// +// Based on the Syrup Project and the Formosana Library +// by Lukhnos Liu (@lukhnos). +// +// 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 Cocoa + +@objc public class clsSFX: NSObject, NSSoundDelegate { + private static let shared = clsSFX() + private override init(){ + super.init() + } + private var currentBeep: NSSound? + private func beep() { + // Stop existing beep + if let beep = currentBeep { + if beep.isPlaying { + beep.stop() + } + } + // Create a new beep sound if possible + var sndBeep:String + if Preferences.shouldNotFartInLieuOfBeep == false { + sndBeep = "Fart" + } else { + sndBeep = "Beep" + } + guard + let beep = NSSound(named:sndBeep) + else { + NSSound.beep() + return + } + beep.delegate = self + beep.volume = 0.4 + beep.play() + currentBeep = beep + } + @objc public func sound(_ sound: NSSound, didFinishPlaying flag: Bool) { + currentBeep = nil + } + @objc static func beep() { + shared.beep() + } +} diff --git a/Source/Engine/vChewing/clsOOBEDefaults.swift b/Source/Engine/vChewing/clsOOBEDefaults.swift index b2c059fe..56975c8b 100644 --- a/Source/Engine/vChewing/clsOOBEDefaults.swift +++ b/Source/Engine/vChewing/clsOOBEDefaults.swift @@ -33,6 +33,7 @@ import Cocoa +private let kShouldNotFartInLieuOfBeep = "ShouldNotFartInLieuOfBeep" private let kCheckUpdateAutomatically = "CheckUpdateAutomatically" private let kCandidateListTextSize = "CandidateListTextSize" private let kChooseCandidateUsingSpaceKey = "ChooseCandidateUsingSpaceKey" @@ -75,6 +76,11 @@ private let kChineseConversionEnabledKey = "ChineseConversionEnabled" if UserDefaults.standard.object(forKey: kChineseConversionEnabledKey) == nil { UserDefaults.standard.set(Preferences.chineseConversionEnabled, forKey: kChineseConversionEnabledKey) } + + // 預設沒事不要在那裡放屁 + if UserDefaults.standard.object(forKey: kShouldNotFartInLieuOfBeep) == nil { + UserDefaults.standard.set(Preferences.shouldNotFartInLieuOfBeep, forKey: kShouldNotFartInLieuOfBeep) + } UserDefaults.standard.synchronize() } diff --git a/Source/Fart.aif b/Source/Fart.aif new file mode 100644 index 00000000..84c06b39 Binary files /dev/null and b/Source/Fart.aif differ diff --git a/Source/InputMethodController.mm b/Source/InputMethodController.mm index 5f6b808d..7582fdcf 100644 --- a/Source/InputMethodController.mm +++ b/Source/InputMethodController.mm @@ -489,8 +489,8 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; } - (void)beep { - // use the system's default sound (configurable in System Preferences) to give a warning - NSBeep(); + // use the vChewing beep. + [clsSFX beep]; } - (string)_currentLayout diff --git a/Source/PreferencesModule.swift b/Source/PreferencesModule.swift index 0ad0fb30..1413218b 100644 --- a/Source/PreferencesModule.swift +++ b/Source/PreferencesModule.swift @@ -45,6 +45,7 @@ private let kChooseCandidateUsingSpaceKey = "ChooseCandidateUsingSpaceKey" private let kChineseConversionEnabledKey = "ChineseConversionEnabled" private let kHalfWidthPunctuationEnabledKey = "HalfWidthPunctuationEnable" private let kEscToCleanInputBufferKey = "EscToCleanInputBuffer" +private let kShouldNotFartInLieuOfBeep = "ShouldNotFartInLieuOfBeep" private let kCandidateTextFontName = "CandidateTextFontName" private let kCandidateKeyLabelFontName = "CandidateKeyLabelFontName" @@ -245,6 +246,15 @@ struct ComposingKeys { @UserDefault(key: kChooseCandidateUsingSpaceKey, defaultValue: true) @objc static var chooseCandidateUsingSpace: Bool + + @UserDefault(key: kShouldNotFartInLieuOfBeep, defaultValue: true) + @objc static var shouldNotFartInLieuOfBeep: Bool + + @objc static func toggleShouldNotFartInLieuOfBeep() -> Bool { + shouldNotFartInLieuOfBeep = !shouldNotFartInLieuOfBeep + UserDefaults.standard.set(shouldNotFartInLieuOfBeep, forKey: kShouldNotFartInLieuOfBeep) + return shouldNotFartInLieuOfBeep + } @UserDefault(key: kChineseConversionEnabledKey, defaultValue: false) @objc static var chineseConversionEnabled: Bool diff --git a/Source/PreferencesWindowController.swift b/Source/PreferencesWindowController.swift index c276871f..d05289bf 100644 --- a/Source/PreferencesWindowController.swift +++ b/Source/PreferencesWindowController.swift @@ -51,6 +51,7 @@ extension RangeReplaceableCollection where Element: Hashable { @IBOutlet weak var fontSizePopUpButton: NSPopUpButton! @IBOutlet weak var basisKeyboardLayoutButton: NSPopUpButton! @IBOutlet weak var selectionKeyComboBox: NSComboBox! + @IBOutlet weak var clickedWhetherIMEShouldNotFartToggle: NSButton! override func awakeFromNib() { let list = TISCreateInputSourceList(nil, true).takeRetainedValue() as! [TISInputSource] @@ -151,12 +152,16 @@ extension RangeReplaceableCollection where Element: Hashable { } } + @IBAction func clickedWhetherIMEShouldNotFartToggleAction(_ sender: Any) { + clsSFX.beep() + } + @IBAction func changeSelectionKeyAction(_ sender: Any) { let keys = (sender as AnyObject).stringValue.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).charDeDuplicate if keys.count != 9 || !keys.canBeConverted(to: .ascii) { selectionKeyComboBox.stringValue = Preferences.defaultKeys Preferences.candidateKeys = Preferences.defaultKeys // 修正記錄:這裡千萬不能是 nil,否則會鬼打牆。 - NSSound.beep() + clsSFX.beep() return } diff --git a/Source/en.lproj/preferences.strings b/Source/en.lproj/preferences.strings index 76042fc3..da828752 100644 --- a/Source/en.lproj/preferences.strings +++ b/Source/en.lproj/preferences.strings @@ -101,6 +101,9 @@ /* Class = "NSTextFieldCell"; title = "UI language setting:"; ObjectID = "9DS-Rc-TXq"; */ "9DS-Rc-TXq.title" = "UI language setting:"; +/* Class = "NSButtonCell"; title = "Stop farting (when typed phonetic combination is invalid, etc.)"; ObjectID = "ArK-Vk-OoT"; */ +"ArK-Vk-OoT.title" = "Stop farting (when typed phonetic combination is invalid, etc.)"; + /* Class = "NSButtonCell"; title = "Auto-convert traditional Chinese glyphs to KangXi characters"; ObjectID = "BSK-bH-Gct"; */ "BSK-bH-Gct.title" = "Auto-convert traditional Chinese glyphs to KangXi characters"; diff --git a/Source/zh-Hans.lproj/preferences.strings b/Source/zh-Hans.lproj/preferences.strings index 572b9b32..0b1869bf 100644 --- a/Source/zh-Hans.lproj/preferences.strings +++ b/Source/zh-Hans.lproj/preferences.strings @@ -101,6 +101,9 @@ /* Class = "NSTextFieldCell"; title = "UI language setting:"; ObjectID = "9DS-Rc-TXq"; */ "9DS-Rc-TXq.title" = "介面语言设定:"; +/* Class = "NSButtonCell"; title = "Stop farting (when typed phonetic combination is invalid, etc.)"; ObjectID = "ArK-Vk-OoT"; */ +"ArK-Vk-OoT.title" = "不要放屁 // 例:当输入的音韵有误时,等。"; + /* Class = "NSButtonCell"; title = "Auto-convert traditional Chinese glyphs to KangXi characters"; ObjectID = "BSK-bH-Gct"; */ "BSK-bH-Gct.title" = "自动将繁体中文字转换为康熙字"; diff --git a/Source/zh-Hant.lproj/preferences.strings b/Source/zh-Hant.lproj/preferences.strings index a43aa075..490bd454 100644 --- a/Source/zh-Hant.lproj/preferences.strings +++ b/Source/zh-Hant.lproj/preferences.strings @@ -101,6 +101,9 @@ /* Class = "NSTextFieldCell"; title = "UI language setting:"; ObjectID = "9DS-Rc-TXq"; */ "9DS-Rc-TXq.title" = "介面語言設定:"; +/* Class = "NSButtonCell"; title = "Stop farting (when typed phonetic combination is invalid, etc.)"; ObjectID = "ArK-Vk-OoT"; */ +"ArK-Vk-OoT.title" = "不要放屁 // 例:當輸入的音韻有誤時,等。"; + /* Class = "NSButtonCell"; title = "Auto-convert traditional Chinese glyphs to KangXi characters"; ObjectID = "BSK-bH-Gct"; */ "BSK-bH-Gct.title" = "自動將繁體中文字轉換為康熙字"; diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 47e78093..34dcd2cf 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -23,6 +23,9 @@ 5BC3EE1C278FC48C00F5E44C /* VTCandidateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3EE19278FC48C00F5E44C /* VTCandidateController.swift */; }; 5BC3EE1D278FC48C00F5E44C /* HorizontalCandidateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3EE1A278FC48C00F5E44C /* HorizontalCandidateController.swift */; }; 5BC3FB83278492DE0022E99A /* data-chs.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BC3FB82278492DE0022E99A /* data-chs.txt */; }; + 5BD0D19427940E9D0008F48E /* Fart.aif in Resources */ = {isa = PBXBuildFile; fileRef = 5BD0D19327940E9D0008F48E /* Fart.aif */; }; + 5BD0D19A27943D390008F48E /* clsSFX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD0D19927943D390008F48E /* clsSFX.swift */; }; + 5BD0D19F279454F60008F48E /* Beep.aif in Resources */ = {isa = PBXBuildFile; fileRef = 5BD0D19E279454F60008F48E /* Beep.aif */; }; 5BD0D1A4279463510008F48E /* clsOOBEDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD0D1A3279463510008F48E /* clsOOBEDefaults.swift */; }; 5BDF2CFE2791BE4400838ADB /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDF2CFD2791BE4400838ADB /* InputSourceHelper.swift */; }; 5BDF2CFF2791BECC00838ADB /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDF2CFD2791BE4400838ADB /* InputSourceHelper.swift */; }; @@ -114,6 +117,9 @@ 5BC3EE19278FC48C00F5E44C /* VTCandidateController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VTCandidateController.swift; sourceTree = ""; }; 5BC3EE1A278FC48C00F5E44C /* HorizontalCandidateController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalCandidateController.swift; sourceTree = ""; }; 5BC3FB82278492DE0022E99A /* data-chs.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "data-chs.txt"; sourceTree = ""; }; + 5BD0D19327940E9D0008F48E /* Fart.aif */ = {isa = PBXFileReference; lastKnownFileType = file; path = Fart.aif; sourceTree = ""; }; + 5BD0D19927943D390008F48E /* clsSFX.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = clsSFX.swift; sourceTree = ""; }; + 5BD0D19E279454F60008F48E /* Beep.aif */ = {isa = PBXFileReference; lastKnownFileType = file; path = Beep.aif; sourceTree = ""; }; 5BD0D1A3279463510008F48E /* clsOOBEDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = clsOOBEDefaults.swift; sourceTree = ""; }; 5BDF2CFD2791BE4400838ADB /* InputSourceHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputSourceHelper.swift; sourceTree = ""; }; 5BDF2D002791C03B00838ADB /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = ""; }; @@ -287,6 +293,14 @@ path = Keyboard; sourceTree = ""; }; + 5BD0D19827943D270008F48E /* SFX */ = { + isa = PBXGroup; + children = ( + 5BD0D19927943D390008F48E /* clsSFX.swift */, + ); + path = SFX; + sourceTree = ""; + }; 5BE798A12792E50F00337FF9 /* UI */ = { isa = PBXGroup; children = ( @@ -396,6 +410,7 @@ 6A0D4F1215FC0EB100ABF4B3 /* Engine */ = { isa = PBXGroup; children = ( + 5BD0D19827943D270008F48E /* SFX */, 5BC2D2892793B8DB002C0BEC /* Keyboard */, 5BC2D2832793B434002C0BEC /* vChewing */, 5BA8DAFE27928120009C9FFF /* LanguageModel */, @@ -475,6 +490,8 @@ 6A0D4F4715FC0EB900ABF4B3 /* Resources */ = { isa = PBXGroup; children = ( + 5BD0D19E279454F60008F48E /* Beep.aif */, + 5BD0D19327940E9D0008F48E /* Fart.aif */, 5BF4A70227844DC5007DC6E7 /* frmAboutWindow.xib */, 6AFF97F0253B299E007F1C49 /* NonModalAlertWindowController.xib */, 6A0D4EEE15FC0DA600ABF4B3 /* Images */, @@ -652,11 +669,13 @@ 5B000FC3278495AD004F02AC /* SimpBopomofo.tiff in Resources */, 6A0D4F5815FC0EF900ABF4B3 /* Localizable.strings in Resources */, 6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */, - 6A38BC1515FC117A00A8A51F /* data.txt in Resources */, + 5BD0D19427940E9D0008F48E /* Fart.aif in Resources */, + 6A38BC1515FC117A00A8A51F /* data-cht.txt in Resources */, 6AFF97F2253B299E007F1C49 /* NonModalAlertWindowController.xib in Resources */, 5B58E87F278413E7003EA2AD /* MITLicense.txt in Resources */, 6A187E2616004C5900466B2E /* MainMenu.xib in Resources */, 5BF4A70027844DC5007DC6E7 /* frmAboutWindow.xib in Resources */, + 5BD0D19F279454F60008F48E /* Beep.aif in Resources */, 5BC3FB83278492DE0022E99A /* data-chs.txt in Resources */, 5B000FC4278495AD004F02AC /* SimpBopomofo@2x.tiff in Resources */, 5BC2D2872793B434002C0BEC /* CMakeLists.txt in Resources */, @@ -706,6 +725,7 @@ files = ( 5BDF2CFE2791BE4400838ADB /* InputSourceHelper.swift in Sources */, 5BC2D28B2793B8FB002C0BEC /* EmacsKeyHelper.swift in Sources */, + 5BD0D19A27943D390008F48E /* clsSFX.swift in Sources */, 5BE798A72793280C00337FF9 /* NotifierController.swift in Sources */, 5B5F4F93279294A300922DC2 /* LanguageModelManager.mm in Sources */, 6A0D4ED215FC0D6400ABF4B3 /* InputMethodController.mm in Sources */,