global shortcut

This commit is contained in:
yanue 2020-02-06 23:42:49 +08:00
parent 0f1018f3ac
commit 65d0dcb0fd
10 changed files with 175 additions and 26 deletions

View File

@ -15,9 +15,8 @@ target 'V2rayU' do
pod 'Sparkle'
pod 'QRCoder'
pod "GCDWebServer"
# pod 'Socket.IO-Client-Swift'
# pod 'SwiftSocket'
pod 'SwiftSocket', :git => 'https://github.com/odariusgeorge/SwiftSocket.git', :branch => 'patch-1'
pod 'MASShortcut'
end

View File

@ -3,6 +3,7 @@ PODS:
- GCDWebServer (3.5.2):
- GCDWebServer/Core (= 3.5.2)
- GCDWebServer/Core (3.5.2)
- MASShortcut (2.3.6)
- Preferences (0.3.0)
- QRCoder (1.1.0)
- Sparkle (1.21.3)
@ -12,6 +13,7 @@ PODS:
DEPENDENCIES:
- Alamofire
- GCDWebServer
- MASShortcut
- Preferences (from `https://github.com/sindresorhus/Preferences.git`)
- QRCoder
- Sparkle
@ -22,6 +24,7 @@ SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
- Alamofire
- GCDWebServer
- MASShortcut
- QRCoder
- Sparkle
- SwiftyJSON
@ -44,12 +47,13 @@ CHECKOUT OPTIONS:
SPEC CHECKSUMS:
Alamofire: ae5c501addb7afdbb13687d7f2f722c78734c2d3
GCDWebServer: ead88cd14596dd4eae4f5830b8877c87c8728990
MASShortcut: 9c215e8a8a78f3d01ce56da48e2730ab66b538fa
Preferences: cfd4b0cbc5adfb5781b819ad3a000324d0fc9f48
QRCoder: cbd2bee531cc86d286df7942334cfed94c803ae4
Sparkle: 3f75576db8b0265adef36c43249d747f22d0b708
SwiftSocket: 2f7a7e26a7489f5f33b69da914ec366368dfcbcc
SwiftyJSON: 36413e04c44ee145039d332b4f4e2d3e8d6c4db7
PODFILE CHECKSUM: 6a9efe1e965935629aec3f60f29e9a3968331249
PODFILE CHECKSUM: 407a3efc71b95e99861a0c05290182ea384ac364
COCOAPODS: 1.8.4

View File

@ -19,6 +19,7 @@
6610ECB721742AFD008FC401 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 664EB378216C9A5F00B6AE0D /* MainMenu.xib */; };
6618372923E9BF1A000F7410 /* ToastWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6618372823E9BF1A000F7410 /* ToastWindow.swift */; };
6618372E23E9BF74000F7410 /* ToastWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6618372C23E9BF73000F7410 /* ToastWindow.xib */; };
66193A7C23EC5F1500289B6A /* Shortcut.m in Sources */ = {isa = PBXBuildFile; fileRef = 66193A7B23EC5F1400289B6A /* Shortcut.m */; };
66406AF42183320000B56041 /* Sample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66406AF32183320000B56041 /* Sample.swift */; };
664EB375216C9A5E00B6AE0D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664EB374216C9A5E00B6AE0D /* AppDelegate.swift */; };
664EB377216C9A5F00B6AE0D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 664EB376216C9A5F00B6AE0D /* Assets.xcassets */; };
@ -130,6 +131,9 @@
66107B8922DEE445002FFB60 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
6618372823E9BF1A000F7410 /* ToastWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToastWindow.swift; sourceTree = "<group>"; };
6618372D23E9BF73000F7410 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ToastWindow.xib; sourceTree = "<group>"; };
6618373D23EB03EC000F7410 /* V2rayU-Bridging-header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "V2rayU-Bridging-header.h"; sourceTree = "<group>"; };
66193A7A23EC5EFA00289B6A /* Shortcut.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Shortcut.h; sourceTree = "<group>"; };
66193A7B23EC5F1400289B6A /* Shortcut.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Shortcut.m; sourceTree = "<group>"; };
66406AF32183320000B56041 /* Sample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sample.swift; sourceTree = "<group>"; };
6646669221CBC0860094F0B7 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
664666A021CBD6C60094F0B7 /* libPods-V2rayUTool.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libPods-V2rayUTool.a"; sourceTree = BUILT_PRODUCTS_DIR; };
@ -332,6 +336,9 @@
6618372823E9BF1A000F7410 /* ToastWindow.swift */,
6618372C23E9BF73000F7410 /* ToastWindow.xib */,
66107B8822DEDBE4002FFB60 /* Localizable.strings */,
66193A7A23EC5EFA00289B6A /* Shortcut.h */,
66193A7B23EC5F1400289B6A /* Shortcut.m */,
6618373D23EB03EC000F7410 /* V2rayU-Bridging-header.h */,
);
path = V2rayU;
sourceTree = "<group>";
@ -643,6 +650,7 @@
6608D9DC2182C6D200A0E0DD /* v2rayInbound.swift in Sources */,
6608D9DE2182C92D00A0E0DD /* v2rayOutbound.swift in Sources */,
6618372923E9BF1A000F7410 /* ToastWindow.swift in Sources */,
66193A7C23EC5F1500289B6A /* Shortcut.m in Sources */,
6608D9DA2182C69D00A0E0DD /* v2rayStruct.swift in Sources */,
66F07CF9236D79540088A4AE /* ping.swift in Sources */,
664EB392216CA9E800B6AE0D /* ConfigWindow.swift in Sources */,
@ -999,6 +1007,7 @@
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1.5.0;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = RJYEH6TCJD;
INFOPLIST_FILE = V2rayU/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -1010,6 +1019,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = NO;
SWIFT_OBJC_BRIDGING_HEADER = "V2rayU/V2rayU-Bridging-header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.2;
};
@ -1025,6 +1035,7 @@
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1.5.0;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = RJYEH6TCJD;
INFOPLIST_FILE = V2rayU/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@ -1036,6 +1047,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = NO;
SWIFT_OBJC_BRIDGING_HEADER = "V2rayU/V2rayU-Bridging-header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.2;
};

View File

@ -12,6 +12,9 @@ import ServiceManagement
let launcherAppIdentifier = "net.yanue.V2rayU.Launcher"
let appVersion = getAppVersion()
let NOTIFY_TOGGLE_RUNNING_SHORTCUT = Notification.Name(rawValue: "NOTIFY_TOGGLE_RUNNING_SHORTCUT")
let NOTIFY_SWITCH_PROXY_MODE_SHORTCUT = Notification.Name(rawValue: "NOTIFY_SWITCH_PROXY_MODE_SHORTCUT")
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
// bar menu
@ -64,6 +67,21 @@ class AppDelegate: NSObject, NSApplicationDelegate {
NSApplication.shared.terminate(self)
}
}
// set global hotkey
let notifyCenter = NotificationCenter.default
notifyCenter.addObserver(forName: NOTIFY_TOGGLE_RUNNING_SHORTCUT, object: nil, queue: nil, using: {
notice in
ToggleRunning()
})
notifyCenter.addObserver(forName: NOTIFY_SWITCH_PROXY_MODE_SHORTCUT, object: nil, queue: nil, using: {
notice in
SwitchProxyMode()
})
// Register global hotkey
ShortcutsController.bindShortcuts()
}
func checkDefault() {
@ -117,6 +135,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
func applicationWillTerminate(_ aNotification: Notification) {
// unregister All shortcut
MASShortcutMonitor.shared().unregisterAllShortcuts()
// Insert code here to tear down your application
V2rayLaunch.Stop()
// restore system proxy

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15400" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15400"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@ -64,8 +64,7 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Servers" id="NCx-DY-Hm4"/>
</menuItem>
<menuItem title="Configure..." id="YoX-II-o27" userLabel="Configure">
<modifierMask key="keyEquivalentModifierMask"/>
<menuItem title="Configure..." keyEquivalent="c" id="YoX-II-o27" userLabel="Configure">
<connections>
<action selector="openConfig:" target="hcZ-V7-Dui" id="cu6-mU-Y02"/>
</connections>
@ -101,8 +100,7 @@
<action selector="scanQrcode:" target="hcZ-V7-Dui" id="URj-Vl-1TY"/>
</connections>
</menuItem>
<menuItem title="Share QR Code" id="0vX-fS-8FW">
<modifierMask key="keyEquivalentModifierMask"/>
<menuItem title="Share QR Code" keyEquivalent="s" id="0vX-fS-8FW">
<connections>
<action selector="generateQrcode:" target="hcZ-V7-Dui" id="cUu-eO-w0Z"/>
</connections>
@ -116,8 +114,7 @@
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="FfA-RW-Poe"/>
<menuItem title="Preferences..." id="6jp-RJ-ww9" userLabel="Preference">
<modifierMask key="keyEquivalentModifierMask"/>
<menuItem title="Preferences..." keyEquivalent="," id="6jp-RJ-ww9" userLabel="Preference">
<connections>
<action selector="openPreferenceGeneral:" target="hcZ-V7-Dui" id="ak7-LN-QXy"/>
</connections>

View File

@ -20,7 +20,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="87d-wY-Ocw">
<rect key="frame" x="57" y="220" width="163" height="18"/>
<rect key="frame" x="46" y="225" width="163" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Launch V2rayU at login" bezelStyle="regularSquare" imagePosition="left" inset="2" id="NZE-cI-j04">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@ -31,7 +31,7 @@
</buttonCell>
</button>
<stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" fixedFrame="YES" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="UJB-Wh-dgF">
<rect key="frame" x="59" y="194" width="216" height="14"/>
<rect key="frame" x="48" y="199" width="216" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<button horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="tgw-Vy-D08" userLabel="Check for Updates automutically">
@ -53,7 +53,7 @@
</customSpacing>
</stackView>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SUN-rQ-2fp">
<rect key="frame" x="162" y="117" width="67" height="17"/>
<rect key="frame" x="66" y="146" width="67" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="inline" title="clear logs" bezelStyle="inline" alignment="center" borderStyle="border" inset="2" id="2vr-uU-fMI">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -64,18 +64,18 @@
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FpH-fQ-KqG">
<rect key="frame" x="78" y="116" width="71" height="19"/>
<rect key="frame" x="137" y="145" width="71" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundRect" title="show logs" bezelStyle="roundedRect" alignment="center" borderStyle="border" inset="2" id="0fD-xL-Tly">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="cellTitle"/>
<font key="font" metaFont="label" size="12"/>
</buttonCell>
<connections>
<action selector="openLogs:" target="-2" id="ZHd-mS-hgK"/>
</connections>
</button>
<stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" fixedFrame="YES" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="WJk-22-Sun">
<rect key="frame" x="59" y="143" width="231" height="14"/>
<rect key="frame" x="48" y="172" width="231" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<button horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="59o-dL-xSh" userLabel="Check for Updates automutically">
@ -97,7 +97,7 @@
</customSpacing>
</stackView>
<button horizontalHuggingPriority="500" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cPC-Na-pRr">
<rect key="frame" x="72" y="43" width="182" height="32"/>
<rect key="frame" x="60" y="25" width="182" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Check for Updates..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="2p9-GL-XZ9">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -107,8 +107,42 @@
<action selector="checkVersion:" target="-2" id="4u0-Zb-Xfz"/>
</connections>
</button>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Elj-N8-4IK" customClass="MASShortcutView">
<rect key="frame" x="247" y="76" width="139" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="associatedUserDefaultsKey" value="SwitchProxyMode"/>
</userDefinedRuntimeAttributes>
</customView>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ti4-xg-ncf" customClass="MASShortcutView">
<rect key="frame" x="247" y="103" width="139" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="associatedUserDefaultsKey" value="ToggleRunning"/>
</userDefinedRuntimeAttributes>
</customView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="UhI-5l-Ytp">
<rect key="frame" x="64" y="77" width="163" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="Switch proxy mode:" id="Eu4-bo-oYs">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vtN-0c-sip">
<rect key="frame" x="64" y="104" width="174" height="17"/>
<constraints>
<constraint firstAttribute="width" constant="212" id="yOV-yV-m0h"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="Toggle V2ray On/Off:" id="0rn-re-Wn3">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button horizontalHuggingPriority="500" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="liJ-Uu-8HQ">
<rect key="frame" x="254" y="43" width="127" height="32"/>
<rect key="frame" x="265" y="25" width="127" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Feedback..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="QjX-NH-23u">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>

View File

@ -45,6 +45,40 @@ func makeToast(message: String, displayDuration: Double? = 2) {
toastWindowCtrl.fadeInHud(displayDuration)
}
func ToggleRunning() {
// turn off
if UserDefaults.getBool(forKey: .v2rayTurnOn) {
menuController.stopV2rayCore()
makeToast(message: "v2ray-core: Off")
return
}
// start
menuController.startV2rayCore()
makeToast(message: "v2ray-core: On")
}
func SwitchProxyMode() {
let runMode = RunMode(rawValue: UserDefaults.get(forKey: .runMode) ?? "manual") ?? .manual
switch runMode {
case .pac:
menuController.switchRunMode(runMode: .global)
makeToast(message: "V2rayU: global Mode")
break
case .global:
menuController.switchRunMode(runMode: .manual)
makeToast(message: "V2rayU: manual Mode")
break
case .manual:
menuController.switchRunMode(runMode: .pac)
makeToast(message: "V2rayU: pac Mode")
break
default: break
}
}
// menu controller
class MenuController: NSObject, NSMenuDelegate {
var closedByConfigWindow: Bool = false
@ -231,14 +265,7 @@ class MenuController: NSObject, NSMenuDelegate {
}
@IBAction func start(_ sender: NSMenuItem) {
// turn off
if UserDefaults.getBool(forKey: .v2rayTurnOn) {
self.stopV2rayCore()
return
}
// start
self.startV2rayCore()
}
@IBAction func quitClicked(_ sender: NSMenuItem) {

15
V2rayU/Shortcut.h Normal file
View File

@ -0,0 +1,15 @@
//
// ShortcutsController.h
// ShadowsocksX-NG
//
// Created by 邱宇舟 on 2017/3/10.
// Copyright © 2017年 qiuyuzhou. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ShortcutsController : NSObject
+ (void)bindShortcuts;
@end

30
V2rayU/Shortcut.m Normal file
View File

@ -0,0 +1,30 @@
//
// ShortcutsController.m
// ShadowsocksX-NG
//
// Created by on 2017/3/10.
// Copyright © 2017 qiuyuzhou. All rights reserved.
//
#import "Shortcut.h"
#import <MASShortcut/Shortcut.h>
@implementation ShortcutsController
+ (void)bindShortcuts {
MASShortcutBinder* binder = [MASShortcutBinder sharedBinder];
[binder
bindShortcutWithDefaultsKey: @"ToggleRunning"
toAction:^{
[[NSNotificationCenter defaultCenter] postNotificationName: @"NOTIFY_TOGGLE_RUNNING_SHORTCUT" object: nil];
}];
[binder
bindShortcutWithDefaultsKey: @"SwitchProxyMode"
toAction:^{
[[NSNotificationCenter defaultCenter] postNotificationName: @"NOTIFY_SWITCH_PROXY_MODE_SHORTCUT" object: nil];
}];
}
@end

View File

@ -0,0 +1,11 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
// Created by yanue on 2020/2/5.
// Copyright © 2020 yanue. All rights reserved.
//
#import <MASShortcut/Shortcut.h>
#import "Shortcut.h"