My goal is to make a open source YouTube player that can be controlled via global media keys.
The global key issue I got it covered but the communication between the YouTube player and my Windows Forms application just doesn't work for some reason.
So far this is what I have:
private AxShockwaveFlashObjects.AxShockwaveFlash player;
player.movie = "http://youtube.googleapis.com/v/9bZkp7q19f0"
...
private void playBtn_Click(object sender, EventArgs e)
{
player.CallFunction("<invoke name=\"playVideo\" returntype=\"xml\"></invoke>");
}
Unfortunately this returns:
"Error HRESULT E_FAIL has been returned from a call to a COM component."
What am I missing? Should I load a different URL?
The documentation states that YouTube player uses ExternalInterface class to control it from JavaScript or AS3 so it should work with c#.
UPDATED:
Method used to embed the player: http://www.youtube.com/watch?v=kg-z8JfOIKw
Also tried to use the JavaScript-API in the WebBrowser control but no luck (player just didn't respond to JavaScript commands, tried even to set WebBrowser.url to a working demo, all that I succeeded is to get the onYouTubePlayerReady() to fire using the simple embedded object version )
I think there might be some security issues that I'm overseeing, don't know.
UPDATE 2:
fond solution, see my answer below.
It sounds like your trying to use Adobe Flash as your interface; then pass certain variables back into C#.
An example would be this:
In Flash; create a button... Actionscript:
on (press) {
fscommand("Yo","dude");
}
Then Visual Studio you just need to add the COM object reference: Shockwave Flash Object
Then set the embed to true;
Then inside Visual Studio you should be able to go to Properties; find fscommand. The fscommand will allow you to physically connect the value from the Flash movie.
AxShockwaveFlashObjects._IShockwaveFlashEvents_FSCommandEvent
That collects; then just use e.command and e.arg for example to have the collected item do something.
Then add this to the EventHandler;
lbl_Result.Text="The "+e.args.ToString()+" "+e.command.ToString()+" was clicked";
And boom it's transmitting it's data from Flash into Visual Studio. No need for any crazy difficult sockets.
On a side note; if you have Flash inside Visual Studio the key is to ensure it's "embed is set to true." That will hold all the path references within the Flash Object; to avoid any miscalling to incorrect paths.
I'm not sure if that is the answer your seeking; or answers your question. But without more details on your goal / error. I can't assist you.
Hope this helps. The first portion should actually show you the best way to embed your Shockwave into Visual Studio.
Make sure you add the correct reference:
Inside your project open 'Solution Explorer'
Right-Click to 'Add Reference'
Go to 'COM Object'
Find Proper object;
COM Objects:
Shockwave ActiveX
Flash Accessibility
Flash Broker
Shockwave Flash
Hope that helps.
It sounds like you aren't embedding it correctly; so you can make the call to it. If I'm slightly mistaken; or is this what you meant:
If your having difficulty Ryk had a post awhile back; with a method to embed YouTube videos:
<% MyYoutubeUtils.ShowEmebddedVideo("<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/gtNlQodFMi8&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/gtNlQodFMi8&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object>") %>
Or...
public static string ShowEmbeddedVideo(string youtubeObject)
{
var xdoc = XDocument.Parse(youtubeObject);
var returnObject = string.Format("<object type=\"{0}\" data=\{1}\"><param name=\"movie\" value=\"{1}\" />",
xdoc.Root.Element("embed").Attribute("type").Value,
xdoc.Root.Element("embed").Attribute("src").Value);
return returnObject;
}
Which you can find the thread here: https://stackoverflow.com/questions/2547101/purify-embedding-youtube-videos-method-in-c-sharp
I do apologize if my post appears fragmented; but I couldn't tell if it was the reference, the variable, the method, or embed that was causing you difficulties. Truly hope this helps; or give me more details and I'll tweak my response accordingly.
C# to ActionScript Communication:
import flash.external.ExternalInterface;
ExternalInterface.addCallback("loadAndPlayVideo", null, loadAndPlayVideo);
function loadAndPlayVideo(uri:String):void
{
videoPlayer.contentPath = uri;
}
Then in C#; add an instance of the ActiveX control and add the content into a Constructor.
private AxShockwaveFlash flashPlayer;
public FLVPlayer ()
{
// Add Error Handling; to condense I left out.
flashPlayer.LoadMovie(0, Application.StartupPath + "\\player.swf");
}
fileDialog = new OpenFileDialog();
fileDialog.Filter = "*.flv|*.flv";
fileDialog.Title = "Select a Flash Video File...";
fileDialog.Multiselect = false;
fileDialog.RestoreDirectory = true;
if (fileDialog.ShowDialog() == DialogResult.OK)
{
flashPlayer.CallFunction("<invoke" + " name=\"loadAndPlayVideo\" returntype=\"xml"> <arguements><string>" + fileDialog.FileName + "</string></arguements></invoke>");
}
ActionScript Communication to C#:
import flash.external.ExternalInterface;
ExternalInterface.call("ResizePlayer", videoPlayer.metadata.width, videoPlayer.metadata.height);
flashPlayer.FlashCall += new _IShockwaveFlashEvents_FlashCallEventHandler(flashPlayer_FlashCall);
Then the XML should appear:
<invoke name="ResizePlayer" returntype="xml">
<arguements>
<number> 320 </number>
<number> 240 </number>
</arguments>
</invoke>
Then parse the XML in the event handler and invoke the C# function locally.
XmlDocument document = new XmlDocument();
document.LoadXML(e.request);
XmlNodeList list = document.GetElementsByTagName("arguements");
ResizePlayer(Convert.ToInt32(list[0].FirstChild.InnerText), Convert.ToInt32(list[0].ChildNodes[1].InnerText));
Now they are both passing data back and forth. That is a basic example; but by utilizing the ActionScript Communication you shouldn't have any issues utilizing the native API.
Hope that is more helpful. You can expand on that idea by a utility class for reuse. Obviously the above code has some limitations; but hopefully it points you in the right direction. Was that direction you were attempting to go? Or did I still miss the point?
Create a new Flash Movie; in ActionScript 3. Then on the initial first frame; apply the below:
Security.allowDomain("www.youtube.com");
var my_player:Object;
var my_loader:Loader = new Loader();
my_loader.load(new URLRequest("http://www.youtube.com/apiplayer?version=3"))
my_loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);
function onLoaderInit(e:Event):void{
addChild(my_loader);
my_player = my_loader.content;
my_player.addEventListener("onReady", onPlayerReady);
}
function onPlayerReady(e:Event):void{
my_player.setSize(640,360);
my_player.loadVideoById("_OBlgSz8sSM",0);
}
So what exactly is that script doing? It is utilizing the native API and using ActionScript Communication. So below I'll break down each line.
Security.allowDomain("www.youtube.com");
Without that line YouTube won't interact with the object.
var my_player:Object;
You can't just load a movie into the movie; so we will create a variable Object. You have to load a special .swf that will contain access to those codes. The below; does just that. So you can access the API.
var my_loader:Loader = new Loader();
my_loader.load(new URLRequest("http://www.youtube.com/apiplayer?version=3"));
We now reference the Google API per their documentation.
my_loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);
But in order to actually work with our object; we need to wait for it to be fully initialized. So the Event Listener will wait; so we know when we can pass commands to it.
The onLoaderInit function will be triggered upon initialization. Then it's first task will be my_loader to display the list so that the video appears.
The addChild(my_loader); is what will load one; the my_player = my_loader.content; will store a reference for easy access to the object.
Though it has been initialized; you have to wait even further... You use my_player.addEventListener("onReady", onPlayerReady); to wait and listen for those custom events. Which will allow a later function to handle.
Now the player is ready for basic configuration;
function onPlayerReady(e:Event):void{
my_player.setSize(640,360);
}
The above function starts very basic manipulation. Then the last line my_player.loadVideoById("_OBlgSz8sSM",0); is referencing the particular video.
Then on your stage; you could create two buttons and apply:
play_btn.addEventListener(MouseEvent.CLICK, playVid);
function playVid(e:MouseEvent):void {
my_player.playVideo();
}
pause_btn.addEventListener(MouseEvent.CLICK, pauseVid);
function pauseVid(e:MouseEvent):void {
my_player.pauseVideo();
}
Which would give you a play and pause functionality. Some additional items you could use our:
loadVideoById()
cueVideoById()
playVideo()
pauseVideo()
stopVideo()
mute()
unMute()
Keep in mind those can't be used or called until it has been fully initialized. But using that; with the earlier method should allow you to layout the goal and actually pass variables between the two for manipulation.
Hopefully that helps.
I'd start by making sure that javascript can talk to your flash app.
make sure you have: allowScriptAccess="sameDomain" set in the embed (from http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html#includeExamplesSummary).
you should validate that html->flash works; then C->html; and gradually work up to C->you-tube-component. you have a lot of potential points of failure between C and the you-tube-component right now and it's hard to address all of them at the same time.
After a lot of tries and head-hammering, I've found a solution:
Seems that the Error HRESULT E_FAIL... happens when the flash dosen't understand the requested flash call. Also for the youtube external api to work, the js api needs to be enabled:
player.movie = "http://www.youtube.com/v/VIDEO_ID?version=3&enablejsapi=1"
As I said in the question the whole program is open source, so you will find the full code at bitbucket. Any advice, suggestions or collaborators are highly appreciated.
The complete solution:
Here is the complete guide for embedding and interacting with the YouTube player or any other flash object.
After following the video tutorial
, set the flash player's FlashCall event to the function that will handle the flash->c# interaction (in my example it's YTplayer_FlashCall )
the generated `InitializeComponent()` should be:
...
this.YTplayer = new AxShockwaveFlashObjects.AxShockwaveFlash();
this.YTplayer.Name = "YTplayer";
this.YTplayer.Enabled = true;
this.YTplayer.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("YTplayer.OcxState")));
this.YTplayer.FlashCall += new AxShockwaveFlashObjects._IShockwaveFlashEvents_FlashCallEventHandler(this.YTplayer_FlashCall);
...
the FlashCall event handler
private void YTplayer_FlashCall(object sender, AxShockwaveFlashObjects._IShockwaveFlashEvents_FlashCallEvent e)
{
Console.Write("YTplayer_FlashCall: raw: "+e.request.ToString()+"\r\n");
// message is in xml format so we need to parse it
XmlDocument document = new XmlDocument();
document.LoadXml(e.request);
// get attributes to see which command flash is trying to call
XmlAttributeCollection attributes = document.FirstChild.Attributes;
String command = attributes.Item(0).InnerText;
// get parameters
XmlNodeList list = document.GetElementsByTagName("arguments");
List<string> listS = new List<string>();
foreach (XmlNode l in list){
listS.Add(l.InnerText);
}
Console.Write("YTplayer_FlashCall: \"" + command.ToString() + "(" + string.Join(",", listS) + ")\r\n");
// Interpret command
switch (command)
{
case "onYouTubePlayerReady": YTready(listS[0]); break;
case "YTStateChange": YTStateChange(listS[0]); break;
case "YTError": YTStateError(listS[0]); break;
default: Console.Write("YTplayer_FlashCall: (unknownCommand)\r\n"); break;
}
}
this will resolve the flash->c# communication
calling the flash external functions (c#->flash):
private string YTplayer_CallFlash(string ytFunction){
string flashXMLrequest = "";
string response="";
string flashFunction="";
List<string> flashFunctionArgs = new List<string>();
Regex func2xml = new Regex(#"([a-z][a-z0-9]*)(\(([^)]*)\))?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
Match fmatch = func2xml.Match(ytFunction);
if(fmatch.Captures.Count != 1){
Console.Write("bad function request string");
return "";
}
flashFunction=fmatch.Groups[1].Value.ToString();
flashXMLrequest = "<invoke name=\"" + flashFunction + "\" returntype=\"xml\">";
if (fmatch.Groups[3].Value.Length > 0)
{
flashFunctionArgs = pars*emphasized text*eDelimitedString(fmatch.Groups[3].Value);
if (flashFunctionArgs.Count > 0)
{
flashXMLrequest += "<arguments><string>";
flashXMLrequest += string.Join("</string><string>", flashFunctionArgs);
flashXMLrequest += "</string></arguments>";
}
}
flashXMLrequest += "</invoke>";
try
{
Console.Write("YTplayer_CallFlash: \"" + flashXMLrequest + "\"\r\n");
response = YTplayer.CallFunction(flashXMLrequest);
Console.Write("YTplayer_CallFlash_response: \"" + response + "\"\r\n");
}
catch
{
Console.Write("YTplayer_CallFlash: error \"" + flashXMLrequest + "\"\r\n");
}
return response;
}
private static List<string> parseDelimitedString (string arguments, char delim = ',')
{
bool inQuotes = false;
bool inNonQuotes = false;
int whiteSpaceCount = 0;
List<string> strings = new List<string>();
StringBuilder sb = new StringBuilder();
foreach (char c in arguments)
{
if (c == '\'' || c == '"')
{
if (!inQuotes)
inQuotes = true;
else
inQuotes = false;
whiteSpaceCount = 0;
}else if (c == delim)
{
if (!inQuotes)
{
if (whiteSpaceCount > 0 && inQuotes)
{
sb.Remove(sb.Length - whiteSpaceCount, whiteSpaceCount);
inNonQuotes = false;
}
strings.Add(sb.Replace("'", string.Empty).Replace("\"", string.Empty).ToString());
sb.Remove(0, sb.Length);
}
else
{
sb.Append(c);
}
whiteSpaceCount = 0;
}
else if (char.IsWhiteSpace(c))
{
if (inNonQuotes || inQuotes)
{
sb.Append(c);
whiteSpaceCount++;
}
}
else
{
if (!inQuotes) inNonQuotes = true;
sb.Append(c);
whiteSpaceCount = 0;
}
}
strings.Add(sb.Replace("'", string.Empty).Replace("\"", string.Empty).ToString());
return strings;
}
adding Youtube event handlers:
private void YTready(string playerID)
{
YTState = true;
//start eventHandlers
YTplayer_CallFlash("addEventListener(\"onStateChange\",\"YTStateChange\")");
YTplayer_CallFlash("addEventListener(\"onError\",\"YTError\")");
}
private void YTStateChange(string YTplayState)
{
switch (int.Parse(YTplayState))
{
case -1: playState = false; break; //not started yet
case 1: playState = true; break; //playing
case 2: playState = false; break; //paused
//case 3: ; break; //buffering
case 0: playState = false; if (!loopFile) mediaNext(); else YTplayer_CallFlash("seekTo(0)"); break; //ended
}
}
private void YTStateError(string error)
{
Console.Write("YTplayer_error: "+error+"\r\n");
}
usage ex:
YTplayer_CallFlash("playVideo()");
YTplayer_CallFlash("pauseVideo()");
YTplayer_CallFlash("loadVideoById(KuNQgln6TL0)");
string currentVideoId = YTplayer_CallFlash("getPlaylist()");
string currentDuration = YTplayer_CallFlash("getDuration()");
The functions YTplayer_CallFlash, YTplayer_FlashCall should work for any flash-C# communication with minor adjustments like the YTplayer_CallFlash's switch (command).
This stumped me for a number of hours.
Just add enable JS to your URL:
http://www.youtube.com/v/9bZkp7q19f0?version=3&enablejsapi=1
CallFunction works fine for me now! Also remove unrequired space in the call.
Related
I have a lot of VBA automation that interlinks an Outlook and Word solution; it is fine, but time is inexorable... so, I'm start to decorating and extending that old solution, wraping it with C#/VS2017.
Through a conventional Winform I can choose my patients, and from this action I do a lot of actions, including open the correct Outlook contact; that's the problem, because I can't get the correct Store; the patients.pst, depending on the machine, may be the 1st, 2nd, 3rd...
In VBA I do this:
WhichStoreNameToPointAt="patients"
Set myNamespace = myolApp.GetNamespace("MAPI")
For i = 1 To myNamespace.Stores.Count Step 1
If myNamespace.Stores.item(i).DisplayName = WhichStoreNameToPointAt Then
intOutlookItemStore = i
End if
End If
Set myFolderPatients = myNamespace.Stores.item(intOutlookItemStore).GetDefaultFolder(olFolderContacts)
And it always functions like a charm.
In C# I tried a lot of variations, and could not point to the correct store:
public void OpenPatientContact(string patientName)
{
Outlook.Store whichStore = null;
Outlook.NameSpace nameSpace = OlkApp.Session;
int i = 1;
foreach (Outlook.Folder folder in nameSpace.Folders)
{
bool p = false;
if (whichStoreNameToPointAt == folder.Name)
{
p = true;
whichStore = folder.Store;
//Correct Store selected; I can tell because of this watch:
//whichStore.displayname == whichStoreNameToPointAt
}
i++;
if (p)
break;
}
var contactItemsOlk = whichStore.Session.GetDefaultFolder
(Outlook.OlDefaultFolders.olFolderContacts).Items;
// The problem is below; always the first Store
Outlook.ContactItem contact = (Outlook.ContactItem)contactItemsOlk
.Find(string.Format("[FullName]='{0}'", patientName)); //[1];
if (contact != null)
{
contact.Display(true);
}
else
{
MessageBox.Show("The contact information was not found.");
}
}
Unfortunately, it keeps pointing ever to the same first Store, the one that has no patients...
If I change the Store order I can get past this and test other stuff, but of course it is not the right way.
Any other heads/eyes to see the light?
TIA
While seated writing the question, looking at a yellow rubber duck - and a lot of other stuff that belongs to my 1 yo daughter ;), I realized that whichStore.Session.GetDefaultFolder is a little strange in this context. I only changed this
var contactItemsOlk = whichStore.Session.GetDefaultFolder
(Outlook.OlDefaultFolders.olFolderContacts).Items;
To that:
var contactItemsOlk = whichStore.GetDefaultFolder
(Outlook.OlDefaultFolders.olFolderContacts).Items;
Voilá! Magic happens with C# too!
Session returns the default NameSpace object for the current session.
PS: yellow rubber duck; guys of The Pragmatic Programmer really knows some secrets and tricks ;)
Thanks Thomas and Hunt!
I am attempting to help a user log into their account using a custom WebBrowser control. I am trying to set the value of an input tag to the players username using the WebBrowser's InvokeScript function. However, my current solution is doing nothing but rendering a blank white page.
My current code looks like this (web is the name for my WebBrowser control):
web.Navigate(CurrentURL, null, #"<script type='text/javascript'>
function SetPlayerData(input) {
username.value = input;
return true;
}
</script>");
web.Navigated += (o, e) =>
{
web.IsScriptEnabled = true;
web.InvokeScript("SetPlayerData", #"test");
};
As mentioned, this does not work right now. I am attempting to do this on Windows Phone so a number of the example's I have found here and in other places will not work as I do not have access to the same functions.
How would I perform this successfully?
EDIT: Perhaps I was not clear, but I am working with Windows Phone, which has a limited API available meaning I do not have access to the Document property and a number of other functions. I do have access to InvokeScript, but not much more.
webBrowser1.Document.GetElementById("navbar_username").InnerText ="Tester";
webBrowser1.Document.GetElementById("navbar_password").InnerText = "xxxxxxxxxxx";
foreach (HtmlElement HtmlElement1 in webBrowser1.Document.Body.All)
{
if (HtmlElement1.GetAttribute("value") == "Log in")
{
HtmlElement1.InvokeMember("click");
break;
}
}
you may find more here : http://deltahacker.gr/2011/08/15/ftiakste-to-diko-sas-robot/
It's been along time since this question is posted but I think I'll post an answer to this so that it will help some one who came across the same situation
try
{
webBrowser1.Document.GetElementById("navbar_username").SetAttribute("value", "your user");
webBrowser1.Document.GetElementById("navbar_password").SetAttribute("value", "your pass");
webBrowser1.Document.GetElementById("Log in").InvokeMember("click");
}
catch { }
Hopefully an easy question for you all but I'm really struggling.
I've only recently started programming and have just had an app certified to the WP7 app store but noticed a bug myself that i would like to fix before making the app public.
Basically I have a search box where the user enters a chemical name and a webservice returns an image and its molecular weight. What i would like to do is cancel the webclient if the user navigates away from the page before the download is completed or if a new search is made before the previous is completed (this currently crashes the app as I believe you can only have one request at a time??)
private void searchCactus()
{
WebClient imgClient = new WebClient();
imgClient.OpenReadCompleted += new OpenReadCompletedEventHandler(imgClient_OpenReadCompleted);
WebClient mwClient = new WebClient();
mwClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(mwClient_DownloadStringCompleted);
if (DeviceNetworkInformation.IsNetworkAvailable == false)
{
MessageBox.Show("No network found, please check network availability and try again");
}
else if (compoundSearchBox.Text.Contains("?"))
{
MessageBox.Show("\"?\" Not Permitted");
return;
}
else if (compoundSearchBox.Text != "")
{
progBar1.IsIndeterminate = true;
string imageuri = "http://cactus.nci.nih.gov/chemical/structure/" + compoundSearchBox.Text + "/image?format=png&width=300&height=300";
string mwURI = "http://cactus.nci.nih.gov/chemical/structure/" + compoundSearchBox.Text + "/mw";
imgClient.OpenReadAsync(new Uri(#imageuri), imgClient);
mwClient.DownloadStringAsync(new Uri(#mwURI), mwClient);
// //lower keyboard
this.Focus();
}
else MessageBox.Show("Enter Search Query");
}
I tried implementing the following button but it does not work
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
imgClient.CancelAsync();
mwClient.CancelAsync();
}
as "the name 'mwClient' does not exist in the current context"
I would be very grateful if anybody could provide some guidance
Just put the two clients into fields in your class.
Please can anyone help me? I search some example how can i get information about speeching text in TTS through SAPI (I am programming my aplication in C# but it is not needed, SAPI is the same in C++, etc.)
Information what I need is for example:
User will write in textbox:
"This is a Text"..
tts.Speak("This is a text"); // this will "read" it..
ok, nice... but I need too get informations about "timing"..
for example:
"Th" (first sound (phoneme) of "This") was "read" in 0.01ms..
"i" (first sound of "is") was "read" in 0.5ms..
"e" (second sound of "Text") was "read" in 1.02ms..
when I save the .wav file generated by SAPI, I need to get information about the timing in the .wav for subsequent "processing" of the wav file.
Sorry for my english and sorry for my bad description of my problem but the problem is i think very simple and all will understand it. If not I will try to describe the problem again :) ^^..
I have used C++ and SAPI 5.1 to synthesize speech and have a virtual character move its lips accordingly. Here is some code that works with visemes. According to the documentation at http://msdn.microsoft.com/en-us/library/ms720164(v=vs.85).aspx, phonemes work the same, except replace SPEI_VISEME with SPEI_PHONEME.
DWORD WINAPI Character::sayMessage(LPVOID lpParam){
HRESULT hres;
try{
::CoInitialize(NULL);
ThreadParam * param = (ThreadParam *)lpParam;
wstring s = param->message;
//first check the string for null
if (s == L"") return false;
//http://msdn.microsoft.com/en-us/library/ms720163(VS.85,classic).asp is my source for this
//set up text to speech
//get the voice associated with the character
ISpVoice * pVoice;
pVoice = param->sceneObject->characterVoice;
if (pVoice != NULL){
pVoice->Speak( NULL, SPF_PURGEBEFORESPEAK, 0 );
SPEVENT event;
ULONG ul;
pVoice->SetInterest(SPFEI(SPEI_VISEME)|SPFEI(SPEI_END_INPUT_STREAM),SPFEI(SPEI_VISEME)|SPFEI(SPEI_END_INPUT_STREAM));
pVoice->SetNotifyCallbackFunction(&eventFunction,0,0);
pVoice->WaitForNotifyEvent(INFINITE);
if (param->sceneObject->age == CHILD){
s = L"<pitch middle=\"+10\">" + s + L"</pitch>";
}
hres = pVoice->Speak(s.c_str(),SPF_ASYNC,NULL);
bool isDone = false;
while(!isDone && pVoice != NULL && !FAILED(hres)){
if(pVoice->GetEvents(1,&event, &ul) == S_OK){
if(event.eEventId==SPEI_VISEME){
//get the viseme
int vis = LOWORD(event.lParam); //handle it however you'd like after this
}
else if(event.eEventId== SPEI_END_INPUT_STREAM){
isDone = true;
s = L"";
return true;
}
}
}
}
}
catch(...){
return false;
}
return !FAILED(hres);
}
I searched around on Google for this, but the only things I came up with were outdated and did not work.
Does anyone have any information on how to get joystick data using C# .NET?
Since this was the top hit I got on google while researching joystick / gamepad input in C#, I thought I should post a response for others to see.
The easiest way I found was to use SharpDX and DirectInput. You can install it via NuGet (SharpDX.DirectInput)
After that, it's simply a matter of calling a few methods:
Sample code from SharpDX
static void Main()
{
// Initialize DirectInput
var directInput = new DirectInput();
// Find a Joystick Guid
var joystickGuid = Guid.Empty;
foreach (var deviceInstance in directInput.GetDevices(DeviceType.Gamepad,
DeviceEnumerationFlags.AllDevices))
joystickGuid = deviceInstance.InstanceGuid;
// If Gamepad not found, look for a Joystick
if (joystickGuid == Guid.Empty)
foreach (var deviceInstance in directInput.GetDevices(DeviceType.Joystick,
DeviceEnumerationFlags.AllDevices))
joystickGuid = deviceInstance.InstanceGuid;
// If Joystick not found, throws an error
if (joystickGuid == Guid.Empty)
{
Console.WriteLine("No joystick/Gamepad found.");
Console.ReadKey();
Environment.Exit(1);
}
// Instantiate the joystick
var joystick = new Joystick(directInput, joystickGuid);
Console.WriteLine("Found Joystick/Gamepad with GUID: {0}", joystickGuid);
// Query all suported ForceFeedback effects
var allEffects = joystick.GetEffects();
foreach (var effectInfo in allEffects)
Console.WriteLine("Effect available {0}", effectInfo.Name);
// Set BufferSize in order to use buffered data.
joystick.Properties.BufferSize = 128;
// Acquire the joystick
joystick.Acquire();
// Poll events from joystick
while (true)
{
joystick.Poll();
var datas = joystick.GetBufferedData();
foreach (var state in datas)
Console.WriteLine(state);
}
}
I hope this helps.
I even got this to work with a DualShock3 and the MotioninJoy drivers.
One: use SlimDX.
Two: it looks something like this (where GamepadDevice is my own wrapper, and the code is slimmed down to just the relevant parts).
Find the joystick / pad GUIDs:
public virtual IList<GamepadDevice> Available()
{
IList<GamepadDevice> result = new List<GamepadDevice>();
DirectInput dinput = new DirectInput();
foreach (DeviceInstance di in dinput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly))
{
GamepadDevice dev = new GamepadDevice();
dev.Guid = di.InstanceGuid;
dev.Name = di.InstanceName;
result.Add(dev);
}
return result;
}
Once the user has selected from the list, acquire the gamepad:
private void acquire(System.Windows.Forms.Form parent)
{
DirectInput dinput = new DirectInput();
pad = new Joystick(dinput, this.Device.Guid);
foreach (DeviceObjectInstance doi in pad.GetObjects(ObjectDeviceType.Axis))
{
pad.GetObjectPropertiesById((int)doi.ObjectType).SetRange(-5000, 5000);
}
pad.Properties.AxisMode = DeviceAxisMode.Absolute;
pad.SetCooperativeLevel(parent, (CooperativeLevel.Nonexclusive | CooperativeLevel.Background));
pad.Acquire();
}
Polling the pad looks like this:
JoystickState state = new JoystickState();
if (pad.Poll().IsFailure)
{
result.Disconnect = true;
return result;
}
if (pad.GetCurrentState(ref state).IsFailure)
{
result.Disconnect = true;
return result;
}
result.X = state.X / 5000.0f;
result.Y = state.Y / 5000.0f;
int ispressed = 0;
bool[] buttons = state.GetButtons();
The bad news is that Microsoft seems to stop supporting their NET libraries for DirectX and focus on XNA instead. I don't work in GameDev so I don't need to use XNA but you may try it if you developing computer games. The good news is that there are other approaches. One is SlimDX the new framework to help you to wok with DirectX from C#. The other way is to directly add references of "Microsoft.DirectX.dll" and "Microsoft.DirectX.DirectInput.dll" to your project. you can find them "..\Windows\Microsoft.NET\DirectX for Managed Code\". if you you are going to use last approach here is a link to codeproject where you can read how to work with a joystick.
EDIT:
If your application is based on NET version newer then 2.0 the application may hang on. To fix this problem change config file and add this:
<startup useLegacyV2RuntimeActivationPolicy="true">
Google led me here and while not a requirement of this question, OpenTK is a good option for Windows and Linux (under mono) support.
From the OpenTK docs, this code works on Raspberry Pi + Raspbian + Mono 3.12.0:
for (int i = 0; i < 4; i++)
{
var state = Joystick.GetState(i);
if (state.IsConnected)
{
float x = state.GetAxis(JoystickAxis.Axis0);
float y = state.GetAxis(JoystickAxis.Axis1);
// Print the current state of the joystick
Console.WriteLine(state);
}
}
This question is old, but it seems to be active even to this day, so I'm posting anyway.
If you need to get input from XInput only, take a look at XInputium. This is a .NET library that is specialized in XInput controllers. It is pretty straightforward, and has many code samples you can look at.