How to 'SendKeys' in C# script

Michael_H wrote on 5/9/2016, 12:28 AM
I found a number of old posts that described using the Windows Script Host (WSH) to send keystrokes after your script had finished running, but this method seems to no longer work.

Is there a way to send keystrokes back to the current Vegas window after a script has completed?

In brief, my script splits an event (and associated audio event) at the cursor (regardless of whether the event at the cursor is selected. The TrackEvent.Split() method doesn't work for me as it leaves both of the events on either side of the cursor grouped. My script copies the event at the cursor then does some AdjustStartLength() and ActiveTake.Offset to get the same result as the split. However, the event on the right of the cursor (the new copy) is not grouped with the corresponding audio event. I therefore leave both of them selected and would like to send a 'g' keystroke to group them. I'm having to remember to do that manually which is obviously not preferred.

Thanks for your help.
Michael

Comments

wwaag wrote on 5/11/2016, 9:56 PM
Is there a way to send keystrokes back to the current Vegas window after a script has completed?

You can probably use SendKeys as part of your script, but once a script has exited, there is no way.

Regardless, if want to group your events, you should probably do so within your script., not afterward. From your description, I'm not sure exactly what you want to do but perhaps this script could be of use to you. It's not mine, but one that I've used for grouping trackevents on the timeline. It shows the basics of how to create groups for events on two tracks, which isn't all that clear from the SDK, Good luck.

wwaag

/**
* Group Track1 and Track2 Events
* Ce script groupe les Events des deux premières pistes
* Auteur Gilles Pialat 09/01/2008
* http://www.cameravideo.net/forum/sony-vegas-dvd-architect/
**/

using System;
using Sony.Vegas;

class EntryPoint
{
public void FromVegas(Vegas vegas)
{
for (int i=0; i< vegas.Project.Tracks[0].Events.Count; i++)
{
TrackEventGroup group = new TrackEventGroup();;
vegas.Project.Groups.Add(group);
group.Add(vegas.Project.Tracks[0].Events[i]);
group.Add(vegas.Project.Tracks[1].Events[i]);

}

}

}

AKA the HappyOtter at https://tools4vegas.com/. System 1: Intel i7-8700k with HD 630 graphics plus an Nvidia RTX4070 graphics card. System 2: Intel i7-3770k with HD 4000 graphics plus an AMD RX550 graphics card. System 3: Laptop. Dell Inspiron Plus 16. Intel i7-11800H, Intel Graphics. Current cameras include Panasonic FZ2500, GoPro Hero11 and Hero8 Black plus a myriad of smartPhone, pocket cameras, video cameras and film cameras going back to the original Nikon S.

Michael_H wrote on 5/16/2016, 12:44 PM
Thanks so much, that's exactly what I was looking for! Sendkeys was just a work around that I saw in some old posts as I didn't realize there was an Add method for TrackEventGroup or vegas.Project.Groups (it's not indicated in the SDK).

Much appreciated.

Michael
Michael_H wrote on 5/16/2016, 1:39 PM
Here's the script that I was working on. It's my first so I know there are better ways to accomplish what I've done, but with works for my needs. I'm putting here in part because I couldn't find much like this so I hope someone finds it of use. There are two scripts, the first splits the event at the cursor (whether it's selected or not), and the second splits then does various manipulation to the event on the left of the split.


/**
* This script recreates the 'S' split keyboard command, but splits at the cursor
* whether the event is selected or not. I assign it to the 'Alt+S' key.
* This is my first script so may not be the most efficient. It's cobbled together
* from various examples in forum posts, so thanks to all those authors.

* The advantage of this script over the TrackEvent.Split() method is that the video and audio
* events on either side of the split are grouped separately (left vid and aud is a group and right vid
* and aud are a different group), as opposed to grouping all four events.

* Note that I've only tested this in the case of one video track and one audio track.
**/

using System;
using Sony.Vegas;

public class EntryPoint
{
public void FromVegas(Vegas vegas)
{
var cursorPosition = vegas.Transport.CursorPosition;

TrackEventGroup group = new TrackEventGroup();
vegas.Project.Groups.Add(group);
foreach (Track track in vegas.Project.Tracks)
{
if (track.IsVideo() && track.Selected)
{
foreach (VideoEvent videoEvent in track.Events)
{
if (videoEvent.Selected)
{
videoEvent.Selected = false;
}
var dStart = videoEvent.Start;
var dLength = videoEvent.Length;
if ( (cursorPosition >= dStart) && ( cursorPosition < (dLength + dStart) ) )
{
TrackEvent SEvent = videoEvent.Copy(track, cursorPosition);
videoEvent.AdjustStartLength(dStart, cursorPosition - dStart, false);
SEvent.AdjustStartLength(cursorPosition, dLength - ( cursorPosition - dStart ), false);
SEvent.ActiveTake.Offset = (SEvent.ActiveTake.Offset + cursorPosition - dStart);
group.Add(SEvent);
SEvent.Selected = true;
break;
}
}
}

if (track.IsAudio())
{
foreach (AudioEvent audioEvent in track.Events)
{
var dStart = audioEvent.Start;
var dLength = audioEvent.Length;
if ( (cursorPosition >= dStart) && ( cursorPosition < (dLength + dStart) ) )
{
TrackEvent SEvent = audioEvent.Copy(track, cursorPosition);
audioEvent.AdjustStartLength(dStart, cursorPosition - dStart, false);
SEvent.AdjustStartLength(cursorPosition, dLength - ( cursorPosition - dStart ), false);
SEvent.ActiveTake.Offset = (SEvent.ActiveTake.Offset + cursorPosition - dStart);
group.Add(SEvent);
break;
}
}
}
}
}
}


Here's the second script. It currently only works if there is only one event to the right of the cursor. Working on fixing this and will post once fixed.


/**
* This script splits the event at the cursor (as in the code above) then does various
* edits on the event on the left of the split. I assign it to the 'Ctrl + Alt + S' key.
* 'Alt + S' (code above) splits the start of the event I want to edit, and 'Ctrl + Alt + S'
* marks the end of the event then edits it. This is my first script so there's I'm sure there's better
* ways to do this... but it works for my needs.

* This is used to slow down a specific point in the event (ie. slow motion focus on a specific action such as a punch or kick)
* Event is slowed by adjusting the playback rate, event length is increased (lengthMultiplyer), Velocity envelope is
* added with several envelope points, audio is also adjusted, but is not slowed as much in order to avoid distortion.


* Note that I've only tested this in the case of one video track and one audio track.
**/

using System;
using Sony.Vegas;

public class EntryPoint
{
public void FromVegas(Vegas vegas)
{
var cursorPosition = vegas.Transport.CursorPosition;
TrackEvent myEvent = null;

//Multiplyer to increase the lentth of the event
double lengthMultiplyer = 2.5;

//Group the video and audio events on the right of the split
TrackEventGroup group = new TrackEventGroup();
vegas.Project.Groups.Add(group);

foreach (Track track in vegas.Project.Tracks)
{
if (track.IsVideo() && track.Selected)
{
bool shiftEvent = false;
bool skipShift = false;
Timecode startTC = Timecode.FromMilliseconds(0);

foreach (VideoEvent videoEvent in track.Events)
{
if (videoEvent.Selected)
{
videoEvent.Selected = false;
}
var dStart = videoEvent.Start;
var dLength = videoEvent.Length;
if (shiftEvent) //ripple all events after the videoEvent event
{
if (skipShift)
{
skipShift = false;
videoEvent.Selected = true;
break;
}
videoEvent.AdjustStartLength(startTC, videoEvent.Length, true);
startTC = videoEvent.End;
}
if ( (cursorPosition >= dStart) && ( cursorPosition < (dLength + dStart) ) )
{
//split at cursor by making copy and adjusting start and lengh
TrackEvent SEvent = videoEvent.Copy(track, cursorPosition);
videoEvent.AdjustStartLength(dStart, cursorPosition - dStart, false);
videoEvent.Selected = false;

//adjust playback rate, start and length
videoEvent.AdjustPlaybackRate( 0.25, true);
double vidLength = videoEvent.Length.ToMilliseconds() * lengthMultiplyer;
Timecode vidTC = Quantize(Timecode.FromMilliseconds(vidLength));
videoEvent.AdjustStartLength(dStart, vidTC, true);

//select event and centre on timeline
vegas.Transport.SelectionStart = videoEvent.Start;
vegas.Transport.SelectionLength = videoEvent.Length;
vegas.Transport.ViewCursor(true);

SEvent.AdjustStartLength(dStart + vidTC, dLength - ( cursorPosition - dStart ), false);
SEvent.ActiveTake.Offset = SEvent.ActiveTake.Offset + cursorPosition - dStart;// + videoEvent.Length;

//create envelope and add points
Envelope velEnv = new Envelope(EnvelopeType.Velocity);
videoEvent.Envelopes.Add(velEnv);

//First number (ie. 0.06), is relative position of point from 0 to 1, second (ie. 0.95) is height relative to the Max from 0 to 1
//Change to velEnv.Min to to get negative.
EnvelopePoint envPoint = new EnvelopePoint(Timecode.FromMilliseconds(0.06 * videoEvent.Length.ToMilliseconds()),0.95 *velEnv.Max);
velEnv.Points.Add(envPoint);

EnvelopePoint envPoint1 = new EnvelopePoint(Timecode.FromMilliseconds(0.2 * videoEvent.Length.ToMilliseconds()),0.95 *velEnv.Max);
velEnv.Points.Add(envPoint1);

EnvelopePoint envPoint2 = new EnvelopePoint(Timecode.FromMilliseconds(0.28 * videoEvent.Length.ToMilliseconds()),0.03 *velEnv.Max);
velEnv.Points.Add(envPoint2);

EnvelopePoint envPoint3 = new EnvelopePoint(Timecode.FromMilliseconds(0.45 * videoEvent.Length.ToMilliseconds()),0.04 *velEnv.Max);
velEnv.Points.Add(envPoint3);

EnvelopePoint envPoint4 = new EnvelopePoint(Timecode.FromMilliseconds(0.55 * videoEvent.Length.ToMilliseconds()),0.07 *velEnv.Max);
velEnv.Points.Add(envPoint4);

EnvelopePoint envPoint5 = new EnvelopePoint(Timecode.FromMilliseconds(0.7 * videoEvent.Length.ToMilliseconds()),0.75 *velEnv.Max);
velEnv.Points.Add(envPoint5);

EnvelopePoint envPoint6 = new EnvelopePoint(Timecode.FromMilliseconds(1 * videoEvent.Length.ToMilliseconds()),1 *velEnv.Max);
velEnv.Points.Add(envPoint6);

SEvent.Selected = true;
group.Add(SEvent);
shiftEvent = true;
skipShift = true;
startTC = dStart + vidTC + SEvent.Length;
}
}
}
if (track.IsAudio())
{
bool shiftEvent = false;
bool skipShift = false;
Timecode startTC = Timecode.FromMilliseconds(0);

foreach (AudioEvent audioEvent in track.Events)
{
var dStart = audioEvent.Start;
var dLength = audioEvent.Length;
if (shiftEvent)
{
if (skipShift)
{
skipShift = false;
break;
}
audioEvent.AdjustStartLength(startTC, audioEvent.Length, true);
startTC = audioEvent.End;
}
if ( (cursorPosition >= dStart) && ( cursorPosition < (dLength + dStart) ) )
{
TrackEvent SEvent = audioEvent.Copy(track, cursorPosition);
audioEvent.AdjustStartLength(dStart, cursorPosition - dStart, false);

//Set playback rate to 0.25 if you want to match Video. Using a large number here reduces the distorion of the sound.
audioEvent.AdjustPlaybackRate(.6, true);
double audLength = audioEvent.Length.ToMilliseconds() * lengthMultiplyer;
Timecode audTC = Quantize(Timecode.FromMilliseconds(audLength));
audioEvent.AdjustStartLength(audioEvent.Start, audTC, true);

//Adjust the integer (30) as well as the sign to shif the offset of the audio relative to the video
audioEvent.ActiveTake.Offset = audioEvent.ActiveTake.Offset - Quantize(Timecode.FromMilliseconds(audLength / 30));

SEvent.AdjustStartLength(dStart + audTC, dLength - ( cursorPosition - dStart ), false);
SEvent.ActiveTake.Offset = SEvent.ActiveTake.Offset + cursorPosition - dStart;// + audioEvent.Length;
audioEvent.Selected = false;
group.Add(SEvent);
shiftEvent = true;
skipShift = true;
startTC = dStart + audTC + SEvent.Length;
}
}
}
}
}

// Round the timecode value to the nearest frame
// Returns the quantized timecode value
Timecode Quantize ( Timecode timecode )
{
Timecode tcPos1 = Timecode.FromFrames(timecode.FrameCount);
Timecode tcPos2 = Timecode.FromFrames(timecode.FrameCount + 1);

long nanoMid = tcPos1.Nanos + Convert.ToInt64((tcPos2.Nanos - tcPos1.Nanos) / 2);

return (timecode.Nanos < nanoMid ) ? tcPos1 : tcPos2;
}
}



Michael
NickHope wrote on 9/12/2016, 8:02 AM

Michael, the first of your two scripts doesn't run for me. I changed "var" in 5 places to "Timecode", saved it as Split.cs, and now it does. It's a useful script which I will probably set to "S" on my keyboard to replace the regular "Split" command. Here it is with those changes and without the double spacing (which I think happened when the old Sony forum data was migrated):

/**
 * This script recreates the 'S' split keyboard command, but splits at the cursor
 * whether the event is selected or not.  I assign it to the 'Alt+S' key.
 * This is my first script so may not be the most efficient.  It's cobbled together
 * from various examples in forum posts, so thanks to all those authors.

 * The advantage of this script over the TrackEvent.Split() method is that the video and audio
 * events on either side of the split are grouped separately (left vid and aud is a group and right vid
 * and aud are a different group), as opposed to grouping all four events.

 * Note that I've only tested this in the case of one video track and one audio track.
 **/

using System;
using Sony.Vegas;

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
	Timecode cursorPosition = vegas.Transport.CursorPosition;

	TrackEventGroup group = new TrackEventGroup();
	vegas.Project.Groups.Add(group);
        foreach (Track track in vegas.Project.Tracks)
        {
            if (track.IsVideo() && track.Selected)
            {
                foreach (VideoEvent videoEvent in track.Events)
                {
                    if (videoEvent.Selected)
                    {
			videoEvent.Selected = false;
                    }
			Timecode dStart = videoEvent.Start;
			Timecode dLength = videoEvent.Length;	
			if ( (cursorPosition >= dStart) && ( cursorPosition < (dLength + dStart) ) )
			{
				TrackEvent SEvent = videoEvent.Copy(track, cursorPosition);
				videoEvent.AdjustStartLength(dStart, cursorPosition - dStart, false);
				SEvent.AdjustStartLength(cursorPosition, dLength - ( cursorPosition - dStart ), false);
				SEvent.ActiveTake.Offset = (SEvent.ActiveTake.Offset + cursorPosition - dStart);
				group.Add(SEvent);
				SEvent.Selected = true;
				break;
			}
                }
	    }

            if (track.IsAudio())
            {
                foreach (AudioEvent audioEvent in track.Events)
                {
			Timecode dStart = audioEvent.Start;
			Timecode dLength = audioEvent.Length;	
			if ( (cursorPosition >= dStart) && ( cursorPosition < (dLength + dStart) ) )
			{
				TrackEvent SEvent = audioEvent.Copy(track, cursorPosition);
				audioEvent.AdjustStartLength(dStart, cursorPosition - dStart, false);
				SEvent.AdjustStartLength(cursorPosition, dLength - ( cursorPosition - dStart ), false);
				SEvent.ActiveTake.Offset = (SEvent.ActiveTake.Offset + cursorPosition - dStart);
				group.Add(SEvent);
				break;
			}
                }
            }
        }
    }
}

 

jetdv wrote on 9/12/2016, 1:48 PM

I would use the "Split" command instead of copying the event and adjusting all of the lengths.

 

//Split the event
TrackEvent SEvnt = evnt.Split(NewLength);
 

 

So you could replace all of this

TrackEvent SEvent = videoEvent.Copy(track, cursorPosition);

videoEvent.AdjustStartLength(dStart, cursorPosition - dStart, false);

SEvent.AdjustStartLength(cursorPosition, dLength - ( cursorPosition - dStart ), false);

SEvent.ActiveTake.Offset = (SEvent.ActiveTake.Offset + cursorPosition - dStart);

 

with

TrackEvent SEvent = videoEvent.Split(cursorPosition - dStart);

NickHope wrote on 9/12/2016, 11:10 PM

Thanks jetdv. That's definitely simpler.

However there is still a problem with splitting audio with this script. For example if one has a video/audio group on the top 2 tracks, and a selected audio-only event on a selected lower track, this script will split the grouped audio event as well as the audio-only event. I'm sure that can be fixed with some work, however I'm now using the Split command in SeMW Extensions instead as I have that installed anyway and it works correctly.