0

I'm learning SwiftUI programming by trying to duplicate basic features in the MacOS Finder.

The groups button in the Finder window (screenshot below) has me stumped. Clicking the menu shows the group options, while option-clicking shows the sort options. I can't figure out how that's done.

enter image description here

My basic code is as follows:

Menu {
  if NSEvent.modifierFlags.contains(.option) {
    Picker(selection: viewSorts, label: EmptyView()) {
      ForEach(viewSorts) { sort in
        Text(sort.name).tag(sort)
      }
    }
    .labelsHidden()
    .pickerStyle(InlinePickerStyle())
  } else {
    Picker(selection: viewGroups, label: EmptyView()) {
      ForEach(viewGroups) { group in
        Text(group.name).tag(group)
    }
    .labelsHidden()
    .pickerStyle(InlinePickerStyle())
  }
} Label: {
  Image(systemName: "square.grid.3x1.below.line.grid.1x2")
}

It works, however NSEvent.modifierFlags.contains(.option) never evaluates to true.

This post has two examples that I used to try to fix the problem:

Using onTapGesture with EventModifiers:

@State private var showSort = false

Menu {
  if showSort {
//    ... show sort picker ...
  } else {
//    ... show group picker ...
  }
} Label: {
  Image(systemName: "square.grid.3x1.below.line.grid.1x2")
}
  .gesture(TapGesture().modifiers(.option).onEnded {
    showSort = true
  })
  .onTapGesture {
    showSort = false
  }

And another using a CGKeyCode extension:

import CoreGraphics

extension CGKeyCode
{
    static let kVK_Option     : CGKeyCode = 0x3A
    static let kVK_RightOption: CGKeyCode = 0x3D
    
    var isPressed: Bool {
        CGEventSource.keyState(.combinedSessionState, key: self)
    }
    
    static var optionKeyPressed: Bool {
        return Self.kVK_Option.isPressed || Self.kVK_RightOption.isPressed
    }
}

Menu {
  if CGKeyCode.optionIsPressed {
//    ... show sort picker ...
  } else {
//    ... show group picker ...
  }
} Label: {
  Image(systemName: "square.grid.3x1.below.line.grid.1x2")
}

And from these two posts (1, 2), addLocalMonitorForEvents:

@State private var showSort = false

Menu {
  if showSort {
//    ... show sort picker ...
  } else {
//    ... show group picker ...
  }
} Label: {
  Image(systemName: "square.grid.3x1.below.line.grid.1x2")
}
.onAppear() {
  NSEvent.addLocalMonitorForEvents(matching: .keyDown) { (keyEvent) -> NSEvent? in
    if keyEvent.modifierFlags == .option {
        showSort = true
    } else {
        showSort = false
    }
    return keyEvent
  }
}

The answer is probably staring at me in the face, but I just can't see it! Thank you for any help!

UPDATE: onContinuousHover does work, but it only updates when the mouse is moving over the menu.

  .onContinuousHover { _ in
    showSort = NSEvent.modifierFlags.contains(.option) ? true : false
  }

But onTapGesture doesn't work

  .onTapGesture {
    showSort = NSEvent.modifierFlags.contains(.option) ? true : false
  }
user09274385
  • 55
  • 1
  • 9
  • As much as possible look for solutions already available in SwiftUI. `EventModifiers` would be able to cater to your needs. Refer: https://stackoverflow.com/a/59308898/1046037 – user1046037 Oct 07 '22 at 16:55
  • Do you feel I didn't look for solutions already available? Did you not see that I tried your solution above? Perhaps you would like to illustrate how I implemented your solution incorrectly? – user09274385 Oct 08 '22 at 00:45

0 Answers0