Skip to content

Commit

Permalink
Auto switch with Alt+Tab (#79)
Browse files Browse the repository at this point in the history
* Auto switch with Alt+Tab
* Add option to turn on/off auto switch
* Only auto switch if setting is turned on
* Clean up options window and add help texts
* Make the hotkey checkbox work
* Show Switcheroo with search activated when Alt+Ctrl+Tab is pressed
  • Loading branch information
kvakulo authored Feb 28, 2018
1 parent 94d22c6 commit 192f1b6
Show file tree
Hide file tree
Showing 7 changed files with 367 additions and 247 deletions.
36 changes: 26 additions & 10 deletions Switcheroo/AltTabHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,21 @@ namespace Switcheroo

public class AltTabHookEventArgs : EventArgs
{
public bool CtrlDown { get; set; }
public bool ShiftDown { get; set; }
public bool Handled { get; set; }
}

public class AltTabHook : IDisposable
{
public event AltTabHookEventHandler Pressed;
private const int AltDown = 32;
private const int AltKey = 32;
private const int CtrlKey = 11;
private readonly KeyboardKey _shiftKey = new KeyboardKey(Keys.LShiftKey);
private readonly KeyboardKey _ctrlKey = new KeyboardKey(Keys.LControlKey);
private readonly KeyboardKey _altKey = new KeyboardKey(Keys.LMenu);
private readonly int WM_KEYDOWN = 0x0100;
private readonly int WM_SYSKEYDOWN = 0x0104;

// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly LowLevelKeyboardHook _lowLevelKeyboardHook;
Expand All @@ -58,28 +64,38 @@ private void OnMessageIntercepted(LowLevelMessage lowLevelMessage, ref bool hand
return;
}

if (!IsAltTabKeyCombination(keyboardMessage))
if (!IsTabKeyDown(keyboardMessage))
{
return;
}

var shiftKeyDown = (_shiftKey.AsyncState & 32768) != 0; // is held down
Trace.WriteLine("Shiftkey: " + shiftKeyDown);
if (!IsKeyDown(_altKey))
{
return;
}

var shiftKeyDown = IsKeyDown(_shiftKey);
var ctrlKeyDown = IsKeyDown(_ctrlKey);

var eventArgs = OnPressed(shiftKeyDown);
var eventArgs = OnPressed(shiftKeyDown, ctrlKeyDown);

handled = eventArgs.Handled;
}

private static bool IsAltTabKeyCombination(LowLevelKeyboardMessage keyboardMessage)
private static bool IsKeyDown(KeyboardKey keyboardKey)
{
return (keyboardKey.AsyncState & 32768) != 0;
}

private bool IsTabKeyDown(LowLevelKeyboardMessage keyboardMessage)
{
return keyboardMessage.VirtualKeyCode == (int) Keys.Tab
&& keyboardMessage.Flags == AltDown;
return keyboardMessage.VirtualKeyCode == (int) Keys.Tab &&
(keyboardMessage.Message == WM_KEYDOWN || keyboardMessage.Message == WM_SYSKEYDOWN);
}

private AltTabHookEventArgs OnPressed(bool shiftDown)
private AltTabHookEventArgs OnPressed(bool shiftDown, bool ctrlDown)
{
var altTabHookEventArgs = new AltTabHookEventArgs { ShiftDown = shiftDown };
var altTabHookEventArgs = new AltTabHookEventArgs { ShiftDown = shiftDown, CtrlDown = ctrlDown };
var handler = Pressed;
if (handler != null)
{
Expand Down
40 changes: 35 additions & 5 deletions Switcheroo/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public partial class MainWindow : Window
private AboutWindow _aboutWindow;
private AltTabHook _altTabHook;
private SystemWindow _foregroundWindow;
private bool _altTabAutoSwitch;

public MainWindow()
{
Expand Down Expand Up @@ -101,6 +102,13 @@ private void SetUpKeyBindings()
{
Opacity = 0;
}
else if (args.SystemKey == Key.S && Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
{
_altTabAutoSwitch = false;
tb.Text = "";
tb.IsEnabled = true;
tb.Focus();
}
};

KeyUp += (sender, args) =>
Expand All @@ -114,7 +122,11 @@ private void SetUpKeyBindings()
{
HideWindow();
}
else if (args.SystemKey == Key.LeftAlt)
else if (args.SystemKey == Key.LeftAlt && !Keyboard.Modifiers.HasFlag(ModifierKeys.Control))
{
Switch();
}
else if (args.Key == Key.LeftAlt && _altTabAutoSwitch)
{
Switch();
}
Expand All @@ -131,8 +143,7 @@ private void SetUpHotKey()
_hotkey.HotkeyPressed += hotkey_HotkeyPressed;
try
{
// Use either custom shortcut or AltTab.
_hotkey.Enabled = !Settings.Default.AltTabHook;
_hotkey.Enabled = Settings.Default.EnableHotKey;
}
catch (HotkeyAlreadyInUseException)
{
Expand Down Expand Up @@ -337,6 +348,7 @@ private void Switch()
var win = (AppWindowViewModel) (lb.SelectedItem ?? lb.Items[0]);
win.AppWindow.SwitchToLastVisibleActivePopup();
}

HideWindow();
}

Expand All @@ -348,7 +360,9 @@ private void HideWindow()
_windowCloser = null;
}

Hide();
_altTabAutoSwitch = false;
Opacity = 0;
Dispatcher.BeginInvoke(new Action(Hide), DispatcherPriority.Input);
}

#endregion
Expand Down Expand Up @@ -424,13 +438,15 @@ private void OnClose(object sender, System.ComponentModel.CancelEventArgs e)

private void hotkey_HotkeyPressed(object sender, EventArgs e)
{
if (Settings.Default.AltTabHook)
if (!Settings.Default.EnableHotKey)
{
return;
}

if (Visibility != Visibility.Visible)
{
tb.IsEnabled = true;

_foregroundWindow = SystemWindow.ForegroundWindow;
Show();
Activate();
Expand All @@ -456,6 +472,8 @@ private void AltTabPressed(object sender, AltTabHookEventArgs e)

if (Visibility != Visibility.Visible)
{
tb.IsEnabled = true;

_foregroundWindow = SystemWindow.ForegroundWindow;

ActivateAndFocusMainWindow();
Expand All @@ -470,6 +488,13 @@ private void AltTabPressed(object sender, AltTabHookEventArgs e)
LoadData(InitialFocus.NextItem);
}

if (Settings.Default.AutoSwitch && !e.CtrlDown)
{
_altTabAutoSwitch = true;
tb.IsEnabled = false;
tb.Text = "Press Alt + S to search";
}

Opacity = 1;
}
else
Expand Down Expand Up @@ -520,6 +545,11 @@ private void ActivateAndFocusMainWindow()

private void TextChanged(object sender, TextChangedEventArgs args)
{
if (!tb.IsEnabled)
{
return;
}

var query = tb.Text;

var context = new WindowFilterContext<AppWindowViewModel>
Expand Down
34 changes: 25 additions & 9 deletions Switcheroo/OptionsWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,40 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Switcheroo Options" ResizeMode="NoResize" SizeToContent="WidthAndHeight"
ShowInTaskbar="False" WindowStyle="ToolWindow" Background="{x:Static SystemColors.WindowBrush}" Height="200"
Width="250">
ShowInTaskbar="False" WindowStyle="ToolWindow" Background="{x:Static SystemColors.WindowBrush}" Height="380"
MaxWidth="350">
<Window.Resources>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Margin="5,5,5,5">
<Label>Activate Switcheroo with this shortcut:</Label>
<TextBox Name="HotkeyPreview" Margin="5"
<CheckBox Name="HotKeyCheckBox" Margin="5,5,5,1" Checked="HotKeyCheckBox_Checked" Unchecked="HotKeyCheckBox_OnUnchecked">Activate Switcheroo with this shortcut:</CheckBox>
<TextBox Name="HotkeyPreview" Margin="25,5,0,10"
PreviewKeyDown="HotkeyPreview_OnPreviewKeyDown"
GotFocus="HotkeyPreview_OnGotFocus"
LostFocus="HotkeyPreview_OnLostFocus" />
<CheckBox Name="AltTabCheckBox" Checked="AltTabCheckBox_OnChecked" Unchecked="AltTabCheckBox_OnUnchecked" Margin="5">Activate Switcheroo with Alt+Tab</CheckBox>

<CheckBox Name="RunAsAdministrator" Margin="5">Run as Administrator on Startup</CheckBox>

LostFocus="HotkeyPreview_OnLostFocus"
Width="150"
HorizontalAlignment="Left"/>
<CheckBox Name="AltTabCheckBox" Checked="AltTabCheckBox_OnChecked" Unchecked="AltTabCheckBox_OnUnchecked" Margin="5,5,5,1">Activate Switcheroo with Alt+Tab</CheckBox>
<TextBlock Margin="25,0,5,10" FontSize="10" Foreground="DimGray" TextWrapping="Wrap">
Use Switcheroo instead of the integrated task switcher in Windows.
</TextBlock>
<CheckBox Name="AutoSwitch" Margin="5,5,5,1">Automatically switch window when releasing Alt + Tab</CheckBox>
<TextBlock Margin="25,0,5,10" FontSize="10" Foreground="DimGray" TextWrapping="Wrap">
Faster and more native-like swiching between windows.<LineBreak />
<LineBreak />
Use <Span FontFamily="Consolas" FontWeight="Bold">Ctrl + Alt + Tab</Span> for displaying Switcheroo with search activated, or
press <Span FontFamily="Consolas" FontWeight="Bold">Alt + S</Span> when the Switcheroo overlay appears.
</TextBlock>
<CheckBox x:Name="RunAsAdministrator" Margin="5,5,5,1" Content="Run as Administrator *"/>
<TextBlock Margin="25,0,5,10" FontSize="10" Foreground="DimGray" TextWrapping="Wrap">
This is needed if you want <Span FontFamily="Consolas" FontWeight="Bold">Alt + Tab</Span> to work when programs
running with higher privileges than your user account are in focus.<LineBreak />
<LineBreak />
<Italic>* Requires a restart of Switcheroo</Italic>
</TextBlock>
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition />
Expand Down
Loading

0 comments on commit 192f1b6

Please sign in to comment.