@@ -179,6 +179,7 @@ @implementation AppDelegate {
179179 NSTimer *_scrollTimer;
180180 NSPoint _scrollDelta;
181181 id _mouseMovedMonitor;
182+ id _scrollWheelMonitor;
182183}
183184
184185- (instancetype )initWithVirtualMachine : (VZVirtualMachine *)virtualMachine
@@ -225,6 +226,10 @@ - (void)dealloc
225226 [NSEvent removeMonitor: _mouseMovedMonitor];
226227 _mouseMovedMonitor = nil ;
227228 }
229+ if (_scrollWheelMonitor) {
230+ [NSEvent removeMonitor: _scrollWheelMonitor];
231+ _scrollWheelMonitor = nil ;
232+ }
228233 [self stopScrollTimer ];
229234 if (_virtualMachine) {
230235 [_virtualMachine removeObserver: self forKeyPath: @" state" ];
@@ -416,6 +421,13 @@ - (void)setupGraphicWindow
416421 return event;
417422 }];
418423
424+ // Add scroll wheel event monitor for zoom functionality
425+ _scrollWheelMonitor = [NSEvent addLocalMonitorForEventsMatchingMask: NSEventMaskScrollWheel
426+ handler: ^NSEvent *(NSEvent *event) {
427+ [self handleScrollWheel: event];
428+ return event;
429+ }];
430+
419431 // Create scroll view for the virtual machine view
420432 NSScrollView *scrollView = [self createScrollViewForVirtualMachineView: _virtualMachineView];
421433 [_window setContentView: scrollView];
@@ -638,6 +650,7 @@ - (void)showErrorAlertWithMessage:(NSString *)message error:(NSError *)error
638650- (void )toggleZoomMode : (id )sender
639651{
640652 _isZoomEnabled = !_isZoomEnabled;
653+ NSScrollView *scrollView = (NSScrollView *)_window.contentView ;
641654
642655 // Reset zoom when zoom mode is disabled.
643656 if (!_isZoomEnabled) {
@@ -646,15 +659,29 @@ - (void)toggleZoomMode:(id)sender
646659 [context setDuration: 0.3 ];
647660 [[_window.contentView animator ] setMagnification: 1.0 ];
648661 }
649- completionHandler: nil ];
662+ completionHandler: ^{
663+ // Hide scrollers when zoom is disabled
664+ if ([scrollView isKindOfClass: [NSScrollView class ]]) {
665+ scrollView.hasVerticalScroller = NO ;
666+ scrollView.hasHorizontalScroller = NO ;
667+ }
668+ }];
669+ } else {
670+ // Show scrollers when zoom is enabled (they'll auto-hide when not needed)
671+ if ([scrollView isKindOfClass: [NSScrollView class ]]) {
672+ scrollView.hasVerticalScroller = YES ;
673+ scrollView.hasHorizontalScroller = YES ;
674+ scrollView.autohidesScrollers = YES ;
675+ }
650676 }
651677}
652678
653679- (NSScrollView *)createScrollViewForVirtualMachineView : (VZVirtualMachineView *)view
654680{
655681 NSScrollView *scrollView = [[[NSScrollView alloc ] initWithFrame: _window.contentView.bounds] autorelease ];
656- scrollView.hasVerticalScroller = YES ;
657- scrollView.hasHorizontalScroller = YES ;
682+ scrollView.hasVerticalScroller = NO ;
683+ scrollView.hasHorizontalScroller = NO ;
684+ scrollView.autohidesScrollers = YES ;
658685 scrollView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
659686 scrollView.documentView = view;
660687
@@ -697,6 +724,40 @@ - (void)handleMagnification:(NSMagnificationGestureRecognizer *)recognizer
697724 [scrollView setMagnification: newMagnification centeredAtPoint: centeredPoint];
698725}
699726
727+ // Handles scroll wheel events for zooming when Command or Option key is held.
728+ // This provides zoom functionality for mice and non-trackpad devices.
729+ - (void )handleScrollWheel : (NSEvent *)event
730+ {
731+ if (!_isZoomEnabled) {
732+ return ;
733+ }
734+
735+ // Only zoom if Command or Option key is held
736+ if (!(event.modifierFlags & NSEventModifierFlagCommand) &&
737+ !(event.modifierFlags & NSEventModifierFlagOption)) {
738+ return ;
739+ }
740+
741+ NSScrollView *scrollView = (NSScrollView *)_window.contentView ;
742+ if (![scrollView isKindOfClass: [NSScrollView class ]]) {
743+ return ;
744+ }
745+
746+ // Calculate zoom delta (scrolling up = zoom in, down = zoom out)
747+ CGFloat zoomDelta = event.scrollingDeltaY * 0.01 ; // Scale factor for smooth zooming
748+ CGFloat currentMagnification = scrollView.magnification ;
749+ CGFloat newMagnification = currentMagnification + zoomDelta;
750+
751+ // Clamp to min/max magnification
752+ newMagnification = MIN (scrollView.maxMagnification , MAX (scrollView.minMagnification , newMagnification));
753+
754+ // Get mouse location for centered zooming
755+ NSPoint mouseLocation = [_window.contentView convertPoint: event.locationInWindow fromView: nil ];
756+ NSPoint centeredPoint = [scrollView.contentView convertPoint: mouseLocation fromView: _window.contentView];
757+
758+ [scrollView setMagnification: newMagnification centeredAtPoint: centeredPoint];
759+ }
760+
700761// When the mouse approaches the window's edges, this handler adjusts the scroll position
701762// to provide a smooth panning experience without requiring manual scroll input.
702763- (void )handleMouseMovement : (NSEvent *)event
0 commit comments