Skip to content

Commit

Permalink
Merge pull request #21 from creasty/highlight
Browse files Browse the repository at this point in the history
Highlight the location of the mouse pointer
  • Loading branch information
creasty authored Jun 2, 2020
2 parents 5769bb3 + f02885e commit 2896d68
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 12 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Cursor pointer:
| <kbd>C+S+J+L</kbd> ||
| <kbd>C+S+K+L</kbd> ||
| <kbd>C+S+H+K</kbd> | ↖️ |
| | **Quick jump actions** |
| | **Quick jump actions** (Highlight enabled) |
| <kbd>C+Y</kbd> | Top-left corner |
| <kbd>C+U</kbd> | Bottom-left corner |
| <kbd>C+I</kbd> | Top-right corner |
Expand All @@ -130,6 +130,12 @@ Scroll:
| <kbd>C+X+K</kbd> | :arrow_up: |
| <kbd>C+X+L</kbd> | :arrow_right: |

Highlight:

| Key | Description |
|:---|:---|
| <kbd>C+Space</kbd> | Highlight the location of the mouse pointer |

### Switch input source

| Key | Description |
Expand Down
6 changes: 4 additions & 2 deletions keyboard.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
31C7CD28248546F000A97A11 /* WordMotionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C7CD27248546F000A97A11 /* WordMotionHandler.swift */; };
31C7CD2A24854BB700A97A11 /* MouseHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C7CD2924854BB700A97A11 /* MouseHandler.swift */; };
31C7CD2C2485DBFB00A97A11 /* NSScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C7CD2B2485DBFB00A97A11 /* NSScreen.swift */; };
31C7CD2E2485F7CE00A97A11 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 31C7CD2D2485F7CE00A97A11 /* MainMenu.xib */; };
31E66C2B2485FD7B004BBEFD /* HighlighterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31E66C2A2485FD7B004BBEFD /* HighlighterView.swift */; };
AE38940621D8CB8C0097BE73 /* AXAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE38940521D8CB8C0097BE73 /* AXAttribute.swift */; };
AE38940821D8DF3A0097BE73 /* AXUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE38940721D8DF3A0097BE73 /* AXUIElement.swift */; };
AE38940A21D8DF9F0097BE73 /* AXError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE38940921D8DF9F0097BE73 /* AXError.swift */; };
Expand Down Expand Up @@ -39,7 +39,7 @@
31C7CD27248546F000A97A11 /* WordMotionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordMotionHandler.swift; sourceTree = "<group>"; };
31C7CD2924854BB700A97A11 /* MouseHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MouseHandler.swift; sourceTree = "<group>"; };
31C7CD2B2485DBFB00A97A11 /* NSScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSScreen.swift; sourceTree = "<group>"; };
31C7CD2D2485F7CE00A97A11 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
31E66C2A2485FD7B004BBEFD /* HighlighterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlighterView.swift; sourceTree = "<group>"; };
AE38940521D8CB8C0097BE73 /* AXAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AXAttribute.swift; sourceTree = "<group>"; };
AE38940721D8DF3A0097BE73 /* AXUIElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AXUIElement.swift; sourceTree = "<group>"; };
AE38940921D8DF9F0097BE73 /* AXError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AXError.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -117,6 +117,7 @@
AE6A00D71ED6A25000A93C2E /* Assets.xcassets */,
AE6A00DC1ED6A25000A93C2E /* Info.plist */,
AE6A00D91ED6A25000A93C2E /* MainMenu.xib */,
31E66C2A2485FD7B004BBEFD /* HighlighterView.swift */,
);
path = keyboard;
sourceTree = "<group>";
Expand Down Expand Up @@ -235,6 +236,7 @@
AE38940621D8CB8C0097BE73 /* AXAttribute.swift in Sources */,
AE6A00D61ED6A25000A93C2E /* AppDelegate.swift in Sources */,
AECCF7DD21D90B5B00B21C0A /* AppSwitchHandler.swift in Sources */,
31E66C2B2485FD7B004BBEFD /* HighlighterView.swift in Sources */,
AE38940821D8DF3A0097BE73 /* AXUIElement.swift in Sources */,
AE38940E21D8E0940097BE73 /* DispatchTime.swift in Sources */,
31C7CD28248546F000A97A11 /* WordMotionHandler.swift in Sources */,
Expand Down
8 changes: 7 additions & 1 deletion keyboard/AppComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ var _eventManager: EventManagerType?
var _eventTap: CFMachPort?

final class AppComponent {
let showHighlightCallback: () -> Void

let nsWorkspace = NSWorkspace.shared
let fileManager = FileManager.default

Expand All @@ -26,6 +28,10 @@ final class AppComponent {

private(set) var emitter: EmitterType = Emitter()

init(showHighlightCallback: @escaping () -> Void) {
self.showHighlightCallback = showHighlightCallback
}

func navigationHandler() -> Handler {
return NavigationHandler(
workspace: nsWorkspace,
Expand All @@ -51,7 +57,7 @@ final class AppComponent {
}

func mouseHandler() -> Handler {
return MouseHandler(emitter: emitter)
return MouseHandler(emitter: emitter, showHighlight: showHighlightCallback)
}

func appSwitchHandler() -> Handler {
Expand Down
47 changes: 46 additions & 1 deletion keyboard/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,21 @@ class AppDelegate: NSObject, NSApplicationDelegate {
return NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
}()

private let appComponent = AppComponent()
private lazy var appComponent: AppComponent = {
return AppComponent(showHighlightCallback: { [weak self] in
self?.showHighlight()
})
}()

private var window: NSWindow?
private var highlighterWork: DispatchWorkItem?

func applicationDidFinishLaunching(_ aNotification: Notification) {
guard isProcessTrusted() else {
exit(1)
}

setupWindow()
setupStatusItem()
setupEventManager()
trapKeyEvents()
Expand All @@ -39,6 +47,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {
_eventManager = appComponent.eventManager()
}

private func setupWindow() {
let window = NSWindow(contentRect: .zero, styleMask: .borderless, backing: .buffered, defer: true)
window.isOpaque = false
window.makeKeyAndOrderFront(nil)
window.backgroundColor = .clear
window.level = .floating
self.window = window
}

private func trapKeyEvents() {
let eventMask = (1 << CGEventType.keyDown.rawValue) | (1 << CGEventType.keyUp.rawValue)

Expand Down Expand Up @@ -71,4 +88,32 @@ class AppDelegate: NSObject, NSApplicationDelegate {
private func handleQuit() {
NSApplication.shared.terminate(nil)
}

private func showHighlight() {
guard let screen = NSScreen.currentScreen else { return }
guard let window = window else { return }

let highlighterView = HighlighterView(frame: screen.frame)
highlighterView.location = {
var mouseLocation = NSEvent.mouseLocation
mouseLocation.x -= screen.frame.origin.x
mouseLocation.y -= screen.frame.origin.y
return mouseLocation
}()

highlighterWork?.cancel()
let work = DispatchWorkItem() { self.hideHighlight() }
highlighterWork = work

window.contentView = highlighterView
window.setFrame(screen.frame, display: true)

let dispatchTime = DispatchTime.now() + DispatchTimeInterval.seconds(1)
DispatchQueue.main.asyncAfter(deadline: dispatchTime, execute: work)
}

private func hideHighlight() {
window?.contentView = nil
window?.setFrame(.zero, display: false)
}
}
26 changes: 19 additions & 7 deletions keyboard/Handlers/MouseHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ final class MouseHandler: Handler {
}

private let emitter: EmitterType
private let showHighlight: () -> Void

init(emitter: EmitterType) {
init(emitter: EmitterType, showHighlight: @escaping () -> Void) {
self.emitter = emitter
self.showHighlight = showHighlight
}

func activateSuperKeys() -> [KeyCode] {
Expand Down Expand Up @@ -86,19 +88,19 @@ final class MouseHandler: Handler {
return true

case [.y]:
moveCursor(.movePropotionallyTo(rx: 0.1, ry: 0.1))
moveCursor(.movePropotionallyTo(rx: 0.1, ry: 0.1), highlight: true)
return true
case [.u]:
moveCursor(.movePropotionallyTo(rx: 0.1, ry: 0.9))
moveCursor(.movePropotionallyTo(rx: 0.1, ry: 0.9), highlight: true)
return true
case [.i]:
moveCursor(.movePropotionallyTo(rx: 0.9, ry: 0.1))
moveCursor(.movePropotionallyTo(rx: 0.9, ry: 0.1), highlight: true)
return true
case [.o]:
moveCursor(.movePropotionallyTo(rx: 0.9, ry: 0.9))
moveCursor(.movePropotionallyTo(rx: 0.9, ry: 0.9), highlight: true)
return true
case [.u, .i]:
moveCursor(.movePropotionallyTo(rx: 0.5, ry: 0.5))
moveCursor(.movePropotionallyTo(rx: 0.5, ry: 0.5), highlight: true)
return true

case [Const.scrollKey, .h]:
Expand All @@ -114,6 +116,10 @@ final class MouseHandler: Handler {
emitter.emit(mouseScroll: .init(x: -50, y: 0))
return true

case [.space]:
showHighlight()
return true

case [.m]:
emitter.emit(mouseClick: .left)
return true
Expand All @@ -127,7 +133,7 @@ final class MouseHandler: Handler {
return false
}

func moveCursor(_ movement: Movement) {
func moveCursor(_ movement: Movement, highlight: Bool = false) {
guard let screenRect = NSScreen.currentScreenRect else { return }
guard let voidEvent = CGEvent(source: nil) else { return }

Expand All @@ -153,5 +159,11 @@ final class MouseHandler: Handler {
location.y = max(screenRect.minY, min(location.y, screenRect.maxY - 1))

emitter.emit(mouseMoveTo: location)

if highlight {
DispatchQueue.main.async {
self.showHighlight()
}
}
}
}
25 changes: 25 additions & 0 deletions keyboard/HighlighterView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Cocoa

class HighlighterView: NSView {
struct Const {
static let size: CGFloat = 32
static let color = NSColor(calibratedRed: 0, green: 0.7, blue: 1.0, alpha: 0.7)
}

var location: CGPoint?

override func draw(_ dirtyRect: NSRect) {
guard let location = location else { return }

let rect = NSMakeRect(
location.x - Const.size / 2,
location.y - Const.size / 2,
Const.size,
Const.size
)
let path = NSBezierPath(roundedRect: rect, xRadius: Const.size, yRadius: Const.size)
Const.color.set()
path.fill()
path.appendRect(dirtyRect)
}
}

0 comments on commit 2896d68

Please sign in to comment.