From aacb44c7a848163f770422a77736b063c8aec0d0 Mon Sep 17 00:00:00 2001 From: Laurence Dougal Myers Date: Sat, 29 Aug 2020 12:00:46 +1000 Subject: [PATCH] - Remove vjoy functionality - Rename files for consistency - Fix accidental creation of both *.ini and *io.ini files - Change hardcoded "version" so that the ini file is called `MidiToMacro.ini` --- .gitignore | 1 + mtjFunctions.ahk => CommonFunctions.ahk | 50 +- ..._GuiMonitor.ahk => MidiInAndGuiMonitor.ahk | 266 ++-- midi_to_joy_3.ahk => MidiToMacro.ahk | 100 +- ...under_the_hood.ahk => MidiUnderTheHood.ahk | 1146 ++++++++--------- VJoy_Test.ahk | 460 ------- VJoy_lib.ahk | 175 --- VJoy_lib_1.ahk | 839 ------------ joystick/joy_info.ahk | 84 -- midi_to_joy_1io.ini | 0 vJoyInterface.dll | Bin 19456 -> 0 bytes x32/vJoyInterface.dll | Bin 16896 -> 0 bytes x64/vJoyInterface.dll | Bin 19456 -> 0 bytes 13 files changed, 782 insertions(+), 2339 deletions(-) rename mtjFunctions.ahk => CommonFunctions.ahk (95%) rename Midi_In_and_GuiMonitor.ahk => MidiInAndGuiMonitor.ahk (97%) rename midi_to_joy_3.ahk => MidiToMacro.ahk (80%) rename Midi_under_the_hood.ahk => MidiUnderTheHood.ahk (96%) delete mode 100644 VJoy_Test.ahk delete mode 100644 VJoy_lib.ahk delete mode 100644 VJoy_lib_1.ahk delete mode 100644 joystick/joy_info.ahk delete mode 100644 midi_to_joy_1io.ini delete mode 100644 vJoyInterface.dll delete mode 100644 x32/vJoyInterface.dll delete mode 100644 x64/vJoyInterface.dll diff --git a/.gitignore b/.gitignore index 751553b..deb9af1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.bak +*.ini diff --git a/mtjFunctions.ahk b/CommonFunctions.ahk similarity index 95% rename from mtjFunctions.ahk rename to CommonFunctions.ahk index afff1dd..d0fafe9 100644 --- a/mtjFunctions.ahk +++ b/CommonFunctions.ahk @@ -1,25 +1,25 @@ - -DisplayOutput(event, value) { - Gui,14:default - Gui,14:ListView, Out1 ; see the second listview midi out monitor - LV_Add("",event,value) - LV_ModifyCol(1,"center") - LV_ModifyCol(2,"center") - If (LV_GetCount() > 10) - { - LV_Delete(1) - } -} - -ConvertToAxis(value, maximum_axis_value) { - return Floor(value * maximum_axis_value) -} - -ConvertCCValueToScale(value, minimum_value, maximum_value) { - if (value > maximum_value) { - value := maximum_value - } else if (value < minimum_value) { - value := minimum_value - } - return (value - minimum_value) / (maximum_value - minimum_value) -} + +DisplayOutput(event, value) { + Gui,14:default + Gui,14:ListView, Out1 ; see the second listview midi out monitor + LV_Add("",event,value) + LV_ModifyCol(1,"center") + LV_ModifyCol(2,"center") + If (LV_GetCount() > 10) + { + LV_Delete(1) + } +} + +ConvertToAxis(value, maximum_axis_value) { + return Floor(value * maximum_axis_value) +} + +ConvertCCValueToScale(value, minimum_value, maximum_value) { + if (value > maximum_value) { + value := maximum_value + } else if (value < minimum_value) { + value := minimum_value + } + return (value - minimum_value) / (maximum_value - minimum_value) +} diff --git a/Midi_In_and_GuiMonitor.ahk b/MidiInAndGuiMonitor.ahk similarity index 97% rename from Midi_In_and_GuiMonitor.ahk rename to MidiInAndGuiMonitor.ahk index 63f0987..06ce2ea 100644 --- a/Midi_In_and_GuiMonitor.ahk +++ b/MidiInAndGuiMonitor.ahk @@ -1,133 +1,133 @@ -/* - PARSE - LAST MIDI MESSAGE RECEIVED - - Midi monitor. -*/ - -;************************************************* -;* MIDI INPUT PARSE FUNCTION -;* -;************************************************* - -; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! no edit below here .... - -MidiMsgDetect(hInput, midiMsg, wMsg) ; Midi input section in "under the hood" 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, byte1, byte2, stb - - statusbyte := midiMsg & 0xFF ; EXTRACT THE STATUS BYTE (WHAT KIND OF MIDI MESSAGE IS IT?) - chan := (statusbyte & 0x0f) + 1 ; WHAT MIDI CHANNEL IS THE MESSAGE ON? - byte1 := (midiMsg >> 8) & 0xFF ; THIS IS DATA1 VALUE = NOTE NUMBER OR CC NUMBER - byte2 := (midiMsg >> 16) & 0xFF ; DATA2 VALUE IS NOTE VELEOCITY OR CC VALUE - pitchb := (byte2 << 7) | byte1 ;(midiMsg >> 8) & 0x7F7F masking to extract the pbs - - - if statusbyte between 176 and 191 ; test for cc - stb := "CC" ; if so then set stp to cc - if statusbyte between 144 and 159 - stb := "NoteOn" - if statusbyte between 128 and 143 - stb := "NoteOff" - if statusbyte between 224 and 239 - stb := "PitchB" - gosub, ShowMidiInMessage ; show updated midi input message on midi monitor gui. - gosub, MidiRules ; run the label in file MidiRules.ahk Edit that file. - - } -; end of MidiMsgDetect funciton - -Return - -;************************************************* -;* SHOW MIDI INPUT ON GUI MONITOR -;************************************************* - -ShowMidiInMessage: ; update the midimonitor gui - -Gui,14:default -Gui,14:ListView, In1 ; see the first listview midi in monitor - LV_Add("",stb,statusbyte,chan,byte1,byte2) - 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 - -;************************************************* -;* SHOW MIDI OUTPUT ON GUI MONITOR -;************************************************* - -ShowMidiOutMessage: ; update the midimonitor gui - -Gui,14:default -Gui,14:ListView, Out1 ; see the second listview midi out monitor - LV_Add("",stb,statusbyte,chan,byte1,byte2) - 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 - -;************************************************* -;* MIDI MONITOR GUI CODE -;************************************************* - -midiMon: ; midi monitor gui with listviews -gui,14:destroy -gui,14:default -gui,14:add,text, x80 y5, Midi Input ; %TheChoice% - Gui,14:Add, DropDownList, x40 y20 w140 Choose%TheChoice% vMidiInPort gDoneInChange altsubmit, %MiList% ; ( -gui,14:add,text, x305 y5, Midi Ouput ; %TheChoice2% - Gui,14:Add, DropDownList, x270 y20 w140 Choose%TheChoice2% vMidiOutPort gDoneOutChange altsubmit , %MoList% -Gui,14:Add, ListView, x5 r11 w220 Backgroundblack caqua Count10 vIn1, EventType|StatB|Ch|Byte1|Byte2| -gui,14:Add, ListView, x+5 r11 w220 Backgroundblack cyellow Count10 vOut1, Event|Value| -LV_ModifyCol(1, 105) -LV_ModifyCol(2, 110) -gui,14:Show, autosize xcenter y5, MidiMonitor - -Return - - -;************************************************* -;* MIDI OUTPUT LABELS TO CALL -;************************************************* - -SendNote: ;(h_midiout,Note) ; send out note messages ; this should probably be a funciton - note = %byte1% ; this var is added to allow transpostion of a note - midiOutShortMsg(h_midiout, statusbyte, note, byte2) ; call the midi funcitons with these params. - gosub, ShowMidiOutMessage -Return - -SendCC: - midiOutShortMsg(h_midiout, statusbyte, cc, byte2) -Return - -SendPC: - gosub, ShowMidiOutMessage - midiOutShortMsg(h_midiout, statusbyte, pc, byte2) -Return - -; MIDI Rules dispatcher - -MidiRules: - if (statusbyte >= 128 and statusbyte <= 159) { ; Note off/on - isNoteOn := (statusbyte >= 144 and byte2 > 0) - ProcessNote(0, chan, byte1, byte2, isNoteOn) - } else if (statusbyte >= 176 and statusbyte <= 191) { ; CC - ProcessCC(0, chan, byte1, byte2) - } else if (statusbyte >= 192 and statusbyte <= 208) { ; PC - ProcessPC(0, chan, byte1, byte2) - } else if (statusbyte >= 224 and statusbyte <= 239) { ; Pitch bend - ProcessPitchBend(0, chan, pitchb) - } - ; Maybe TODO: Key aftertouch, channel aftertouch, -Return +/* + PARSE - LAST MIDI MESSAGE RECEIVED - + Midi monitor. +*/ + +;************************************************* +;* MIDI INPUT PARSE FUNCTION +;* +;************************************************* + +; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! no edit below here .... + +MidiMsgDetect(hInput, midiMsg, wMsg) ; Midi input section in "under the hood" 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, byte1, byte2, stb + + statusbyte := midiMsg & 0xFF ; EXTRACT THE STATUS BYTE (WHAT KIND OF MIDI MESSAGE IS IT?) + chan := (statusbyte & 0x0f) + 1 ; WHAT MIDI CHANNEL IS THE MESSAGE ON? + byte1 := (midiMsg >> 8) & 0xFF ; THIS IS DATA1 VALUE = NOTE NUMBER OR CC NUMBER + byte2 := (midiMsg >> 16) & 0xFF ; DATA2 VALUE IS NOTE VELEOCITY OR CC VALUE + pitchb := (byte2 << 7) | byte1 ;(midiMsg >> 8) & 0x7F7F masking to extract the pbs + + + if statusbyte between 176 and 191 ; test for cc + stb := "CC" ; if so then set stp to cc + if statusbyte between 144 and 159 + stb := "NoteOn" + if statusbyte between 128 and 143 + stb := "NoteOff" + if statusbyte between 224 and 239 + stb := "PitchB" + gosub, ShowMidiInMessage ; show updated midi input message on midi monitor gui. + gosub, MidiRules ; run the label in file MidiRules.ahk Edit that file. + + } +; end of MidiMsgDetect funciton + +Return + +;************************************************* +;* SHOW MIDI INPUT ON GUI MONITOR +;************************************************* + +ShowMidiInMessage: ; update the midimonitor gui + +Gui,14:default +Gui,14:ListView, In1 ; see the first listview midi in monitor + LV_Add("",stb,statusbyte,chan,byte1,byte2) + 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 + +;************************************************* +;* SHOW MIDI OUTPUT ON GUI MONITOR +;************************************************* + +ShowMidiOutMessage: ; update the midimonitor gui + +Gui,14:default +Gui,14:ListView, Out1 ; see the second listview midi out monitor + LV_Add("",stb,statusbyte,chan,byte1,byte2) + 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 + +;************************************************* +;* MIDI MONITOR GUI CODE +;************************************************* + +midiMon: ; midi monitor gui with listviews +gui,14:destroy +gui,14:default +gui,14:add,text, x80 y5, Midi Input ; %TheChoice% + Gui,14:Add, DropDownList, x40 y20 w140 Choose%TheChoice% vMidiInPort gDoneInChange altsubmit, %MiList% ; ( +gui,14:add,text, x305 y5, Midi Ouput ; %TheChoice2% + Gui,14:Add, DropDownList, x270 y20 w140 Choose%TheChoice2% vMidiOutPort gDoneOutChange altsubmit , %MoList% +Gui,14:Add, ListView, x5 r11 w220 Backgroundblack caqua Count10 vIn1, EventType|StatB|Ch|Byte1|Byte2| +gui,14:Add, ListView, x+5 r11 w220 Backgroundblack cyellow Count10 vOut1, Event|Value| +LV_ModifyCol(1, 105) +LV_ModifyCol(2, 110) +gui,14:Show, autosize xcenter y5, MidiMonitor + +Return + + +;************************************************* +;* MIDI OUTPUT LABELS TO CALL +;************************************************* + +SendNote: ;(h_midiout,Note) ; send out note messages ; this should probably be a funciton + note = %byte1% ; this var is added to allow transpostion of a note + midiOutShortMsg(h_midiout, statusbyte, note, byte2) ; call the midi funcitons with these params. + gosub, ShowMidiOutMessage +Return + +SendCC: + midiOutShortMsg(h_midiout, statusbyte, cc, byte2) +Return + +SendPC: + gosub, ShowMidiOutMessage + midiOutShortMsg(h_midiout, statusbyte, pc, byte2) +Return + +; MIDI Rules dispatcher + +MidiRules: + if (statusbyte >= 128 and statusbyte <= 159) { ; Note off/on + isNoteOn := (statusbyte >= 144 and byte2 > 0) + ProcessNote(0, chan, byte1, byte2, isNoteOn) + } else if (statusbyte >= 176 and statusbyte <= 191) { ; CC + ProcessCC(0, chan, byte1, byte2) + } else if (statusbyte >= 192 and statusbyte <= 208) { ; PC + ProcessPC(0, chan, byte1, byte2) + } else if (statusbyte >= 224 and statusbyte <= 239) { ; Pitch bend + ProcessPitchBend(0, chan, pitchb) + } + ; Maybe TODO: Key aftertouch, channel aftertouch, +Return diff --git a/midi_to_joy_3.ahk b/MidiToMacro.ahk similarity index 80% rename from midi_to_joy_3.ahk rename to MidiToMacro.ahk index 81c1421..d96907f 100644 --- a/midi_to_joy_3.ahk +++ b/MidiToMacro.ahk @@ -1,50 +1,50 @@ -/* - -MIDI to joy. -Based on GENERIC MIDI APP V.0.6 by genmce and contributors. - -Edit the "VARIBLES TO SET @ STARTUP" section. - -MidiRules.ahk contains the logic that maps from MIDI controllers to VJoy. - - -Sections with !!!!!!!!!!!!!!!!!!!! - don't edit between these, unless you know what you are doing (uykwyad) ! - -Sections with ++++++++++++++++++++ Edit between these marks. You won't break it, I don't think??? - -*/ - - -#Include mtjFunctions.ahk - -#Persistent -#SingleInstance -SendMode Input ; Recommended for new scripts due to its superior speed and reliability. -SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. - -if A_OSVersion in WIN_NT4,WIN_95,WIN_98,WIN_ME ; if not xp or 2000 quit -{ - MsgBox This script requires Windows 2000/XP or later. - ExitApp -} - -version = midi_to_joy_3 -readini() ; load values from the ini file, via the readini function - see Midi_under_the_hood.ahk file -gosub, MidiPortRefresh ; used to refresh the input and output port lists - see Midi_under_the_hood.ahk file -port_test(numports,numports2) ; test the ports - check for valid ports? - see Midi_under_the_hood.ahk file -gosub, midiin_go ; opens the midi input port listening routine see Midi_under_the_hood.ahk file -gosub, midiout ; opens the midi out port see Midi_under_the_hood.ahk file -gosub, midiMon ; see below - a monitor gui - see Midi_In_and_GuiMonitor.ahk - -;************************************************* -;* VARIBLES TO SET @ STARTUP -;************************************************* - -#Include UserVariables.ahk - -return - - -#Include Midi_In_and_GuiMonitor.ahk ; this file contains: the function to parse midi message into parts we can work with and a midi monitor. -#Include MidiRules.ahk ; this file contains: Rules for manipulating midi input then sending modified midi output. -#Include Midi_under_the_hood.ahk ; this file contains: (DO NOT EDIT THIS FILE) all the dialogs to set up midi ports and midi message handling. \ No newline at end of file +/* + +MIDI to joy. +Based on GENERIC MIDI APP V.0.6 by genmce and contributors. + +Edit the "VARIBLES TO SET @ STARTUP" section. + +MidiRules.ahk contains the logic that maps from MIDI controllers to VJoy. + + +Sections with !!!!!!!!!!!!!!!!!!!! - don't edit between these, unless you know what you are doing (uykwyad) ! + +Sections with ++++++++++++++++++++ Edit between these marks. You won't break it, I don't think??? + +*/ + + +#Include CommonFunctions.ahk + +#Persistent +#SingleInstance +SendMode Input ; Recommended for new scripts due to its superior speed and reliability. +SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. + +if A_OSVersion in WIN_NT4,WIN_95,WIN_98,WIN_ME ; if not xp or 2000 quit +{ + MsgBox This script requires Windows 2000/XP or later. + ExitApp +} + +version = MidiToMacro +readini() ; load values from the ini file, via the readini function - see Midi_under_the_hood.ahk file +gosub, MidiPortRefresh ; used to refresh the input and output port lists - see Midi_under_the_hood.ahk file +port_test(numports,numports2) ; test the ports - check for valid ports? - see Midi_under_the_hood.ahk file +gosub, midiin_go ; opens the midi input port listening routine see Midi_under_the_hood.ahk file +gosub, midiout ; opens the midi out port see Midi_under_the_hood.ahk file +gosub, midiMon ; see below - a monitor gui - see Midi_In_and_GuiMonitor.ahk + +;************************************************* +;* VARIBLES TO SET @ STARTUP +;************************************************* + +#Include userVariables.ahk + +return + + +#Include MidiInAndGuiMonitor.ahk ; this file contains: the function to parse midi message into parts we can work with and a midi monitor. +#Include MidiRules.ahk ; this file contains: Rules for manipulating midi input then sending modified midi output. +#Include MidiUnderTheHood.ahk ; this file contains: (DO NOT EDIT THIS FILE) all the dialogs to set up midi ports and midi message handling. \ No newline at end of file diff --git a/Midi_under_the_hood.ahk b/MidiUnderTheHood.ahk similarity index 96% rename from Midi_under_the_hood.ahk rename to MidiUnderTheHood.ahk index 12b28cd..eed2493 100644 --- a/Midi_under_the_hood.ahk +++ b/MidiUnderTheHood.ahk @@ -1,573 +1,573 @@ - -; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! no edit below here, unless you know what you are doing. - -;************************************************* -;* MIDI UNDER THE HOOD -;* DO NOT EDIT IN HERE, unless you know what -;* what you are doing! -;************************************************* - -;**************************************************************************************************************** -;******************************************** midi "under the hood" ********************************************* -/* - This part is meant to take care of the "under the hood" midi input and output selection and save selection to an ini file. - Hopefully it simplifies usage for others out here trying to do things with midi and ahk. - - * use it as an include. - - The code here was taken/modified from the work by TomB/Lazslo on Midi Output - http://www.autohotkey.com/forum/viewtopic.php?t=18711&highlight=midi+output - - Orbik's Midi input thread - http://www.autohotkey.com/forum/topic30715.html - This method does NOT use the midi_in.dll, it makes direct calls to the winmm.dll - - Many different people took part in the creation of this file. - - ; Last edited 6/17/2010 11:30 AM by genmce - -*/ - -;************************************************* -;* GET PORTS LIST PARSE -;************************************************* -MidiPortRefresh: ; get the list of ports - - MIlist := MidiInsList(NumPorts) - Loop Parse, MIlist, | - { - } - TheChoice := MidiInDevice + 1 - -MOlist := MidiOutsList(NumPorts2) - Loop Parse, MOlist, | - { - } - TheChoice2 := MidiOutDevice + 1 - -return - -;************************************************* -;* LOAD UP SOME STUFF. -;************************************************* -;----------------------------------------------------------------- - -ReadIni() ; also set up the tray Menu - { - Menu, tray, add, MidiSet ; set midi ports tray item - Menu, tray, add, ResetAll ; Delete the ini file for testing -------------------------------- - menu, tray, add, MidiMon - global MidiInDevice, MidiOutDevice, 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 - IniRead, MidiOutDevice, %version%.ini, Settings, MidiOutDevice , %MidiOutDevice% ; read the midi out 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 - ;WriteIni() - } - } -;************************************************* -;* WRITE TO INI FILE FUNCTION -;************************************************* - -;CALLED TO UPDATE INI WHENEVER SAVED PARAMETERS CHANGE -WriteIni() - { - global MidiInDevice, MidiOutDevice, version - - IfNotExist, %version%io.ini ; if no ini - FileAppend,, %version%io.ini ; make one with the following entries. - IniWrite, %MidiInDevice%, %version%.ini, Settings, MidiInDevice - IniWrite, %MidiOutDevice%, %version%.ini, Settings, MidiOutDevice - } - -;************************************************* -;* PORT TESTING -;************************************************* -;------------ port testing to make sure selected midi port is valid -------------------------------- - -port_test(numports,numports2) ; confirm selected ports exist ; CLEAN THIS UP STILL - - { - global midiInDevice, midiOutDevice, midiok - - ; ----- 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 - } - ; ----- out port selection test based on numports2 - If MidiOutDevice not Between 0 and %numports2% - { - MidiOut := 0 ; set var to 0 as Error state. - If (MidiOutDevice = "") ; if blank - MidiOuterr = Midi Out Port EMPTY. ; set this error message - ;MsgBox, 0, , midi o port EMPTY - If (midiOutDevice > %numports2%) ; if greater than number of availble ports - MidiOuterr = Midi Out Port Out Invalid. ; set this error message - ;MsgBox, 0, , midi out port out of range - } - Else - { - MidiOut := 1 ;set var to 1 as valid state. - } - ; ---- test to see if ports valid, if either invalid load the gui to select. - ;midicheck(MCUin,MCUout) - If (%MidiIn% = 0) Or (%MidiOut% = 0) - { - MsgBox, 49, Midi Port Error!,%MidiInerr%`n%MidiOuterr%`n`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 - -;************************************************* -;* MIDI SET GUI -;************************************************* -; ------------------ end of port testing --------------------------- - - -MidiSet: ; midi port selection gui - - ; ------------- MIDI INPUT SELECTION ----------------------- - Gui, 6: Destroy - Gui, 2: Destroy - Gui, 3: Destroy - Gui, 4: Destroy - Gui, 4: +LastFound +AlwaysOnTop +Caption +ToolWindow ;-SysMenu - Gui, 4: Font, s12 - Gui, 4: add, text, x10 y10 w300 cmaroon, Select Midi Ports. ; Text title - Gui, 4: Font, s8 - Gui, 4: Add, Text, x10 y+10 w175 Center , Midi In Port ;Just text label - Gui, 4: font, s8 - ; midi ins list box - Gui, 4: Add, ListBox, x10 w200 h100 Choose%TheChoice% vMidiInPort gDoneInChange AltSubmit, %MiList% ; --- midi in listing of ports - ;Gui, Add, DropDownList, x10 w200 h120 Choose%TheChoice% vMidiInPort gDoneInChange altsubmit, %MiList% ; ( you may prefer this style, may need tweak) - - ; --------------- MidiOutSet --------------------- - Gui, 4: Add, TEXT, x220 y40 w175 Center, Midi Out Port ; gDoneOutChange - ; midi outlist box - Gui, 4: Add, ListBox, x220 y62 w200 h100 Choose%TheChoice2% vMidiOutPort gDoneOutChange AltSubmit, %MoList% ; --- midi out listing - ;Gui, Add, DropDownList, x220 y97 w200 h120 Choose%TheChoice2% vMidiOutPort gDoneOutChange altsubmit , %MoList% - Gui, 4: add, Button, x10 w205 gSet_Done, Done - Reload script. - Gui, 4: add, Button, xp+205 w205 gCancel, Cancel - ;gui, 4: add, checkbox, x10 y+10 vNotShown gDontShow, Do Not Show at startup. - ;IfEqual, NotShown, 1 - ;guicontrol, 4:, NotShown, 1 - Gui, 4: show , , %version% Midi Port Selection ; main window title and command to show it. - -Return - -;-----------------gui done change stuff - see label in both gui listbox line - - - - -;44444444444444444444444444 NEED TO EDIT THIS TO REFLECT CHANGES IN GENMCE PRIOR TO SEND OUT - -DoneInChange: - gui +lastfound - Gui, Submit, NoHide - Gui, Flash - Gui, 4: Submit, NoHide - Gui, 4: 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, 4:, UDPort, %MidiIndevice% - WriteIni() - ;MsgBox, 32, , midi in device = %MidiInDevice%`nmidiinport = %MidiInPort%`nport = %port%`ndevice= %device% `n UDPort = %UDport% ; only for testing -Return - -DoneOutChange: - gui +lastfound - Gui, Submit, NoHide - Gui, Flash - - Gui, 4: Submit, NoHide - Gui, 4: Flash - If %MidiOutPort% - UDPort2:= MidiOutPort - 1 , MidiOutDevice:= UDPort2 - GuiControl, 4: , UDPort2, %MidiOutdevice% - WriteIni() - ;Gui, Destroy -Return - -;------------------------ end of the doneout change stuff. - -Set_Done: ; aka reload program, called from midi selection gui - Gui, 3: Destroy - Gui, 4: Destroy - sleep, 100 - Reload -Return - -Cancel: - Gui, Destroy - Gui, 2: Destroy - Gui, 3: Destroy - Gui, 4: Destroy - Gui, 5: Destroy -Return - -;************************************************* -;* MIDI OUTPUT - UNDER THE HOOD -;************************************************* -; ********************** Midi output detection - -MidiOut: ; Function to load new settings from midi out menu item - OpenCloseMidiAPI() - h_midiout := midiOutOpen(MidiOutDevice) ; OUTPUT PORT 1 SEE BELOW FOR PORT 2 -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 - midiOutClose(h_midiout) - - Gui, 6: Destroy - Gui, 2: Destroy - Gui, 3: Destroy - Gui, 4: Destroy - Gui, 5: Destroy - gui, 7: destroy - ;gui, - Sleep 100 - ;winclose, Midi_in_2 ;close the midi in 2 ahk file - ExitApp - -;************************************************* -;* MIDI INPUT / OUTPUT UNDER THE HOOD -;************************************************* - -;############################################## 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 -;************************************************* - -;--- MIDI INS LIST FUNCTIONS - port handling ----- - -MidiInsList(ByRef NumPorts) - { ; Returns a "|"-separated list of midi output devices - local List, MidiInCaps, PortName, result, PortNameSize - PortNameSize := 32 * (A_IsUnicode ? 2 : 1) - VarSetCapacity(MidiInCaps, 50, 0) - VarSetCapacity(PortName, PortNameSize) ; PortNameSize 32 - - NumPorts := DllCall("winmm.dll\midiInGetNumDevs") ; #midi output devices on system, First device ID = 0 - - Loop %NumPorts% - { - result := DllCall("winmm.dll\midiInGetDevCapsA", UInt,A_Index-1, UInt,&MidiInCaps, UInt,50, UInt) - If (result OR ErrorLevel) { - List .= "|-Error-" - Continue - } - DllCall("RtlMoveMemory", Str,PortName, UInt,&MidiInCaps+8, UInt,PortNameSize) ; PortNameOffset 8, PortNameSize 32 - if (A_IsUnicode) { - PortName := Strget(&PortName, "UTF-8") - } - 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 * (A_IsUnicode ? 2 : 1) - 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) - if (A_IsUnicode) { - PortName := Strget(&PortName, "UTF-8") - } - 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 - } - -;************************************************* -;* MIDI OUT LIBRARY FROM lASZLO/TOMB -; Modified by JimF - removed long message -; handling as well as combining status byte with ch -; see commented out section below if you want to change it back -;************************************************* -; =============== end of midi selection stuff - - -MidiOutsList(ByRef NumPorts) - { ; Returns a "|"-separated list of midi output devices - local List, MidiOutCaps, PortName, result - PortNameSize := 32 * (A_IsUnicode ? 2 : 1) - VarSetCapacity(MidiOutCaps, 50, 0) - VarSetCapacity(PortName, PortNameSize) ; PortNameSize 32 - - NumPorts := DllCall("winmm.dll\midiOutGetNumDevs") ; #midi output devices on system, First device ID = 0 - - Loop %NumPorts% - { - result := DllCall("winmm.dll\midiOutGetDevCapsA", UInt,A_Index-1, UInt,&MidiOutCaps, UInt,50, UInt) - If (result OR ErrorLevel) - { - List .= "|-Error-" - Continue - } - DllCall("RtlMoveMemory", Str,PortName, UInt,&MidiOutCaps+8, UInt,PortNameSize) ; PortNameOffset 8, PortNameSize 32 - if (A_IsUnicode) { - PortName := Strget(&PortName, "UTF-8") - } - List .= "|" PortName - } - Return SubStr(List,2) - } -;---------------------midiOut from TomB and Lazslo and JimF -------------------------------- - -;THATS THE END OF MY STUFF (JimF) THE REST ID WHAT LASZLo AND PAXOPHONE WERE USING ALREADY -;AHK FUNCTIONS FOR MIDI OUTPUT - calling winmm.dll -;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_multimedia_functions.asp -;Derived from Midi.ahk dated 29 August 2008 - streaming support removed - (JimF) - - -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 - } - } - -;FUNCTIONS FOR SENDING SHORT MESSAGES - -midiOutOpen(uDeviceID = 0) { ; Open midi port for sending individual midi messages --> handle - strh_midiout = 0000 - - result := DllCall("winmm.dll\midiOutOpen", UInt,&strh_midiout, UInt,uDeviceID, UInt,0, UInt,0, UInt,0, UInt) - If (result or ErrorLevel) { - MsgBox There was an Error opening the midi port.`nError code %result%`nErrorLevel = %ErrorLevel% - Return -1 - } - Return UInt@(&strh_midiout) - } - -midiOutShortMsg(h_midiout, MidiStatus, Param1, Param2) { ;Channel, - ;h_midiout: handle to midi output device returned by midiOutOpen - ;EventType, Channel combined -> MidiStatus byte: http://www.harmony-central.com/MIDI/Doc/table1.html - ;Param3 should be 0 for PChange, ChanAT, or Wheel - ;Wheel events: entire Wheel value in Param2 - the function splits it into two bytes -/* - If (EventType = "NoteOn" OR EventType = "N1") - MidiStatus := 143 + Channel - Else If (EventType = "NoteOff" OR EventType = "N0") - MidiStatus := 127 + Channel - Else If (EventType = "CC") - MidiStatus := 175 + Channel - Else If (EventType = "PolyAT" OR EventType = "PA") - MidiStatus := 159 + Channel - Else If (EventType = "ChanAT" OR EventType = "AT") - MidiStatus := 207 + Channel - Else If (EventType = "PChange" OR EventType = "PC") - MidiStatus := 191 + Channel - Else If (EventType = "Wheel" OR EventType = "W") { - MidiStatus := 223 + Channel - Param2 := Param1 >> 8 ; MSB of wheel value - Param1 := Param1 & 0x00FF ; strip MSB - } -*/ - result := DllCall("winmm.dll\midiOutShortMsg", UInt,h_midiout, UInt, MidiStatus|(Param1<<8)|(Param2<<16), UInt) - If (result or ErrorLevel) { - MsgBox There was an Error Sending the midi event: (%result%`, %ErrorLevel%) - Return -1 - } - } - -midiOutClose(h_midiout) { ; Close MidiOutput - Loop 9 { - result := DllCall("winmm.dll\midiOutClose", UInt,h_midiout) - If !(result or ErrorLevel) - Return - Sleep 250 - } - MsgBox Error in closing the midi output port. There may still be midi events being Processed. - Return -1 - } - -;UTILITY FUNCTIONS -MidiOutGetNumDevs() { ; Get number of midi output devices on system, first device has an ID of 0 - Return DllCall("winmm.dll\midiOutGetNumDevs") - } - -MidiOutNameGet(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(MidiOutCaps, 50, 0) ; allows for szPname to be 32 bytes - OffsettoPortName := 8 - PortNameSize := 32 * (A_IsUnicode ? 2 : 1) - result := DllCall("winmm.dll\midiOutGetDevCapsA", UInt,uDeviceID, UInt,&MidiOutCaps, UInt,50, UInt) - - If (result OR ErrorLevel) { - MsgBox Error %result% (ErrorLevel = %ErrorLevel%) in retrieving the name of midi output %uDeviceID% - Return -1 - } - - VarSetCapacity(PortName, PortNameSize) - DllCall("RtlMoveMemory", Str,PortName, Uint,&MidiOutCaps+OffsettoPortName, Uint,PortNameSize) - if (A_IsUnicode) { - PortName := Strget(&PortName, "UTF-8") - } - Return PortName - } - -MidiOutsEnumerate() { ; Returns number of midi output devices, creates global array MidiOutPortName with their names - local NumPorts, PortID - MidiOutPortName = - NumPorts := MidiOutGetNumDevs() - - Loop %NumPorts% { - PortID := A_Index -1 - MidiOutPortName%PortID% := MidiOutNameGet(PortID) - } - Return NumPorts - } - -UInt@(ptr) { -Return *ptr | *(ptr+1) << 8 | *(ptr+2) << 16 | *(ptr+3) << 24 -} - -PokeInt(p_value, p_address) { ; Windows 2000 and later - DllCall("ntdll\RtlFillMemoryUlong", UInt,p_address, UInt,4, UInt,p_value) -} + +; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! no edit below here, unless you know what you are doing. + +;************************************************* +;* MIDI UNDER THE HOOD +;* DO NOT EDIT IN HERE, unless you know what +;* what you are doing! +;************************************************* + +;**************************************************************************************************************** +;******************************************** midi "under the hood" ********************************************* +/* + This part is meant to take care of the "under the hood" midi input and output selection and save selection to an ini file. + Hopefully it simplifies usage for others out here trying to do things with midi and ahk. + + * use it as an include. + + The code here was taken/modified from the work by TomB/Lazslo on Midi Output + http://www.autohotkey.com/forum/viewtopic.php?t=18711&highlight=midi+output + + Orbik's Midi input thread + http://www.autohotkey.com/forum/topic30715.html + This method does NOT use the midi_in.dll, it makes direct calls to the winmm.dll + + Many different people took part in the creation of this file. + + ; Last edited 6/17/2010 11:30 AM by genmce + +*/ + +;************************************************* +;* GET PORTS LIST PARSE +;************************************************* +MidiPortRefresh: ; get the list of ports + + MIlist := MidiInsList(NumPorts) + Loop Parse, MIlist, | + { + } + TheChoice := MidiInDevice + 1 + +MOlist := MidiOutsList(NumPorts2) + Loop Parse, MOlist, | + { + } + TheChoice2 := MidiOutDevice + 1 + +return + +;************************************************* +;* LOAD UP SOME STUFF. +;************************************************* +;----------------------------------------------------------------- + +ReadIni() ; also set up the tray Menu + { + Menu, tray, add, MidiSet ; set midi ports tray item + Menu, tray, add, ResetAll ; Delete the ini file for testing -------------------------------- + menu, tray, add, MidiMon + global MidiInDevice, MidiOutDevice, 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 + IniRead, MidiOutDevice, %version%.ini, Settings, MidiOutDevice , %MidiOutDevice% ; read the midi out 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 + ;WriteIni() + } + } +;************************************************* +;* WRITE TO INI FILE FUNCTION +;************************************************* + +;CALLED TO UPDATE INI WHENEVER SAVED PARAMETERS CHANGE +WriteIni() + { + global MidiInDevice, MidiOutDevice, version + + IfNotExist, %version%.ini ; if no ini + FileAppend,, %version%.ini ; make one with the following entries. + IniWrite, %MidiInDevice%, %version%.ini, Settings, MidiInDevice + IniWrite, %MidiOutDevice%, %version%.ini, Settings, MidiOutDevice + } + +;************************************************* +;* PORT TESTING +;************************************************* +;------------ port testing to make sure selected midi port is valid -------------------------------- + +port_test(numports,numports2) ; confirm selected ports exist ; CLEAN THIS UP STILL + + { + global midiInDevice, midiOutDevice, midiok + + ; ----- 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 + } + ; ----- out port selection test based on numports2 + If MidiOutDevice not Between 0 and %numports2% + { + MidiOut := 0 ; set var to 0 as Error state. + If (MidiOutDevice = "") ; if blank + MidiOuterr = Midi Out Port EMPTY. ; set this error message + ;MsgBox, 0, , midi o port EMPTY + If (midiOutDevice > %numports2%) ; if greater than number of availble ports + MidiOuterr = Midi Out Port Out Invalid. ; set this error message + ;MsgBox, 0, , midi out port out of range + } + Else + { + MidiOut := 1 ;set var to 1 as valid state. + } + ; ---- test to see if ports valid, if either invalid load the gui to select. + ;midicheck(MCUin,MCUout) + If (%MidiIn% = 0) Or (%MidiOut% = 0) + { + MsgBox, 49, Midi Port Error!,%MidiInerr%`n%MidiOuterr%`n`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 + +;************************************************* +;* MIDI SET GUI +;************************************************* +; ------------------ end of port testing --------------------------- + + +MidiSet: ; midi port selection gui + + ; ------------- MIDI INPUT SELECTION ----------------------- + Gui, 6: Destroy + Gui, 2: Destroy + Gui, 3: Destroy + Gui, 4: Destroy + Gui, 4: +LastFound +AlwaysOnTop +Caption +ToolWindow ;-SysMenu + Gui, 4: Font, s12 + Gui, 4: add, text, x10 y10 w300 cmaroon, Select Midi Ports. ; Text title + Gui, 4: Font, s8 + Gui, 4: Add, Text, x10 y+10 w175 Center , Midi In Port ;Just text label + Gui, 4: font, s8 + ; midi ins list box + Gui, 4: Add, ListBox, x10 w200 h100 Choose%TheChoice% vMidiInPort gDoneInChange AltSubmit, %MiList% ; --- midi in listing of ports + ;Gui, Add, DropDownList, x10 w200 h120 Choose%TheChoice% vMidiInPort gDoneInChange altsubmit, %MiList% ; ( you may prefer this style, may need tweak) + + ; --------------- MidiOutSet --------------------- + Gui, 4: Add, TEXT, x220 y40 w175 Center, Midi Out Port ; gDoneOutChange + ; midi outlist box + Gui, 4: Add, ListBox, x220 y62 w200 h100 Choose%TheChoice2% vMidiOutPort gDoneOutChange AltSubmit, %MoList% ; --- midi out listing + ;Gui, Add, DropDownList, x220 y97 w200 h120 Choose%TheChoice2% vMidiOutPort gDoneOutChange altsubmit , %MoList% + Gui, 4: add, Button, x10 w205 gSet_Done, Done - Reload script. + Gui, 4: add, Button, xp+205 w205 gCancel, Cancel + ;gui, 4: add, checkbox, x10 y+10 vNotShown gDontShow, Do Not Show at startup. + ;IfEqual, NotShown, 1 + ;guicontrol, 4:, NotShown, 1 + Gui, 4: show , , %version% Midi Port Selection ; main window title and command to show it. + +Return + +;-----------------gui done change stuff - see label in both gui listbox line + + + + +;44444444444444444444444444 NEED TO EDIT THIS TO REFLECT CHANGES IN GENMCE PRIOR TO SEND OUT + +DoneInChange: + gui +lastfound + Gui, Submit, NoHide + Gui, Flash + Gui, 4: Submit, NoHide + Gui, 4: 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, 4:, UDPort, %MidiIndevice% + WriteIni() + ;MsgBox, 32, , midi in device = %MidiInDevice%`nmidiinport = %MidiInPort%`nport = %port%`ndevice= %device% `n UDPort = %UDport% ; only for testing +Return + +DoneOutChange: + gui +lastfound + Gui, Submit, NoHide + Gui, Flash + + Gui, 4: Submit, NoHide + Gui, 4: Flash + If %MidiOutPort% + UDPort2:= MidiOutPort - 1 , MidiOutDevice:= UDPort2 + GuiControl, 4: , UDPort2, %MidiOutdevice% + WriteIni() + ;Gui, Destroy +Return + +;------------------------ end of the doneout change stuff. + +Set_Done: ; aka reload program, called from midi selection gui + Gui, 3: Destroy + Gui, 4: Destroy + sleep, 100 + Reload +Return + +Cancel: + Gui, Destroy + Gui, 2: Destroy + Gui, 3: Destroy + Gui, 4: Destroy + Gui, 5: Destroy +Return + +;************************************************* +;* MIDI OUTPUT - UNDER THE HOOD +;************************************************* +; ********************** Midi output detection + +MidiOut: ; Function to load new settings from midi out menu item + OpenCloseMidiAPI() + h_midiout := midiOutOpen(MidiOutDevice) ; OUTPUT PORT 1 SEE BELOW FOR PORT 2 +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 + midiOutClose(h_midiout) + + Gui, 6: Destroy + Gui, 2: Destroy + Gui, 3: Destroy + Gui, 4: Destroy + Gui, 5: Destroy + gui, 7: destroy + ;gui, + Sleep 100 + ;winclose, Midi_in_2 ;close the midi in 2 ahk file + ExitApp + +;************************************************* +;* MIDI INPUT / OUTPUT UNDER THE HOOD +;************************************************* + +;############################################## 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 +;************************************************* + +;--- MIDI INS LIST FUNCTIONS - port handling ----- + +MidiInsList(ByRef NumPorts) + { ; Returns a "|"-separated list of midi output devices + local List, MidiInCaps, PortName, result, PortNameSize + PortNameSize := 32 * (A_IsUnicode ? 2 : 1) + VarSetCapacity(MidiInCaps, 50, 0) + VarSetCapacity(PortName, PortNameSize) ; PortNameSize 32 + + NumPorts := DllCall("winmm.dll\midiInGetNumDevs") ; #midi output devices on system, First device ID = 0 + + Loop %NumPorts% + { + result := DllCall("winmm.dll\midiInGetDevCapsA", UInt,A_Index-1, UInt,&MidiInCaps, UInt,50, UInt) + If (result OR ErrorLevel) { + List .= "|-Error-" + Continue + } + DllCall("RtlMoveMemory", Str,PortName, UInt,&MidiInCaps+8, UInt,PortNameSize) ; PortNameOffset 8, PortNameSize 32 + if (A_IsUnicode) { + PortName := Strget(&PortName, "UTF-8") + } + 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 * (A_IsUnicode ? 2 : 1) + 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) + if (A_IsUnicode) { + PortName := Strget(&PortName, "UTF-8") + } + 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 + } + +;************************************************* +;* MIDI OUT LIBRARY FROM lASZLO/TOMB +; Modified by JimF - removed long message +; handling as well as combining status byte with ch +; see commented out section below if you want to change it back +;************************************************* +; =============== end of midi selection stuff + + +MidiOutsList(ByRef NumPorts) + { ; Returns a "|"-separated list of midi output devices + local List, MidiOutCaps, PortName, result + PortNameSize := 32 * (A_IsUnicode ? 2 : 1) + VarSetCapacity(MidiOutCaps, 50, 0) + VarSetCapacity(PortName, PortNameSize) ; PortNameSize 32 + + NumPorts := DllCall("winmm.dll\midiOutGetNumDevs") ; #midi output devices on system, First device ID = 0 + + Loop %NumPorts% + { + result := DllCall("winmm.dll\midiOutGetDevCapsA", UInt,A_Index-1, UInt,&MidiOutCaps, UInt,50, UInt) + If (result OR ErrorLevel) + { + List .= "|-Error-" + Continue + } + DllCall("RtlMoveMemory", Str,PortName, UInt,&MidiOutCaps+8, UInt,PortNameSize) ; PortNameOffset 8, PortNameSize 32 + if (A_IsUnicode) { + PortName := Strget(&PortName, "UTF-8") + } + List .= "|" PortName + } + Return SubStr(List,2) + } +;---------------------midiOut from TomB and Lazslo and JimF -------------------------------- + +;THATS THE END OF MY STUFF (JimF) THE REST ID WHAT LASZLo AND PAXOPHONE WERE USING ALREADY +;AHK FUNCTIONS FOR MIDI OUTPUT - calling winmm.dll +;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_multimedia_functions.asp +;Derived from Midi.ahk dated 29 August 2008 - streaming support removed - (JimF) + + +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 + } + } + +;FUNCTIONS FOR SENDING SHORT MESSAGES + +midiOutOpen(uDeviceID = 0) { ; Open midi port for sending individual midi messages --> handle + strh_midiout = 0000 + + result := DllCall("winmm.dll\midiOutOpen", UInt,&strh_midiout, UInt,uDeviceID, UInt,0, UInt,0, UInt,0, UInt) + If (result or ErrorLevel) { + MsgBox There was an Error opening the midi port.`nError code %result%`nErrorLevel = %ErrorLevel% + Return -1 + } + Return UInt@(&strh_midiout) + } + +midiOutShortMsg(h_midiout, MidiStatus, Param1, Param2) { ;Channel, + ;h_midiout: handle to midi output device returned by midiOutOpen + ;EventType, Channel combined -> MidiStatus byte: http://www.harmony-central.com/MIDI/Doc/table1.html + ;Param3 should be 0 for PChange, ChanAT, or Wheel + ;Wheel events: entire Wheel value in Param2 - the function splits it into two bytes +/* + If (EventType = "NoteOn" OR EventType = "N1") + MidiStatus := 143 + Channel + Else If (EventType = "NoteOff" OR EventType = "N0") + MidiStatus := 127 + Channel + Else If (EventType = "CC") + MidiStatus := 175 + Channel + Else If (EventType = "PolyAT" OR EventType = "PA") + MidiStatus := 159 + Channel + Else If (EventType = "ChanAT" OR EventType = "AT") + MidiStatus := 207 + Channel + Else If (EventType = "PChange" OR EventType = "PC") + MidiStatus := 191 + Channel + Else If (EventType = "Wheel" OR EventType = "W") { + MidiStatus := 223 + Channel + Param2 := Param1 >> 8 ; MSB of wheel value + Param1 := Param1 & 0x00FF ; strip MSB + } +*/ + result := DllCall("winmm.dll\midiOutShortMsg", UInt,h_midiout, UInt, MidiStatus|(Param1<<8)|(Param2<<16), UInt) + If (result or ErrorLevel) { + MsgBox There was an Error Sending the midi event: (%result%`, %ErrorLevel%) + Return -1 + } + } + +midiOutClose(h_midiout) { ; Close MidiOutput + Loop 9 { + result := DllCall("winmm.dll\midiOutClose", UInt,h_midiout) + If !(result or ErrorLevel) + Return + Sleep 250 + } + MsgBox Error in closing the midi output port. There may still be midi events being Processed. + Return -1 + } + +;UTILITY FUNCTIONS +MidiOutGetNumDevs() { ; Get number of midi output devices on system, first device has an ID of 0 + Return DllCall("winmm.dll\midiOutGetNumDevs") + } + +MidiOutNameGet(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(MidiOutCaps, 50, 0) ; allows for szPname to be 32 bytes + OffsettoPortName := 8 + PortNameSize := 32 * (A_IsUnicode ? 2 : 1) + result := DllCall("winmm.dll\midiOutGetDevCapsA", UInt,uDeviceID, UInt,&MidiOutCaps, UInt,50, UInt) + + If (result OR ErrorLevel) { + MsgBox Error %result% (ErrorLevel = %ErrorLevel%) in retrieving the name of midi output %uDeviceID% + Return -1 + } + + VarSetCapacity(PortName, PortNameSize) + DllCall("RtlMoveMemory", Str,PortName, Uint,&MidiOutCaps+OffsettoPortName, Uint,PortNameSize) + if (A_IsUnicode) { + PortName := Strget(&PortName, "UTF-8") + } + Return PortName + } + +MidiOutsEnumerate() { ; Returns number of midi output devices, creates global array MidiOutPortName with their names + local NumPorts, PortID + MidiOutPortName = + NumPorts := MidiOutGetNumDevs() + + Loop %NumPorts% { + PortID := A_Index -1 + MidiOutPortName%PortID% := MidiOutNameGet(PortID) + } + Return NumPorts + } + +UInt@(ptr) { +Return *ptr | *(ptr+1) << 8 | *(ptr+2) << 16 | *(ptr+3) << 24 +} + +PokeInt(p_value, p_address) { ; Windows 2000 and later + DllCall("ntdll\RtlFillMemoryUlong", UInt,p_address, UInt,4, UInt,p_value) +} diff --git a/VJoy_Test.ahk b/VJoy_Test.ahk deleted file mode 100644 index ae40d70..0000000 --- a/VJoy_Test.ahk +++ /dev/null @@ -1,460 +0,0 @@ -; VJoy_Test.ahk - -#include %A_ScriptDir%\VJoy_lib.ahk - - VJoy_Init() - nButtons := VJoy_GetVJDButtonNumber(iInterface) - - cbtn := 1 - - StatStr := (status = VJD_STAT_OWN) ? "OWN" : "FREE" ; only FREE state required. - - AxisMax_X := VJoy_GetVJDAxisMax(iInterface, HID_USAGE_X) - AxisMax_Y := VJoy_GetVJDAxisMax(iInterface, HID_USAGE_Y) - AxisMax_Z := VJoy_GetVJDAxisMax(iInterface, HID_USAGE_Z) - AxisMax_RX := VJoy_GetVJDAxisMax(iInterface, HID_USAGE_RX) - AxisMax_RY := VJoy_GetVJDAxisMax(iInterface, HID_USAGE_RY) - AxisMax_RZ := VJoy_GetVJDAxisMax(iInterface, HID_USAGE_RZ) - AxisMax_SL0 := VJoy_GetVJDAxisMax(iInterface, HID_USAGE_SL0) - AxisMax_SL1 := VJoy_GetVJDAxisMax(iInterface, HID_USAGE_SL1) - AxisMax_WHL := VJoy_GetVJDAxisMax(iInterface, HID_USAGE_WHL) - - ; build gui - Gui, Add, Text, w80 , Status: %StatStr% - Gui, add, Button, x100 y5 Default gBtnReset, Re&set - Gui, add, Button, x150 y5 gBtnReload, &Reload - Gui, add, Button, x200 y5 gBtnjoycpl, Open &cpl - Gui, Add, Text, x10, %nButtons% Buttons supported - Gui, Add, Button, x140 y30 gBtnTestAllON, Test all On - Gui, Add, Button, x210 y30 gBtnTestAllOFF, Off - - Loop, %nButtons% - { - bX := ((Mod((A_Index-1), 8)) * 30 ) + 10 - bY := FLOOR((A_Index-1) / 8) * 24 + 70 - Gui, add, Button, h5 x%bx% y%by% gBtn%A_Index%, %A_Index% - } - - nexty := 180 - if (VJoy_GetVJDAxisExist(iInterface, HID_USAGE_X)) { - Gui, Add, Text, x10 w130 y%nexty%, Axis X: 0 / %AxisMax_X% - Gui, Add, Slider, x140 y%nexty% vAxisX gSliderXChanged - nexty += 40 - } else { - Gui, Add, Text, x0 y0 - } - - if (VJoy_GetVJDAxisExist(iInterface, HID_USAGE_Y)) { - Gui, Add, Text, x10 w130 y%nexty%, Axis Y: 0 / %AxisMax_Y% - Gui, Add, Slider, x140 y%nexty% vAxisY gSliderYChanged - nexty += 40 - } else { - Gui, Add, Text, x0 y0 - } - - if (VJoy_GetVJDAxisExist(iInterface, HID_USAGE_Z)) { - Gui, Add, Text, x10 w130 y%nexty%, Axis Z: 0 / %AxisMax_Z% - Gui, Add, Slider, x140 y%nexty% vAxisZ gSliderZChanged - nexty += 40 - } else { - Gui, Add, Text, x0 y0 - } - - if (VJoy_GetVJDAxisExist(iInterface, HID_USAGE_RX)) { - Gui, Add, Text, x10 w130 y%nexty%, Axis RX: 0 / %AxisMax_RX% - Gui, Add, Slider, x140 y%nexty% vAxisRX gSliderRXChanged - nexty += 40 - } else { - Gui, Add, Text, x0 y0 - } - - if (VJoy_GetVJDAxisExist(iInterface, HID_USAGE_RY)) { - Gui, Add, Text, x10 w130 y%nexty%, Axis RY: 0 / %AxisMax_RY% - Gui, Add, Slider, x140 y%nexty% vAxisRY gSliderRYChanged - nexty += 40 - } else { - Gui, Add, Text, x0 y0 - } - - if (VJoy_GetVJDAxisExist(iInterface, HID_USAGE_RZ)) { - Gui, Add, Text, x10 w130 y%nexty%, Axis RZ: 0 / %AxisMax_RZ% - Gui, Add, Slider, x140 y%nexty% vAxisRZ gSliderRZChanged - nexty += 40 - } else { - Gui, Add, Text, x0 y0 - } - - if (VJoy_GetVJDAxisExist(iInterface, HID_USAGE_SL0)) { - Gui, Add, Text, x10 w130 y%nexty%, Slider0: 0 / %AxisMax_SL0% - Gui, Add, Slider, x140 y%nexty% vAxisSL0 gSliderSL0Changed - nexty += 40 - } else { - Gui, Add, Text, x0 y0 - } - - if (VJoy_GetVJDAxisExist(iInterface, HID_USAGE_SL1)) { - Gui, Add, Text, x10 w130 y%nexty%, Slider1: 0 / %AxisMax_SL1% - Gui, Add, Slider, x140 y%nexty% vAxisSL1 gSliderSL1Changed - nexty += 40 - } else { - Gui, Add, Text, x0 y0 - } - - if (VJoy_GetVJDAxisExist(iInterface, HID_USAGE_WHL)) { - Gui, Add, Text, x10 w130 y%nexty%, Wheel: 0 / %AxisMax_WHL% - Gui, Add, Slider, x140 y%nexty% vAxisWHL gSliderWHLChanged - nexty += 40 - } else { - Gui, Add, Text, x0 y0 - } - - if (ContPovNumber) { - Gui, Add, Text, x10 y%nexty%,Number of Continuous POVs: %ContPovNumber% - nexty += 20 - Gui, Add, Text, x10 y%nexty%, Continuous Pov test - Gui, Add, Slider, x140 y%nexty% vPovValSlider gSliderContPov - nexty+=40 - Gui, Add, Edit, x10 w80 y%nexty% vPovValDirect gEditContPov, -1 - Loop, %ContPovNumber% - { - _contpov_listing := % _contpov_listing . A_Index - if (A_Index < ContPovNumber) { - _contpov_listing := % _contpov_listing . "|" - } - } - Gui, Add, ListBox, x140 w40 y%nexty% vContPovChoice gContPovChoose, %_contpov_listing% - nexty += 30 - } - - if (DiscPovNumber) { - Gui, Add, Text, x10 y%nexty%,Number of Descrete POVs: %DiscPovNumber% - nexty += 20 - - tmpy := nexty - Gui, Add, Button, x160 y%tmpy% gBtnPovN, N - tmpy := nexty + 30 - Gui, Add, Button, x155 y%tmpy% gBtnPovNeu, Neu - tmpy := nexty + 60 - Gui, Add, Button, x160 y%tmpy% gBtnPovS, S - tmpy := nexty + 30 - Gui, Add, Button, x120 y%tmpy% gBtnPovW, W - Gui, Add, Button, x200 y%tmpy% gBtnPovE, E - - Loop, %DiscPovNumber% - { - _contpov_listing := % _contpov_listing . A_Index - if (A_Index < DiscPovNumber) { - _contpov_listing := % _contpov_listing . "|" - } - } - Gui, Add, ListBox, x10 w40 y%nexty% vDiscPovChoice gDiscPovChoose, %_contpov_listing% - - nexty += 100 - } - GetKeyState, _JoyStat, JoyInfo - Gui, Add, Text, x10 y%nexty%, JoyInfo: %_JoyStat% - Gui, Show - -return - -SliderXChanged: - Gui, Submit, NoHide - tmp_axis_val := Floor(AxisMax_X * AxisX / 100) - VJoy_SetAxis(tmp_axis_val, iInterface, HID_USAGE_X) - ControlSetText, Static3, Axis X %tmp_axis_val% / %AxisMax_X% -return - -SliderYChanged: - Gui, Submit, NoHide - tmp_axis_val := Floor(AxisMax_Y * AxisY / 100) - VJoy_SetAxis(tmp_axis_val, iInterface, HID_USAGE_Y) - ControlSetText, Static4, Axis Y %tmp_axis_val% / %AxisMax_Y% -return - -SliderZChanged: - Gui, Submit, NoHide - tmp_axis_val := Floor(AxisMax_Z * AxisZ / 100) - VJoy_SetAxis(tmp_axis_val, iInterface, HID_USAGE_Z) - ControlSetText, Static5, Axis Z %tmp_axis_val% / %AxisMax_Z% -return - -SliderRXChanged: - Gui, Submit, NoHide - tmp_axis_val := Floor(AxisMax_RX * AxisRX / 100) - VJoy_SetAxis(tmp_axis_val, iInterface, HID_USAGE_RX) - ControlSetText, Static6, Axis RX %tmp_axis_val% / %AxisMax_RX% -return - -SliderRYChanged: - Gui, Submit, NoHide - tmp_axis_val := Floor(AxisMax_RY * AxisRY / 100) - VJoy_SetAxis(tmp_axis_val, iInterface, HID_USAGE_RY) - ControlSetText, Static7, Axis RY %tmp_axis_val% / %AxisMax_RY% -return - -SliderRZChanged: - Gui, Submit, NoHide - tmp_axis_val := Floor(AxisMax_RZ * AxisRZ / 100) - VJoy_SetAxis(tmp_axis_val, iInterface, HID_USAGE_RZ) - ControlSetText, Static8, Axis RZ %tmp_axis_val% / %AxisMax_RZ% -return - -SliderSL0Changed: - Gui, Submit, NoHide - tmp_axis_val := Floor(AxisMax_SL0 * AxisSL0 / 100) - VJoy_SetAxis(tmp_axis_val, iInterface, HID_USAGE_SL0) - ControlSetText, Static9, Slider0 %tmp_axis_val% / %AxisMax_SL0% -return - -SliderSL1Changed: - Gui, Submit, NoHide - tmp_axis_val := Floor(AxisMax_SL1 * AxisSL1 / 100) - VJoy_SetAxis(tmp_axis_val, iInterface, HID_USAGE_SL1) - ControlSetText, Static10, Slider1 %tmp_axis_val% / %AxisMax_SL1% -return - -SliderWHLChanged: - Gui, Submit, NoHide - tmp_axis_val := Floor(AxisMax_WHL * AxisWHL / 100) - VJoy_SetAxis(tmp_axis_val, iInterface, HID_USAGE_WHL) - ControlSetText, Static11, Wheel %tmp_axis_val% / %AxisMax_WHL% -return - -BtnReload: -F12:: - VJoy_Close(iInterface) - Reload -return - -;GuiClose: -; ExitApp -;return - -OnExit: - VJoy_Close(iInterface) -return - -; GUIBtn test all buttons -BtnTestAllON: - Loop, %nButtons% - { - VJoy_SetBtn(1, iInterface, A_Index) - } -return -BtnTestAllOFF: - Loop, %nButtons% - { - VJoy_SetBtn(0, iInterface, A_Index) - } -return - -BtnTest(id, btn) { - VJoy_SetBtn(1, id, btn) - Sleep, 100 - VJoy_SetBtn(0, id, btn) ; Release button 1 -} - -; GUIBtn1 for test button1 -Btn1: - BtnTest(iInterface, 1) -return -Btn2: - BtnTest(iInterface, 2) -return -Btn3: - BtnTest(iInterface, 3) -return -Btn4: - BtnTest(iInterface, 4) -return -Btn5: - BtnTest(iInterface, 5) -return -Btn6: - BtnTest(iInterface, 6) -return -Btn7: - BtnTest(iInterface, 7) -return -Btn8: - BtnTest(iInterface, 8) -return -Btn9: - BtnTest(iInterface, 9) -return -Btn10: - BtnTest(iInterface, 10) -return -Btn11: - BtnTest(iInterface, 11) -return -Btn12: - BtnTest(iInterface, 12) -return -Btn13: - BtnTest(iInterface, 13) -return -Btn14: - BtnTest(iInterface, 14) -return -Btn15: - BtnTest(iInterface, 15) -return -Btn16: - BtnTest(iInterface, 16) -return -Btn17: - BtnTest(iInterface, 17) -return -Btn18: - BtnTest(iInterface, 18) -return -Btn19: - BtnTest(iInterface, 19) -return -Btn20: - BtnTest(iInterface, 20) -return -Btn21: - BtnTest(iInterface, 21) -return -Btn22: - BtnTest(iInterface, 22) -return -Btn23: - BtnTest(iInterface, 23) -return -Btn24: - BtnTest(iInterface, 24) -return -Btn25: - BtnTest(iInterface, 25) -return -Btn26: - BtnTest(iInterface, 26) -return -Btn27: - BtnTest(iInterface, 27) -return -Btn28: - BtnTest(iInterface, 28) -return -Btn29: - BtnTest(iInterface, 29) -return -Btn30: - BtnTest(iInterface, 30) -return -Btn31: - BtnTest(iInterface, 31) -return -Btn32: - BtnTest(iInterface, 32) -return - -; Open Game Control Panel -Btnjoycpl: - RunWait %ComSpec% /C start joy.cpl,, Hide -return - -BtnReset: - AxisX := AxisY := AxisZ := AxisRX := AxisRY := AxisRZ := Slider0 := Slider1 := 0 - Gui, Submit, NoHide - - VJoy_Close(iInterface) - VJoy_Init() -return - -EditContPov: - Gui, Submit, NoHide - - GuiControlGet, ContPovChoice - if (ContPovChoice < 1 or ContPovChoice > ContPovNumber) { - MsgBox, Please select a pov - return - } - - if (PovValDirect < -1) { - PovValDirect := -1 - Gui, Submit, NoHide - return - } - if (PovValDirect > 35999) { - PovValDirect := 35999 - Gui, Submit, NoHide - return - } - VJoy_SetContPov(PovValDirect, iInterface, ContPovChoice) -return - -SliderContPov: - Gui, Submit, NoHide - GuiControlGet, ContPovChoice - if (ContPovChoice < 1 or ContPovChoice > ContPovNumber) { - MsgBox, Please select a pov - return - } - PovValDirect := Floor(35999 * PovValSlider / 100) - ControlSetText, Edit1, %PovValDirect% - VJoy_SetContPov(PovValDirect, iInterface, ContPovChoice) -return - -ContPovChoose: - Gui, Submit, NoHide - GuiControlGet, ContPovChoice -return - -BtnPovNeu: - Gui, Submit, NoHide - GuiControlGet, DiscPovChoice - if (DiscPovChoice < 1 or DiscPovChoice > DiscPovNumber) { - MsgBox, Please select a pov - return - } - VJoy_SetDiscPov(-1, iInterface, DiscPovChoice) -return - -BtnPovN: - Gui, Submit, NoHide - GuiControlGet, DiscPovChoice - if (DiscPovChoice < 1 or DiscPovChoice > DiscPovNumber) { - MsgBox, Please select a pov - return - } - VJoy_SetDiscPov(0, iInterface, DiscPovChoice) -return - -BtnPovE: - Gui, Submit, NoHide - GuiControlGet, DiscPovChoice - if (DiscPovChoice < 1 or DiscPovChoice > DiscPovNumber) { - MsgBox, Please select a pov - return - } - VJoy_SetDiscPov(1, iInterface, DiscPovChoice) -return - -BtnPovS: - Gui, Submit, NoHide - GuiControlGet, DiscPovChoice - if (DiscPovChoice < 1 or DiscPovChoice > DiscPovNumber) { - MsgBox, Please select a pov - return - } - VJoy_SetDiscPov(2, iInterface, DiscPovChoice) -return - -BtnPovW: - Gui, Submit, NoHide - GuiControlGet, DiscPovChoice - if (DiscPovChoice < 1 or DiscPovChoice > DiscPovNumber) { - MsgBox, Please select a pov - return - } - VJoy_SetDiscPov(3, iInterface, DiscPovChoice) -return - -DiscPovChoose: - Gui, Submit, NoHide - GuiControlGet, DiscPovChoice -return \ No newline at end of file diff --git a/VJoy_lib.ahk b/VJoy_lib.ahk deleted file mode 100644 index 508d8dc..0000000 --- a/VJoy_lib.ahk +++ /dev/null @@ -1,175 +0,0 @@ -;VJoy_lib.ahk - - iInterface = 2 ; Default target vJoy device - - ; ported from VjdStat in vjoyinterface.h - VJD_STAT_OWN := 0 ; The vJoy Device is owned by this application. - VJD_STAT_FREE := 1 ; The vJoy Device is NOT owned by any application (including this one). - VJD_STAT_BUSY := 2 ; The vJoy Device is owned by another application. It cannot be acquired by this application. - VJD_STAT_MISS := 3 ; The vJoy Device is missing. It either does not exist or the driver is down. - VJD_STAT_UNKN := 4 ; Unknown - - ;HID Descriptor definitions(ported from public.h - HID_USAGE_X := 0x30 - HID_USAGE_Y := 0x31 - HID_USAGE_Z := 0x32 - HID_USAGE_RX := 0x33 - HID_USAGE_RY := 0x34 - HID_USAGE_RZ := 0x35 - HID_USAGE_SL0 := 0x36 - HID_USAGE_SL1 := 0x37 - HID_USAGE_WHL := 0x38 - HID_USAGE_POV := 0x39 - -VJoy_init() { - Global iInterface, VJD_STAT_OWN, VJD_STAT_FREE, VJD_STAT_BUSY, VJD_STAT_MISS, VJD_STAT_UNKN, ContPovNumber, DiscPovNumber, hDLL - - SetWorkingDir, %A_ScriptDir% - curdir:=A_WorkingDir - - if (!hDLL) { - dllpath = %A_ScriptDir%\vJoyInterface.dll - hDLL := DLLCall("LoadLibrary", "Str", dllpath) - if (!hDLL) { - MsgBox, LoadLibrary %dllpath% fail - } - } - - result := DllCall("vJoyInterface.dll\vJoyEnabled", "Int") - if (ErrorLevel = 4) { - MsgBox, Error! VJoy library "vJoyInterface.dll" is not found!`nErrorLevel:%ErrorLevel% - ExitApp - } - if (!result) { - MsgBox, Error! VJoy interface is not installed!`nErrorLevel:%ErrorLevel% - ExitApp - } - - status := DllCall("vJoyInterface\GetVJDStatus", "Int", iInterface) - if (status = VJD_STAT_OWN) { - ToolTip, vJoy Device %iInterface% is already owned by this feeder - } else if (status = VJD_STAT_FREE) { - ToolTip, vJoy Device %iInterface% is free - } else if (status = VJD_STAT_BUSY) { - MsgBox vJoy Device %iInterface% is already owned by another feeder`nCannot continue`n - ExitApp - } else if (status = VJD_STAT_MISS) { - MsgBox vJoy Device %iInterface% is not installed or disabled`nCannot continue`n - ExitApp - } else { - MsgBox vJoy Device %iInterface% general error`nCannot continue`n - ExitApp - } - Sleep, 50 - ToolTip - - ; Get the number of buttons and POV Hat switchessupported by this vJoy device - ContPovNumber := DllCall("vJoyInterface\GetVJDContPovNumber", "UInt", iInterface, "Int") - DiscPovNumber := DllCall("vJoyInterface\GetVJDDiscPovNumber", "UInt", iInterface, "Int") - - ; Acquire the target device - if (status = VJD_STAT_FREE) { - ac_jvd := VJoy_AcquireVJD(iInterface) - } - if ((status = VJD_STAT_OWN) || ((status = VJD_STAT_FREE) && (!ac_jvd))) { - MsgBox % "Failed to acquire vJoy device number % iInterface " - ExitApp - } else { - ToolTip, Acquired: vJoy device number %iInterface% - } - Sleep, 50 - ToolTip - - VJoy_ResetVJD(iInterface) - -; VJoy_RelinquishVJD(iInterface) - - return -} - -VJoy_AcquireVJD(id) { - return DllCall("vJoyInterface\AcquireVJD", "UInt", id) -} - - -VJoy_GetVJDStatus(id) { - status := DllCall("vJoyInterface\GetVJDStatus", "UInt", id) - return status -} - -VJoy_GetVJDButtonNumber(id) { - res := DllCall("vJoyInterface\GetVJDButtonNumber", "Int", id) - return res -} - -VJoy_SetBtn(sw, id, btn_id) { - res := DllCall("vJoyInterface\SetBtn", "Int", sw, "UInt", id, "UChar", btn_id) - if (!res) { - MsgBox, SetBtn(%sw%, %id%, %btn_id%) err: %ErrorLevel%`nnLastError: %A_LastError% - } - return res -} - -VJoy_ResetAll() { - res := DllCall("vJoyInterface\ResetAll") - return res -} - -VJoy_ResetVJD(id) { - res := DllCall("vJoyInterface\ResetVJD", "UInt", id) - return res -} - -VJoy_GetVJDAxisMax(id, usage) { - res := DllCall("vJoyInterface\GetVJDAxisMax", "Int", id, "Int", usage, "IntP", Max_Axis) - return Max_Axis -} - -VJoy_GetVJDAxisExist(id, usage) { - Axis_t := DllCall("vJoyInterface\GetVJDAxisExist", "UInt", id, "UInt", usage) - if (!Axis_t) { -; MsgBox, GetVJDAxisExist Error!`nErrorLevel:%ErrorLevel% - } - if (ErrorLevel) { - ToolTip, GetVJDAxisExist Warning!`nErrorLevel:%ErrorLevel% - ToolTip - } - return Axis_t -} - -VJoy_SetAxis(axis_val, id, usage) { - res := DllCall("vJoyInterface\SetAxis", "Int", axis_val, "UInt", id, "UInt", usage) - if (!res) { - MsgBox, SetAxis Error!`nErrorLevel:%ErrorLevel% - } - return res -} - -VJoy_RelinquishVJD(id) { - DllCall("vJoyInterface\RelinquishVJD", "UInt", id) -} - -VJoy_Close(id) { - VJoy_ResetAll() - VJoy_RelinquishVJD(id) - if (hDLL) { - DLLCall("FreeLibraly", "Ptr", hDLL) - hDLL:= - } -} - -VJoy_SetDiscPov(Value, id, nPov) { - _res := DllCall("vJoyInterface\SetDiscPov", "Int", Value, "UInt", id, "UChar", nPov) - if (!_res) { - MsgBox, SetDiscPov err: %ErrorLevel% - } - return _ef_res -} - -VJoy_SetContPov(Value, id, nPov) { - _res := DllCall("vJoyInterface\SetContPov", "Int", Value, "UInt", id, "UChar", nPov) - if (!_res) { - MsgBox, SetContPov err: %ErrorLevel% - } - return _ef_res -} \ No newline at end of file diff --git a/VJoy_lib_1.ahk b/VJoy_lib_1.ahk deleted file mode 100644 index c4af3c0..0000000 --- a/VJoy_lib_1.ahk +++ /dev/null @@ -1,839 +0,0 @@ -; VJoy_lib.ahk Ver1.1 -; Original code by Axlar - http://www.autohotkey.com/board/topic/87690- -; modded by evilC - VJoy_SetAxis fix (Bad ternary operator) - - VJD_MAXDEV := 16 - - ; ported from VjdStat in vjoyinterface.h - VJD_STAT_OWN := 0 ; The vJoy Device is owned by this application. - VJD_STAT_FREE := 1 ; The vJoy Device is NOT owned by any application (including this one). - VJD_STAT_BUSY := 2 ; The vJoy Device is owned by another application. It cannot be acquired by this application. - VJD_STAT_MISS := 3 ; The vJoy Device is missing. It either does not exist or the driver is down. - VJD_STAT_UNKN := 4 ; Unknown - - ; HID Descriptor definitions(ported from public.h - HID_USAGE_X := 0x30 - HID_USAGE_Y := 0x31 - HID_USAGE_Z := 0x32 - HID_USAGE_RX:= 0x33 - HID_USAGE_RY:= 0x34 - HID_USAGE_RZ:= 0x35 - HID_USAGE_SL0:= 0x36 - HID_USAGE_SL1:= 0x37 - - VJDev := Object() - -; Load lib from already load or current/system directory -VJoy_LoadLibrary() { - Global hVJDLL - if (hVJDLL) { - return hVJDLL - } - - ; Load dll from any path or get handle of already loaded - hVJDLL := DLLCall("LoadLibrary", "Str", "vJoyInterface") - if (hVJDLL) { - return hVJDLL - } - - ; If dll deployed into current and it was wrong, warn - dllpath = %A_ScriptDir%\vJoyInterface.dll - if (FileExist(dllpath)) { - if (A_Is64bitOS) { - is64bit = 64-bitOS - } - AHKEd := (A_PtrSize = 4) ? "32-bit" : "64-bit" - RequiredDLL := (A_PtrSize = 4) ? "x86" : "x64" - dll_info := GetFileVersion(dllpath) - if (dll_info and !InStr(dll_info, RequiredDLL)) { - isWrong = =wrong! - } - MsgBox, - ( -LoadLibrary %dllpath% failed! -Exiting. -Make sure %RequiredDLL% vJoyInterface.dll is in %A_ScriptDir% - (%dll_info%%isWrong%) - AutoHotkey: %AHKEd% - OSVersion:%A_OSVersion% %is64bit% - ) - } - return 0 -} - -GetFileVersion(pszFilePath) { - dwSize := DLLCall("Version\GetFileVersionInfoSize", "Str", pszFilePath) - if (!dwSize) { - return - } - VarSetCapacity(pvData, dwSize) - if (!DLLCall("Version\GetFileVersionInfo", "Str", pszFilePath - , "Int", 0, "Int", dwSize, "Ptr", &pvData)) { - return - } - ; Get British product version string - if (!DLLCall("Version\VerQueryValue", "UInt", &pvData, "Str" - , "\\StringFileInfo\\040904b0\\ProductVersion", "UIntP" - , lpTranslate, "UInt", 0)) { - return - } - return StrGet(lpTranslate) -} - -Class VJoyDev { - __New(dev_id) { - - Global NoticeDone, hVJDLL, VJD_STAT_OWN, VJD_STAT_FREE, VJD_STAT_BUSY, VJD_STAT_MISS, VJD_STAT_UNKN,HID_USAGE_X,HID_USAGE_Y,HID_USAGE_Z,HID_USAGE_RX,HID_USAGE_RY,HID_USAGE_RZ,HID_USAGE_SL0,HID_USAGE_SL1 - - if (!hVJDLL) { - hVJDLL := VJoy_LoadLibrary() - } - if (!hVJDLL) { - if (!NoticeDone) { - NoticeDone := True - MsgBox, [VJoy Constructer] LoadLibrary vJoyInterface.dll failed! - } - return - } - - this.DeviceEnabled := DllCall("vJoyInterface.dll\vJoyEnabled") - if (ErrorLevel = 4) { - MsgBox, Error! VJoy library "vJoyInterface.dll" is not found!`nErrorLevel:%ErrorLevel% - return - } - if (!this.DeviceEnabled) { - ;MsgBox, Error! VJoy interface is not installed!`nErrorLevel:%ErrorLevel% - return - } - - DeviceStatus := DllCall("vJoyInterface\GetVJDStatus", "UInt", dev_id) - if (DeviceStatus = VJD_STAT_OWN) { - stat_str = VJD_STAT_OWN - ;ToolTip, vJoy Device %dev_id% is already owned by this feeder - } else if (DeviceStatus = VJD_STAT_FREE) { - ;ToolTip, vJoy Device %dev_id% is free - stat_str = VJD_STAT_FREE - } else if (DeviceStatus = VJD_STAT_BUSY) { - MsgBox vJoy Device %dev_id% is already owned by another feeder`nCannot continue`n - stat_str = VJD_STAT_BUSY - return - } else if (DeviceStatus = VJD_STAT_MISS) { - ;MsgBox vJoy Device %dev_id% is not installed or disabled`nCannot continue`n - stat_str = VJD_STAT_MISS - return - } else { - stat_str = VJD_STAT_UNKN - MsgBox vJoy Device %dev_id% general error`nCannot continue`n - return - } - ;ToolTip - - ; Get the number of buttons and POV Hat switchessupported by this vJoy device - this.ContPovNumber := DllCall("vJoyInterface\GetVJDContPovNumber", "UInt", dev_id) - this.ContPov := Object() - Loop, % this.ContPovNumber ; insert dummy - this.ContPov.Insert(A_Index, 0) - - this.DiscPovNumber := DllCall("vJoyInterface\GetVJDDiscPovNumber", "UInt", dev_id) - this.DiscPov := Object() - Loop, % this.DiscPovNumber ; insert dummy - this.DiscPov.Insert(A_Index, 0) - - this.NumberOfButtons := DllCall("vJoyInterface\GetVJDButtonNumber", "Int", dev_id) - this.Btn := Object() - Loop, % this.NumberOfButtons ; insert dummy - this.Btn.Insert(A_Index, 0) - - this.AxisExist_X := DllCall("vJoyInterface\GetVJDAxisExist", "Int", dev_id, "Int", HID_USAGE_X ) - this.AxisExist_Y := DllCall("vJoyInterface\GetVJDAxisExist", "Int", dev_id, "Int", HID_USAGE_Y ) - this.AxisExist_Z := DllCall("vJoyInterface\GetVJDAxisExist", "Int", dev_id, "Int", HID_USAGE_Z ) - this.AxisExist_RX := DllCall("vJoyInterface\GetVJDAxisExist", "Int", dev_id, "Int", HID_USAGE_RX ) - this.AxisExist_RY := DllCall("vJoyInterface\GetVJDAxisExist", "Int", dev_id, "Int", HID_USAGE_RY ) - this.AxisExist_RZ := DllCall("vJoyInterface\GetVJDAxisExist", "Int", dev_id, "Int", HID_USAGE_RZ ) - this.AxisExist_SL0 := DllCall("vJoyInterface\GetVJDAxisExist", "Int", dev_id, "Int", HID_USAGE_SL0) - this.AxisExist_SL1 := DllCall("vJoyInterface\GetVJDAxisExist", "Int", dev_id, "Int", HID_USAGE_SL1) - - if (DllCall("vJoyInterface\GetVJDAxisMax", "Int", dev_id, "Int", HID_USAGE_X, "IntP", nResult)) { - this.AxisMax_X := nResult - } - if (DllCall("vJoyInterface\GetVJDAxisMax", "Int", dev_id, "Int", HID_USAGE_Y, "IntP", nResult)) { - this.AxisMax_Y := nResult - } - if (DllCall("vJoyInterface\GetVJDAxisMax", "Int", dev_id, "Int", HID_USAGE_Z, "IntP", nResult)) { - this.AxisMax_Z := nResult - } - if (DllCall("vJoyInterface\GetVJDAxisMax", "Int", dev_id, "Int", HID_USAGE_RX, "IntP", nResult)) { - this.AxisMax_RX := nResult - } - if (DllCall("vJoyInterface\GetVJDAxisMax", "Int", dev_id, "Int", HID_USAGE_RY, "IntP", nResult)) { - this.AxisMax_RY := nResult - } - if (DllCall("vJoyInterface\GetVJDAxisMax", "Int", dev_id, "Int", HID_USAGE_RZ, "IntP", nResult)) { - this.AxisMax_RZ := nResult - } - if (DllCall("vJoyInterface\GetVJDAxisMax", "Int", dev_id, "Int", HID_USAGE_SL0, "IntP", nResult)) { - this.Slider0_Max := nResult - } - if (DllCall("vJoyInterface\GetVJDAxisMax", "Int", dev_id, "Int", HID_USAGE_SL1, "IntP", nResult)) { - this.Slider1_Max := nResult - } - - ; Acquire the target device - if (DeviceStatus = VJD_STAT_FREE) { - ac_jvd := DllCall("vJoyInterface\AcquireVJD", "UInt", dev_id) - if (!ac_jvd) { - MsgBox, Dev:%dev_id% aquire fail ErrorLevel: %ErrorLevel% - } - } - - if (DeviceStatus = VJD_STAT_OWN) { - MsgBox % "Failed to acquire vJoy device number: " dev_id "`n(Other process owned device)" - return - } else if (DeviceStatus = VJD_STAT_FREE and !ac_jvd ) { - MsgBox % "Failed to acquire vJoy device number: " dev_id "`nAcquired: " ac_jvd - return - } else { - ;ToolTip, % "Acquired: vJoy device number: " dev_id - } - ;ToolTip - - this.DeviceID := dev_id - this.DeviceStatus := DeviceStatus - this.Reset() - this.DeviceReady := True - - return this - } - - __Delete() { - this.Relinquish() - } - - SetAxis(axis_val, usage) { - res := DllCall("vJoyInterface\SetAxis", "Int", axis_val, "UInt", this.DeviceID, "UInt", usage) - if (!res) { - MsgBox, SetAxis(%axis_val%`,%usage%) Error!`nErrorLevel:%ErrorLevel% - } - return res - } - - SetAxis_X(axis_val) { - Global HID_USAGE_X - new_val := parse_rel_val(axis_val, this.Axis_X, this.AxisMax_X) - res := this.SetAxis(new_val, HID_USAGE_X) - if (res) { - this.Axis_X := new_val - } - return res - } - SetAxis_Y(axis_val) { - Global HID_USAGE_Y - new_val := parse_rel_val(axis_val, this.Axis_Y, this.AxisMax_Y) - res := this.SetAxis(new_val, HID_USAGE_Y) - if (res) { - this.Axis_Y := new_val - } - return res - } - SetAxis_Z(axis_val) { - Global HID_USAGE_Z - new_val := parse_rel_val(axis_val, this.Axis_Z, this.AxisMax_Z) - res := this.SetAxis(new_val, HID_USAGE_Z) - if (res) { - this.Axis_Z := new_val - } - return res - } - SetAxis_RX(axis_val) { - Global HID_USAGE_RX - new_val := parse_rel_val(axis_val, this.Axis_RX, this.AxisMax_RX) - res := this.SetAxis(new_val, HID_USAGE_RX) - if (res) { - this.Axis_RX := new_val - } - return res - } - SetAxis_RY(axis_val) { - Global HID_USAGE_RY - new_val := parse_rel_val(axis_val, this.Axis_RY, this.AxisMax_RY) - res := this.SetAxis(new_val, HID_USAGE_RY) - if (res) { - this.Axis_RY := new_val - } - return res - } - SetAxis_RZ(axis_val) { - Global HID_USAGE_RZ - new_val := parse_rel_val(axis_val, this.Axis_RZ, this.AxisMax_RZ) - res := this.SetAxis(new_val, HID_USAGE_RZ) - if (res) { - this.Axis_RZ := new_val - } - return res - } - SetAxis_SL0(axis_val) { - Global HID_USAGE_SL0 - new_val := parse_rel_val(axis_val, this.Axis_SL0, this.AxisMax_SL0) - res := this.SetAxis(new_val, HID_USAGE_SL0) - if (res) { - this.Slider0 := new_val - } - return res - } - SetAxis_SL1(axis_val) { - Global HID_USAGE_SL1 - new_val := parse_rel_val(axis_val, this.Axis_SL1, this.AxisMax_SL1) - res := this.SetAxis(new_val, HID_USAGE_SL1) - if (res) { - this.Slider1 := new_val - } - return res - } - - GetBtn(bid) { - if (bid < 1 or bid > this.NumberOfButtons) { - return 0 - } - return this.Btn[bid] - } - - SetBtn(sw, btn_id) { - if (btn_id < 1 or btn_id > this.NumberOfButtons) { - MsgBox, SetBtn: range check error! - return 0 - } - res := DllCall("vJoyInterface\SetBtn", "Int", sw, "UInt", this.DeviceID, "UChar", btn_id) - if (res) { - this.Btn[btn_id] := sw - } - return res - } - - SetDiscPov(Value, nPov) { - _res := DllCall("vJoyInterface\SetDiscPov", "Int", Value, "UInt", this.DeviceID, "UChar", nPov) - if (!_res) { - MsgBox, SetDiscPov err: %ErrorLevel% - } else { - this.DiscPov[nPov] := Value - } - return _res - } - - SetContPov(Value, nPov) { - _res := DllCall("vJoyInterface\SetContPov", "Int", Value, "UInt", this.DeviceID, "UChar", nPov) - if (!_res) { - MsgBox, SetContPov err: %ErrorLevel% - } else { - this.ContPov[nPov] := Value - } - return _res - } - - Reset() { - ; Reset local state values - this.Axis_X := 0 - this.Axis_Y := 0 - this.Axis_Z := 0 - this.Axis_RX := 0 - this.Axis_RY := 0 - this.Axis_RZ := 0 - this.Slider0 := 0 - this.Slider1 := 0 - - for i in this.ContPov - this.ContPov[i] := 0 - for i in this.DiscPov - this.DiscPov[i] := 0 - for i in this.Btn - this.Btn[i] := 0 - return DllCall("vJoyInterface\ResetVJD", "UInt", this.DeviceID) - } - - Relinquish() { - return DllCall("vJoyInterface\RelinquishVJD", "UInt", this.DeviceID) - } -} - -VJoy_init(id := 1) { - Global VJDev, VJD_MAXDEV - if (id < 1 || id > VJD_MAXDEV) { - MsgBox, [%A_ThisFunc%] Device %id% is invalid. Please specify 1-%VJD_MAXDEV%. - return - } - VJDev[id] := new VJoyDev(id) - return VJDev[id] -} - - -VJoy_DeviceErr(id) { - Global VJD_MAXDEV, VJDev - if (id < 1 or id > VJD_MAXDEV) { - MsgBox, [%A_ThisFunc%] Device %id% is invalid. Please specify 1-%VJD_MAXDEV%. - return True - } - if (!VJDev[id].DeviceReady) { - MsgBox, [%A_ThisFunc%] Device %id% is not ready. - return True - } - return False -} -VJoy_Ready(id) { - Global VJD_MAXDEV, VJDev - if (id < 1 || id > VJD_MAXDEV) { - return False - } - return VJDev[id].DeviceReady -} - -VJoy_ResetVJD(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Reset() -} - -VJoy_ResetAll() { - return DllCall("vJoyInterface\ResetAll") -} - -; Release device -VJoy_RelinquishVJD(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Relinquish() -} - -; Acquire device - added by evilC -VJoy_AcquireVJD(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return DllCall("vJoyInterface\AcquireVJD", "UInt", id) -} - -; destructor -VJoy_Close() { - Global VJDev - - VJoy_ResetAll() - - for idx, dev in VJDev - dev.delete - if (hVJDLL) { - DLLCall("FreeLibraly", "Ptr", hVJDLL) - hVJDLL:= - } -} - -VJoy_GetContPovNumber(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].ContPovNumber -} - -VJoy_GetDiscPovNumber(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].DiscPovNumber -} - -VJoy_GetVJDButtonNumber(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].NumberOfButtons -} - -VJoy_GetAxisExist_X(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisExist_X -} -VJoy_GetAxisExist_Y(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisExist_Y -} -VJoy_GetAxisExist_Z(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisExist_Z -} -VJoy_GetAxisExist_RX(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisExist_RX -} -VJoy_GetAxisExist_RY(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisExist_RY -} -VJoy_GetAxisExist_RZ(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisExist_RZ -} -VJoy_GetAxisExist_SL0(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisExist_SL0 -} -VJoy_GetAxisExist_SL1(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisExist_SL1 -} - - -VJoy_GetAxisMax_X(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisMax_X -} -VJoy_GetAxisMax_Y(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisMax_Y -} -VJoy_GetAxisMax_Z(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisMax_Z -} -VJoy_GetAxisMax_RX(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisMax_RX -} -VJoy_GetAxisMax_RY(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisMax_RY -} -VJoy_GetAxisMax_RZ(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].AxisMax_RZ -} -VJoy_GetAxisMax_SL0(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Slider0_Max -} -VJoy_GetAxisMax_SL1(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Slider1_Max -} - -; for compatibility -VJoy_GetVJDAxisMax(id, usage) { - - Global VJDev, HID_USAGE_X,HID_USAGE_Y,HID_USAGE_Z,HID_USAGE_RX,HID_USAGE_RY,HID_USAGE_RZ,HID_USAGE_SL0,HID_USAGE_SL1 - if (VJoy_DeviceErr(id)) - return False - - return (usage = HID_USAGE_X) ? VJDev[id].AxisMax_X : - (usage = HID_USAGE_Y) ? VJDev[id].AxisMax_Y : - (usage = HID_USAGE_Z) ? VJDev[id].AxisMax_Z : - (usage = HID_USAGE_RX) ? VJDev[id].AxisMax_RX : - (usage = HID_USAGE_RY) ? VJDev[id].AxisMax_RY : - (usage = HID_USAGE_RZ) ? VJDev[id].AxisMax_RZ : - (usage = HID_USAGE_SL0) ? VJDev[id].AxisMax_Y : - VJDev[id].AxisMax_SL1 -} - -VJoy_GetVJDAxisExist(id, usage) { - - Global VJDev, HID_USAGE_X,HID_USAGE_Y,HID_USAGE_Z,HID_USAGE_RX,HID_USAGE_RY,HID_USAGE_RZ,HID_USAGE_SL0,HID_USAGE_SL1 - if (VJoy_DeviceErr(id)) - return False - - return (usage = HID_USAGE_X) ? VJDev[id].AxisExist_X : - (usage = HID_USAGE_Y) ? VJDev[id].AxisExist_Y : - (usage = HID_USAGE_Z) ? VJDev[id].AxisExist_Z : - (usage = HID_USAGE_RX) ? VJDev[id].AxisExist_RX : - (usage = HID_USAGE_RY) ? VJDev[id].AxisExist_RY : - (usage = HID_USAGE_RZ) ? VJDev[id].AxisExist_RZ : - (usage = HID_USAGE_SL0) ? VJDev[id].AxisExist_Y : - VJDev[id].AxisExist_SL1 -} - -VJoy_GetBtn(id, btn_id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].GetBtn(btn_id) -} - -VJoy_SetBtn(sw, id, btn_id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - res := VJDev[id].SetBtn(sw, btn_id) - if (!res) { - MsgBox, SetBtn(%sw%, %id%, %btn_id%) err: %ErrorLevel%`nnLastError: %A_LastError% - } - return res -} - -VJoy_GetAxis_X(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Axis_X -} -VJoy_GetAxis_Y(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Axis_Y -} -VJoy_GetAxis_Z(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Axis_Z -} -VJoy_GetAxis_RX(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Axis_RX -} -VJoy_GetAxis_RY(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Axis_RY -} -VJoy_GetAxis_RZ(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Axis_RZ -} -VJoy_GetAxis_SL0(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Slider0 -} -VJoy_GetAxis_SL1(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].Slider1 -} - -VJoy_SetAxis_X(axis_val, id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].SetAxis_X(axis_val) -} -VJoy_SetAxis_Y(axis_val, id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].SetAxis_Y(axis_val) -} -VJoy_SetAxis_Z(axis_val, id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].SetAxis_Z(axis_val) -} -VJoy_SetAxis_RX(axis_val, id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].SetAxis_RX(axis_val) -} -VJoy_SetAxis_RY(axis_val, id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].SetAxis_RY(axis_val) -} -VJoy_SetAxis_RZ(axis_val, id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].SetAxis_RZ(axis_val) -} -VJoy_SetAxis_SL0(axis_val, id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].SetAxis_SL0(axis_val) -} -VJoy_SetAxis_SL1(axis_val, id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].SetAxis_SL1(axis_val) -} - -; for compatibility -VJoy_SetAxis(axis_val, id, usage) { - Global VJDev, HID_USAGE_X,HID_USAGE_Y,HID_USAGE_Z,HID_USAGE_RX,HID_USAGE_RY,HID_USAGE_RZ,HID_USAGE_SL0,HID_USAGE_SL1 - if (VJoy_DeviceErr(id)) - return False - - if (usage == HID_USAGE_X){ - return VJDev[id].SetAxis_X(axis_val) - } else if (usage == HID_USAGE_Y){ - return VJDev[id].SetAxis_Y(axis_val) - } else if (usage == HID_USAGE_Z){ - return VJDev[id].SetAxis_Z(axis_val) - } else if (usage == HID_USAGE_RX){ - return VJDev[id].SetAxis_RX(axis_val) - } else if (usage == HID_USAGE_RY){ - return VJDev[id].SetAxis_RY(axis_val) - } else if (usage == HID_USAGE_RZ){ - return VJDev[id].SetAxis_RZ(axis_val) - } else if (usage == HID_USAGE_SL0){ - return VJDev[id].SetAxis_SL0(axis_val) - } else if (usage == HID_USAGE_SL1){ - return VJDev[id].SetAxis_SL1(axis_val) - } else { - MsgBox, Unknown Axis: %usage% - } -} - -VJoy_GetDiscPov(id, nPov) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].DiscPov[nPov] -} -VJoy_SetDiscPov(Value, id, nPov) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].SetDiscPov(Value, nPov) -} - -VJoy_GetContPov(id, nPov) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].ContPov[nPov] -} -VJoy_SetContPov(Value, id, nPov) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - return VJDev[id].SetContPov(Value, nPov) -} - -; for debug: dump value of structure -VJoy_Dump(id) { - Global VJDev - if (VJoy_DeviceErr(id)) - return False - - num := VJoy_GetVJDButtonNumber(id) - for idx, btn in VJDev[id].Btn - { - if (idx<10) - buf1 .= "_" - buf1 .= idx . "|" - buf2 .= "_" . btn . "|" - } - str_btn = Button(%num%):`n %buf1%`n %buf2%`n - - if (VJoy_GetAxisMax_X(id)) { - str_btn .= "Axis_X: " . VJoy_GetAxis_X(id) . "`n" - } - if (VJoy_GetAxisMax_Y(id)) { - str_btn .= "Axis_Y: " . VJoy_GetAxis_Y(id) . "`n" - } - if (VJoy_GetAxisMax_Z(id)) { - str_btn .= "Axis_Z: " . VJoy_GetAxis_Z(id) . "`n" - } - if (VJoy_GetAxisMax_RX(id)) { - str_btn .= "Axis_RX: " . VJoy_GetAxis_RX(id) . "`n" - } - if (VJoy_GetAxisMax_RY(id)) { - str_btn .= "Axis_RY: " . VJoy_GetAxis_RY(id) . "`n" - } - if (VJoy_GetAxisMax_RZ(id)) { - str_btn .= "Axis_RZ: " . VJoy_GetAxis_RZ(id) . "`n" - } - if (VJoy_GetAxisMax_SL0(id)) { - str_btn .= "Axis_SL0: " . VJoy_GetAxis_SL0(id) . "`n" - } - if (VJoy_GetAxisMax_SL1(id)) { - str_btn .= "Axis_SL1: " . VJoy_GetAxis_SL1(id) . "`n" - } - - num := VJoy_GetContPovNumber(id) - if (num) { - for idx, btn in VJDev[id].ContPov - { - Loop, % (StrLen(btn) - 1) - buf3 .= "_" - buf3 .= idx . "|" - buf4 .= btn . "|" - } - str_cont = ContPov(%num%):`n %buf3%`n %buf4%`n - } else { - str_cont = No Continuous Button.`n - } - str_btn .= str_cont - - num := VJoy_GetDiscPovNumber(id) - if (num) { - for idx, btn in VJDev[id].DiscPov - { - Loop, % (StrLen(btn) - 1) - buf5 .= "_" - buf5 .= idx . "|" - buf6 .= btn . "|" - } - str_Disc = DiscPov(%num%):`n %buf5%`n %buf6%`n - } else { - str_Disc = No Discrete Button.`n - } - str_btn .= str_Disc - ToolTip, %str_btn% -} - -parse_rel_val(invar, curval, max) { - if (InStr(invar, "+")) { - StringReplace, _buffer, invar, + - res := curval + _buffer - if (res > max) - return max - return res - } else if (InStr(invar, "-")) { - StringReplace, _buffer, invar, - - res := curval - _buffer - if (res < 0) - return 0 - return res - } - return invar -} \ No newline at end of file diff --git a/joystick/joy_info.ahk b/joystick/joy_info.ahk deleted file mode 100644 index 1c43fa2..0000000 --- a/joystick/joy_info.ahk +++ /dev/null @@ -1,84 +0,0 @@ -; none of this is written by genmce - just lifted from ahk forum -; I think Chris wrote it - good for joystick info. - -; July 6, 2005: Added auto-detection of joystick number. -; May 8, 2005 : Fixed: JoyAxes is no longer queried as a means of -; detecting whether the joystick is connected. Some joysticks are -; gamepads and don't have even a single axis. - -; If you want to unconditionally use a specific joystick number, change -; the following value from 0 to the number of the joystick (1-16). -; A value of 0 causes the joystick number to be auto-detected: -JoystickNumber = 2 - -; END OF CONFIG SECTION. Do not make changes below this point unless -; you wish to alter the basic functionality of the script. - -; Auto-detect the joystick number if called for: -if JoystickNumber <= 0 -{ - Loop 16 ; Query each joystick number to find out which ones exist. - { - GetKeyState, JoyName, %A_Index%JoyName - if JoyName <> - { - JoystickNumber = %A_Index% - break - } - } - if JoystickNumber <= 0 - { - MsgBox The system does not appear to have any joysticks. - ExitApp - } -} - -#SingleInstance -SetFormat, float, 03 ; Omit decimal point from axis position percentages. -GetKeyState, joy_buttons, %JoystickNumber%JoyButtons -GetKeyState, joy_name, %JoystickNumber%JoyName -GetKeyState, joy_info, %JoystickNumber%JoyInfo -Loop -{ - buttons_down = - Loop, %joy_buttons% - { - GetKeyState, joy%a_index%, %JoystickNumber%joy%a_index% - if joy%a_index% = D - buttons_down = %buttons_down%%a_space%%a_index% - } - GetKeyState, joyx, %JoystickNumber%JoyX - axis_info = X%joyx% - GetKeyState, joyy, %JoystickNumber%JoyY - axis_info = %axis_info%%a_space%%a_space%Y%joyy% - IfInString, joy_info, Z - { - GetKeyState, joyz, %JoystickNumber%JoyZ - axis_info = %axis_info%%a_space%%a_space%Z%joyz% - } - IfInString, joy_info, R - { - GetKeyState, joyr, %JoystickNumber%JoyR - axis_info = %axis_info%%a_space%%a_space%R%joyr% - } - IfInString, joy_info, U - { - GetKeyState, joyu, %JoystickNumber%JoyU - axis_info = %axis_info%%a_space%%a_space%U%joyu% - } - IfInString, joy_info, V - { - GetKeyState, joyv, %JoystickNumber%JoyV - axis_info = %axis_info%%a_space%%a_space%V%joyv% - } - IfInString, joy_info, P - { - GetKeyState, joyp, %JoystickNumber%JoyPOV - axis_info = %axis_info%%a_space%%a_space%POV%joyp% - } - ToolTip, %joy_name% (#%JoystickNumber%):`n%axis_info%`nButtons Down: %buttons_down%`n`n(right-click the tray icon to exit) - Sleep, 100 -} -return - -esc::ExitApp diff --git a/midi_to_joy_1io.ini b/midi_to_joy_1io.ini deleted file mode 100644 index e69de29..0000000 diff --git a/vJoyInterface.dll b/vJoyInterface.dll deleted file mode 100644 index e93a41b83f0b89d1b8653a578db028abbde93293..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19456 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 Q=6BC`8u(5F|A7Yn8)CUiumAu6 diff --git a/x64/vJoyInterface.dll b/x64/vJoyInterface.dll deleted file mode 100644 index e93a41b83f0b89d1b8653a578db028abbde93293..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19456 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