This blog contains reflections and thoughts on my work as a software engineer

onsdag den 7. oktober 2009

Stop whining!

This is a little out of the ordinary but what the heck... There has to be room for a little fun from time to time

You know Arnold Schwarzenegger? Of course you do... He has become famous for quotes like "I'll be back", "Aaaaargh" and various other sentences which primarily excels in containing words exceeding no more than two syllables. There's one quote in particular I like (and so does my fellow coworkers). It is "Stop whining" from Kindergarten Cop - when spoken McBain style nobody at our team can continue whining over bad code, cold coffee, stupid typos etc but inevitably start smiling because whining is such an easy trap to fall into when the right thing to do is just to get the job done and get going.

How does this relate to coding? Well, tonight I wondered how to play media files in C#... I never actually tried coding audio stuff in C# so I figured that I wanted to find a WAV file containing the infamous Arnold shouting "Stop whining"... And so I did and it turned out to be a very little deal getting it out. It was actually two lines of code:


var myPlayer = new System.Media.SoundPlayer("myfile.wav");
myPlayer.Play();


Then I figured that I wanted to play it using a keyboard stroke - to make some kind of Arnold soundboard just using keyboard shortcuts - how would that be possible? Capturing keyboard strokes isn't hard at all - if your program is in focus but I wanted to have some keyboard hook which would catch my keyboard strokes globally... I knew it had to be done invoking unmanaged code which isn't something I do on an everyday basis... so instead of doing all the WinAPI stuff myself (yes, I am a lazy bastard) I dug up this article on CodeProject which I could make use of. It basicly encapsulates the WinAPI goodies required to globally listen to whatever the user is doing with his keyboard. The hardest part was actually getting raw WAV-files with Arnold quotes - I managed to find some but it required me to save them in a different format as the .NET Sound API only allows PCM files. Enter Audacity, a load and a save later on each file and I was good to go. I needed to research a little getting the Windows Form to hide itself as a tray icon (yet another thing I've never tried before) but it was also a nobrainer.



So as of tonight I have whipped up a small application which can store itself in the tray and listen to keyboard events. If you press down S, T, O and P down, Arnold will in his informal voice speak out "Stop whining!". Try the following for yourself: LACK and COP... The implementation is here (I won't cover the GlobalKeyboardHook as it is covered in the CodeProject article):



    public partial class ArnoldForm : Form
{
private GlobalKeyboardHook _gkh;
private List _pressedKeys = new List();
public ArnoldForm()
{
InitializeComponent();

_gkh = new GlobalKeyboardHook();
_gkh.HookedKeys.Add(Keys.S);
_gkh.HookedKeys.Add(Keys.T);
_gkh.HookedKeys.Add(Keys.O);
_gkh.HookedKeys.Add(Keys.P);

_gkh.HookedKeys.Add(Keys.C);
_gkh.HookedKeys.Add(Keys.P);

_gkh.HookedKeys.Add(Keys.L);
_gkh.HookedKeys.Add(Keys.A);
_gkh.HookedKeys.Add(Keys.K);



_gkh.KeyDown += gkh_KeyDown;
_gkh.KeyUp += gkh_KeyUp;
}

private void gkh_KeyUp(object sender, KeyEventArgs e)
{
if (_pressedKeys.Contains(e.KeyCode))
_pressedKeys.Remove(e.KeyCode);
}

private void gkh_KeyDown(object sender, KeyEventArgs e)
{
_pressedKeys.Add(e.KeyCode);
var arnold = new Arnold();
arnold.Speak(_pressedKeys);
}

private void Form1_Resize(object sender, EventArgs e)
{
if (FormWindowState.Minimized == WindowState)
Hide();
}

private void notifyIcon1_DoubleClick(object sender, EventArgs e)
{
Show();
WindowState = FormWindowState.Normal;
}
}

public class Arnold
{
public void Speak(List keys)
{
string voiceFile = GetVoiceFile(keys);

if (!string.IsNullOrEmpty(voiceFile))
{
var asm = Assembly.GetExecutingAssembly();
var file = asm.GetManifestResourceStream(voiceFile);

var myPlayer = new System.Media.SoundPlayer(file);
myPlayer.Play();
}
}

private static string GetVoiceFile(ICollection keys)
{

if (keys.Contains(Keys.S) &&
keys.Contains(Keys.T) &&
keys.Contains(Keys.O) &&
keys.Contains(Keys.P))
{
return "ArnoldQuotesForm.media.stop_whining.wav";
}

if (keys.Contains(Keys.C) &&
keys.Contains(Keys.O) &&
keys.Contains(Keys.P))
{
return "ArnoldQuotesForm.media.cop.wav";
}

if (keys.Contains(Keys.L) &&
keys.Contains(Keys.A) &&
keys.Contains(Keys.C) &&
keys.Contains(Keys.K))
{
return "ArnoldQuotesForm.media.lack_discipline.wav";
}

return null;
}
}


Download the entire project here


It's not exactly rocket science but I had a few hours of fun building the thing. Comments are welcome - until next time...  :o)

Ingen kommentarer: