Windows 10 keystrokes not reaching Davinci resolve

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
dj53144
Posts: 1
Joined: 20 Sep 2022, 14:16

Windows 10 keystrokes not reaching Davinci resolve

Post by dj53144 » 20 Sep 2022, 15:00

I installed and tested the current version (not v2) and a test works sending text to notepad.
I want to use a script with midi2keypress from https://youtu.be/h0IZiYEkvLg to control davinci resolve with a behringer x touch one.
I tried his first method using bome miditranslator classic and it sort of worked but quit as I was try to adjust things.
I didn't care for the program so I tried the auto hotkey route. I got it installed and used his script and I can see all of the midi events but davinci resolve doesn't seem to be getting the keystrokes being sent. i googled it and tried many things with running as administrator, compatibility to windows 8, uninstalling deleting directory reinstalling.
I see that there are different types of sends in the syntax, is this where the problem might be?
I like autohotkey because I can program anything that I want easily.
Unfortunately, if windows is intercepting the keystrokes it won't be of any use.
Is there a good way of seeing what keystrokes are being sent so that I can trouble shoot the output?
I get the feeling that DaVinci resolve's midi implementation is not very robust.
I also use traction waveform pro and it has a midi learn function that works well.
by the way, I test by going to waveform and resolve and blender and the keystrokes don't seem to be reaching them either.
anyways, thanks in advance for any help.

Here is the script:

Code: Select all

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; Ruud Boer, January 2022
; The videos:
; 1: https://www.youtube.com/watch?v=Y3gow1TlL78
; 2: https://www.youtube.com/watch?v=D-Wvf4HNBnU
; 3: https://www.youtube.com/watch?v=h0IZiYEkvLg
; The scripts: https://github.com/RudyB24/AutoHotKey_Bome_MIDI_2_Key
; MIDI events received from the Behringer X Touch One are transferred into
; keyboard shortcuts for DaVinci Resolve (or any other app you'd wish to use)
; Based on https://github.com/genmce/AHK_Midi2Keypress ... author unknown.
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

#Persistent
#SingleInstance, force
SetTitleMatchMode, 2
SendMode Input              	; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% 	; Ensures a consistent starting directory.
; =============== 
version = XTouchOne2DaVinciResolve
; =============== 
readini()					            ; load midi port from .ini file 
gosub, MidiPortRefresh        ; used to refresh the input and output port lists - see label below 
port_test(numports)   		    ; test the ports - check for valid ports?
gosub, midiin_go              ; opens the midi input port listening routine
gosub, midiMon           	    ; see below - a midi monitor gui - for learning mostly - comment this line eventually.

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; MidiMsgDetect is called each time a MIDI message is received.
; The MIDI message is broken up into 5 variables: statusbyte, chan, data1, data2 ,pitchb.
; See http://www.midi.org/techspecs/midimessages.php (decimal values).
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

MidiMsgDetect(hInput, midiMsg, wMsg) ; !!!! Midi input section in calls this function each time a midi message is received. Then the midi message is broken up into parts for manipulation.  See http://www.midi.org/techspecs/midimessages.php (decimal values).
{
	global statusbyte, chan, note, cc, data1, data2, stb ;Make these vars global to be used in other functions
	statusbyte :=  midiMsg & 0xFF          ; Extract statusbyte = what type of MIDI message and what channel
	chan       := (statusbyte & 0x0f) + 1  ; The MIDI channel
	data1      := (midiMsg >> 8) & 0xFF    ; data1 is Note # or CC #
	data2      := (midiMsg >> 16) & 0xFF   ; data2 is Velocity or CC value
	pitchb     := (data2 << 7) | data1     ; (midiMsg >> 8) & 0x7F7F  masking to extract the pitchbends  

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; ADD YOUR OWN INSTRUCTIONS HERE USING: if (data1=... [and/or data2=...) Send ...
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

if statusbyte between 176 and 191  ; MIDI CC
  {
    stb := "CC" ;The stb variable is used for the MIDI Monitor display
    if (data1=60 and data2=65)
      Send +{Left} ; Jog wheel left = Left 1s
    if (data1=60 and data2=1)
      Send +{Right} ; Jog wheel right = Right 1s
    if (data1=16 and data2=65)
      Send {Left} ; Pan knob left = Left 1 frame
    if (data1=16 and data2=1)
      Send {Right} ; Pan knob right = Right 1 frame
  }
if statusbyte between 144 and 159  ; MIDI NoteOn
  {
    stb := "NoteOn"
    if (data1=46 and data2=127) ; Bank Left = Clip In point
      Send i
    if (data1=47 and data2=127) ; Bank Right = Clip Out point
      Send o
    if (data1=54 and data2=127) ; F1 = Append at End
      Send +{F12}
    if (data1=55 and data2=127) ; F2 = Insert
      Send {F9}
    if (data1=56 and data2=127) ; F3 = Place on Top
      Send {F12}
    if (data1=57 and data2=127) ; F4 = Replace
      Send +{F11}
    if (data1=58 and data2=127) ; F5 = Overwrite
      Send {F10}
    if (data1=59 and data2=127) ; F6 = Ripple Overwrite
      Send +{F10}
    if (data1=84 and data2=127) ; Marker = place marker on timeline
      Send m
    if (data1=85 and data2=127) ; Nudge = Trim Edit Mode
      Send a
    if (data1=86 and data2=127) ; Cycle = Dynamic Trim Mode
      Send t
    if (data1=87 and data2=127) ; Drop = Cut Blade
      Send b
    if (data1=88 and data2=127) ; Replace = Magnet Snap Toggle
      Send n
    if (data1=89 and data2=127) ; Click = Undo
      Send ^z
    if (data1=90 and data2=127) ; Solo = Redo
      Send ^+z
    if (data1=96 and data2=127) ; Up = Zoom in
      Send ^{+}
    if (data1=97 and data2=127) ; Down = Zoom out
      Send ^-
    if (data1=98 and data2=127) ; Left = Cursor to previous edit
      Send {Up}
    if (data1=99 and data2=127) ; Right = Cursor to next edit
      Send {Down}
    if (data1=91 and data2=127) ; << = Fast rewind
      Send +j
    if (data1=92 and data2=127) ; >> = Fast forward
      Send +l
    if (data1=93 and data2=127) ; Stop = Stop
      Send k
    if (data1=94 and data2=127) ; Play = Play / Pause
      Send {Space}
    if (data1=101 and data2=127) ; Scrub = Audio scrub
      Send +s
    if (data1=100 and data2=127) ; Zoom = Zoom toggle
      Send +z
    if (data1=102 and data2=0)   ; Foot switch Play / Pause
      Send {Space}
  }
if statusbyte between 128 and 143 ; MIDI NoteOff
  {
    stb := "NoteOff"
  }
if statusbyte between 192 and 208 ; MIDI Program Change
  {
    stb := "PC"
  }
if statusbyte between 224 and 254 ; MIDI Pitch Bend
  {
    stb := "PitchB"
  }

MidiInDisplay(stb, statusbyte, chan, data1, data2) ; midi display function called when message received
} ; end of MidiMsgDetect funciton
return

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; NO NEED TO EDIT ANYTHING BELOW HERE
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

MidiInDisplay(stb, statusbyte, chan, data1, data2) ; update the midimonitor gui
{
Gui,3:default
Gui,3:ListView, In1 					; see the first listview midi in monitor
  LV_Add("",stb,statusbyte,chan,data1,data2)
  LV_ModifyCol(1,"center")
  LV_ModifyCol(2,"center")
  LV_ModifyCol(3,"center")
  LV_ModifyCol(4,"center")
  LV_ModifyCol(5,"center")
  If (LV_GetCount() > 10)
    {
      LV_Delete(1)
    }
}
return

midiMon: ; midi monitor gui with listviews
gui,3:destroy
gui,3:default
Gui,3:Add, ListView, x5 r11 w220 Backgroundblack cyellow Count10 vIn1,  EventType|StatB|Ch|data1|data2| 
gui,3:Show, autosize xcenter y5, MidiMonitor

return

MidiPortRefresh: 				; get the list of ports !!!! nothing to edit here

MIlist := MidiInsList(NumPorts) 
Loop Parse, MIlist, | 
{
}
TheChoice := MidiInDevice + 1
return

;-----------------------------------------------------------------

ReadIni() ; also set up the tray Menu !!!! Nothing to edit here
{
	Menu, tray, add, MidiSet            ; set midi ports tray item 
	Menu, tray, add, ResetAll           ; Delete the ini file for testing --------------------------------
	
	global MidiInDevice, version ; version var is set at the beginning.
	IfExist, %version%.ini
	{
		IniRead, MidiInDevice, %version%.ini, Settings, MidiInDevice , %MidiInDevice%     ; read the midi In port from ini file
	}
	Else ; no ini exists and this is either the first run or reset settings.
	{
		MsgBox, 1, No ini file found, Select midi ports?
		IfMsgBox, Cancel
			ExitApp
		IfMsgBox, yes
			gosub, midiset
	}
}

;CALLED TO UPDATE INI WHENEVER SAVED PARAMETERS CHANGE - !!!! nothing to edit here
WriteIni()
{
	global MidiInDevice, version 		; global vars needed
	
	IfNotExist, %version%.ini 		; does .ini file exist? 
		FileAppend,, %version%.ini 	; make one with name of the .ahk file and the following entries.
	IniWrite, %MidiInDevice%, %version%.ini, Settings, MidiInDevice
}

;------------ port testing to make sure selected midi port is valid --------------------------------

port_test(numports) ; confirm selected ports exist - !!!!! nothing to edit here

{
	global midiInDevice, midiok ;midiOutDevice
	
	; ----- In port selection test based on numports
	If MidiInDevice not Between 0 and %numports% 
		{
			MidiIn := 0 ; this var is just to show if there is an error - set if the ports are valid = 1, invalid = 0
			;MsgBox, 0, , midi in port Error ; (this is left only for testing)
			If (MidiInDevice = "")              ; if there is no midi in device 
				MidiInerr = Midi In Port EMPTY. ; set this var = error message
			;MsgBox, 0, , midi in port EMPTY
			If (midiInDevice > %numports%)          ; if greater than the number of ports on the system.
				MidiInnerr = Midi In Port Invalid.  ; set this error message
			;MsgBox, 0, , midi in port out of range
		}
	Else
		{
			MidiIn := 1 ; setting var to non-error state or valid
		}

	If (%MidiIn% = 0)
	{
		MsgBox, 49, Midi Port Error!,%MidiInerr%`nLaunch Midi Port Selection!
		IfMsgBox, Cancel
			ExitApp
		midiok = 0 ; Not sure if this is really needed now....
		Gosub, MidiSet ;Gui, show Midi Port Selection
	}
	Else
	{
		midiok = 1
		Return ; DO NOTHING - PERHAPS DO THE NOT TEST INSTEAD ABOVE.
	}
}
return

; ------------------ end of port testing ---------------------------

MidiSet: ; midi port selection gui

; ------------- MIDI INPUT SELECTION -----------------------

Gui, 1: +LastFound +AlwaysOnTop   +Caption +ToolWindow ;-SysMenu
Gui, 1: Font, s12
Gui, 1: add, text, x10 y8 w200 cmaroon, Select Midi Input ; Text title
Gui, 1: Font, s9
Gui, 1: font, s9
Gui, 1: Add, ListBox, x10 w175 h100  Choose%TheChoice% vMidiInPort gDoneInChange AltSubmit, %MiList% ; --- midi in listing of ports

Gui, 1: add, Button, x10 w80 gSet_Done, Done - Reload
Gui, 1: add, Button, xp+80 w80 gCancel, Cancel
Gui, 1: show , , %version% Midi Input ; main window title and command to show it.

Return

;~ ------------------------------- methods to save midi port selection -----------------------------

DoneInChange:
Gui, 1: Submit, NoHide
Gui, 1: Flash
If %MidiInPort%
	UDPort:= MidiInPort - 1, MidiInDevice:= UDPort ; probably a much better way do this, I took this from JimF's qwmidi without out editing much.... it does work same with doneoutchange below.
GuiControl, 1:, UDPort, %MidiIndevice%
WriteIni()		; Write .ini file in same folder as ahk file 
Return

Set_Done: 		; aka reload program, called from midi selection gui
Gui, 1: Destroy
sleep, 100
Reload
Return

Cancel:
Gui, Destroy
Gui, 2: Destroy
Return

ResetAll: 		; for development only, leaving this in for a program reset if needed by user
MsgBox, 33, %version% - Reset All?, This will delete ALL settings`, and restart this program!
IfMsgBox, OK
{
	FileDelete, %version%.ini   ; delete the ini file to reset ports, probably a better way to do this ...
	Reload                      ; restart the app.
}
IfMsgBox, Cancel
	Return

GuiClose: 		; on x exit app
Suspend, Permit 	; allow Exit to work Paused. I just added this yesterday 3.16.09 Can now quit when Paused.

MsgBox, 4, Exit %version%, Exit %version% %ver%? ; 
IfMsgBox No
	Return
Else IfMsgBox Yes
Gui, 6: Destroy
Gui, 2: Destroy
Gui, 3: Destroy
Sleep 100

ExitApp


;~ -------------------------------------------------------------------------------------------------
;~ -----------------------        Original work by lots of ahk gurus        ------------------------
;~ ----------------------- DO NOT EDIT - unless you know what you are doing ------------------------
;~ -----------------------                                                  ------------------------
;~ -------------------------------------------------------------------------------------------------

;############################################## MIDI LIB from orbik and lazslo#############
;-------- orbiks midi input code --------------
; Set up midi input and callback_window based on the ini file above.
; This code copied from ahk forum Orbik's post on midi input

; nothing below here to edit. !!!!!!!!!!!!
; =============== midi in =====================

Midiin_go:
DeviceID := MidiInDevice      ; midiindevice from IniRead above assigned to deviceid
CALLBACK_WINDOW := 0x10000    ; from orbiks code for midi input

Gui, +LastFound 	; set up the window for midi data to arrive.
hWnd := WinExist()	;MsgBox, 32, , line 176 - mcu-input  is := %MidiInDevice% , 3 ; this is just a test to show midi device selection

hMidiIn =
VarSetCapacity(hMidiIn, 4, 0)
result := DllCall("winmm.dll\midiInOpen", UInt,&hMidiIn, UInt,DeviceID, UInt,hWnd, UInt,0, UInt,CALLBACK_WINDOW, "UInt")
If result
	{
		MsgBox, Error, midiInOpen Returned %result%`n
		;GoSub, sub_exit
	}

hMidiIn := NumGet(hMidiIn) ; because midiInOpen writes the value in 32 bit binary Number, AHK stores it as a string
result := DllCall("winmm.dll\midiInStart", UInt,hMidiIn)
If result
	{
		MsgBox, Error, midiInStart Returned %result%`nRight Click on the Tray Icon - Left click on MidiSet to select valid midi_in port.
		;GoSub, sub_exit
	}

OpenCloseMidiAPI()

; ----- the OnMessage listeners ----

; #define MM_MIM_OPEN 0x3C1 /* MIDI input */
; #define MM_MIM_CLOSE 0x3C2
; #define MM_MIM_DATA 0x3C3
; #define MM_MIM_LONGDATA 0x3C4
; #define MM_MIM_ERROR 0x3C5
; #define MM_MIM_LONGERROR 0x3C6

OnMessage(0x3C1, "MidiMsgDetect")  ; calling the function MidiMsgDetect in get_midi_in.ahk
OnMessage(0x3C2, "MidiMsgDetect")  
OnMessage(0x3C3, "MidiMsgDetect")
;OnMessage(0x3C4, "MidiMsgDetect")
;OnMessage(0x3C5, "MidiMsgDetect")
;OnMessage(0x3C6, "MidiMsgDetect")

Return

;*************************************************
;*          MIDI IN PORT HANDLING
;*************************************************

MidiInsList(ByRef NumPorts)                                             ; should work for unicode now... 
  { ; Returns a "|"-separated list of midi output devices
	local List, MidiInCaps, PortName, result, midisize
	(A_IsUnicode)? offsetWordStr := 64: offsetWordStr := 32
	midisize := offsetWordStr + 18
	VarSetCapacity(MidiInCaps, midisize, 0)
	VarSetCapacity(PortName, offsetWordStr)                       ; PortNameSize 32

	NumPorts := DllCall("winmm.dll\midiInGetNumDevs") ; #midi output devices on system, First device ID = 0

	Loop %NumPorts%
      {
        result := DllCall("winmm.dll\midiInGetDevCaps", "UInt",A_Index-1, "Ptr",&MidiInCaps, "UInt",midisize)
    
        If (result OR ErrorLevel) {
            List .= "|-Error-"
            Continue
          }
    PortName := StrGet(&MidiInCaps + 8, offsetWordStr)
        List .= "|" PortName
      }
    Return SubStr(List,2)
  }

MidiInGetNumDevs() { ; Get number of midi output devices on system, first device has an ID of 0
    Return DllCall("winmm.dll\midiInGetNumDevs")
  }
MidiInNameGet(uDeviceID = 0) {                  ; Get name of a midiOut device for a given ID

;MIDIOUTCAPS struct
;    WORD      wMid;
;    WORD      wPid;
;    MMVERSION vDriverVersion;
;    CHAR      szPname[MAXPNAMELEN];
;    WORD      wTechnology;
;    WORD      wVoices;
;    WORD      wNotes;
;    WORD      wChannelMask;
;    DWORD     dwSupport;

    VarSetCapacity(MidiInCaps, 50, 0)               ; allows for szPname to be 32 bytes
    OffsettoPortName := 8, PortNameSize := 32
    result := DllCall("winmm.dll\midiInGetDevCapsA", UInt,uDeviceID, UInt,&MidiInCaps, UInt,50, UInt)

    If (result OR ErrorLevel) {
        MsgBox Error %result% (ErrorLevel = %ErrorLevel%) in retrieving the name of midi Input %uDeviceID%
        Return -1
      }

    VarSetCapacity(PortName, PortNameSize)
    DllCall("RtlMoveMemory", Str,PortName, Uint,&MidiInCaps+OffsettoPortName, Uint,PortNameSize)
    Return PortName
  }

MidiInsEnumerate() { ; Returns number of midi output devices, creates global array MidiOutPortName with their names
    local NumPorts, PortID
    MidiInPortName =
    NumPorts := MidiInGetNumDevs()

    Loop %NumPorts% {
        PortID := A_Index -1
        MidiInPortName%PortID% := MidiInNameGet(PortID)
      }
    Return NumPorts
  }


OpenCloseMidiAPI() {  ; at the beginning to load, at the end to unload winmm.dll
	static hModule
	If hModule
		DllCall("FreeLibrary", UInt,hModule), hModule := ""
	If (0 = hModule := DllCall("LoadLibrary",Str,"winmm.dll")) {
		MsgBox Cannot load libray winmm.dll
		Exit
	}
}
[Mod edit: [code][/code] tags added.]
Last edited by gregster on 20 Sep 2022, 15:08, edited 1 time in total.
Reason: Please use code tags. Thank you!

User avatar
SteveMylo
Posts: 233
Joined: 22 Jun 2021, 00:50
Location: Australia
Contact:

Re: Windows 10 keystrokes not reaching Davinci resolve

Post by SteveMylo » 24 Nov 2022, 20:17

I have absolutely no idea but try changing SendMode Input to Event Or Play
and maybe add #IfWinActive, ahk_exe Resolve.exe at the top

hagmon
Posts: 1
Joined: 16 May 2022, 06:27

Re: Windows 10 keystrokes not reaching Davinci resolve

Post by hagmon » 02 Dec 2022, 08:35

Thanks for the information.

Post Reply

Return to “Ask for Help (v1)”