-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resize window, teleport mouse, and more.
- Added a menu button to reset the window size to match the configured resolution. - Added a menu button to enable/disable the ability to teleport the mouse cursor to the virtual display when clicking over the window. - Added a menu button to enable/disable the ability to resize the window. - Increased the maximum possible virtual display resolution to 2K monitors (3840x2160). - Added more standard resolutions. - Removed the previous way to detect whether the mouse is in the virtual display based on periodic polling. - Added events to capture the mouse movement and when the window is clicked. - Enhanced the MouseLocationState to include mouse-related characteristics as the mouse location, the event generted by the mouse, as well as the screen where the mouse is positioned, and flags to know the current mouse status and position, which can be used to later enhance this application.
- Loading branch information
Earl Ramirez Sanchez
committed
Nov 2, 2023
1 parent
2267a19
commit 38682a5
Showing
5 changed files
with
222 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 87 additions & 11 deletions
98
DeskPad/Backend/MouseLocation/MouseLocationSideEffect.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,98 @@ | ||
import Foundation | ||
import ReSwift | ||
|
||
private var timer: Timer? | ||
|
||
enum MouseLocationAction: Action { | ||
case located(isWithinScreen: Bool) | ||
case located(isWithinVirtualDisplay: Bool) | ||
case setWindow(window: NSWindow) | ||
case update(screenContainingMouse: NSScreen?, screenContainingWindow: NSScreen?, screenVirtualDisplay: NSScreen?, isWithinVirtualDisplay: Bool, isWithinScreenContainingWindow: Bool, isWithinWindow: Bool, isWithinWindowContent: Bool, isWithinVirtualDisplayBorder: Bool) | ||
} | ||
|
||
enum MouseLocationSettings: Action { | ||
case enableTeleport(isTeleportEnabled: Bool) | ||
case enableWindowResize(isWindowResizeAllowed: Bool) | ||
case resetWindowSize | ||
} | ||
|
||
enum MouseLocationEvent: Action { | ||
case localMouseClicked(mouseLocation: NSPoint, event: NSEvent) | ||
case localMouseMoved(mouseLocation: NSPoint, event: NSEvent) | ||
case globalMouseMoved(mouseLocation: NSPoint, event: NSEvent) | ||
} | ||
|
||
func mouseLocationSideEffect() -> SideEffect { | ||
return { _, dispatch, getState in | ||
if timer == nil { | ||
timer = Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { _ in | ||
let mouseLocation = NSEvent.mouseLocation | ||
let screens = NSScreen.screens | ||
let screenContainingMouse = (screens.first { NSMouseInRect(mouseLocation, $0.frame, false) }) | ||
let isWithinScreen = screenContainingMouse?.displayID == getState()?.screenConfigurationState.displayID | ||
dispatch(MouseLocationAction.located(isWithinScreen: isWithinScreen)) | ||
return { action, dispatch, getState in | ||
guard let appState = getState() else { return } | ||
UserDefaults.standard.set(appState.mouseLocationState.isTeleportEnabled, forKey: "isTeleportEnabled") | ||
UserDefaults.standard.set(appState.mouseLocationState.isWindowResizeAllowed, forKey: "isWindowResizeAllowed") | ||
let event = appState.mouseLocationState.event | ||
if event != nil, appState.screenConfigurationState.resolution != .zero { | ||
let mouseLocation = appState.mouseLocationState.mouseLocation | ||
let screens = NSScreen.screens | ||
let window = appState.mouseLocationState.window | ||
let screenContainingMouse = (screens.first { NSMouseInRect(mouseLocation, $0.frame, false) }) | ||
let screenContainingWindow = (screens.first { NSPointInRect((window?.frame.origin)!, $0.frame) }) | ||
let screenVirtualDisplay = (screens.first { $0.displayID == appState.screenConfigurationState.displayID }) | ||
let isWithinVirtualDisplay = screenContainingMouse?.displayID == screenVirtualDisplay?.displayID | ||
let isWithinScreenContainingWindow = screenContainingMouse?.displayID == screenContainingWindow?.displayID | ||
let isWithinWindow = NSMouseInRect(mouseLocation, (window?.frame)!, false) | ||
let isWithinWindowContent = NSMouseInRect((window?.mouseLocationOutsideOfEventStream)!, (window?.contentView?.frame)!, false) | ||
// let isTeleportEnabled = appState.mouseLocationState.isTeleportEnabled | ||
|
||
let borderWidth: CGFloat = 5 // Border width | ||
let innerRect = NSInsetRect((screenVirtualDisplay?.frame)!, borderWidth, borderWidth) | ||
let isWithinInnerRectangle = NSMouseInRect(mouseLocation, innerRect, false) | ||
let isWithinVirtualDisplayBorder = isWithinVirtualDisplay && !isWithinInnerRectangle ? true : false | ||
|
||
/* print("") | ||
print("Mouse event") | ||
print("event:", event) | ||
print("windowNumber:", window?.windowNumber as Any) | ||
print("screenContainingMouse:", screenContainingMouse?.localizedName as Any) | ||
print("screenContainingWindow:", screenContainingWindow?.localizedName as Any) | ||
print("screenVirtualDisplay:", screenVirtualDisplay?.localizedName as Any) | ||
print("isWithinVirtualDisplay:", isWithinVirtualDisplay) | ||
print("isWithinScreenContainingWindow:", isWithinScreenContainingWindow) | ||
print("isWithinWindow:", isWithinWindow) | ||
print("isWithinWindowContent:", isWithinWindowContent) | ||
print("isWithinVirtualDisplayBorder:", isWithinVirtualDisplayBorder) | ||
print("isTeleportEnabled:", isTeleportEnabled) */ | ||
|
||
dispatch(MouseLocationAction.update(screenContainingMouse: screenContainingMouse, screenContainingWindow: screenContainingWindow, screenVirtualDisplay: screenVirtualDisplay, isWithinVirtualDisplay: isWithinVirtualDisplay, isWithinScreenContainingWindow: isWithinScreenContainingWindow, isWithinWindow: isWithinWindow, isWithinWindowContent: isWithinWindowContent, isWithinVirtualDisplayBorder: isWithinVirtualDisplayBorder)) | ||
} | ||
|
||
switch action { | ||
case MouseLocationEvent.localMouseClicked: | ||
// print("localClick:", mouseLocation) | ||
if appState.mouseLocationState.isTeleportEnabled, appState.mouseLocationState.isWithinWindowContent { | ||
teleportMouseToVirtualDisplay(state: appState.mouseLocationState) | ||
} | ||
case MouseLocationEvent.localMouseMoved: | ||
// print("localMove:", mouseLocation) | ||
do {} | ||
case MouseLocationEvent.globalMouseMoved: | ||
// print("globalMove:", mouseLocation) | ||
do {} | ||
case MouseLocationSettings.resetWindowSize: | ||
appState.mouseLocationState.window?.contentAspectRatio = appState.screenConfigurationState.resolution | ||
appState.mouseLocationState.window?.setContentSize(appState.screenConfigurationState.resolution) | ||
appState.mouseLocationState.window?.center() | ||
case MouseLocationSettings.enableWindowResize: | ||
if appState.mouseLocationState.isWindowResizeAllowed { | ||
appState.mouseLocationState.window?.styleMask = [.titled, .closable, .resizable, .miniaturizable] | ||
} else { | ||
appState.mouseLocationState.window?.styleMask = [.titled, .closable, .miniaturizable] | ||
} | ||
default: | ||
return | ||
} | ||
} | ||
} | ||
|
||
func teleportMouseToVirtualDisplay(state: MouseLocationState) { | ||
// Move the mouse to the virtual display | ||
let newX = CGFloat(state.window!.mouseLocationOutsideOfEventStream.x * (state.screenVirtualDisplay!.frame.width / state.window!.contentView!.frame.size.width)) | ||
let newY = CGFloat(state.screenVirtualDisplay!.frame.height - state.window!.mouseLocationOutsideOfEventStream.y * (state.screenVirtualDisplay!.frame.height / state.window!.contentView!.frame.size.height)) | ||
let newPoint = NSPoint(x: newX, y: newY) | ||
// print("newPoint:", newPoint) | ||
CGDisplayMoveCursorToPoint(state.screenVirtualDisplay!.displayID, newPoint) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.