Zonble: Swiftify // PreferencesWindowController

This commit is contained in:
ShikiSuen 2022-01-14 22:37:05 +08:00
parent 1572ae5d8f
commit 5b1d05564c
5 changed files with 150 additions and 197 deletions

View File

@ -38,7 +38,7 @@
#import "AppDelegate.h"
#import "OVNonModalAlertWindowController.h"
#import "PreferencesWindowController.h"
#import "vChewing-Swift.h"
#import "frmAboutWindow.h"
extern void LTLoadLanguageModel(void);

View File

@ -1,50 +0,0 @@
//
// PreferencesWindowController.h
//
// Copyright (c) 2021 The vChewing Project.
//
// Contributors:
// Mengjuei Hsieh (@mjhsieh)
// Weizhong Yang (@zonble)
//
// 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/Cocoa.h>
@interface PreferencesWindowController : NSWindowController
{
@private
NSPopUpButton *__weak _fontSizePopUpButton;
NSPopUpButton *__weak _basisKeyboardLayoutButton;
NSComboBox *__weak _selectionKeyComboBox;
}
- (IBAction)updateBasisKeyboardLayoutAction:(id)sender;
- (IBAction)changeSelectionKeyAction:(id)sender;
@property (weak, nonatomic) IBOutlet NSPopUpButton *fontSizePopUpButton;
@property (weak, nonatomic) IBOutlet NSPopUpButton *basisKeyboardLayoutButton;
@property (weak, nonatomic) IBOutlet NSComboBox *selectionKeyComboBox;
@end

View File

@ -1,139 +0,0 @@
//
// PreferencesWindowController.m
//
// Copyright (c) 2021 The vChewing Project.
//
// Contributors:
// Mengjuei Hsieh (@mjhsieh)
// Weizhong Yang (@zonble)
//
// 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 "PreferencesWindowController.h"
#import <Carbon/Carbon.h>
static NSString *const kBasisKeyboardLayoutPreferenceKey = @"BasisKeyboardLayout"; // alphanumeric ("ASCII") input basis
static NSString *const kCandidateKeys = @"CandidateKeys";
static NSString *const kDefaultKeys = @"123456789";
@implementation PreferencesWindowController
@synthesize fontSizePopUpButton = _fontSizePopUpButton;
@synthesize basisKeyboardLayoutButton = _basisKeyboardLayoutButton;
@synthesize selectionKeyComboBox = _selectionKeyComboBox;
- (void)awakeFromNib
{
CFArrayRef list = TISCreateInputSourceList(NULL, true);
NSMenuItem *usKeyboardLayoutItem = nil;
NSMenuItem *chosenItem = nil;
[self.basisKeyboardLayoutButton.menu removeAllItems];
NSString *basisKeyboardLayoutID = [[NSUserDefaults standardUserDefaults] stringForKey:kBasisKeyboardLayoutPreferenceKey];
for (int i = 0; i < CFArrayGetCount(list); i++) {
TISInputSourceRef source = (TISInputSourceRef)CFArrayGetValueAtIndex(list, i);
CFStringRef category = TISGetInputSourceProperty(source, kTISPropertyInputSourceCategory);
if (CFStringCompare(category, kTISCategoryKeyboardInputSource, 0) != kCFCompareEqualTo) {
continue;
}
CFBooleanRef asciiCapable = TISGetInputSourceProperty(source, kTISPropertyInputSourceIsASCIICapable);
if (!CFBooleanGetValue(asciiCapable)) {
continue;
}
CFStringRef sourceType = TISGetInputSourceProperty(source, kTISPropertyInputSourceType);
if (CFStringCompare(sourceType, kTISTypeKeyboardLayout, 0) != kCFCompareEqualTo) {
continue;
}
NSString *sourceID = (__bridge NSString *)TISGetInputSourceProperty(source, kTISPropertyInputSourceID);
NSString *localizedName = (__bridge NSString *)TISGetInputSourceProperty(source, kTISPropertyLocalizedName);
NSMenuItem *item = [[NSMenuItem alloc] init];
item.title = localizedName;
item.representedObject = sourceID;
if ([sourceID isEqualToString:@"com.apple.keylayout.US"]) {
usKeyboardLayoutItem = item;
}
// false if nil
if ([basisKeyboardLayoutID isEqualToString:sourceID]) {
chosenItem = item;
}
[self.basisKeyboardLayoutButton.menu addItem:item];
}
[self.basisKeyboardLayoutButton selectItem:(chosenItem ? chosenItem : usKeyboardLayoutItem)];
CFRelease(list);
self.selectionKeyComboBox.usesDataSource = NO;
[self.selectionKeyComboBox removeAllItems];
[self.selectionKeyComboBox addItemsWithObjectValues:@[
kDefaultKeys,
@"ASDFGHJKL",
@"ASDFZXCVB"
]];
NSString *ckeys = [[NSUserDefaults standardUserDefaults] stringForKey:kCandidateKeys];
if (!ckeys || [ckeys stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length == 0) {
ckeys = kDefaultKeys;
}
[self.selectionKeyComboBox setStringValue:ckeys];
}
- (IBAction)updateBasisKeyboardLayoutAction:(id)sender
{
NSString *sourceID = [[self.basisKeyboardLayoutButton selectedItem] representedObject];
if (sourceID) {
[[NSUserDefaults standardUserDefaults] setObject:sourceID forKey:kBasisKeyboardLayoutPreferenceKey];
}
}
- (IBAction)changeSelectionKeyAction:(id)sender
{
NSString *keys = [[sender stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (keys.length != 9 ||
![keys canBeConvertedToEncoding:NSASCIIStringEncoding]) {
[self.selectionKeyComboBox setStringValue:kDefaultKeys];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:kCandidateKeys];
NSBeep();
return;
}
[self.selectionKeyComboBox setStringValue:keys];
if ([keys isEqualToString:kDefaultKeys]) {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:kCandidateKeys];
} else {
[[NSUserDefaults standardUserDefaults] setObject:keys forKey:kCandidateKeys];
}
}
@end

View File

@ -0,0 +1,144 @@
//
// PreferencesWindowController.swift
//
// Copyright (c) 2011-2022 The OpenVanilla Project.
//
// Contributors:
// Mengjuei Hsieh (@mjhsieh) @ OpenVanilla
// Weizhong Yang (@zonble) @ OpenVanilla
// Lukhnos Liu (@lukhnos) @ OpenVanilla
//
// 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
import Carbon
private let kBasisKeyboardLayoutPreferenceKey = "BasisKeyboardLayout"
private let kCandidateKeys = "CandidateKeys"
private let kDefaultKeys = "123456789"
// Please note that the class should be exposed as "PreferencesWindowController"
// in Objective-C in order to let IMK to see the same class name as
// the "InputMethodServerPreferencesWindowControllerClass" in Info.plist.
@objc (PreferencesWindowController) class PreferencesWindowController: NSWindowController {
@IBOutlet weak var fontSizePopUpButton: NSPopUpButton!
@IBOutlet weak var basisKeyboardLayoutButton: NSPopUpButton!
@IBOutlet weak var selectionKeyComboBox: NSComboBox!
override func awakeFromNib() {
let list = TISCreateInputSourceList(nil, true).takeRetainedValue() as! [TISInputSource]
var usKeyboardLayoutItem: NSMenuItem? = nil
var chosenItem: NSMenuItem? = nil
basisKeyboardLayoutButton.menu?.removeAllItems()
let basisKeyboardLayoutID = UserDefaults.standard.string(forKey: kBasisKeyboardLayoutPreferenceKey)
for source in list {
if let categoryPtr = TISGetInputSourceProperty(source, kTISPropertyInputSourceCategory) {
let category = Unmanaged<CFString>.fromOpaque(categoryPtr).takeUnretainedValue()
if category != kTISCategoryKeyboardInputSource {
continue
}
} else {
continue
}
if let asciiCapablePtr = TISGetInputSourceProperty(source, kTISPropertyInputSourceIsASCIICapable) {
let asciiCapable = Unmanaged<CFBoolean>.fromOpaque(asciiCapablePtr).takeUnretainedValue()
if asciiCapable != kCFBooleanTrue {
continue
}
} else {
continue
}
if let sourceTypePtr = TISGetInputSourceProperty(source, kTISPropertyInputSourceType) {
let sourceType = Unmanaged<CFString>.fromOpaque(sourceTypePtr).takeUnretainedValue()
if sourceType != kTISTypeKeyboardLayout {
continue
}
} else {
continue
}
guard let sourceIDPtr = TISGetInputSourceProperty(source, kTISPropertyInputSourceID),
let localizedNamePtr = TISGetInputSourceProperty(source, kTISPropertyLocalizedName) else {
continue
}
let sourceID = String(Unmanaged<CFString>.fromOpaque(sourceIDPtr).takeUnretainedValue())
let localizedName = String(Unmanaged<CFString>.fromOpaque(localizedNamePtr).takeUnretainedValue())
let menuItem = NSMenuItem()
menuItem.title = localizedName
menuItem.representedObject = sourceID
if sourceID == "com.apple.keylayout.US" {
usKeyboardLayoutItem = menuItem
}
if basisKeyboardLayoutID == sourceID {
chosenItem = menuItem
}
basisKeyboardLayoutButton.menu?.addItem(menuItem)
}
basisKeyboardLayoutButton.select(chosenItem ?? usKeyboardLayoutItem)
selectionKeyComboBox.usesDataSource = false
selectionKeyComboBox.addItems(withObjectValues: [kDefaultKeys, "asdfghjkl", "asdfzxcvb"])
var candidateSelectionKeys = (UserDefaults.standard.string(forKey: kCandidateKeys) ?? kDefaultKeys)
.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
if candidateSelectionKeys.isEmpty {
candidateSelectionKeys = kDefaultKeys
}
selectionKeyComboBox.stringValue = candidateSelectionKeys
}
@IBAction func updateBasisKeyboardLayoutAction(_ sender:Any) {
if let sourceID = basisKeyboardLayoutButton.selectedItem?.representedObject {
UserDefaults.standard.set(sourceID, forKey: kBasisKeyboardLayoutPreferenceKey)
}
}
@IBAction func changeSelectionKeyAction(_ sender: Any) {
let keys = (sender as AnyObject).stringValue.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
if keys.count != 9 || !keys.canBeConverted(to: .ascii) {
selectionKeyComboBox.stringValue = kDefaultKeys
UserDefaults.standard.removeObject(forKey: kCandidateKeys)
NSSound.beep()
return
}
selectionKeyComboBox.stringValue = keys
if keys == kDefaultKeys {
UserDefaults.standard.removeObject(forKey: kCandidateKeys)
} else {
UserDefaults.standard.set(keys, forKey: kCandidateKeys)
}
}
}

View File

@ -18,6 +18,7 @@
5BC3FB83278492DE0022E99A /* data-chs.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5BC3FB82278492DE0022E99A /* data-chs.txt */; };
5BDF2CFE2791BE4400838ADB /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDF2CFD2791BE4400838ADB /* InputSourceHelper.swift */; };
5BDF2CFF2791BECC00838ADB /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDF2CFD2791BE4400838ADB /* InputSourceHelper.swift */; };
5BDF2D012791C03B00838ADB /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDF2D002791C03B00838ADB /* PreferencesWindowController.swift */; };
5BF4A6FE27844738007DC6E7 /* frmAboutWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BF4A6FC27844738007DC6E7 /* frmAboutWindow.m */; };
5BF4A70027844DC5007DC6E7 /* frmAboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BF4A70227844DC5007DC6E7 /* frmAboutWindow.xib */; };
6A0421A815FEF3F50061ED63 /* FastLM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A0421A615FEF3F50061ED63 /* FastLM.cpp */; };
@ -25,7 +26,6 @@
6A0D4ED015FC0D6400ABF4B3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EC415FC0D6400ABF4B3 /* AppDelegate.m */; };
6A0D4ED215FC0D6400ABF4B3 /* InputMethodController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EC715FC0D6400ABF4B3 /* InputMethodController.mm */; };
6A0D4ED315FC0D6400ABF4B3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4EC815FC0D6400ABF4B3 /* main.m */; };
6A0D4ED515FC0D6400ABF4B3 /* PreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4ECC15FC0D6400ABF4B3 /* PreferencesWindowController.m */; };
6A0D4F0815FC0DA600ABF4B3 /* Bopomofo.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 6A0D4EEF15FC0DA600ABF4B3 /* Bopomofo.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 */; };
@ -94,6 +94,7 @@
5BC3EE1A278FC48C00F5E44C /* HorizontalCandidateController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalCandidateController.swift; sourceTree = "<group>"; };
5BC3FB82278492DE0022E99A /* data-chs.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "data-chs.txt"; sourceTree = "<group>"; };
5BDF2CFD2791BE4400838ADB /* InputSourceHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputSourceHelper.swift; sourceTree = "<group>"; };
5BDF2D002791C03B00838ADB /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
5BF4A6FB27844738007DC6E7 /* frmAboutWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = frmAboutWindow.h; sourceTree = "<group>"; };
5BF4A6FC27844738007DC6E7 /* frmAboutWindow.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = frmAboutWindow.m; sourceTree = "<group>"; };
5BF4A70327844DD0007DC6E7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/frmAboutWindow.xib; sourceTree = "<group>"; };
@ -111,8 +112,6 @@
6A0D4EC615FC0D6400ABF4B3 /* InputMethodController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputMethodController.h; sourceTree = "<group>"; };
6A0D4EC715FC0D6400ABF4B3 /* InputMethodController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InputMethodController.mm; sourceTree = "<group>"; };
6A0D4EC815FC0D6400ABF4B3 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
6A0D4ECB15FC0D6400ABF4B3 /* PreferencesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesWindowController.h; sourceTree = "<group>"; };
6A0D4ECC15FC0D6400ABF4B3 /* PreferencesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesWindowController.m; sourceTree = "<group>"; };
6A0D4EEF15FC0DA600ABF4B3 /* Bopomofo.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Bopomofo.tiff; sourceTree = "<group>"; };
6A0D4EF015FC0DA600ABF4B3 /* Bopomofo@2x.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "Bopomofo@2x.tiff"; sourceTree = "<group>"; };
6A0D4EF515FC0DA600ABF4B3 /* vChewing-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "vChewing-Info.plist"; sourceTree = "<group>"; };
@ -264,7 +263,6 @@
6A0D4EC215FC0D3C00ABF4B3 /* Source */ = {
isa = PBXGroup;
children = (
5BDF2CFD2791BE4400838ADB /* InputSourceHelper.swift */,
5B58E87D278413E7003EA2AD /* MITLicense.txt */,
6A0D4ED815FC0DA600ABF4B3 /* CandidateUI */,
6A38BBDD15FC115800A8A51F /* Data */,
@ -281,9 +279,9 @@
6A0D4EF615FC0DA600ABF4B3 /* vChewing-Prefix.pch */,
6AFF97EF253B299E007F1C49 /* OVNonModalAlertWindowController.h */,
6AFF97F1253B299E007F1C49 /* OVNonModalAlertWindowController.m */,
6A0D4ECB15FC0D6400ABF4B3 /* PreferencesWindowController.h */,
6A0D4ECC15FC0D6400ABF4B3 /* PreferencesWindowController.m */,
5BDF2D002791C03B00838ADB /* PreferencesWindowController.swift */,
D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */,
5BDF2CFD2791BE4400838ADB /* InputSourceHelper.swift */,
D427A9BF25ED28CC005D43E0 /* vChewing-Bridging-Header.h */,
5BA923AC2791B7C20001323A /* vChewingInstaller-Bridging-Header.h */,
5B42B63E27876FDC00BB9B9F /* UserOverrideModel.cpp */,
@ -630,11 +628,11 @@
5BF4A6FE27844738007DC6E7 /* frmAboutWindow.m in Sources */,
5BC3EE1B278FC48C00F5E44C /* VerticalCandidateController.swift in Sources */,
5B42B64027876FDC00BB9B9F /* UserOverrideModel.cpp in Sources */,
6A0D4ED515FC0D6400ABF4B3 /* PreferencesWindowController.m in Sources */,
6AFF97F3253B299E007F1C49 /* OVNonModalAlertWindowController.m in Sources */,
D427A9C125ED28CC005D43E0 /* OpenCCBridge.swift in Sources */,
6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */,
6A0421A815FEF3F50061ED63 /* FastLM.cpp in Sources */,
5BDF2D012791C03B00838ADB /* PreferencesWindowController.swift in Sources */,
5BC3EE1C278FC48C00F5E44C /* VTCandidateController.swift in Sources */,
5BC3EE1D278FC48C00F5E44C /* HorizontalCandidateController.swift in Sources */,
);