Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fee08c000b | ||
|
|
e087df3b93 | ||
|
|
a7d112a8ba | ||
|
|
b4175bae13 | ||
|
|
a63fd85bc5 | ||
|
|
ff1063c8e2 | ||
|
|
1305e4366a | ||
|
|
4cad88d0cd | ||
|
|
58f3ef9ecd | ||
|
|
8b907ac7ed | ||
|
|
e5ce05dc89 | ||
|
|
42f88bcf53 |
@@ -7,7 +7,9 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
15349DB820BAE3F70071CAA1 /* NSBezierPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15349DB720BAE3F70071CAA1 /* NSBezierPath.swift */; };
|
||||
15492103207B53AE00E45BBC /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15492102207B53AE00E45BBC /* Util.swift */; };
|
||||
15493F6720BE6E0F007B2BA5 /* CGImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15493F6620BE6E0F007B2BA5 /* CGImage.swift */; };
|
||||
155D2C03204F61220087478B /* Credits.rtfd in Resources */ = {isa = PBXBuildFile; fileRef = 155D2C02204F61220087478B /* Credits.rtfd */; };
|
||||
159F304E2079A111000BD387 /* AppDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159F304D2079A111000BD387 /* AppDelegateTests.swift */; };
|
||||
159F30522079A147000BD387 /* PPStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 159F30512079A147000BD387 /* PPStateTests.swift */; };
|
||||
@@ -65,7 +67,9 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
15349DB720BAE3F70071CAA1 /* NSBezierPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSBezierPath.swift; sourceTree = "<group>"; };
|
||||
15492102207B53AE00E45BBC /* Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Util.swift; sourceTree = "<group>"; };
|
||||
15493F6620BE6E0F007B2BA5 /* CGImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGImage.swift; sourceTree = "<group>"; };
|
||||
155D2C02204F61220087478B /* Credits.rtfd */ = {isa = PBXFileReference; lastKnownFileType = wrapper.rtfd; path = Credits.rtfd; sourceTree = "<group>"; };
|
||||
159F304D2079A111000BD387 /* AppDelegateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegateTests.swift; sourceTree = "<group>"; };
|
||||
159F30512079A147000BD387 /* PPStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PPStateTests.swift; sourceTree = "<group>"; };
|
||||
@@ -171,6 +175,7 @@
|
||||
B3B4C2BF1E25894B009F8E4E /* PixelPicker */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
15493F6620BE6E0F007B2BA5 /* CGImage.swift */,
|
||||
BA74C13420A6F1BE00306B27 /* ShowAndHideCursor.h */,
|
||||
BA74C13220A6F16C00306B27 /* ShowAndHideCursor.m */,
|
||||
BA71817320AE2DCC00619700 /* PPMenuShortcutView.h */,
|
||||
@@ -180,6 +185,7 @@
|
||||
BA74C14D20ADA33E00306B27 /* PPColor.swift */,
|
||||
15FC8CC7204E2E2C000B5E1E /* PPState.swift */,
|
||||
159ED10B207EB2EF005489ED /* OverlayPanel */,
|
||||
15349DB720BAE3F70071CAA1 /* NSBezierPath.swift */,
|
||||
BA74C14120AA409D00306B27 /* NSColor.swift */,
|
||||
15492102207B53AE00E45BBC /* Util.swift */,
|
||||
B3B4C2C21E25894B009F8E4E /* Assets.xcassets */,
|
||||
@@ -333,6 +339,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
BA74C13320A6F16C00306B27 /* ShowAndHideCursor.m in Sources */,
|
||||
15349DB820BAE3F70071CAA1 /* NSBezierPath.swift in Sources */,
|
||||
BA71817220AE2DB400619700 /* PPMenuShortcutView.m in Sources */,
|
||||
B3B4C2C11E25894B009F8E4E /* AppDelegate.swift in Sources */,
|
||||
BA22232920B04D660001069C /* AppDelegate+Menu.swift in Sources */,
|
||||
@@ -342,6 +349,7 @@
|
||||
BA74C14020AA390400306B27 /* PPOverlayPreview.swift in Sources */,
|
||||
BA74C14420AA609500306B27 /* PPOverlayWrapper.swift in Sources */,
|
||||
BA74C0F820A692D100306B27 /* PPOverlayController.swift in Sources */,
|
||||
15493F6720BE6E0F007B2BA5 /* CGImage.swift in Sources */,
|
||||
BA74C14220AA409D00306B27 /* NSColor.swift in Sources */,
|
||||
15492103207B53AE00E45BBC /* Util.swift in Sources */,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// CGImage.swift
|
||||
// PixelPicker
|
||||
//
|
||||
|
||||
import CleanroomLogger
|
||||
|
||||
extension CGImage {
|
||||
// In order to get the color at a given pixel from a CGImage, we need to convert the CGImage's
|
||||
// data to a bitmap and draw it. We do so via a CGContext, and then manually extract the data at
|
||||
// the desired pixel.
|
||||
func colorAt(x: Int, y: Int) -> NSColor {
|
||||
assert(0 <= x && x < self.width)
|
||||
assert(0 <= y && y < self.height)
|
||||
|
||||
let bitmapBytesPerRow = width * 4
|
||||
let bitmapByteCount = bitmapBytesPerRow * Int(self.height)
|
||||
|
||||
// Allocate memory for image data. This is the destination in memory where any drawing to
|
||||
// the bitmap context will be rendered.
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
|
||||
let bitmapData = malloc(bitmapByteCount)
|
||||
|
||||
// Since we manually allocate memeory for the data, we must ensure that the same memory is
|
||||
// freed after we've used it.
|
||||
defer { free(bitmapData) }
|
||||
|
||||
// Create the bitmap context.
|
||||
let context = CGContext(
|
||||
data: bitmapData,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
bitsPerComponent: 8,
|
||||
bytesPerRow: bitmapBytesPerRow,
|
||||
space: CGColorSpaceCreateDeviceRGB(),
|
||||
bitmapInfo: bitmapInfo.rawValue
|
||||
)
|
||||
|
||||
// Extract the pixel data from the right offset.
|
||||
if context != nil {
|
||||
// First, we draw the image data onto the context we created.
|
||||
let rect = CGRect(x: 0, y: 0, width: self.width, height: self.height)
|
||||
context!.draw(self, in: rect)
|
||||
|
||||
// Then we extract the data at the right spot.
|
||||
let data = context!.data!
|
||||
let offset = 4 * (y * width + x)
|
||||
|
||||
let a = CGFloat(data.load(fromByteOffset: offset, as: UInt8.self)) / 255.0
|
||||
let r = CGFloat(data.load(fromByteOffset: offset + 1, as: UInt8.self)) / 255.0
|
||||
let g = CGFloat(data.load(fromByteOffset: offset + 2, as: UInt8.self)) / 255.0
|
||||
let b = CGFloat(data.load(fromByteOffset: offset + 3, as: UInt8.self)) / 255.0
|
||||
return NSColor(red: r, green: g, blue: b, alpha: a)
|
||||
}
|
||||
|
||||
// Creating the context failed, so return a default color instead.
|
||||
// Hopefully, this should never happen.
|
||||
Log.error?.message("Failed to create CGContext!")
|
||||
return NSColor.black
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2.0</string>
|
||||
<string>1.2.2</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5</string>
|
||||
<string>7</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// NSBezierPath.swift
|
||||
// PixelPicker
|
||||
//
|
||||
|
||||
// Extend NSBezierPath to allow easy conversion to a CGPath.
|
||||
// https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Paths/Paths.html#//apple_ref/doc/uid/TP40003290-CH206-SW2
|
||||
extension NSBezierPath {
|
||||
var cgPath: CGPath {
|
||||
let path = CGMutablePath()
|
||||
var points = [CGPoint](repeating: .zero, count: 3)
|
||||
for i in 0 ..< self.elementCount {
|
||||
switch self.element(at: i, associatedPoints: &points) {
|
||||
case .moveToBezierPathElement: path.move(to: points[0])
|
||||
case .lineToBezierPathElement: path.addLine(to: points[0])
|
||||
case .curveToBezierPathElement: path.addCurve(to: points[2], control1: points[0], control2: points[1])
|
||||
case .closePathBezierPathElement: path.closeSubpath()
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
}
|
||||
@@ -90,19 +90,28 @@ class PPOverlayController: NSWindowController {
|
||||
// When the user clicks, animate the cursor out, save the picked color and copy it.
|
||||
override func mouseDown(with event: NSEvent) {
|
||||
hidePicker(animate: true)
|
||||
|
||||
let pickedColor = PPPickedColor(color: lastHighlightedColor, format: PPState.shared.chosenFormat)
|
||||
PPState.shared.addRecentPick(pickedColor)
|
||||
copyToPasteboard(stringValue: pickedColor.asString)
|
||||
pickColor()
|
||||
}
|
||||
|
||||
// Close picker immediately when the user presses the escape key.
|
||||
// Listen to key events.
|
||||
override func keyDown(with event: NSEvent) {
|
||||
if event.keyCode == kVK_Escape { hidePicker(animate: false) }
|
||||
if event.keyCode == kVK_Space {
|
||||
let format = PPState.shared.chosenFormat
|
||||
PPState.shared.chosenFormat = event.modifierFlags.contains(.shift) ? format.previous() : format.next()
|
||||
switch Int(event.keyCode) {
|
||||
// Close immediately on escape.
|
||||
case kVK_Escape:
|
||||
hidePicker(animate: false)
|
||||
// Act as if the user clicked on space.
|
||||
case kVK_Space:
|
||||
hidePicker(animate: true)
|
||||
pickColor()
|
||||
// Cycle between formats when the user presses the left or right arrow keys.
|
||||
case kVK_LeftArrow:
|
||||
PPState.shared.chosenFormat = PPState.shared.chosenFormat.previous()
|
||||
updateInfoPanel(lastHighlightedColor, lastHighlightedColor.bestContrastingColor())
|
||||
case kVK_RightArrow:
|
||||
PPState.shared.chosenFormat = PPState.shared.chosenFormat.next()
|
||||
updateInfoPanel(lastHighlightedColor, lastHighlightedColor.bestContrastingColor())
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +156,12 @@ class PPOverlayController: NSWindowController {
|
||||
}
|
||||
}
|
||||
|
||||
func pickColor() {
|
||||
let pickedColor = PPPickedColor(color: lastHighlightedColor, format: PPState.shared.chosenFormat)
|
||||
PPState.shared.addRecentPick(pickedColor)
|
||||
copyToPasteboard(stringValue: pickedColor.asString)
|
||||
}
|
||||
|
||||
// Show the picker, save the previously active application, and hide the cursor.
|
||||
func showPicker() {
|
||||
if overlayPanel.isVisible || infoPanel.isVisible { return }
|
||||
@@ -236,6 +251,10 @@ class PPOverlayController: NSWindowController {
|
||||
// Ensure the overlayPanel is always the key window.
|
||||
if !overlayPanel.isKeyWindow {
|
||||
overlayPanel.activate(withSize: panelSize, infoPanel: infoPanel)
|
||||
// Reset the cursor state to ensure it's hidden (the foremost application changes then
|
||||
// WindowServer resets our "SetsCursorInBackground" magic).
|
||||
ShowCursor()
|
||||
HideCursor()
|
||||
}
|
||||
|
||||
// Center the mouse in the picker window.
|
||||
@@ -316,58 +335,3 @@ class PPOverlayController: NSWindowController {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
extension CGImage {
|
||||
// In order to get the color at a given pixel from a CGImage, we need to convert the CGImage's
|
||||
// data to a bitmap and draw it. We do so via a CGContext, and then manually extract the data at
|
||||
// the desired pixel.
|
||||
func colorAt(x: Int, y: Int) -> NSColor {
|
||||
assert(0 <= x && x < self.width)
|
||||
assert(0 <= y && y < self.height)
|
||||
|
||||
let bitmapBytesPerRow = width * 4
|
||||
let bitmapByteCount = bitmapBytesPerRow * Int(self.height)
|
||||
|
||||
// Allocate memory for image data. This is the destination in memory where any drawing to
|
||||
// the bitmap context will be rendered.
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
|
||||
let bitmapData = malloc(bitmapByteCount)
|
||||
|
||||
// Since we manually allocate memeory for the data, we must ensure that the same memory is
|
||||
// freed after we've used it.
|
||||
defer { free(bitmapData) }
|
||||
|
||||
// Create the bitmap context.
|
||||
let context = CGContext(
|
||||
data: bitmapData,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
bitsPerComponent: 8,
|
||||
bytesPerRow: bitmapBytesPerRow,
|
||||
space: CGColorSpaceCreateDeviceRGB(),
|
||||
bitmapInfo: bitmapInfo.rawValue
|
||||
)
|
||||
|
||||
// Extract the pixel data from the right offset.
|
||||
if context != nil {
|
||||
// First, we draw the image data onto the context we created.
|
||||
let rect = CGRect(x: 0, y: 0, width: self.width, height: self.height)
|
||||
context!.draw(self, in: rect)
|
||||
|
||||
// Then we extract the data at the right spot.
|
||||
let data = context!.data!
|
||||
let offset = 4 * (y * width + x)
|
||||
|
||||
let a = CGFloat(data.load(fromByteOffset: offset, as: UInt8.self)) / 255.0
|
||||
let r = CGFloat(data.load(fromByteOffset: offset + 1, as: UInt8.self)) / 255.0
|
||||
let g = CGFloat(data.load(fromByteOffset: offset + 2, as: UInt8.self)) / 255.0
|
||||
let b = CGFloat(data.load(fromByteOffset: offset + 3, as: UInt8.self)) / 255.0
|
||||
return NSColor(red: r, green: g, blue: b, alpha: a)
|
||||
}
|
||||
|
||||
// Creating the context failed, so return a default color instead.
|
||||
// Hopefully, this should never happen.
|
||||
Log.error?.message("Failed to create CGContext!")
|
||||
return NSColor.black
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,14 +24,15 @@ class PPOverlayPreview: NSView, CALayerDelegate {
|
||||
layer?.contentsGravity = kCAGravityResizeAspectFill
|
||||
layer?.delegate = self
|
||||
|
||||
// Add the grid shape layers to the view.
|
||||
grid.strokeColor = NSColor.gray.cgColor
|
||||
grid.fillColor = nil
|
||||
layer?.addSublayer(grid)
|
||||
|
||||
// Prepare crosshair shape layers.
|
||||
crosshair.strokeColor = NSColor.black.cgColor
|
||||
crosshair.fillColor = nil
|
||||
layer?.addSublayer(crosshair)
|
||||
|
||||
grid.strokeColor = NSColor.gray.cgColor
|
||||
grid.fillColor = nil
|
||||
layer?.addSublayer(grid)
|
||||
}
|
||||
|
||||
// Update the crosshair with the correct color, position and size.
|
||||
@@ -71,21 +72,3 @@ class PPOverlayPreview: NSView, CALayerDelegate {
|
||||
grid.path = path.cgPath
|
||||
}
|
||||
}
|
||||
|
||||
// Extend NSBezierPath to allow easy conversion to a CGPath.
|
||||
// https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Paths/Paths.html#//apple_ref/doc/uid/TP40003290-CH206-SW2
|
||||
extension NSBezierPath {
|
||||
var cgPath: CGPath {
|
||||
let path = CGMutablePath()
|
||||
var points = [CGPoint](repeating: .zero, count: 3)
|
||||
for i in 0 ..< self.elementCount {
|
||||
switch self.element(at: i, associatedPoints: &points) {
|
||||
case .moveToBezierPathElement: path.move(to: points[0])
|
||||
case .lineToBezierPathElement: path.addLine(to: points[0])
|
||||
case .curveToBezierPathElement: path.addCurve(to: points[2], control1: points[0], control2: points[1])
|
||||
case .closePathBezierPathElement: path.closeSubpath()
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,18 @@ void LogWarning(void);
|
||||
|
||||
// We use an undocumented API to hide the cursor even when the application *isn't* active.
|
||||
// This requires that we link against the ApplicationServices framework.
|
||||
// See https://stackoverflow.com/a/3939241/5552584
|
||||
// and https://web.archive.org/web/20150609013355/http://lists.apple.com:80/archives/carbon-dev/2006/Jan/msg00555.html
|
||||
// and http://doomlaser.com/cursorcerer-hide-your-cursor-at-will/
|
||||
void CGSSetConnectionProperty(int a, int b, CFStringRef c, CFBooleanRef d);
|
||||
int _CGSDefaultConnection(void);
|
||||
// See: https://stackoverflow.com/a/3939241/5552584
|
||||
// Also: https://github.com/asmagill/hammerspoon_asm.undocumented/blob/master/cursor/CGSConnection.h
|
||||
|
||||
// Every application is given a singular connection ID through which it can receieve and manipulate
|
||||
// values, state, notifications, events, etc. in the Window Server.
|
||||
typedef int CGSConnectionID;
|
||||
|
||||
// Associates a value for the given key on the given connection.
|
||||
CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value);
|
||||
|
||||
// Gets the default connection for this process. `CGSMainConnectionID` is just a more modern name.
|
||||
CGSConnectionID _CGSDefaultConnection(void);
|
||||
CGSConnectionID CGSMainConnectionID(void);
|
||||
|
||||
#endif /* ShowAndHideCursor_h */
|
||||
|
||||
@@ -31,7 +31,8 @@ void HideCursor() {
|
||||
#endif
|
||||
|
||||
CFStringRef propertyString = CFStringCreateWithCString(NULL, "SetsCursorInBackground", kCFStringEncodingUTF8);
|
||||
CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanTrue);
|
||||
CGSConnectionID cid = _CGSDefaultConnection();
|
||||
CGSSetConnectionProperty(cid, cid, propertyString, kCFBooleanTrue);
|
||||
CFRelease(propertyString);
|
||||
|
||||
CGDisplayHideCursor(kCGDirectMainDisplay);
|
||||
|
||||
@@ -4,11 +4,13 @@ PixelPicker is like Digital Color Meter, but lives in your menu bar and lets you
|
||||
|
||||
### Features
|
||||
|
||||
* Pick *any* pixel on your screen with ease
|
||||
* Different zoom levels
|
||||
* Multiple color export formats
|
||||
* Multi-monitor support
|
||||
* Global keyboard shortcuts
|
||||
* 📸 Pick *any* pixel on your screen with ease
|
||||
* 🔎 Different magnification levels
|
||||
* ✏ Multiple color export formats
|
||||
* 🖥 Multi-monitor support
|
||||
* 🎨 Supports different color spaces
|
||||
* ⌨️ Global keyboard shortcut activation
|
||||
* 🌄 Customisable preview
|
||||
* ✨
|
||||
|
||||

|
||||
@@ -25,10 +27,10 @@ After you've installed PixelPicker, it will live in your menu bar. You have many
|
||||
* Select the "Pick a Pixel" item in the dropdown menu to activate the picker
|
||||
* Simply right-click the menu item and the picker will activate
|
||||
|
||||
Once you have the picker open, it should be quite straightforward! Move your mouse around the screen and click on the pixel you want.
|
||||
Once you have the picker open, it should be quite straightforward! Move your mouse around the screen and click (or press <kbd>space</kbd> on the pixel you want.
|
||||
You can also hold down the <kbd>control (⌃)</kbd> key (this can be changed to another key) while the picker is open, and the picker will enter "Focus Mode". This will zoom the pixel preview even further, and will slow down the picker's movement to make it easier to pick that hard-to-get pixel!
|
||||
|
||||
Remember, you can press <kbd>space</kbd> (or <kbd>shift</kbd> + <kbd>space</kbd>) to cycle between color formats while the picker is open.
|
||||
**ProTip:** Remember, you can use the left or right arrow keys to cycle between color formats while the picker is open.
|
||||
|
||||
### Options
|
||||
|
||||
@@ -36,24 +38,26 @@ All of PixelPicker's options are in its menubar dropdown. Simply click on the me
|
||||
|
||||
PixelPicker provides some neat options:
|
||||
|
||||
* **Color Format**
|
||||
* How should the color be copied when you select it? Examples include CSS Hex: `#aabbcc`, or Java RGB: `new Color(158, 198, 117)`, etc.
|
||||
* **Focus Modifier**
|
||||
* Choose which modifier activates focus mode. When focus mode is active, the picker zooms closer in, and your mouse moves slower to help you pick the right pixel.
|
||||
* **Color Space**
|
||||
* Computer screens are complex things, and have various different color spaces. You can either leave this setting as its default (it will choose the default color space of your screen) or you can specify a specific color space and PixelPicker will try and use that instead (compatibility depends on your computer's screen/monitor).
|
||||
* **Show Grid**
|
||||
* 🔳 **Show Grid**
|
||||
* Whether or not to show a grid around the pixels in the picker's preview.
|
||||
* **Float Precision**
|
||||
* 🎨 **Color Space**
|
||||
* Computer screens are complex things, and have various color spaces. You can either leave this setting as its default (it will choose the default color space of your screen) or you can specify a specific color space and PixelPicker will try and use that instead (compatibility depends on your computer's screen/monitor).
|
||||
* ✏️ **Color Format**
|
||||
* How should the color be copied when you select it? Examples include CSS Hex: `#aabbcc`, or Java RGB: `new Color(158, 198, 117)`, etc.
|
||||
* 🔍 **Magnification**
|
||||
- How far in should the preview zoom/how big should each pixel be?
|
||||
* 🧐 **Focus Modifier**
|
||||
* Choose which modifier activates focus mode. When focus mode is active, the picker zooms even closer in, and your mouse moves slower to help you pick the right pixel.
|
||||
* 🔢 **Float Precision**
|
||||
* This controls how many digits will come after the decimal point when using float-based color formats.
|
||||
* **Picker Shortcut**
|
||||
* ⌨️ **Picker Shortcut**
|
||||
* The global keyboard shortcut to use that will activate Pixel Picker.
|
||||
* **Launch at Login**
|
||||
* 🚀 **Launch at Login**
|
||||
* If this is enabled then PixelPicker will be launched when you log into your computer.
|
||||
|
||||
#### Extra Overrides or Hidden Settings
|
||||
|
||||
PixelPicker has some experimental overrides that can be toggled via the Terminal (`defaults write ...`, etc). Look under the "Experimental Overrides" section at `PixelPicker` -> `About` for more information.
|
||||
In some releases PixelPicker might have some experimental overrides that can be toggled via the Terminal (`defaults write ...`, etc). Look under the "Experimental Overrides" section at `PixelPicker` -> `About` for more information.
|
||||
|
||||
## Questions/Concerns
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 328 KiB After Width: | Height: | Size: 354 KiB |
Reference in New Issue
Block a user