Hammerspoon / hammerspoon

Staggeringly powerful macOS desktop automation with Lua
http://www.hammerspoon.org
MIT License
12.16k stars 587 forks source link

hs.midi is quitting browser apps. #2755

Open benjaminwelch opened 3 years ago

benjaminwelch commented 3 years ago

I have a Brave (Chrome) Browser app Roam Research, for some reason, when I run my midi code, it quits that app specifically, if it's open. I haven't noticed this with any other app. Here's the midi code I'm using:

midiDevice = hs.midi.newVirtualSource("Maschine MK3 Virtual Input")
if midiDevice then
midiDevice:callback(function(object, deviceName, commandType, description, metadata)
       print("object: " .. tostring(object))
       print("deviceName: " .. deviceName)
       print("commandType: " .. commandType)
       print("description: " .. description)
       print("metadata: " .. hs.inspect(metadata))

    win = hs.window.get("SooperLooper v 1.7.3")
    if win then
      win:focus()
    end
    local sL = "SooperLooper"
-- could turn the below into a for loop maybe to save some code?
    if metadata.controllerNumber == 100 and metadata.channel == 9 then
      hs.eventtap.keyStroke({}, "1", 0, "SooperLooper")
    elseif metadata.controllerNumber == 101 and metadata.channel == 9 then
      hs.eventtap.keyStroke({}, "2", 0, "SooperLooper")
    elseif metadata.controllerNumber == 102 and metadata.channel == 9 then
      hs.eventtap.keyStroke({}, "3", 0, sL)
    elseif metadata.controllerNumber == 103 and metadata.channel == 9 then
      hs.eventtap.keyStroke({}, "4", 0, sL)
    elseif metadata.controllerNumber == 104 and metadata.channel == 9 then
      hs.eventtap.keyStroke({}, "5", 0, sL)
    elseif metadata.controllerNumber == 105 and metadata.channel == 9 then
      hs.eventtap.keyStroke({}, "6", 0, sL)
    elseif metadata.controllerNumber == 106 and metadata.channel == 9 then
      hs.eventtap.keyStroke({}, "7", 0, sL)
    elseif metadata.controllerNumber == 107 and metadata.channel == 9 then
      hs.eventtap.keyStroke({}, "8", 0, sL)
    end
end)
end

I have a music looper app called SooperLooper that accepts midi messages but it doesn't allow you to specify a track/loop via midi, the corresponding numbers on the computer keyboard are automatically mapped to each track/loop. Since I wanted to switch loops via the midi controller, I wrote the code above which works great.

However, using the MK3 controller will quit an app I often leave open all the time, Roam Research. I tested this with another Brave Browser app and it does the same thing. However, it doesn't quit Brave itself which seems odd. And the apps will quit if I turn the MK3 on. Once it boots up, it quits those apps. If anyone has any suggestions on how I might debug this, I'll try it out!

cmsj commented 3 years ago

Wow, that is super weird! Does it happen the same way even if Hammerspoon isn't running?

benjaminwelch commented 3 years ago

@cmsj Yeah, very strange! No, it doesn't. If I quit Hammerspoon and turn off/on the MK3, Roam stays open. If I launch Hammerspoon, then turn off/on the MK3, Roam is quit as soon as the MK3 boots into MIDI Mode (ready to play).

And if I have the MK3 on already, Roam will stay open until I press any (not just the ones with keyStrokes) button/key on the controller and then it quits Roam again. You can see I tried to target SooperLooper with the keystrokes but that didn't fix it. The keystrokes are still sent to all apps so I might have messed something up there.

It may be related to the callback. If I comment out everything but: midiDevice = hs.midi.newVirtualSource("Maschine MK3 Virtual Input") Roam stays open regardless.

If there's a way I could bind the midi messages to keyStrokes without the callback, that might solve this issue but it's still a very odd and specific behavior. I'm happy to test or debug but I'll need some pointers.

benjaminwelch commented 3 years ago

In case it helps, here is what is printed to the console when I turn on the MK3:

2021-03-11 12:23:18: object: hs.midi: Maschine MK3 Virtual Input (0x600001ab09f8)
2021-03-11 12:23:18: deviceName: Maschine MK3 Virtual Input
2021-03-11 12:23:18: commandType: systemExclusive
2021-03-11 12:23:18: description: <MIKMIDISystemExclusiveCommand: 0x600000efd470> time: 12:23:18.639 command: 240 universal: 0 sysexChannel: 0 
    data: <f0002109 16004d50 00014601 f7>
2021-03-11 12:23:18: metadata: {
  data = "f000210916004d5000014601f7",
  isVirtual = true,
  manufacturerID = 0,
  sysexChannel = 0,
  sysexData = "210916004d5000014601",
  timestamp = "12:23:18.639"
}

The above will cause Roam to quit. And here's what happens when I hit a key/button:

2021-03-11 12:25:05: object: hs.midi: Maschine MK3 Virtual Input (0x600001a28138)
2021-03-11 12:25:05: deviceName: Maschine MK3 Virtual Input
2021-03-11 12:25:05: commandType: controlChange
2021-03-11 12:25:05: description: <MIKMIDIControlChangeCommand: 0x600000eeb990> time: 12:25:05.645 command: 191 channel 9 control number: 100 value: 127 14-bit? 0 
    data: <b9647f>
2021-03-11 12:25:05: metadata: {
  channel = 9,
  controllerNumber = 100,
  controllerValue = 127,
  data = "b9647f",
  fourteenBitCommand = false,
  fourteenBitValue = 16256,
  isVirtual = true,
  timestamp = "12:25:05.645"
}
2021-03-11 12:25:05: targetApp: SooperLooper
2021-03-11 12:25:05: keyDelay: 0

This will also cause Roam to quit.

cmsj commented 3 years ago

Couple of thoughts that don't directly tie into the issue you're having - I'm not sure i'd set the keyStroke() delay as low as 0, you ideally want at least a small delay for it to be handled. Secondly, the final argument to keyStroke() isn't a string, it should be an hs.application object (in this case, the result of hs.application.get("SooperLooper").

latenitefilms commented 3 years ago

What happens if you comment out everything after the last print in the callback? Does it still cause the app to quit?

It's very odd that the callback itself would cause another app to randomly close - so my GUESS is that for some reason the keystrokes themselves are trigging the window to close somehow.

benjaminwelch commented 3 years ago

@cmsj thanks for the pointers. I added the default delay and fixed the application argument. That is now targeting the keyStroke correctly.

@latenitefilms thanks, I messed around based on your notes and I believe this is the culprit:

    win = hs.window.get("SooperLooper v 1.7.3")

I was using this to bring the SooperLooper window into focus whenever I use the MK3. It does focus the SL window but when I comment this out, Roam doesn't quit. I'm not sure why this would target another app or quit it. Here's what I see in the console when Roam quits:

2021-03-15 11:21:09: -- Loading extension: window
2021-03-15 11:21:09: -- Loading extension: eventtap
2021-03-15 11:21:09: targetApp: hs.application: SooperLooper (0x606001040998)
2021-03-15 11:21:09: keyDelay: 200000

Here's what I see in the console when I comment out win = hs.window.get("SooperLooper v 1.7.3"):

2021-03-15 11:23:23: -- Loading extension: eventtap
2021-03-15 11:23:23: targetApp: hs.application: SooperLooper (0x6060010833b8)
2021-03-15 11:23:23: keyDelay: 200000

Roam remains open. Definitely closer. I use win = hs.window.focusedWindow() above to move windows around and Roam stays open. I've hit another dead-end. I appreciate the help. Let me know if there's anything else I can try or add to figure out what's going on. Thanks!

benjaminwelch commented 3 years ago

Okay, I still haven't figured out why the app was being quit. I'm happy to test that further if that would be useful, just let me know.

I did solve the issue by using hs.application:getWindow("SooperLooper v 1.7.3") instead of hs.window.get("SooperLooper v 1.7.3"):

local sL = hs.application.get("SooperLooper")
    local win = sL:getWindow("SooperLooper v 1.7.3")
    if win then
      win:focus()
      print(win)
    end

Roam remains open, SooperLooper is focused, and the keyStrokes changes the highlighted track as expected. Here's what I see in the console with the above:

2021-03-15 11:49:02: hs.window: SooperLooper v 1.7.3 (0x60600066dcd8)
2021-03-15 11:49:02: targetApp: hs.application: SooperLooper (0x606000667438)
2021-03-15 11:49:02: keyDelay: 200000

In case this is helpful. Thanks again for the help here.