Added support for customizable keyboard shortcuts. Keyboard shortcuts can be added in flat_layout.xml by adding <shortcut> tags around the desired clients (No changes regarding the other xml files because I'm not sure what they do exactly...). Keyboard shortcuts are parsed as strings using KeysConverter without much sophistication. Some keys won't work, and there's no error reporting. Here's on that does work: Ctrl+Alt+F12. Also, added additional code to prevent preview windows and overlays from being shown when alt+tabbing.

This commit is contained in:
HomigoshZur
2015-02-19 00:11:11 -06:00
parent 6f5e818ddd
commit 37c3a20ece
5 changed files with 370 additions and 0 deletions

302
Hotkey.cs Normal file
View File

@@ -0,0 +1,302 @@
using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Xml.Serialization;
using System.Runtime.InteropServices;
namespace MovablePython
{
public class Hotkey : IMessageFilter
{
#region Interop
[DllImport("user32.dll", SetLastError = true)]
private static extern int RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, Keys vk);
[DllImport("user32.dll", SetLastError=true)]
private static extern int UnregisterHotKey(IntPtr hWnd, int id);
private const uint WM_HOTKEY = 0x312;
private const uint MOD_ALT = 0x1;
private const uint MOD_CONTROL = 0x2;
private const uint MOD_SHIFT = 0x4;
private const uint MOD_WIN = 0x8;
private const uint ERROR_HOTKEY_ALREADY_REGISTERED = 1409;
#endregion
private static int currentID;
private const int maximumID = 0xBFFF;
private Keys keyCode;
private bool shift;
private bool control;
private bool alt;
private bool windows;
[XmlIgnore]
private int id;
[XmlIgnore]
private bool registered;
[XmlIgnore]
private Control windowControl;
public event HandledEventHandler Pressed;
public Hotkey() : this(Keys.None, false, false, false, false)
{
// No work done here!
}
public Hotkey(Keys keyCode, bool shift, bool control, bool alt, bool windows)
{
// Assign properties
this.KeyCode = keyCode;
this.Shift = shift;
this.Control = control;
this.Alt = alt;
this.Windows = windows;
// Register us as a message filter
Application.AddMessageFilter(this);
}
~Hotkey()
{
// Unregister the hotkey if necessary
if (this.Registered)
{ this.Unregister(); }
}
public Hotkey Clone()
{
// Clone the whole object
return new Hotkey(this.keyCode, this.shift, this.control, this.alt, this.windows);
}
public bool GetCanRegister(Control windowControl)
{
// Handle any exceptions: they mean "no, you can't register" :)
try
{
// Attempt to register
if (!this.Register(windowControl))
{ return false; }
// Unregister and say we managed it
this.Unregister();
return true;
}
catch (Win32Exception)
{ return false; }
catch (NotSupportedException)
{ return false; }
}
public bool Register(Control windowControl)
{
// Check that we have not registered
if (this.registered)
{ throw new NotSupportedException("You cannot register a hotkey that is already registered"); }
// We can't register an empty hotkey
if (this.Empty)
{ throw new NotSupportedException("You cannot register an empty hotkey"); }
// Get an ID for the hotkey and increase current ID
this.id = Hotkey.currentID;
Hotkey.currentID = Hotkey.currentID + 1 % Hotkey.maximumID;
// Translate modifier keys into unmanaged version
uint modifiers = (this.Alt ? Hotkey.MOD_ALT : 0) | (this.Control ? Hotkey.MOD_CONTROL : 0) |
(this.Shift ? Hotkey.MOD_SHIFT : 0) | (this.Windows ? Hotkey.MOD_WIN : 0);
// Register the hotkey
if (Hotkey.RegisterHotKey(windowControl.Handle, this.id, modifiers, keyCode) == 0)
{
// Is the error that the hotkey is registered?
if (Marshal.GetLastWin32Error() == ERROR_HOTKEY_ALREADY_REGISTERED)
{ return false; }
else
{ throw new Win32Exception(); }
}
// Save the control reference and register state
this.registered = true;
this.windowControl = windowControl;
// We successfully registered
return true;
}
public void Unregister()
{
// Check that we have registered
if (!this.registered)
{ throw new NotSupportedException("You cannot unregister a hotkey that is not registered"); }
// It's possible that the control itself has died: in that case, no need to unregister!
if (!this.windowControl.IsDisposed)
{
// Clean up after ourselves
if (Hotkey.UnregisterHotKey(this.windowControl.Handle, this.id) == 0)
{ throw new Win32Exception(); }
}
// Clear the control reference and register state
this.registered = false;
this.windowControl = null;
}
private void Reregister()
{
// Only do something if the key is already registered
if (!this.registered)
{ return; }
// Save control reference
Control windowControl = this.windowControl;
// Unregister and then reregister again
this.Unregister();
this.Register(windowControl);
}
public bool PreFilterMessage(ref Message message)
{
// Only process WM_HOTKEY messages
if (message.Msg != Hotkey.WM_HOTKEY)
{ return false; }
// Check that the ID is our key and we are registerd
if (this.registered && (message.WParam.ToInt32() == this.id))
{
// Fire the event and pass on the event if our handlers didn't handle it
return this.OnPressed();
}
else
{ return false; }
}
private bool OnPressed()
{
// Fire the event if we can
HandledEventArgs handledEventArgs = new HandledEventArgs(false);
if (this.Pressed != null)
{ this.Pressed(this, handledEventArgs); }
// Return whether we handled the event or not
return handledEventArgs.Handled;
}
public override string ToString()
{
// We can be empty
if (this.Empty)
{ return "(none)"; }
// Build key name
string keyName = Enum.GetName(typeof(Keys), this.keyCode);;
switch (this.keyCode)
{
case Keys.D0:
case Keys.D1:
case Keys.D2:
case Keys.D3:
case Keys.D4:
case Keys.D5:
case Keys.D6:
case Keys.D7:
case Keys.D8:
case Keys.D9:
// Strip the first character
keyName = keyName.Substring(1);
break;
default:
// Leave everything alone
break;
}
// Build modifiers
string modifiers = "";
if (this.shift)
{ modifiers += "Shift+"; }
if (this.control)
{ modifiers += "Control+"; }
if (this.alt)
{ modifiers += "Alt+"; }
if (this.windows)
{ modifiers += "Windows+"; }
// Return result
return modifiers + keyName;
}
public bool Empty
{
get { return this.keyCode == Keys.None; }
}
public bool Registered
{
get { return this.registered; }
}
public Keys KeyCode
{
get { return this.keyCode; }
set
{
// Save and reregister
this.keyCode = value;
this.Reregister();
}
}
public bool Shift
{
get { return this.shift; }
set
{
// Save and reregister
this.shift = value;
this.Reregister();
}
}
public bool Control
{
get { return this.control; }
set
{
// Save and reregister
this.control = value;
this.Reregister();
}
}
public bool Alt
{
get { return this.alt; }
set
{
// Save and reregister
this.alt = value;
this.Reregister();
}
}
public bool Windows
{
get { return this.windows; }
set
{
// Save and reregister
this.windows = value;
this.Reregister();
}
}
}
}

View File

@@ -6,6 +6,7 @@ using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using MovablePython;
namespace PreviewToy
{
@@ -26,6 +27,7 @@ namespace PreviewToy
private bool has_been_set_up = false;
private bool thumbnail_has_been_set_up = false;
private PreviewToyHandler spawner;
private Hotkey hotkey;
private bool hide = false;
@@ -41,6 +43,8 @@ namespace PreviewToy
return this.Text;
}
public void MakeTopMost(bool topmost)
{
this.TopMost = topmost && !(this.hide);
@@ -66,6 +70,8 @@ namespace PreviewToy
this.old_position = this.Location;
has_been_set_up = true;
}
public void preview_MouseHover(object sender, System.EventArgs e)
@@ -84,6 +90,46 @@ namespace PreviewToy
RefreshPreview();
}
protected override CreateParams CreateParams
{
get
{
var Params = base.CreateParams;
Params.ExStyle |= 0x80;
return Params;
}
}
public void registerShortcut(string shortcut)
{
if (shortcut == "")
return;
var cvt = new KeysConverter();
var key = (Keys)cvt.ConvertFrom(shortcut);
Hotkey hotkey = new Hotkey();
if ((key & Keys.Shift) == Keys.Shift)
{
hotkey.Shift = true;
}
if ((key & Keys.Alt) == Keys.Alt)
{
hotkey.Alt = true;
}
if ((key & Keys.Control) == Keys.Control)
{
hotkey.Control = true;
}
key = key & ~Keys.Shift & ~Keys.Alt & ~Keys.Control;
hotkey.KeyCode = key;
hotkey.Register(this);
hotkey.Pressed += delegate { bring_client_to_foreground(); spawner.preview_did_switch(); };
this.hotkey = hotkey;
}
public void doZoom()
{
if (is_zoomed)

View File

@@ -27,6 +27,7 @@ namespace PreviewToy
private Dictionary<String, Dictionary<String, Point>> unique_layouts;
private Dictionary<String, Point> flat_layout;
private Dictionary<String, String> flat_layout_shortcuts;
private Dictionary<String, ClientLocation> client_layout;
private bool is_initialized;
@@ -89,6 +90,7 @@ namespace PreviewToy
unique_layouts = new Dictionary<String, Dictionary<String, Point>>();
flat_layout = new Dictionary<String, Point>();
flat_layout_shortcuts = new Dictionary<String, String>();
client_layout = new Dictionary<String, ClientLocation>();
ignoring_size_sync = new Stopwatch();
@@ -197,6 +199,8 @@ namespace PreviewToy
else if (previews.ContainsKey(process.MainWindowHandle) && process.MainWindowTitle != previews[process.MainWindowHandle].Text) //or update the preview titles
{
previews[process.MainWindowHandle].SetLabel(process.MainWindowTitle);
string key = previews[process.MainWindowHandle].Text;
previews[process.MainWindowHandle].registerShortcut(flat_layout_shortcuts[key]);
refresh_client_window_locations(process);
}
@@ -299,6 +303,12 @@ namespace PreviewToy
foreach (var el in rootElement.Elements())
{
flat_layout[ParseXElement(el)] = new Point(Convert.ToInt32(el.Element("x").Value), Convert.ToInt32(el.Element("y").Value));
flat_layout_shortcuts[ParseXElement(el)] = "";
if (el.Element("shortcut") != null)
{
flat_layout_shortcuts[ParseXElement(el)] = el.Element("shortcut").Value;
}
}
}
@@ -355,6 +365,7 @@ namespace PreviewToy
XElement layout = MakeXElement(clientKV.Key);
layout.Add(new XElement("x", clientKV.Value.X));
layout.Add(new XElement("y", clientKV.Value.Y));
layout.Add(new XElement("shortcut", flat_layout_shortcuts[clientKV.Key]));
el2.Add(layout);
}

View File

@@ -41,5 +41,15 @@ namespace PreviewToy
}
protected override CreateParams CreateParams
{
get
{
var Params = base.CreateParams;
Params.ExStyle |= 0x80;
return Params;
}
}
}
}

View File

@@ -95,6 +95,7 @@
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Hotkey.cs" />
<Compile Include="PreviewHandler.cs">
<SubType>Form</SubType>
</Compile>