0

Using Xcode 8, Swift 3 and Interface Builder with Storyboards and a very basic view controller featuring only a button (Play) and a slider (volume).

I'm trying to use my NSSlider while pressing a button at the same time. For instance, I need to be able to keep pressing "Play" while slowly lowering the volume. What happens instead is that only one button can be in use at a time. So, as long as I am pressing "Play" using the return key, I can't adjust the volume and vice versa.

In this example, the Play button is triggered by the "return" key.

Here is the code in ViewController.swift. This is just an example app I created quickly to study the problem.

Is there an Interface Builder setting on the NSSLider that I am missing, or can I do something in my code to achieve what I am trying to do?

import Cocoa
import AVFoundation

class ViewController: NSViewController {

    var audioPlayer = AVAudioPlayer()
    var sliderValue: Float = 0

    @IBOutlet weak var volumeSliderOutlet: NSSlider!

    override func viewDidLoad() {
        super.viewDidLoad()
        do{
            audioPlayer =  try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "bell ding", ofType: "wav")!))
        }
        catch {
            print(error)
        }
        audioPlayer.prepareToPlay()


        // Do any additional setup after loading the view.
    }

    @IBAction func playButtonAction(_ sender: NSButton) {
        if audioPlayer.isPlaying {
            audioPlayer.currentTime = 0.0
            audioPlayer.play()
        } else {
        audioPlayer.prepareToPlay()
        audioPlayer.play()
        }
    }

    @IBAction func volumeSliderAction(_ sender: NSSlider) {
        if audioPlayer.isPlaying {
            sliderValue = self.volumeSliderOutlet.floatValue
            audioPlayer.volume = sliderValue
        } else {
            return
        }
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }


}

I've also tried this, based on advice from @inspector_60, but it doesn't work either. Still can't handle the slider while continuing to press the shortcut key for the button "return".

override func keyDown(with event: NSEvent) {
        if (event.keyCode == 36) {
            self.playButtonAction(nil)
        }
        else {
            return
        }
    }

    func playButtonAction(_ sender: NSButton?) {
        if audioPlayer.isPlaying {
            audioPlayer.currentTime = 0.0
            audioPlayer.play()
        } else {
            audioPlayer.prepareToPlay()
            audioPlayer.play()
        }
    }
  • Can't you use the Play action on the VolumeSliderAction combined? – Pedro Pinho Jul 18 '17 at 21:57
  • I'm not sure what you mean. I need to be able to use both actions at the same time or separately. I'd like to be playing the sound over and over again by pressing "return" while (with my other hand) using the mouse to drag the slider up and down thereby changing the volume. As of now, I can only do one or the other. Can you give me an example of what you mean? – RickshawBoy Jul 18 '17 at 22:18

1 Answers1

0

IBAction are UI events so not suitable for multiple simultaneous clicks (you have only one mouse pointer). Use handling key events in order to handle keyboard events for simultaneous actions.

You need to also implement the mouse events, these links should help:

  1. Apple document about mouse events and specifically Filtering Out Key Events During Mouse-Tracking Operations
  2. This stack overflow answer on how to implement this approach
  3. This post that will give you more information and example - Ron's answer links to a question not that different from yours
inspector_60
  • 448
  • 1
  • 3
  • 12
  • Thank you. I've tried adjusting the code so that instead of using the IB built in "Key Equivalent", I'm just using the keyDown to call a function to play the sound. I still end up with the same problem. So long as I am controlling the slider with the mouse, I cannot trigger the play function with a key. – RickshawBoy Jul 18 '17 at 23:27
  • I've been trying to use your advice but I just can't seem to make it work. I keep looking over all the links you shared and trying to translate from Objective-C to Swift with no luck. This kinda thing just happens in Python (in another version of the same app I created). Any chance you can give me a Swift example? I just want to be able to keep hitting my key equivalent (return) while I'm adjusting the volume of the sound. – RickshawBoy Jul 26 '17 at 03:33