├── MenuLock-v2.0.png
├── MenuLock
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ ├── icon16x16.png
│ │ ├── icon32x32.png
│ │ ├── icon64x64.png
│ │ ├── icon1024x1024.png
│ │ ├── icon128x128.png
│ │ ├── icon256x256.png
│ │ ├── icon512x512.png
│ │ └── Contents.json
├── Podfile
├── io.fti.MenuLock.plist
├── Info.plist
├── KeyMap.swift
├── Base.lproj
│ └── MainMenu.xib
└── AppDelegate.swift
├── MenuLock.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcuserdata
│ └── fti.xcuserdatad
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── MenuLock.xcscheme
└── project.pbxproj
├── Podfile
├── MenuLock.xcworkspace
└── contents.xcworkspacedata
├── .gitignore
└── README.md
/MenuLock-v2.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shufflepuck/MenuLock/HEAD/MenuLock-v2.0.png
--------------------------------------------------------------------------------
/MenuLock/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/MenuLock/Assets.xcassets/AppIcon.appiconset/icon16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shufflepuck/MenuLock/HEAD/MenuLock/Assets.xcassets/AppIcon.appiconset/icon16x16.png
--------------------------------------------------------------------------------
/MenuLock/Assets.xcassets/AppIcon.appiconset/icon32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shufflepuck/MenuLock/HEAD/MenuLock/Assets.xcassets/AppIcon.appiconset/icon32x32.png
--------------------------------------------------------------------------------
/MenuLock/Assets.xcassets/AppIcon.appiconset/icon64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shufflepuck/MenuLock/HEAD/MenuLock/Assets.xcassets/AppIcon.appiconset/icon64x64.png
--------------------------------------------------------------------------------
/MenuLock/Assets.xcassets/AppIcon.appiconset/icon1024x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shufflepuck/MenuLock/HEAD/MenuLock/Assets.xcassets/AppIcon.appiconset/icon1024x1024.png
--------------------------------------------------------------------------------
/MenuLock/Assets.xcassets/AppIcon.appiconset/icon128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shufflepuck/MenuLock/HEAD/MenuLock/Assets.xcassets/AppIcon.appiconset/icon128x128.png
--------------------------------------------------------------------------------
/MenuLock/Assets.xcassets/AppIcon.appiconset/icon256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shufflepuck/MenuLock/HEAD/MenuLock/Assets.xcassets/AppIcon.appiconset/icon256x256.png
--------------------------------------------------------------------------------
/MenuLock/Assets.xcassets/AppIcon.appiconset/icon512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shufflepuck/MenuLock/HEAD/MenuLock/Assets.xcassets/AppIcon.appiconset/icon512x512.png
--------------------------------------------------------------------------------
/MenuLock.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MenuLock/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '8.0'
3 | # Uncomment this line if you're using Swift
4 | use_frameworks!
5 |
6 | target 'MenuLock' do
7 | pod 'MASShortcut'
8 |
9 | end
10 |
11 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '8.0'
3 | # Uncomment this line if you're using Swift
4 | #platform :osx, '10.10'
5 | use_frameworks!
6 |
7 | target 'MenuLock' do
8 | pod 'MASShortcut'
9 | #pod 'Cereal', '~> 2.0'
10 |
11 | end
12 |
13 |
--------------------------------------------------------------------------------
/MenuLock.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/MenuLock/io.fti.MenuLock.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | RunAtLoad
6 |
7 | Program
8 | /Applications/MenuLock.app/Contents/MacOS/MenuLock
9 | Label
10 | io.fti.MenuLock
11 |
12 |
13 |
--------------------------------------------------------------------------------
/MenuLock.xcodeproj/xcuserdata/fti.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | MenuLock.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 4768F0E01C84910E0069C875
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/MenuLock/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 2.0.2
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | LSUIElement
28 |
29 | NSHumanReadableCopyright
30 | Copyright © 2016 François Levaux. All rights reserved.
31 | NSMainNibFile
32 | MainMenu
33 | NSPrincipalClass
34 | NSApplication
35 |
36 |
37 |
--------------------------------------------------------------------------------
/MenuLock/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "icon16x16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "icon32x32.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "icon32x32.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "icon64x64.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "icon128x128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "icon256x256.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "icon256x256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "icon512x512.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "icon512x512.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "icon1024x1024.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | },
68 | "properties" : {
69 | "pre-rendered" : true
70 | }
71 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xcuserstate
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | ## Playgrounds
31 | timeline.xctimeline
32 | playground.xcworkspace
33 |
34 | # Swift Package Manager
35 | #
36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
37 | # Packages/
38 | .build/
39 |
40 | # CocoaPods
41 | #
42 | # We recommend against adding the Pods directory to your .gitignore. However
43 | # you should judge for yourself, the pros and cons are mentioned at:
44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
45 | #
46 | Pods/
47 | Podfile.lock
48 |
49 | # Carthage
50 | #
51 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
52 | # Carthage/Checkouts
53 |
54 | Carthage/Build
55 |
56 | # fastlane
57 | #
58 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
59 | # screenshots whenever they are needed.
60 | # For more information about the recommended setup visit:
61 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
62 |
63 | fastlane/report.xml
64 | fastlane/Preview.html
65 | fastlane/screenshots
66 | fastlane/test_output
67 |
68 |
--------------------------------------------------------------------------------
/MenuLock/KeyMap.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeyMapClass.swift
3 | // MenuLock
4 | //
5 | // Created by keyboard on 13/07/2016.
6 | // Copyright © 2016 François Levaux. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class Key: NSObject, NSCoding {
12 | let name: String
13 | let keyCode: UInt
14 | let keyMask: NSEventModifierFlags
15 | let keyEquivalent: String
16 |
17 | init(name: String, keyCode: UInt, keyMask: NSEventModifierFlags, keyEquivalent: AnyObject) {
18 | self.name = name
19 | self.keyCode = keyCode
20 | self.keyMask = keyMask
21 | if let keyString = keyEquivalent as? String {
22 | self.keyEquivalent = keyString
23 | } else if let keyInt = keyEquivalent as? Int {
24 | self.keyEquivalent = String(utf16CodeUnits: [unichar(keyInt)], count: 1)
25 | } else {
26 | abort()
27 | }
28 |
29 | }
30 |
31 | required convenience init?(coder aDecoder: NSCoder) {
32 | guard let name = aDecoder.decodeObject(forKey: "keyName") as? String,
33 | let keyCode = aDecoder.decodeObject(forKey: "keyCode") as? UInt,
34 | let keyMask = aDecoder.decodeObject(forKey: "keyMask") as? UInt,
35 | let keyEquivalent = aDecoder.decodeObject(forKey: "keyEquivalent") as? String
36 | else { return nil }
37 |
38 | let keyMaskFlags = NSEventModifierFlags(rawValue: keyMask)
39 | self.init(name: name, keyCode: keyCode, keyMask: keyMaskFlags, keyEquivalent: keyEquivalent as AnyObject)
40 |
41 | }
42 |
43 |
44 | func encode(with aCoder: NSCoder) {
45 | aCoder.encode(self.name, forKey: "keyName")
46 | aCoder.encode(self.keyCode, forKey: "keyCode")
47 | aCoder.encode(self.keyMask.rawValue, forKey: "keyMask")
48 | aCoder.encode(self.keyEquivalent, forKey: "keyEquivalent")
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/MenuLock/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/MenuLock.xcodeproj/xcuserdata/fti.xcuserdatad/xcschemes/MenuLock.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MenuLock
2 | implements CMD+L for windows enthusiasts
3 | To be more precise, it puts display to sleep.
4 |
5 | To lock your computer, you need to have `System Preferences > Security & Privacy > Require the password Immediately after sleep saver begins`, and a password set.
6 |
7 | 
8 |
9 | (Hi, Cédric!)
10 |
11 | # Why ?
12 | - Because Keychain Access' menubar introduce the question: "Why lock keychain?"
13 | - Because ctrl+shift+power/eject can become halt or reboot if user is not careful
14 | - Because Hot Corners are not loved by everyone (and they only start screensaver)
15 |
16 | # Some details
17 |
18 | ## Building the App
19 |
20 | ### Workspace Setup
21 | This app uses [Cocoapods](https://cocoapods.org). Please first install it (usually with `sudo gem install cocoapods`).
22 | Then follow this:
23 |
24 | - `git clone https://github.com/ftiff/MenuLock.git`
25 | - `cd MenuLock`
26 | - `pod install`
27 | - `open MenuLock.xcworkspace/`
28 |
29 | Then go to `Product > Scheme > Edit Scheme…` and make sure `Run > Executable` is set to "MenuLock.app".
30 |
31 | ### Build
32 | - Modify APP_VERSION in Build Settings (see https://ftiff.wordpress.com/2016/04/01/xcode-automatically-sign-and-build-package/)
33 | - In Terminal.app, navigate to the MenuLock directory
34 | - `xcodebuild -workspace MenuLock.xcworkspace -scheme MenuLock install`
35 |
36 | ### install
37 | - `sudo installer -target / -pkg /tmp/MenuLock-1.1.pkg`
38 | - `sudo launchctl load /Library/LaunchAgents/io.fti.MenuLock.plist`
39 |
40 | ## Key Modifiers
41 |
42 | `let keyMask: NSEventModifierFlags = [ .AlternateKeyMask, .ShiftKeyMask]`
43 |
44 | event modifier flag | Description
45 | --------------------|------------
46 | AlphaShiftKeyMask | Caps Lock
47 | ShiftKeyMask | Shift
48 | ControlKeyMask | Control
49 | AlternateKeyMask | Alt
50 | CommandKeyMask | Command
51 | NumericPadKeyMask | Set if any key in the numeric keypad is pressed (and arrows)
52 | HelpKeyMask | Help Key (does this still exists?)
53 | FunctionKeyMask | The function keys include the F keys at the top of most keyboards (F1, F2, and so on) and the navigation keys in the center of most keyboards (Help, Forward Delete, Home, End, Page Up, Page Down, and the arrow keys).
54 |
55 | ## Key Code
56 |
57 | `let keyCode = UInt(0x25)`
58 |
59 | These are defined in `/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h`. Be careful these work for US Keyboards. I'd love to learn a better way to do this.
60 |
61 | Key Code | Hex Equivalent
62 | ---------|---------------
63 | A |0x00
64 | S |0x01
65 | D |0x02
66 | F |0x03
67 | H |0x04
68 | G |0x05
69 | Z |0x06
70 | X |0x07
71 | C |0x08
72 | V |0x09
73 | B |0x0B
74 | Q |0x0C
75 | W |0x0D
76 | E |0x0E
77 | R |0x0F
78 | Y |0x10
79 | T |0x11
80 | 1 |0x12
81 | 2 |0x13
82 | 3 |0x14
83 | 4 |0x15
84 | 6 |0x16
85 | 5 |0x17
86 | Equal |0x18
87 | 9 |0x19
88 | 7 |0x1A
89 | Minus |0x1B
90 | 8 |0x1C
91 | 0 |0x1D
92 | RightBracket |0x1E
93 | O |0x1F
94 | U |0x20
95 | LeftBracket |0x21
96 | I |0x22
97 | P |0x23
98 | L |0x25
99 | J |0x26
100 | Quote |0x27
101 | K |0x28
102 | Semicolon |0x29
103 | Backslash |0x2A
104 | Comma |0x2B
105 | Slash |0x2C
106 | N |0x2D
107 | M |0x2E
108 | Period |0x2F
109 | Grave |0x32
110 | KeypadDecimal |0x41
111 | KeypadMultiply |0x43
112 | KeypadPlus |0x45
113 | KeypadClear |0x47
114 | KeypadDivide |0x4B
115 | KeypadEnter |0x4C
116 | KeypadMinus |0x4E
117 | KeypadEquals |0x51
118 | Keypad0 |0x52
119 | Keypad1 |0x53
120 | Keypad2 |0x54
121 | Keypad3 |0x55
122 | Keypad4 |0x56
123 | Keypad5 |0x57
124 | Keypad6 |0x58
125 | Keypad7 |0x59
126 | Keypad8 |0x5B
127 | Keypad9 |0x5C
128 | Return | 0x24
129 | Tab | 0x30
130 | Space | 0x31
131 | Delete | 0x33
132 | Escape | 0x35
133 | Command | 0x37
134 | Shift | 0x38
135 | CapsLock | 0x39
136 | Option | 0x3A
137 | Control | 0x3B
138 | RightShift | 0x3C
139 | RightOption | 0x3D
140 | RightControl | 0x3E
141 | Function | 0x3F
142 | F17 | 0x40
143 | VolumeUp | 0x48
144 | VolumeDown | 0x49
145 | Mute | 0x4A
146 | F18 | 0x4F
147 | F19 | 0x50
148 | F20 | 0x5A
149 | F5 | 0x60
150 | F6 | 0x61
151 | F7 | 0x62
152 | F3 | 0x63
153 | F8 | 0x64
154 | F9 | 0x65
155 | F11 | 0x67
156 | F13 | 0x69
157 | F16 | 0x6A
158 | F14 | 0x6B
159 | F10 | 0x6D
160 | F12 | 0x6F
161 | F15 | 0x71
162 | Help | 0x72
163 | Home | 0x73
164 | PageUp | 0x74
165 | ForwardDelete | 0x75
166 | F4 | 0x76
167 | End | 0x77
168 | F2 | 0x78
169 | PageDown | 0x79
170 | F1 | 0x7A
171 | LeftArrow | 0x7B
172 | RightArrow | 0x7C
173 | DownArrow | 0x7D
174 | UpArrow | 0x7E
175 |
--------------------------------------------------------------------------------
/MenuLock/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // MenuLock
4 | //
5 | // Created by François Levaux on 29.02.16.
6 | // Copyright © 2016 François Levaux. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import MASShortcut
11 |
12 |
13 | @NSApplicationMain
14 | class AppDelegate: NSObject, NSApplicationDelegate {
15 |
16 | @IBOutlet weak var statusBar: NSMenu!
17 | @IBOutlet weak var statusLockScreen: NSMenuItem!
18 |
19 | @IBOutlet weak var activeKeyMenu: NSMenu!
20 |
21 | let statusItem = NSStatusBar.system().statusItem(withLength: NSSquareStatusItemLength)
22 | var activeKey: Key = Key(name: "CMD + L", keyCode: 0x25, keyMask: [ .command ], keyEquivalent: "l" as AnyObject)
23 |
24 |
25 | // List of available Keys
26 |
27 | var keyMaps = [
28 | Key(name: "F19", keyCode: 80, keyMask: [], keyEquivalent: NSF19FunctionKey as AnyObject),
29 | Key(name: "CMD + F12", keyCode: 0x6F, keyMask: [ .command ], keyEquivalent: NSF12FunctionKey as AnyObject),
30 | Key(name: "CMD + L", keyCode: 0x25, keyMask: [ .command ], keyEquivalent: "l" as AnyObject),
31 | Key(name: "CMD + K", keyCode: 0x28, keyMask: [ .command ], keyEquivalent: "k" as AnyObject)
32 | ]
33 |
34 | @IBAction func statusItemQuit(sender: NSMenuItem) {
35 | NSApplication.shared().terminate(self)
36 | }
37 |
38 | @IBAction func statusItemLock(sender: NSMenuItem) {
39 | screenSleep()
40 | }
41 |
42 |
43 | func applicationDidFinishLaunching(_ notification: Notification) {
44 |
45 | // Setup icon
46 |
47 | let icon = NSImage(named: NSImageNameLockLockedTemplate)
48 | statusItem.image = icon
49 | statusItem.menu = statusBar
50 |
51 |
52 | // Defaults
53 |
54 | setGlobalShortcut()
55 |
56 |
57 | // Setup Active Key Menu
58 |
59 | for key in keyMaps {
60 | let menuItem = NSMenuItem()
61 | menuItem.title = key.name
62 | if activeKey.name == key.name {
63 | menuItem.state = NSOnState
64 | }
65 | menuItem.representedObject = key
66 | menuItem.action = #selector(setActiveKey(sender:))
67 | activeKeyMenu.addItem(menuItem)
68 | }
69 |
70 | }
71 |
72 |
73 | func setGlobalShortcut() {
74 |
75 | if let key: Key = readPrefs() {
76 | activeKey = key
77 | } else {
78 | NSLog("Cannot get activeKey from UserDefaults. Setting current key.")
79 | savePrefs(key: activeKey)
80 | }
81 |
82 | // Set Menu Item Key Equivalent
83 | statusLockScreen.keyEquivalent = activeKey.keyEquivalent
84 | statusLockScreen.keyEquivalentModifierMask = activeKey.keyMask
85 |
86 | // Setup Global Shortcut
87 | let shortcut = MASShortcut(keyCode: activeKey.keyCode, modifierFlags: activeKey.keyMask.rawValue)
88 | MASShortcutMonitor.shared().register(shortcut, withAction: screenSleep)
89 |
90 |
91 | }
92 |
93 |
94 | // Set which key should trigger the sleep
95 |
96 | func setActiveKey(sender: NSMenuItem) {
97 |
98 | for menuItem in activeKeyMenu.items {
99 | menuItem.state = NSOffState
100 | }
101 | sender.state = NSOnState
102 | if let key: Key = (sender.representedObject as? Key) {
103 | savePrefs(key: key)
104 |
105 | //activeKey = key
106 | } else {
107 | NSLog("cannot see representedObject")
108 | }
109 | setGlobalShortcut()
110 | }
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | // Sleep Screen methods
119 |
120 | func screenSleep() -> Void {
121 | let registry: io_registry_entry_t = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler")
122 | let _ = IORegistryEntrySetCFProperty(registry, "IORequestIdle" as CFString!, true as CFTypeRef!)
123 | IOObjectRelease(registry)
124 | }
125 |
126 | func lockScreenImmediate() -> Void {
127 | // Note: Private -- Do not use!
128 | // http://stackoverflow.com/questions/34669958/swift-how-to-call-a-c-function-loaded-from-a-dylib
129 |
130 | let libHandle = dlopen("/System/Library/PrivateFrameworks/login.framework/Versions/Current/login", RTLD_LAZY)
131 | let sym = dlsym(libHandle, "SACLockScreenImmediate")
132 | typealias myFunction = @convention(c) (Void) -> Void
133 | let SACLockScreenImmediate = unsafeBitCast(sym, to: myFunction.self)
134 | SACLockScreenImmediate()
135 | }
136 |
137 |
138 |
139 | // Preferences
140 |
141 | func savePrefs(key: Key) {
142 | let prefs = UserDefaults()
143 | let data = NSKeyedArchiver.archivedData(withRootObject: key)
144 | prefs.set(data, forKey: "currentKey")
145 | prefs.synchronize()
146 | }
147 |
148 | func readPrefs() -> Key? {
149 | let prefs = UserDefaults()
150 | if let object = prefs.object(forKey: "currentKey") {
151 | if let data = object as? Data {
152 | return NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? Key
153 | } else {
154 | NSLog("cannot convert to Data")
155 | return nil
156 | }
157 | } else {
158 | return nil
159 | }
160 | }
161 |
162 | }
163 |
164 |
--------------------------------------------------------------------------------
/MenuLock.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 4768F0E51C84910E0069C875 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4768F0E41C84910E0069C875 /* AppDelegate.swift */; };
11 | 4768F0E71C84910E0069C875 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4768F0E61C84910E0069C875 /* Assets.xcassets */; };
12 | 4768F0EA1C84910E0069C875 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4768F0E81C84910E0069C875 /* MainMenu.xib */; };
13 | 877996C61282AD19DA70A5C6 /* Pods_MenuLock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE9A6DE3DBC86D67F62CD9B8 /* Pods_MenuLock.framework */; };
14 | D666B0361D362BE9005296DC /* KeyMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = D666B0351D362BE9005296DC /* KeyMap.swift */; };
15 | /* End PBXBuildFile section */
16 |
17 | /* Begin PBXFileReference section */
18 | 0E392E529B6CA297CE7ABE66 /* Pods-MenuLock.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MenuLock.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MenuLock/Pods-MenuLock.debug.xcconfig"; sourceTree = ""; };
19 | 4768F0E11C84910E0069C875 /* MenuLock.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MenuLock.app; sourceTree = BUILT_PRODUCTS_DIR; };
20 | 4768F0E41C84910E0069C875 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
21 | 4768F0E61C84910E0069C875 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
22 | 4768F0E91C84910E0069C875 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
23 | 4768F0EB1C84910E0069C875 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
24 | A7628FF9B155D1AC48E9C276 /* Pods-MenuLock.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MenuLock.release.xcconfig"; path = "Pods/Target Support Files/Pods-MenuLock/Pods-MenuLock.release.xcconfig"; sourceTree = ""; };
25 | D666B0351D362BE9005296DC /* KeyMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyMap.swift; sourceTree = ""; };
26 | DE9A6DE3DBC86D67F62CD9B8 /* Pods_MenuLock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MenuLock.framework; sourceTree = BUILT_PRODUCTS_DIR; };
27 | /* End PBXFileReference section */
28 |
29 | /* Begin PBXFrameworksBuildPhase section */
30 | 4768F0DE1C84910E0069C875 /* Frameworks */ = {
31 | isa = PBXFrameworksBuildPhase;
32 | buildActionMask = 2147483647;
33 | files = (
34 | 877996C61282AD19DA70A5C6 /* Pods_MenuLock.framework in Frameworks */,
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXFrameworksBuildPhase section */
39 |
40 | /* Begin PBXGroup section */
41 | 4768F0D81C84910E0069C875 = {
42 | isa = PBXGroup;
43 | children = (
44 | 4768F0E31C84910E0069C875 /* MenuLock */,
45 | 4768F0E21C84910E0069C875 /* Products */,
46 | 9724658849CEC9A1240B8971 /* Pods */,
47 | 5F60155205FA337FA7E20B39 /* Frameworks */,
48 | );
49 | sourceTree = "";
50 | };
51 | 4768F0E21C84910E0069C875 /* Products */ = {
52 | isa = PBXGroup;
53 | children = (
54 | 4768F0E11C84910E0069C875 /* MenuLock.app */,
55 | );
56 | name = Products;
57 | sourceTree = "";
58 | };
59 | 4768F0E31C84910E0069C875 /* MenuLock */ = {
60 | isa = PBXGroup;
61 | children = (
62 | 4768F0E41C84910E0069C875 /* AppDelegate.swift */,
63 | D666B0351D362BE9005296DC /* KeyMap.swift */,
64 | 4768F0E61C84910E0069C875 /* Assets.xcassets */,
65 | 4768F0E81C84910E0069C875 /* MainMenu.xib */,
66 | 4768F0EB1C84910E0069C875 /* Info.plist */,
67 | );
68 | path = MenuLock;
69 | sourceTree = "";
70 | };
71 | 5F60155205FA337FA7E20B39 /* Frameworks */ = {
72 | isa = PBXGroup;
73 | children = (
74 | DE9A6DE3DBC86D67F62CD9B8 /* Pods_MenuLock.framework */,
75 | );
76 | name = Frameworks;
77 | sourceTree = "";
78 | };
79 | 9724658849CEC9A1240B8971 /* Pods */ = {
80 | isa = PBXGroup;
81 | children = (
82 | 0E392E529B6CA297CE7ABE66 /* Pods-MenuLock.debug.xcconfig */,
83 | A7628FF9B155D1AC48E9C276 /* Pods-MenuLock.release.xcconfig */,
84 | );
85 | name = Pods;
86 | sourceTree = "";
87 | };
88 | /* End PBXGroup section */
89 |
90 | /* Begin PBXNativeTarget section */
91 | 4768F0E01C84910E0069C875 /* MenuLock */ = {
92 | isa = PBXNativeTarget;
93 | buildConfigurationList = 4768F0EE1C84910E0069C875 /* Build configuration list for PBXNativeTarget "MenuLock" */;
94 | buildPhases = (
95 | 4490B3C84A19D0D9FE98B2CA /* [CP] Check Pods Manifest.lock */,
96 | 4768F0DD1C84910E0069C875 /* Sources */,
97 | 4768F0DE1C84910E0069C875 /* Frameworks */,
98 | 4768F0DF1C84910E0069C875 /* Resources */,
99 | A2053F2E26D1B73BCC26FA4A /* [CP] Embed Pods Frameworks */,
100 | D0D3B6E27959104FD9F63B29 /* [CP] Copy Pods Resources */,
101 | );
102 | buildRules = (
103 | );
104 | dependencies = (
105 | );
106 | name = MenuLock;
107 | productName = MenuLock;
108 | productReference = 4768F0E11C84910E0069C875 /* MenuLock.app */;
109 | productType = "com.apple.product-type.application";
110 | };
111 | /* End PBXNativeTarget section */
112 |
113 | /* Begin PBXProject section */
114 | 4768F0D91C84910E0069C875 /* Project object */ = {
115 | isa = PBXProject;
116 | attributes = {
117 | LastSwiftUpdateCheck = 0720;
118 | LastUpgradeCheck = 0810;
119 | ORGANIZATIONNAME = "François Levaux";
120 | TargetAttributes = {
121 | 4768F0E01C84910E0069C875 = {
122 | CreatedOnToolsVersion = 7.2.1;
123 | DevelopmentTeam = EM3ER8T33A;
124 | DevelopmentTeamName = "Francois TIFFREAU";
125 | LastSwiftMigration = 0800;
126 | ProvisioningStyle = Automatic;
127 | SystemCapabilities = {
128 | com.apple.Sandbox = {
129 | enabled = 0;
130 | };
131 | };
132 | };
133 | };
134 | };
135 | buildConfigurationList = 4768F0DC1C84910E0069C875 /* Build configuration list for PBXProject "MenuLock" */;
136 | compatibilityVersion = "Xcode 3.2";
137 | developmentRegion = English;
138 | hasScannedForEncodings = 0;
139 | knownRegions = (
140 | en,
141 | Base,
142 | );
143 | mainGroup = 4768F0D81C84910E0069C875;
144 | productRefGroup = 4768F0E21C84910E0069C875 /* Products */;
145 | projectDirPath = "";
146 | projectRoot = "";
147 | targets = (
148 | 4768F0E01C84910E0069C875 /* MenuLock */,
149 | );
150 | };
151 | /* End PBXProject section */
152 |
153 | /* Begin PBXResourcesBuildPhase section */
154 | 4768F0DF1C84910E0069C875 /* Resources */ = {
155 | isa = PBXResourcesBuildPhase;
156 | buildActionMask = 2147483647;
157 | files = (
158 | 4768F0E71C84910E0069C875 /* Assets.xcassets in Resources */,
159 | 4768F0EA1C84910E0069C875 /* MainMenu.xib in Resources */,
160 | );
161 | runOnlyForDeploymentPostprocessing = 0;
162 | };
163 | /* End PBXResourcesBuildPhase section */
164 |
165 | /* Begin PBXShellScriptBuildPhase section */
166 | 4490B3C84A19D0D9FE98B2CA /* [CP] Check Pods Manifest.lock */ = {
167 | isa = PBXShellScriptBuildPhase;
168 | buildActionMask = 2147483647;
169 | files = (
170 | );
171 | inputPaths = (
172 | );
173 | name = "[CP] Check Pods Manifest.lock";
174 | outputPaths = (
175 | );
176 | runOnlyForDeploymentPostprocessing = 0;
177 | shellPath = /bin/sh;
178 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
179 | showEnvVarsInLog = 0;
180 | };
181 | A2053F2E26D1B73BCC26FA4A /* [CP] Embed Pods Frameworks */ = {
182 | isa = PBXShellScriptBuildPhase;
183 | buildActionMask = 2147483647;
184 | files = (
185 | );
186 | inputPaths = (
187 | );
188 | name = "[CP] Embed Pods Frameworks";
189 | outputPaths = (
190 | );
191 | runOnlyForDeploymentPostprocessing = 0;
192 | shellPath = /bin/sh;
193 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MenuLock/Pods-MenuLock-frameworks.sh\"\n";
194 | showEnvVarsInLog = 0;
195 | };
196 | D0D3B6E27959104FD9F63B29 /* [CP] Copy Pods Resources */ = {
197 | isa = PBXShellScriptBuildPhase;
198 | buildActionMask = 2147483647;
199 | files = (
200 | );
201 | inputPaths = (
202 | );
203 | name = "[CP] Copy Pods Resources";
204 | outputPaths = (
205 | );
206 | runOnlyForDeploymentPostprocessing = 0;
207 | shellPath = /bin/sh;
208 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MenuLock/Pods-MenuLock-resources.sh\"\n";
209 | showEnvVarsInLog = 0;
210 | };
211 | /* End PBXShellScriptBuildPhase section */
212 |
213 | /* Begin PBXSourcesBuildPhase section */
214 | 4768F0DD1C84910E0069C875 /* Sources */ = {
215 | isa = PBXSourcesBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | 4768F0E51C84910E0069C875 /* AppDelegate.swift in Sources */,
219 | D666B0361D362BE9005296DC /* KeyMap.swift in Sources */,
220 | );
221 | runOnlyForDeploymentPostprocessing = 0;
222 | };
223 | /* End PBXSourcesBuildPhase section */
224 |
225 | /* Begin PBXVariantGroup section */
226 | 4768F0E81C84910E0069C875 /* MainMenu.xib */ = {
227 | isa = PBXVariantGroup;
228 | children = (
229 | 4768F0E91C84910E0069C875 /* Base */,
230 | );
231 | name = MainMenu.xib;
232 | sourceTree = "";
233 | };
234 | /* End PBXVariantGroup section */
235 |
236 | /* Begin XCBuildConfiguration section */
237 | 4768F0EC1C84910E0069C875 /* Debug */ = {
238 | isa = XCBuildConfiguration;
239 | buildSettings = {
240 | ALWAYS_SEARCH_USER_PATHS = NO;
241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
242 | CLANG_CXX_LIBRARY = "libc++";
243 | CLANG_ENABLE_MODULES = YES;
244 | CLANG_ENABLE_OBJC_ARC = YES;
245 | CLANG_WARN_BOOL_CONVERSION = YES;
246 | CLANG_WARN_CONSTANT_CONVERSION = YES;
247 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
248 | CLANG_WARN_EMPTY_BODY = YES;
249 | CLANG_WARN_ENUM_CONVERSION = YES;
250 | CLANG_WARN_INFINITE_RECURSION = YES;
251 | CLANG_WARN_INT_CONVERSION = YES;
252 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
253 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
254 | CLANG_WARN_UNREACHABLE_CODE = YES;
255 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
256 | CODE_SIGN_IDENTITY = "-";
257 | COPY_PHASE_STRIP = NO;
258 | DEBUG_INFORMATION_FORMAT = dwarf;
259 | ENABLE_STRICT_OBJC_MSGSEND = YES;
260 | ENABLE_TESTABILITY = YES;
261 | GCC_C_LANGUAGE_STANDARD = gnu99;
262 | GCC_DYNAMIC_NO_PIC = NO;
263 | GCC_NO_COMMON_BLOCKS = YES;
264 | GCC_OPTIMIZATION_LEVEL = 0;
265 | GCC_PREPROCESSOR_DEFINITIONS = (
266 | "DEBUG=1",
267 | "$(inherited)",
268 | );
269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
271 | GCC_WARN_UNDECLARED_SELECTOR = YES;
272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
273 | GCC_WARN_UNUSED_FUNCTION = YES;
274 | GCC_WARN_UNUSED_VARIABLE = YES;
275 | MACOSX_DEPLOYMENT_TARGET = 10.11;
276 | MTL_ENABLE_DEBUG_INFO = YES;
277 | ONLY_ACTIVE_ARCH = YES;
278 | SDKROOT = macosx;
279 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
280 | };
281 | name = Debug;
282 | };
283 | 4768F0ED1C84910E0069C875 /* Release */ = {
284 | isa = XCBuildConfiguration;
285 | buildSettings = {
286 | ALWAYS_SEARCH_USER_PATHS = NO;
287 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
288 | CLANG_CXX_LIBRARY = "libc++";
289 | CLANG_ENABLE_MODULES = YES;
290 | CLANG_ENABLE_OBJC_ARC = YES;
291 | CLANG_WARN_BOOL_CONVERSION = YES;
292 | CLANG_WARN_CONSTANT_CONVERSION = YES;
293 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
294 | CLANG_WARN_EMPTY_BODY = YES;
295 | CLANG_WARN_ENUM_CONVERSION = YES;
296 | CLANG_WARN_INFINITE_RECURSION = YES;
297 | CLANG_WARN_INT_CONVERSION = YES;
298 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
299 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
300 | CLANG_WARN_UNREACHABLE_CODE = YES;
301 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
302 | CODE_SIGN_IDENTITY = "-";
303 | COPY_PHASE_STRIP = NO;
304 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
305 | ENABLE_NS_ASSERTIONS = NO;
306 | ENABLE_STRICT_OBJC_MSGSEND = YES;
307 | GCC_C_LANGUAGE_STANDARD = gnu99;
308 | GCC_NO_COMMON_BLOCKS = YES;
309 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
310 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
311 | GCC_WARN_UNDECLARED_SELECTOR = YES;
312 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
313 | GCC_WARN_UNUSED_FUNCTION = YES;
314 | GCC_WARN_UNUSED_VARIABLE = YES;
315 | MACOSX_DEPLOYMENT_TARGET = 10.11;
316 | MTL_ENABLE_DEBUG_INFO = NO;
317 | SDKROOT = macosx;
318 | };
319 | name = Release;
320 | };
321 | 4768F0EF1C84910E0069C875 /* Debug */ = {
322 | isa = XCBuildConfiguration;
323 | baseConfigurationReference = 0E392E529B6CA297CE7ABE66 /* Pods-MenuLock.debug.xcconfig */;
324 | buildSettings = {
325 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
326 | CODE_SIGN_IDENTITY = "Mac Developer";
327 | COMBINE_HIDPI_IMAGES = YES;
328 | DEVELOPMENT_TEAM = EM3ER8T33A;
329 | INFOPLIST_FILE = MenuLock/Info.plist;
330 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
331 | MACOSX_DEPLOYMENT_TARGET = 10.9;
332 | PRODUCT_BUNDLE_IDENTIFIER = io.fti.MenuLock;
333 | PRODUCT_NAME = "$(TARGET_NAME)";
334 | PROVISIONING_PROFILE = "";
335 | PROVISIONING_PROFILE_SPECIFIER = "";
336 | SWIFT_VERSION = 3.0;
337 | };
338 | name = Debug;
339 | };
340 | 4768F0F01C84910E0069C875 /* Release */ = {
341 | isa = XCBuildConfiguration;
342 | baseConfigurationReference = A7628FF9B155D1AC48E9C276 /* Pods-MenuLock.release.xcconfig */;
343 | buildSettings = {
344 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
345 | CODE_SIGN_IDENTITY = "Mac Developer";
346 | COMBINE_HIDPI_IMAGES = YES;
347 | DEVELOPMENT_TEAM = EM3ER8T33A;
348 | INFOPLIST_FILE = MenuLock/Info.plist;
349 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
350 | MACOSX_DEPLOYMENT_TARGET = 10.9;
351 | PRODUCT_BUNDLE_IDENTIFIER = io.fti.MenuLock;
352 | PRODUCT_NAME = "$(TARGET_NAME)";
353 | PROVISIONING_PROFILE = "";
354 | PROVISIONING_PROFILE_SPECIFIER = "";
355 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
356 | SWIFT_VERSION = 3.0;
357 | };
358 | name = Release;
359 | };
360 | /* End XCBuildConfiguration section */
361 |
362 | /* Begin XCConfigurationList section */
363 | 4768F0DC1C84910E0069C875 /* Build configuration list for PBXProject "MenuLock" */ = {
364 | isa = XCConfigurationList;
365 | buildConfigurations = (
366 | 4768F0EC1C84910E0069C875 /* Debug */,
367 | 4768F0ED1C84910E0069C875 /* Release */,
368 | );
369 | defaultConfigurationIsVisible = 0;
370 | defaultConfigurationName = Release;
371 | };
372 | 4768F0EE1C84910E0069C875 /* Build configuration list for PBXNativeTarget "MenuLock" */ = {
373 | isa = XCConfigurationList;
374 | buildConfigurations = (
375 | 4768F0EF1C84910E0069C875 /* Debug */,
376 | 4768F0F01C84910E0069C875 /* Release */,
377 | );
378 | defaultConfigurationIsVisible = 0;
379 | defaultConfigurationName = Release;
380 | };
381 | /* End XCConfigurationList section */
382 | };
383 | rootObject = 4768F0D91C84910E0069C875 /* Project object */;
384 | }
385 |
--------------------------------------------------------------------------------