I am displaying a website to users of my C# application using a ChromiumWebBrowser
provided by the CefSharp
library.
I am trying to add functionality to allow the users to 'zoom in/out' using keyboard shortcuts, i.e. CTRL +
/ CTRL -
.
I have managed to add a KeyboardListener
to the embedded browser using the 'Low Level Global Keyboard Hook/ Sink available at: http://www.dylansweb.com/2014/10/low-level-global-keyboard-hook-sink-in-c-net/
At the moment, my application will 'zoom in' on the browser, when the browser is 'in focus', and the user presses '+' on the keyboard. I've done this using:
private void _listener_OnKeyPressed(object sender, KeyPressedArgs e)
{
if(e.KeyPressed == Key.Add)
{
zoomInExecuted();
}
}
What I actually want, is only to allow the zoom in when the users holds either 'CTRL' key down, and then presses '+'.
I've written the following method in my C# (this is the method being called:
private void _listener_OnKeyPressed(object sender, KeyPressedArgs e)
{
Debug.WriteLine("e: " + e.KeyPressed.ToString());
if(e.KeyPressed == Key.LeftCtrl)
{
leftCtrlDown = true;
Debug.WriteLine("LeftCtrl pressed, leftCtrlDown should be true: ", leftCtrlDown.ToString());
}
else
{
leftCtrlDown = false;
}
if(e.KeyPressed == Key.RightCtrl)
{
rightCtrlDown = true;
Debug.WriteLine("RightCtrl pressed, rightCtrlDown should be true: ", rightCtrlDown.ToString());
}
else
{
rightCtrlDown = false;
}
if((leftCtrlDown == true)) //&& (e.KeyPressed == Key.Add))
{
if (e.KeyPressed == Key.Add)
{
Debug.WriteLine("Ctrl & + pressed, 'zoomInExecuted()' should be called ");
zoomInExecuted();
}
}else if((rightCtrlDown == true)) //&& (e.KeyPressed == Key.Add))
{
if (e.KeyPressed == Key.Add)
{
Debug.WriteLine("rightCtrl & + pressed, 'zoomInExecuted()' should be called ");
zoomInExecuted();
}
}
}
I'm calling this method using the <KeyBinding>
tag on the <Grid>
in which the browser is displayed in my XAML:
<KeyBinding Modifiers="Ctrl" Key="LeftCtrl" Command="{Binding _listener_OnKeyPressed}"></KeyBinding>
But the problem I'm having with this is: although the application detects when the 'CTRL' key is pressed (the debug is written to the console), it seems that it then can't detect the press on the second key (the '+' key).
I tried adding a second listener, that is called inside the first listener, only when either of the leftCtrlDown
or rightCtrlDown
booleans are true (i.e. when the user is pressing either CTRL key), but the application still doesn't seem to detect the press of a second key...
How can I make my app 'listen' for a press to another key, while it's already acknowledging that one key is currently being pressed down?
Edit
I've tried doing what was suggested in the answer, and now have in my XAML:
<Window x:Class="..."
....
xmlns:local="clr-namespace:Agent"
... >
<Window.Resources>
...
</Window.Resources>
<Grid Name="grid">
...
<Grid x:Name="grdBrowserHost" MinHeight="900" Height="Auto" MinWidth="1205" Width="Auto" Margin="5,0,0,0" DockPanel.Dock="Bottom" Grid.ColumnSpan="1" >
<Grid.InputBindings>
<KeyBinding Modifiers="Ctrl" Key="Add" Command="{Binding _listener_OnKeyPressed}"></KeyBinding>
</Grid.InputBindings>
...
<cefSharp:ChromiumWebBrowser Name="browser" ...>
<KeyBinding Modifiers="Ctrl" Key="Add">
<KeyBinding.Command>
<local:Zoom Executed="zoomInExecuted" />
</KeyBinding.Command>
</KeyBinding>
</cefSharp:ChromiumWebBrowser.InputBindings>
</Grid>
</Grid>
...
</Window>
The Zoom.cs
class that I've added is as follows:
namespace Agent
{
class Zoom : ICommand
{
public event EventHandler<object> Executed;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
if (Executed != null)
Executed(this, parameter);
}
public event EventHandler CanExecuteChanged;
}
}
But for some reason, I'm getting a compile error in the XAML, on the line:
<local:Zoom Executed="zoomInExecuted" />
which says:
The name "Zoom" does not exist in the namespace "clr-namespace:Agent".
even though it clearly does.
This line can't work:
<KeyBinding Modifiers="Ctrl" Key="LeftCtrl" Command="{Binding _listener_OnKeyPressed}"/>
KeyBinding.Command
expects an object implementing ICommand
, you are binding it to a method.
A basic implementation of the ICommand
interface would look something like this:
class SimpleCommand : ICommand
{
public event EventHandler<object> Executed;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
if (Executed != null)
Executed(this, parameter);
}
public event EventHandler CanExecuteChanged;
}
Which you could use like this:
<Window.InputBindings>
<KeyBinding Modifiers="Control" Key="Add">
<KeyBinding.Command>
<local:SimpleCommand Executed="SimpleCommand_OnExecuted"/>
</KeyBinding.Command>
</KeyBinding>
</Window.InputBindings>
And in code behind:
private void SimpleCommand_OnExecuted(object sender, object e)
{
MessageBox.Show("SimpleCommand Executed");
}
Usually you would use Commanding to define the Command in code and use it in XAML. When you bind that Command to a KeyBinding
, Button
or MenuItem
(or something else), the CanExecute
method of your implementation can be used to disable the command (and therefore disabling the Element it's bound to).