Shuttlepro v2 & AHK scripts

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
AudioBabble
Posts: 37
Joined: 16 Mar 2022, 20:38

Shuttlepro v2 & AHK scripts

Post by AudioBabble » 05 Oct 2022, 15:01

I wonder if anyone could give me some advice...
I have a contour shuttlepro V2 editing controller, which has it's own control panel for assigning keystrokes, macros and the like to its buttons.
My specific problem is to do with Adobe Audition which (for its own reasons I suppose) disables auto-repeat of keys. So I wrote a little AHK script which works great with keys on the keyboard - it's just a loop of key-up and key-down with small sleep intervals between them that triggers while the key is pressed.
However, if i assign the same keys to be triggered by the shuttlepro, nothing happens. I can only assume that this is because the signal from the shuttlepro is not the keyboard itself and the shuttlepro software is taking care of the translation into key-strokes-- which never arrive to the program as the AHK script has them "held captive" for its own script. If I stop the script, of course everything works with the shuttlepro, but unfortunately there's no way (that I can think of anyway) to get the shuttlepro software to run a script like the one I have in AHK, so the keystrokes repeat while the button is held... well, there is.. it works in notepad, but it doesn't fool Adobe Auditon!
I had a bit of browse around the archived posts here and saw mention of a script to view HID input devices, which would seem like a good starting point. However, the script gave me an error about calling a non-existent function when i tried to run it, so I don't know if it's out of date, or maybe never worked in the first place... or I need a dependency.

Sorry for the rather verbose description, but I was hoping someone might be able to point me in the right direction. Cheers! :)
Last edited by gregster on 05 Oct 2022, 17:34, edited 1 time in total.
Reason: Topic moved from 'Scripts and Functions'.

AudioBabble
Posts: 37
Joined: 16 Mar 2022, 20:38

Re: Shuttlepro v2 & AHK scripts

Post by AudioBabble » 05 Oct 2022, 22:53

a small update, I found an apparently working script here: https://www.autohotkey.com/board/topic/36304-hidextended-input-devices-ms-natural-keyboard-4000-etc/

unfortunately, when I run it, it tells me i have no raw input devices (despite actually having two shuttlepro controllers connected)... not quite what I was hoping for!

Perhaps the problem is that the shuttlepro doesn't send anything that the script would recognize (well, I guess that's obvious really) and I'm beginning to wonder if I might not have much luck if the drivers for it are in some way proprietory and only the software for the device can decode its signals.

hmmm.

AudioBabble
Posts: 37
Joined: 16 Mar 2022, 20:38

Re: Shuttlepro v2 & AHK scripts

Post by AudioBabble » 06 Oct 2022, 15:53

back again after a bit more digging....

Seems the thing I was referring to that I found in "old threads" was AHKHID: https://www.autohotkey.com/board/topic/38015-ahkhid-an-ahk-implementation- GitHub: https://github.com/jleb/AHKHID

Most obvious question that springs to mind is whether anyone's still using this ? the last post on the thread is nearly 9 years old...

Did this functionality get added to AHK at some point... seems like such a good idea!

I'm able to at least get some readouts from pressing the keys on my shuttle pro using the AHKHID example scripts, but that doesn't bring me much closer to being able to implement anything. Already in way over my head if I'm honest!

AudioBabble
Posts: 37
Joined: 16 Mar 2022, 20:38

Re: Shuttlepro v2 & AHK scripts

Post by AudioBabble » 08 Oct 2022, 08:40

Progress... found this: https://www.autohotkey.com/board/topic/92213-shuttlepro2-simple-script/

I'm going to re-post it here just to keep it alive for any other Shuttlepro "tinkerers":

NOTE: AHKHID script is a dependency (https://github.com/jleb/AHKHID), put AHKHID.ahk in root folder where the below script is run from.

This script will make the Shuttpro "do something" in AHK... Unfortunately I'm too dumb to figure out how to integrate it into my own scripts just at the moment. However I'm sure if a stare at the code for long enough, something might click. :geek:

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#SingleInstance force

#include AHKHID.ahk

AHKHID_UseConstants() ;Set up the constants

	/*
Define a simple Gui
we need some sort of gui for the messages
it doesn't have to be visible, though

*/


Gui +LastFound -Resize -MaximizeBox -MinimizeBox
Gui, Font, w700 s8, Courier New
Gui, Add, ListBox, h600 w1000 vlbxInput hwndhlbxInput,


GuiHandle := WinExist() ;Keep handle

r := AHKHID_Register(12,1, GuiHandle) ; register shuttlepro page 12 usage 1

; set initial values for the two jog wheels
shuttlepro_speed_saved:=0 ; for the speed dial
shuttlepro_shuttle_start:=True ; for the inner wheel
shuttlepro_old_4:=shuttlepro_old_5:=0 ; initial state assumes no key pressed

; Set the layerkeys
; kill this and further below if you don't want to have any layer keys
; this is just an example
; simple list of the keys used as layerkeys.
shuttlepro_layerkeys_2=14,11
shuttlepro_layerkeys_3=15,10

; create the layermasks
; a layermask has a 1 in the bit if the key represents a layer key
; for byte 4
shuttlepro_layermask_4_2:=0
shuttlepro_layermask_4_3:=0

Loop,8
	{
		If A_Index in %shuttlepro_layerkeys_2%
				shuttlepro_layermask_4_2|=2**(A_Index-1)

		If A_Index in %shuttlepro_layerkeys_3%
				shuttlepro_layermask_4_3|=2**(A_Index-1)
	}


; for byte 5
shuttlepro_layermask_5_2:=0
shuttlepro_layermask_5_3:=0

Loop,7
	{
		i:=8+A_Index
		If i in %shuttlepro_layerkeys_2%
				shuttlepro_layermask_5_2|=2**(A_Index-1)

		If i in %shuttlepro_layerkeys_3%
				shuttlepro_layermask_5_3|=2**(A_Index-1)
	}

; calculate inverse masks once so we save time later
shuttlepro_inverse_layermask_4:=~(shuttlepro_layermask_4_2|shuttlepro_layermask_4_3)
shuttlepro_inverse_layermask_5:=~(shuttlepro_layermask_5_2|shuttlepro_layermask_5_3)

; kill up to here if you don't need layers


;Intercept WM_INPUT
OnMessage(0x00FF, "ShuttleProIntercept")


Gui, Show
Return


GuiClose:
	ExitApp

;########## If Anything happens on the Shuttlepro, this function is called automagically from onMessage #####

ShuttleProIntercept(wParam, lParam)
	{
		local devicetype, hid_handle,length,vendor_id,product_id, layer
		Critical


		r := AHKHID_GetInputInfo(lParam, 0) ;Get device type

		If (r = RIM_TYPEHID) ; this is how the SHuttlepro identifies
			{
				hid_handle := AHKHID_GetInputInfo(lParam, 8) ; Handle to device
				length := AHKHID_GetInputData(lParam, uData)-1 ; input length
				Vendor_id:=AHKHID_GetDevInfo(hid_handle, DI_HID_VENDORID,     True)
				product_id:=AHKHID_GetDevInfo(hid_handle, DI_HID_PRODUCTID,    True)

				If (vendor_id=2867 And product_id=48)
					{
						; shuttlepro 2

						; get the data and convert to bytes
						Loop, %length%
								byte%A_Index%:=NumGet(udata,A_Index,"uchar")


						; byte 1 : Outer ring goes 1-7 (right) and 249-255 (left)
						; byte 2 : Innner rin g goes 0-255 and rotates through 0 absolute
						; byte 3 : unused
						; byte 4 : has keys 1-8 as bits ; 1 = key is pressed
						; byte 5 : has keys 9-15 as bits ; 1 = key is pressed

						; the bits are set for all keys that are being held down

						a:="" ; global string for demo

						; deal with layers here
						; start deleting here if you don't need layers


						layer2:=layer3:=False ; reset

						; see whether a layer key is pressed and set the appropriate flag
						If ((byte4 & shuttlepro_layermask_4_2))
								layer2:=True

						If ((byte4 & shuttlepro_layermask_4_3))
								layer3:=True

						If ((byte5 & shuttlepro_layermask_5_2))
								layer2:=True

						If ((byte5 & shuttlepro_layermask_5_3))
								layer3:=True

						; set the layer variable accordingly
						If (layer2 && layer3)
								layer:=4
						Else if layer3
								layer:=3
						Else if layer2
								layer:=2
						Else
								layer:=1

						; mask out the layerkeys
						; so they do not appear pushed below
						byte4&=shuttlepro_inverse_layermask_4
						byte5&=shuttlepro_inverse_layermask_5


						; if you don't need layers, delete until here

						; compare to old ket to see only new keys pressed
						byte4_new:=byte4&shuttlepro_old_4
						byte5_new:=byte5&shuttlepro_old_5
						shuttlepro_old_4:=~byte4 ; invert for quick mask next time around
						shuttlepro_old_5:=~byte5  ; invert for quick mask next time around

						; sort out the keys
						; loops through the bytes and sets the variable shuttlepro%keynbumber% to true if the key was pressed
						; byte 4 has 8 keys
						Loop,8
							{
								shuttlepro%A_Index%:=byte4_new&1
								byte4_new>>=1
							}
						; byte 5 has 7 keys
						i:=9
						Loop,7
							{
								shuttlepro%i%:=byte5_new&1
								byte5_new>>=1
								i++
							}

						; now we know the exact state
						; byte 1 and 2 have the wheel states
						; shuttlepro%keynumber% is true if the key was just pressed


						; byte 1: outer wheel reports 1-7 or -1 to -7 (signed byte)
						If (byte1<>shuttlepro_speed_saved) ; value has changed
								execute_shuttlepro_speed(byte1,layer) ; execute function

						shuttlepro_speed_saved:=byte1 ; save value


						; byte2 : reports absolute value of shuttle wheel
						If shuttlepro_shuttle_start ; this is the first time we run it
							{
								shuttlepro_shuttle_saved:=byte2
								shuttlepro_shuttle_start:=False
							}

						Else
							{
								If (byte2<>shuttlepro_shuttle_saved) ; value has changed
										execute_shuttlepro_shuttle(byte2,layer) ; execute function
							}

						shuttlepro_shuttle_saved:=byte2 ; save value


						;loop through 15 buttons
						Loop, 15
								If (shuttlepro%A_Index%)
										execute_shuttlepro(A_Index,layer) ; replace accordingly if you don't want layers



						; for demo, update the gui
						GuiControl,, lbxInput, %a%

					}
			}
		SendMessage, 0x018B, 0, 0,, ahk_id %hlbxInput%
		SendMessage, 0x0186, ErrorLevel - 1, 0,, ahk_id %hlbxInput%
	}


;############### Functions that are called when something happens on the Shuttlepro #########

; A Key was pressed
execute_shuttlepro(key,layer)
	{
		global
		; Do what needs to be done here
		; at the moment, just add to the global string

		a.= "key: " . key . " in layer " . layer
		Return
	}

; the outer wheel was turned
execute_shuttlepro_speed(speed,layer)
	{
		global
		; do what needs to be done here
		; at the moment, just add to the global string
		If (speed>200)
				speed:=speed-256 ; make negative

		a.="Speed: " . speed . " in layer " . layer

		Return
	}

; the inner wheel was turned
execute_shuttlepro_shuttle(shuttle_value,layer)
	{
		global
		; Do what needs to be done here
		; at the moment, just add to the global string

		a.="shuttle: " . shuttle_value . " in layer " . layer

		Return
	}
;
NOTE: this may have been written for the earlier type of Shuttlepro, on the one I have (v.2), some of the additional buttons don't work, but it's a good starting point.

Post Reply

Return to “Ask for Help (v2)”