Silverlight Hot Keys

Hot keys like available in windows based application where you specify using caption like &print is not available in Silverlight.There are two ways to capture keydown or key up when silverlight is running inside web browser.The first way is the HTML Bridge to capture HTML event KeyUp on HTML document.This is fired when focus is not captured by silverlight application.Another way is to handle event in silverlight itself,since silverlight events are routed events i.e you need to capture hot / shortcut keys on root element i.e RootVisual.

* Check for update in the bottom  of this article for simplified version of hot key library..

There is limitation on keys like F1,F3 etc. which are handled by browser before they reach to the contents of web browser.These keys however can be used when running out of browser as HTML Bridge will be disabled while running out of browser.

The code presented here in this article can be used in two ways.

  • Global Hot keys
  • Page Specific hot keys.

Global Hot keys will be available throught the application life cycle where as page hot keys will be only available when specific page is active.

To use global hot keys use below mentioned code.Where you need to specify ModifierKeys,Keys and EventHandler to the callback function.

App.GlobalHotKeyHandler.RegisterShortcut(System.Windows.Input.ModifierKeys.Control,
               System.Windows.Input.Key.D9, new KeyDownHandler(LogOff));

void LogOff(object sender, System.EventArgs e)
        {
            LoginRegistrationWindow loginWindow = new LoginRegistrationWindow();
            loginWindow.Show();
        }

Singleton Pattern is used to provide single instance of HotKeyHandler class throughout application.Normally GlobalHotKeyHandler code will be writen under either App.xaml.cs or MainPage.xaml.cs in your Silverlight business application.

In case of shortcut keys for specific page use below mentioned code inside specific silverlight page.

//Create module level variable in page
 HotKeyHandler hkeyHandler = new HotKeyHandler();

//On Page_Loaded use Register and RegisterShortcut functions
hkeyHandler.Register();
hkeyHandler.RegisterShortcut(System.Windows.Input.ModifierKeys.None,
                  System.Windows.Input.Key.F1, new KeyDownHandler(LogOff));

//On Page__Unloaded call Unregister
hkeyHandler.Unregister();

Note that the above code while running in out of browser silverlight application will behave properly.In case of web browser mode you need to avoid using shortcut keys assigned to browser.

Here is the full code to add HotKey feature to your application.Add file HotKeyHandler.cs to your silverlight business application and paste the code for here…

public partial class App : Application
{
    public static HotKeyHandler GlobalHotKeyHandler { get; private set; }
    internal static Dictionary< Key,int> KeyCodeLookUp = new Dictionary();
    static App()
    {
        //start thread here to process this from backend

        GlobalHotKeyHandler = new HotKeyHandler();

        //  KeyCodeLookUp.Add(Key.D1,49);
        //Digits
        for (int i = (int)Key.D0; i <= (int)Key.D9;i++ )
            KeyCodeLookUp.Add((Key)i, i+28);
        //Chars
        for (int i = (int)Key.A; i <= (int)Key.Z; i++)
            KeyCodeLookUp.Add((Key)i, i + 35);

        //functional Key
        for (int i = (int)Key.F1; i <= (int)Key.F12; i++)             KeyCodeLookUp.Add((Key)i, i + 65);         KeyCodeLookUp.Add(Key.Escape, 1);     } } public delegate void KeyUpHandler(object sender,EventArgs e); public sealed class HotKeyHandler {     private List<Shortcut> shortcuts = new List<Shortcut>();
    public HotKeyHandler() {  }
    private bool isRegistered = false;
    public void Register()
    {
        if (this.isRegistered == false)
        {
            try
            {
                App.Current.RootVisual.KeyUp += new System.Windows.Input.KeyEventHandler(RootVisual_KeyUp);
                HtmlDocument document = HtmlPage.Document;
                EventHandler<HtmlEventArgs> KeyDownHandler;
                KeyDownHandler = new EventHandler<HtmlEventArgs>(OnBodyKeyUp);
                bool b = document.AttachEvent("onkeyup", KeyDownHandler);
            }
            catch (Exception ex) { }
            finally
            {
                this.isRegistered = true;
            }
        }
    }

    public void Unregister()
    {
        if (this.isRegistered)
        {
            try
            {
                App.Current.RootVisual.KeyUp -= RootVisual_KeyUp;
                HtmlDocument document = HtmlPage.Document;
                EventHandler<HtmlEventArgs> KeyDownHandler;
                KeyDownHandler = new EventHandler<HtmlEventArgs>(OnBodyKeyUp);
                document.DetachEvent("onkeyup", KeyDownHandler);
            }
            catch (Exception ex) { }
            finally
            {
                this.isRegistered = false;
            }
        }
    }

    private void RaiseOnKeyUp(ModifierKeys modKey,int keyCode,System.Windows.Input.KeyEventArgs ke,HtmlEventArgs he)
    {
        var handlers = (from h in this.shortcuts
                        where h.ModKeys == modKey &&
                        (ke!= null? h.Key == ke.Key : h.KeyCode==he.KeyCode)
                        select h);
        foreach (Shortcut s in handlers)
        {
            s.Handler(this, null);
        }
    }

    public void RegisterShortcut(ModifierKeys ModKeys, Key key, KeyUpHandler handler)
    {
        var shortAlready = from s in shortcuts
                            where s.ModKeys == ModKeys &&
                            s.Key == key && s.Handler.Method.Equals(handler.Method)
                            select s;
        if (shortAlready.Count() == 0)
        {
            Shortcut shortcut = new Shortcut { ModKeys = ModKeys, Key = key, Handler = handler };
            shortcuts.Add(shortcut);
        }
    }

    private void OnBodyKeyUp(object sender, HtmlEventArgs e)
    {
        RaiseOnKeyUp(GetModKey(e), e.KeyCode,null,e);

    }

    private ModifierKeys GetModKey(HtmlEventArgs e)
    {
        ModifierKeys modKey = ModifierKeys.None;
        if (e.CtrlKey) modKey = modKey | ModifierKeys.Control;
        if (e.AltKey) modKey = modKey | ModifierKeys.Alt;
        if (e.ShiftKey) modKey = modKey | ModifierKeys.Shift;

        return modKey;
    }

    void RootVisual_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
    {

        RaiseOnKeyUp(Keyboard.Modifiers,e.PlatformKeyCode,e,null);
    }

    private class Shortcut
    {
        public KeyUpHandler Handler { get; set; }
        public ModifierKeys ModKeys { get; set; }
        Key key;
        public Key Key
        {
            get { return key; }
            set {key=value;
                KeyCode = App.KeyCodeLookUp[value]; }
        }
        public int KeyCode { get; set; }
    }
}

Note that the code maintains the relationship beetwen HTML KeyCode and Silverlight Keys Enum.This is not required when you run in out of browser mode.The above code can be optimized by checking the out of browser mode at run time.

You may even develop system wide hot keys which will work even if you silverlight application is not in focus. This can be achived by using the system32 api’s to register the system wide hooks.The logic needs to be developed in some COM based component which needs to be deployed on client machine and can be communicated via COM bridge available in Silverlight 4. No doubt this will add very nice feature but the cost is more.. like it can be used only on windows system, it needs to be run as out of browser. That all realy depends on your requirements.

Code is available at : link /rajnish/uploads/code/HotKeyHandler.cs.txt

include the cs file in your project and update appropriate name space.

in you silverlight page use following code to register shortcut and define call back function

 public partial class MainPage : UserControl
    {
        HotKeyHandler hkeyHandler = new HotKeyHandler();

        public void RegisterShortcuts()
        {
            hkeyHandler.Register();
	    hkeyHandler.RegisterShortcut(System.Windows.Input.ModifierKeys.Control,
               System.Windows.Input.Key.D9, new KeyUpHandler(Logout));
        }

        void Logout(object sender, EventArgsKeyUp e)
        {
            App.RootActivity.ActiveContent = "Logging out...";
            App.RootActivity.IsActive = true;

            WebContext.Current.Authentication.Logout(false).Completed += new EventHandler(Logout_Completed);
        }
    }

off-course you need to call RegisterShortcuts function on page load.

/***************************************************************************************/

Update 1.0 : Nov 2010

Another simplified version of Hot Key library which can be used in XAML (without c# code) with just below mentioned two line. Hot key is exposed as attachable property.

xmlns:hkey="clr-namespace:Silverlight.Controls.HotKeys;assembly=Silverlight.Controls.HotKeys"
<Button Click="BtnAClick"   Grid.Column="0" Grid.Row="0" Height="25" Content="Button A"  >
 <hkey:HotKeyService.HotKey >
  <hkey:HotKey Shortcut="A" Click="BtnAClick" />
 </hkey:HotKeyService.HotKey>
</Button>

or with XAML code

xmlns:hkey="clr-namespace:Silverlight.Controls.HotKeys;assembly=Silverlight.Controls.HotKeys"
<Button Click="BtnAClick"   Grid.Column="0" Grid.Row="0" Height="25" Content="Button A" hkey:HotKeyService.HotKey="A" />

Source code (Vs2010,Sl 4.0) is available here. This library can be used to provide office xp like shortcut navigation in your silverlight application.

/***************************************************************************************/

7 thoughts on “Silverlight Hot Keys

  1. How can i prevent default keydown/keyup events?
    For example i want to create shortcut on ArrowLeft (<-) and prevent Slider change value, when it has focus.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s