实现思路:

override func mouseDown(with event: NSEvent) {
      let location = event.locationInWindow
      switch ClipManager.shared.status {
      case .ready:
          // ....
      case .select:
					// 判断鼠标区域
          guard let rect = self.highlightRect,
								rect.contains(location)
					else { return }
					ClipManager.shared.status = .drag
					self.lastPoint = location
      default:
          return
      }
  }
override func mouseUp(with event: NSEvent) {
    switch ClipManager.shared.status {
    case .start:
        // ....
    case .drag, .adjust:
				// 保存高亮区域信息
				guard let rect = self.highlightRect else { return }
        self.startPoint = rect.origin
        self.selectDotType = .none
        self.lastRect = rect
        ClipManager.shared.status = .select
    default:
        return
    }
}
override func mouseDragged(with event: NSEvent) {
    let location = event.locationInWindow
    switch ClipManager.shared.status {
    case .start:
        // ....
    case .adjust:
        // 暂不实现
				break
    case .drag:
        guard var rect = self.highlightRect,
                  let window = self.window
        else { break }
        
				// 和上一次检测的鼠标位置的偏移
        var dx = location.x - self.lastPoint!.x
        var dy = location.y - self.lastPoint!.y

				// 偏移后的rect
        let offsetRect = rect.offsetBy(dx: dx, dy: dy)
        switch RectUtil.detectOverflow(rect: offsetRect, in: window) {
        case .bothOverflow:
						// 如果x和y都溢出,则抹零两轴的偏移量
            dx = 0
            dy = 0
        case .xOverflow:
						// x溢出,抹零x轴偏移量
            dx = 0
        case .yOverflow:
						// y溢出,抹零y轴偏移量
            dy = 0
        default:
            break
        }
        rect = rect.offsetBy(dx: dx, dy: dy)
        
				// 更新highlightRect,记录鼠标位置
        self.highlightRect = rect
        self.lastPoint = location
        self.highlight()
    default:
        break
    }
}

其中rect溢出检测实现为:

class RectUtil: NSObject {
		static func detectOverflow(rect: NSRect, in window:NSWindow) -> RectIssue {
        let origin = rect.origin
        let points = [origin,
                      origin.offsetBy(dx: rect.width, dy: 0),
                      origin.offsetBy(dx: 0, dy: rect.height),
                      origin.offsetBy(dx: rect.width, dy: rect.height)
        ]
        var xFlag = false
        var yFlag = false
        for p in points {
            if p.x < 0 || p.x > window.frame.width{
                xFlag = true
            }
            if p.y < 0 || p.y > window.frame.height{
                yFlag = true
            }
        }
        if xFlag && yFlag {
            return .bothOverflow
        }else if xFlag {
            return .xOverflow
        }else if yFlag {
            return .yOverflow
        }else{
            return .normal
        }
    }
	  // ... other functions
}

enum RectIssue {
    case xOverflow
    case yOverflow
    case bothOverflow
    case normal
}

高亮区域的调整 ➡️