diff --git a/Examples/example.gif b/Examples/example.gif new file mode 100644 index 0000000..d21397f Binary files /dev/null and b/Examples/example.gif differ diff --git a/Opener.xcodeproj/project.pbxproj b/Opener.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5723cae --- /dev/null +++ b/Opener.xcodeproj/project.pbxproj @@ -0,0 +1,322 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + EAECDC25222A48BA0059100B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAECDC24222A48BA0059100B /* AppDelegate.swift */; }; + EAECDC27222A48BA0059100B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAECDC26222A48BA0059100B /* Assets.xcassets */; }; + EAECDC2A222A48BA0059100B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = EAECDC28222A48BA0059100B /* MainMenu.xib */; }; + EAECDC4E222B4F090059100B /* ClearPanelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAECDC4C222B4F090059100B /* ClearPanelController.swift */; }; + EAECDC4F222B4F090059100B /* ClearPanelController.xib in Resources */ = {isa = PBXBuildFile; fileRef = EAECDC4D222B4F090059100B /* ClearPanelController.xib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + EAECDC21222A48BA0059100B /* Opener.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Opener.app; sourceTree = BUILT_PRODUCTS_DIR; }; + EAECDC24222A48BA0059100B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + EAECDC26222A48BA0059100B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + EAECDC29222A48BA0059100B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + EAECDC2B222A48BA0059100B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EAECDC2C222A48BA0059100B /* Opener.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Opener.entitlements; sourceTree = ""; }; + EAECDC4C222B4F090059100B /* ClearPanelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearPanelController.swift; sourceTree = ""; }; + EAECDC4D222B4F090059100B /* ClearPanelController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ClearPanelController.xib; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + EAECDC1E222A48BA0059100B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + EAECDC18222A48BA0059100B = { + isa = PBXGroup; + children = ( + EAECDC23222A48BA0059100B /* Opener */, + EAECDC22222A48BA0059100B /* Products */, + ); + sourceTree = ""; + }; + EAECDC22222A48BA0059100B /* Products */ = { + isa = PBXGroup; + children = ( + EAECDC21222A48BA0059100B /* Opener.app */, + ); + name = Products; + sourceTree = ""; + }; + EAECDC23222A48BA0059100B /* Opener */ = { + isa = PBXGroup; + children = ( + EAECDC24222A48BA0059100B /* AppDelegate.swift */, + EAECDC4C222B4F090059100B /* ClearPanelController.swift */, + EAECDC4D222B4F090059100B /* ClearPanelController.xib */, + EAECDC26222A48BA0059100B /* Assets.xcassets */, + EAECDC28222A48BA0059100B /* MainMenu.xib */, + EAECDC2B222A48BA0059100B /* Info.plist */, + EAECDC2C222A48BA0059100B /* Opener.entitlements */, + ); + path = Opener; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + EAECDC20222A48BA0059100B /* Opener */ = { + isa = PBXNativeTarget; + buildConfigurationList = EAECDC2F222A48BA0059100B /* Build configuration list for PBXNativeTarget "Opener" */; + buildPhases = ( + EAECDC1D222A48BA0059100B /* Sources */, + EAECDC1E222A48BA0059100B /* Frameworks */, + EAECDC1F222A48BA0059100B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Opener; + productName = Opener; + productReference = EAECDC21222A48BA0059100B /* Opener.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + EAECDC19222A48BA0059100B /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 0920; + ORGANIZATIONNAME = sparthaje; + TargetAttributes = { + EAECDC20222A48BA0059100B = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = EAECDC1C222A48BA0059100B /* Build configuration list for PBXProject "Opener" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = EAECDC18222A48BA0059100B; + productRefGroup = EAECDC22222A48BA0059100B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + EAECDC20222A48BA0059100B /* Opener */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + EAECDC1F222A48BA0059100B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EAECDC27222A48BA0059100B /* Assets.xcassets in Resources */, + EAECDC2A222A48BA0059100B /* MainMenu.xib in Resources */, + EAECDC4F222B4F090059100B /* ClearPanelController.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + EAECDC1D222A48BA0059100B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EAECDC4E222B4F090059100B /* ClearPanelController.swift in Sources */, + EAECDC25222A48BA0059100B /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + EAECDC28222A48BA0059100B /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + EAECDC29222A48BA0059100B /* Base */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + EAECDC2D222A48BA0059100B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + EAECDC2E222A48BA0059100B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Mac Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + }; + name = Release; + }; + EAECDC30222A48BA0059100B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Opener/Opener.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 679T2G5882; + INFOPLIST_FILE = Opener/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.sparthaje.Opener; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + EAECDC31222A48BA0059100B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Opener/Opener.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 679T2G5882; + INFOPLIST_FILE = Opener/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.sparthaje.Opener; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + EAECDC1C222A48BA0059100B /* Build configuration list for PBXProject "Opener" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EAECDC2D222A48BA0059100B /* Debug */, + EAECDC2E222A48BA0059100B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EAECDC2F222A48BA0059100B /* Build configuration list for PBXNativeTarget "Opener" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EAECDC30222A48BA0059100B /* Debug */, + EAECDC31222A48BA0059100B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = EAECDC19222A48BA0059100B /* Project object */; +} diff --git a/Opener.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Opener.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..625c773 --- /dev/null +++ b/Opener.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Opener/AppDelegate.swift b/Opener/AppDelegate.swift new file mode 100644 index 0000000..eb78bd9 --- /dev/null +++ b/Opener/AppDelegate.swift @@ -0,0 +1,212 @@ +// +// AppDelegate.swift +// Opener +// +// Created by Shreepa Parthaje on 3/2/19. +// Copyright © 2019 https://github.com/sparthaje. All rights reserved. +// + +import Cocoa +import Carbon + +let letterToKey = [ + "a": 0, + "b": 11, + "c": 8, + "d": 2, + "e": 14, + "f": 3, + "g": 5, + "h": 4, + "i": 34, + "j": 38, + "k": 40, + "l": 37, + "m": 46, + "n": 45, + "o": 31, + "p": 35, + "q": 12, + "r": 15, + "s": 1, + "t": 17, + "u": 32, + "v": 9, + "w": 13, + "x": 7, + "y": 16, + "z": 6, + "1": 18, + "2": 19, + "3": 20, + "4": 21, + "5": 23, + "6": 22, + "7": 26, + "8": 28, + "9": 25, + "0": 29, + ";": 41, + ".": 47 +] + +let keyToLetter: [UInt16:String] = [ + 0: "a", + 11: "b", + 8: "c", + 2: "d", + 14: "e", + 3: "f", + 5: "g", + 4: "h", + 34: "i", + 38: "j", + 40: "k", + 37: "l", + 46: "m", + 45: "n", + 31: "o", + 35: "p", + 12: "q", + 15: "r", + 1: "s", + 17: "t", + 32: "u", + 9: "v", + 13: "w", + 7: "x", + 16: "y", + 6: "z", + 18: "1", + 19: "2", + 20: "3", + 21: "4", + 23: "5", + 22: "6", + 26: "7", + 28: "8", + 25: "9", + 29: "0", + 41: ";", + 47: "." +] + +let modifiersToFlag = [ + "command": 1048840, + "option": 524576, + "control": 262401, + "shift": 131330, + "fn": 8388864, + "command-shift":1179914, + "command-control":1310985, + "option-shift":655650, + "option-command":1573160 +] + +var waitForNextLetter = false + +var windows: [NSWindow] = [] + +// SETTINGS + +var flagname = "command-shift" +var hotkey = "2" +var letterToPath: [String:String] = [:] +var clear = false + +func loadSettings() { + let file = "/Users/" + NSUserName() + "/.opener_settings" + let fileURL = URL(fileURLWithPath: file) + let fileManager = FileManager.default + + if !fileManager.fileExists(atPath: file) { + let contents = "command-shift:2\nfalse\n9:.opener_settings" + try! contents.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8) + } + + do { + let content = try String(contentsOf: fileURL, encoding: .utf8).components(separatedBy: "\n") + for line in content { + if line.first! != "#" { + let arguments = line.components(separatedBy: ":") + if arguments[0] == "true" { + clear = true + continue + } + if arguments[0] == "false" { + clear = false + continue + } + if arguments[0].count > 1 { + flagname = arguments[0] + hotkey = arguments[1] + continue + } + if arguments[1] == ".opener_settings" { + letterToPath[arguments[0]] = file + continue + } + letterToPath[arguments[0]] = arguments[1] + } + } + } + catch { + print(error) + } +} + +@NSApplicationMain +class AppDelegate: NSObject, NSApplicationDelegate { + + func hideTitleBar(window: NSWindow!) { + window.titleVisibility = .hidden + window.titlebarAppearsTransparent = true; + window.isMovableByWindowBackground = true + window.standardWindowButton(.closeButton)!.isHidden = true + window.standardWindowButton(.miniaturizeButton)!.isHidden = true + window.standardWindowButton(.zoomButton)!.isHidden = true + } + + func makeClear(window: NSWindow!) { + window.isOpaque = false + window.backgroundColor = .clear + } + + func handler(event: NSEvent!) { + + let key = event.keyCode + let flag = event.modifierFlags.rawValue + + if key == letterToKey[hotkey]! && flag == modifiersToFlag[flagname]! { + waitForNextLetter = true + // CGEventTap + NSApplication.shared.activate(ignoringOtherApps: true) + + let window = NSWindow(contentViewController: ClearPanelController()) + window.level = .floating + window.display() + window.makeKey() + window.orderFrontRegardless() + + hideTitleBar(window: window) + + if clear { + makeClear(window: window) + } + + windows.append(window) + } + } + + func applicationDidFinishLaunching(_ aNotification: Notification) { + let options = NSDictionary(object: kCFBooleanTrue, forKey: kAXTrustedCheckOptionPrompt.takeUnretainedValue() as NSString) as CFDictionary + let trusted = AXIsProcessTrustedWithOptions(options) + if (trusted) { + NSEvent.addGlobalMonitorForEvents(matching: .keyDown, handler: self.handler) + } + + loadSettings() + } + +} + diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/Contents.json b/Opener/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a8ae39c --- /dev/null +++ b/Opener/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "icon_16x16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "icon_16x16@2x.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "icon_32x32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "icon_32x32@2x.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "icon_128x128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "icon_128x128@2x.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "icon_256x256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "icon_256x256@2x.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "icon_512x512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "Icon1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/Icon1024.png b/Opener/Assets.xcassets/AppIcon.appiconset/Icon1024.png new file mode 100644 index 0000000..b2d33ea Binary files /dev/null and b/Opener/Assets.xcassets/AppIcon.appiconset/Icon1024.png differ diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/Opener/Assets.xcassets/AppIcon.appiconset/icon_128x128.png new file mode 100644 index 0000000..401242d Binary files /dev/null and b/Opener/Assets.xcassets/AppIcon.appiconset/icon_128x128.png differ diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/Opener/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png new file mode 100644 index 0000000..d9aff49 Binary files /dev/null and b/Opener/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png differ diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/Opener/Assets.xcassets/AppIcon.appiconset/icon_16x16.png new file mode 100644 index 0000000..ac419ed Binary files /dev/null and b/Opener/Assets.xcassets/AppIcon.appiconset/icon_16x16.png differ diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/Opener/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png new file mode 100644 index 0000000..e0d2561 Binary files /dev/null and b/Opener/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png differ diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/Opener/Assets.xcassets/AppIcon.appiconset/icon_256x256.png new file mode 100644 index 0000000..d9aff49 Binary files /dev/null and b/Opener/Assets.xcassets/AppIcon.appiconset/icon_256x256.png differ diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/Opener/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png new file mode 100644 index 0000000..b732cd2 Binary files /dev/null and b/Opener/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png differ diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/Opener/Assets.xcassets/AppIcon.appiconset/icon_32x32.png new file mode 100644 index 0000000..e0d2561 Binary files /dev/null and b/Opener/Assets.xcassets/AppIcon.appiconset/icon_32x32.png differ diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/Opener/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png new file mode 100644 index 0000000..97e5518 Binary files /dev/null and b/Opener/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png differ diff --git a/Opener/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/Opener/Assets.xcassets/AppIcon.appiconset/icon_512x512.png new file mode 100644 index 0000000..b732cd2 Binary files /dev/null and b/Opener/Assets.xcassets/AppIcon.appiconset/icon_512x512.png differ diff --git a/Opener/Base.lproj/MainMenu.xib b/Opener/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..ab9e5a1 --- /dev/null +++ b/Opener/Base.lproj/MainMenu.xib @@ -0,0 +1,678 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Opener/ClearPanelController.swift b/Opener/ClearPanelController.swift new file mode 100644 index 0000000..6309a68 --- /dev/null +++ b/Opener/ClearPanelController.swift @@ -0,0 +1,93 @@ +// +// ClearPanelController.swift +// Opener +// +// Created by Shreepa Parthaje on 3/2/19. +// Copyright © 2019 https://github.com/sparthaje. All rights reserved. +// + +import Cocoa + +class ClearPanelController: NSViewController { + + @IBOutlet var leftPane: NSTextField! + @IBOutlet var rightPane: NSTextField! + + func handler(event: NSEvent!) -> NSEvent? { + + let key = event.keyCode + + if key == 51 { + loadSettings() + for window in windows { + window.close() + } + return nil + } + + if waitForNextLetter { + waitForNextLetter = false + if keyToLetter.keys.contains(key) { + let letter = keyToLetter[key]! + if letterToPath.keys.contains(letter) { + let filePath = letterToPath[letter]! + + if filePath.contains(",") { + let arguments = filePath.components(separatedBy: ",") + CGDisplayMoveCursorToPoint(CGMainDisplayID(), CGPoint(x: Double(arguments[0])!, y: Double(arguments[1])!)) + } + + NSWorkspace.shared.open(URL(fileURLWithPath: filePath)) + for window in windows { + window.close() + } + return nil + } + } + } + + for window in windows { + window.close() + } + + return event + } + + override func viewDidLoad() { + super.viewDidLoad() + NSEvent.addLocalMonitorForEvents(matching: .keyDown, handler: self.handler) + + var leftDirs: [String] = [] + var rightDirs: [String] = [] + var onLeft = true + + for letter in letterToPath.keys { + let name = letterToPath[letter]!.components(separatedBy: "/").last! + if (onLeft) { + leftDirs.append(letter + " " + name) + onLeft = false + continue + } + rightDirs.append(letter + " " + name) + onLeft = true + } + + var left = "" + var right = "" + + for dir in leftDirs { + left += dir + "\n" + } + + for dir in rightDirs { + right += dir + "\n" + } + + if !clear { + leftPane.placeholderString = left + rightPane.placeholderString = right + } + + } + +} diff --git a/Opener/ClearPanelController.xib b/Opener/ClearPanelController.xib new file mode 100644 index 0000000..e4e06ed --- /dev/null +++ b/Opener/ClearPanelController.xib @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Opener/Info.plist b/Opener/Info.plist new file mode 100644 index 0000000..fcd6860 --- /dev/null +++ b/Opener/Info.plist @@ -0,0 +1,34 @@ + + + + + LSUIElement + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2019 sparthaje. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/Opener/Opener.entitlements b/Opener/Opener.entitlements new file mode 100644 index 0000000..311b32b --- /dev/null +++ b/Opener/Opener.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..8e6f039 --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# Opener + +[![Github](http://img.shields.io/badge/github-sparthaje-green.svg?style=flat)](https://github.com/sparthaje) +[![Swift 4.2](https://img.shields.io/badge/swift-4.0.3-orange.svg?style=flat)](https://github.com/apple/swift) +[![Platform](http://img.shields.io/badge/platform-macOS-blue.svg?style=flat)](https://developer.apple.com/macos/) + +Opener is a customizable application/file opener utility for macOS. With it, you can map any application or file to two key strokes. The first hotkey makes Opener listen for an input, and the following letter opens the mapped applicaiton or file. + +Video Demonstration (Note: The pop-up window can be disabled in the settings file) + +![Video Demonstration](https://raw.githubusercontent.com/sparthaje/Opener/master/Examples/example.gif) + +All the commands can be mapped in a file called `.opener_settings` in the home directory. The first line in this file defines the global hot key for the app. The following lines define what application/file to open following the global hot key. + +# Installation +1. Download the [app](https://github.com/sparthaje/Opener/releases/download/v1.0.0/Opener.zip) from the releases page +2. Move the app into the `/Applications/` directory +4. Open the app +5. Go to Security > Privacy > Accebiliity and enable Opener.app +6. Edit the configuration file (`⌘⇧2` followed by `9`) + +# Configuring .opener_settings + +Any line starting with a `#` will be ignored, so it can be used to seperate/block of segments + +--- + +The first line is `command-shift:2` by default. This defines the hot key that activates Opener. The `command-shift` is the modifer and the `2` is the key. All the modifiers and keys are listed at the bottom of the README.md. + +--- + +The second line should just be a boolean `true` or `false`. If it is `true`, not window show up to indicate when Opener is listening for input. If it is `false`, whenever the hot key is clicked and Opener starts to listen for an input, a window with avaliable inputs will pop up. + +--- + +The third line is `9:.opener_settings` by default. Only change the key value before the colon. This key value defines what key opens the settings file to edit it. All the modifiers and keys are listed at the bottom of the README.md. + +--- + +The following lines deifne what key will map to which application. The general format for this is `key:absolute_file_path`. Some examples are listed below: + + n:/Applications/Notes.app + p:/Applications/PyCharm CE.app + t:/Applications/iTerm.app + +--- + +To reload the settings defined, use the hot key (`⌘⇧2` by default) followed by a `delete`. + +--- + +Avaliable Modifiers (case-sensitive): + + command + option + control + shift + fn + command-shift + command-control + option-shift + option-command + +Avaliable Keys (case-sensitive): + + a b c d e f g h i j k l m n o p q r s t u v w x y z + 1 2 3 4 5 6 7 8 9 0 ; .