Skip to content

Commit 817a475

Browse files
Sébastien GeiserSébastien Geiser
Sébastien Geiser
authored and
Sébastien Geiser
committed
Copy,Paste and other hotkeys now works
1 parent b5a0968 commit 817a475

File tree

6 files changed

+490
-53
lines changed

6 files changed

+490
-53
lines changed

CSharpRegexTools4Npp/CSharpRegexTools4Npp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
<Compile Include="PluginInfrastructure\DllExport\DllExportAttribute.cs" />
8989
<Compile Include="PluginInfrastructure\Docking_h.cs" />
9090
<Compile Include="PluginInfrastructure\GatewayDomain.cs" />
91+
<Compile Include="Utils\KeyboardHookManager.cs" />
9192
<Compile Include="PluginInfrastructure\MenuCmdID_h.cs" />
9293
<Compile Include="PluginInfrastructure\Msgs_h.cs" />
9394
<Compile Include="PluginInfrastructure\NotepadPPGateway.cs" />

CSharpRegexTools4Npp/Main.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,6 @@ public static void ShowTheDialog()
9999

100100
SetText = text =>
101101
{
102-
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
103-
{
104-
Npp.Notepad.FileNew();
105-
}
106-
107102
Npp.Text = text;
108103
},
109104

@@ -114,6 +109,8 @@ public static void ShowTheDialog()
114109
Npp.Text = text;
115110
},
116111

112+
SetSelectedText = text => Npp.SelectedText = text,
113+
117114
GetSelectedText = () => Npp.SelectedText,
118115

119116
SetPosition = (index, length) => Npp.SelectTextAndShow(index, index + length),
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using System.Windows;
4+
using System.Windows.Forms;
5+
using System.Windows.Interop;
6+
7+
namespace CSharpRegexTools4Npp.PluginInfrastructure
8+
{
9+
public class KeyboardHookManager
10+
{
11+
private const int WH_KEYBOARD_LL = 13;
12+
private const int WM_KEYDOWN = 0x0100;
13+
private const int WM_SYSKEYDOWN = 0x0104;
14+
15+
private static IntPtr _hookID = IntPtr.Zero;
16+
private static Window _targetWindow;
17+
private static LowLevelKeyboardProc _proc;
18+
private static bool _isHookInstalled = false;
19+
20+
public static event EventHandler<KeyPressedEventArgs> KeyPressed;
21+
22+
public static void Initialize(Window window)
23+
{
24+
_targetWindow = window;
25+
_proc = HookCallback;
26+
27+
// S'abonner aux événements de focus de la fenêtre
28+
window.Activated += Window_Activated;
29+
window.Deactivated += Window_Deactivated;
30+
}
31+
32+
private static void Window_Activated(object sender, EventArgs e)
33+
{
34+
InstallHook();
35+
}
36+
37+
private static void Window_Deactivated(object sender, EventArgs e)
38+
{
39+
UninstallHook();
40+
}
41+
42+
private static void InstallHook()
43+
{
44+
if (!_isHookInstalled)
45+
{
46+
_hookID = SetHook(_proc);
47+
_isHookInstalled = true;
48+
}
49+
}
50+
51+
private static void UninstallHook()
52+
{
53+
if (_isHookInstalled)
54+
{
55+
UnhookWindowsHookEx(_hookID);
56+
_isHookInstalled = false;
57+
}
58+
}
59+
60+
private static IntPtr SetHook(LowLevelKeyboardProc proc)
61+
{
62+
using (var curProcess = System.Diagnostics.Process.GetCurrentProcess())
63+
using (var curModule = curProcess.MainModule)
64+
{
65+
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
66+
GetModuleHandle(curModule.ModuleName), 0);
67+
}
68+
}
69+
70+
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
71+
72+
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
73+
{
74+
if (nCode >= 0)
75+
{
76+
var windowHandle = GetForegroundWindow();
77+
var activeWindow = HwndSource.FromHwnd(windowHandle)?.RootVisual as Window;
78+
79+
// Vérifier si la fenêtre active est notre fenêtre cible
80+
if (activeWindow == _targetWindow)
81+
{
82+
if ((wParam == (IntPtr)WM_KEYDOWN) || (wParam == (IntPtr)WM_SYSKEYDOWN))
83+
{
84+
int vkCode = Marshal.ReadInt32(lParam);
85+
bool isCtrlPressed = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
86+
bool isAltPressed = (GetKeyState(VK_MENU) & 0x8000) != 0;
87+
bool isShiftPressed = (GetKeyState(VK_SHIFT) & 0x8000) != 0;
88+
89+
var args = new KeyPressedEventArgs(
90+
(Keys)vkCode,
91+
isCtrlPressed,
92+
isAltPressed,
93+
isShiftPressed
94+
);
95+
96+
KeyPressed?.Invoke(null, args);
97+
98+
// Si l'événement a été géré, on empêche sa propagation
99+
if (args.Handled)
100+
{
101+
return (IntPtr)1;
102+
}
103+
}
104+
}
105+
}
106+
return CallNextHookEx(_hookID, nCode, wParam, lParam);
107+
}
108+
109+
private const int VK_CONTROL = 0x11;
110+
private const int VK_MENU = 0x12; // ALT
111+
private const int VK_SHIFT = 0x10;
112+
113+
[DllImport("user32.dll")]
114+
private static extern IntPtr GetForegroundWindow();
115+
116+
[DllImport("user32.dll")]
117+
private static extern short GetKeyState(int nVirtKey);
118+
119+
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
120+
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn,
121+
IntPtr hMod, uint dwThreadId);
122+
123+
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
124+
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
125+
126+
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
127+
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
128+
IntPtr wParam, IntPtr lParam);
129+
130+
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
131+
private static extern IntPtr GetModuleHandle(string lpModuleName);
132+
}
133+
134+
public class KeyPressedEventArgs : EventArgs
135+
{
136+
public Keys Key { get; private set; }
137+
public bool Control { get; private set; }
138+
public bool Alt { get; private set; }
139+
public bool Shift { get; private set; }
140+
public bool Handled { get; set; }
141+
142+
public KeyPressedEventArgs(Keys key, bool control, bool alt, bool shift)
143+
{
144+
Key = key;
145+
Control = control;
146+
Alt = alt;
147+
Shift = shift;
148+
Handled = false;
149+
}
150+
}
151+
}

RegexDialog/RegExToolDialog.xaml

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
Loaded="Root_Loaded"
1616
SizeChanged="Root_SizeChanged"
1717
LocationChanged="Root_LocationChanged"
18-
PreviewKeyDown="Root_PreviewKeyDown"
1918
DataContext="{x:Static local:Config.Instance}"
2019
local:WindowHelper.CloseOnKey="Esc"
2120
x:Name="Root">
@@ -87,12 +86,12 @@
8786
</MenuItem.Icon>
8887
</MenuItem>
8988
<Separator/>
90-
<MenuItem Header="_Open" Click="Open_MenuItem_Click">
89+
<MenuItem Header="_Open" Click="Open_MenuItem_Click" InputGestureText="Ctrl+O">
9190
<MenuItem.Icon>
9291
<Image Source="{StaticResource OpenPicture}" />
9392
</MenuItem.Icon>
9493
</MenuItem>
95-
<MenuItem Header="Save _As..." Click="Save_as_MenuItem_Click" >
94+
<MenuItem Header="Save _As..." Click="Save_as_MenuItem_Click" InputGestureText="Ctrl+S">
9695
<MenuItem.Icon>
9796
<Image Source="{StaticResource SavePicture}" />
9897
</MenuItem.Icon>
@@ -111,29 +110,32 @@
111110
</MenuItem>
112111
</MenuItem>
113112
<MenuItem Header="_Actions" >
114-
<MenuItem Header="_Is Match ?" Click="IsMatchButton_Click">
113+
<MenuItem Header="_Is Match ?" Click="IsMatchButton_Click" InputGestureText="Ctrl+Space">
115114
<MenuItem.Icon>
116115
<Image Source="{StaticResource IsMatchPicture}" Width="16" Height="16" />
117116
</MenuItem.Icon>
118117
</MenuItem>
119-
<MenuItem Header="_Matches" Click="ShowMatchesButton_Click">
118+
<MenuItem Header="_Matches" Click="ShowMatchesButton_Click" InputGestureText="Ctrl+Enter">
120119
<MenuItem.Icon>
121120
<Image Source="{StaticResource MatchPicture}" Width="16" Height="16" />
122121
</MenuItem.Icon>
123122
</MenuItem>
124-
<MenuItem Header="_Select All Matches" Click="SelectAllButton_Click" IsEnabled="{Binding TextSourceOn, Converter={converters:EnumBooleanConverter InverseBool=True}, ConverterParameter='Directory'}">
123+
<MenuItem Header="_Select All Matches"
124+
Click="SelectAllButton_Click"
125+
IsEnabled="{Binding TextSourceOn, Converter={converters:EnumBooleanConverter InverseBool=True}, ConverterParameter='Directory'}"
126+
InputGestureText="Ctrl+Shift+S">
125127
<MenuItem.Icon>
126128
<Image Source="{StaticResource SelectPicture}"
127129
Width="16"
128130
Height="16"/>
129131
</MenuItem.Icon>
130132
</MenuItem>
131-
<MenuItem Header="_Extract All Matches" Click="ExtractMatchesButton_Click">
133+
<MenuItem Header="_Extract All Matches" Click="ExtractMatchesButton_Click" InputGestureText="Ctrl+(Shift)+E" ToolTip="Maintain [Shift] Key down to apply the replacement in the extraction">
132134
<MenuItem.Icon>
133135
<Image Source="{StaticResource ExtractPicture}" Width="16" Height="16" />
134136
</MenuItem.Icon>
135137
</MenuItem>
136-
<MenuItem Header="_Replace All" Click="ReplaceAllButton_Click">
138+
<MenuItem Header="_Replace All" Click="ReplaceAllButton_Click" InputGestureText="Ctrl+(Shift)+R" ToolTip="Maintain [Shift] Key down to put the result in a new tab">
137139
<MenuItem.Icon>
138140
<Image Source="{StaticResource ReplacePicture}" Width="16" Height="16" />
139141
</MenuItem.Icon>
@@ -189,18 +191,16 @@
189191
<Style BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" TargetType="Button" />
190192
<Style BasedOn="{StaticResource {x:Static ToolBar.ToggleButtonStyleKey}}" TargetType="ToggleButton" />
191193
</WrapPanel.Resources>
192-
<Button x:Name="IsMatchButton" Click="IsMatchButton_Click" >
194+
<Button x:Name="IsMatchButton" Click="IsMatchButton_Click" ToolTip="Is Match ? [Ctrl+Space]" >
193195
<StackPanel Orientation="Horizontal">
194-
<Image Source="{StaticResource IsMatchPicture}" Width="16" Height="16" ToolTip="Is Match ?"/>
196+
<Image Source="{StaticResource IsMatchPicture}" Width="16" Height="16" />
195197
</StackPanel>
196198
</Button>
197-
<Button x:Name="ShowMatchesButton" Click="ShowMatchesButton_Click" >
199+
<Button x:Name="ShowMatchesButton" Click="ShowMatchesButton_Click" ToolTip="Matches [Ctrl+Enter]">
198200
<StackPanel Orientation="Horizontal">
199201
<Image Source="{StaticResource MatchPicture}"
200202
Width="16"
201-
Height="16"
202-
ToolTip="Matches"
203-
/>
203+
Height="16"/>
204204
</StackPanel>
205205
</Button>
206206
<Button x:Name="SelectAllButton" Click="SelectAllButton_Click" IsEnabled="{Binding TextSourceOn, Converter={converters:ExpressionEvalConverter Expression='binding == RegexTextSource.CurrentTab || binding == RegexTextSource.CurrentSelection'}}">
@@ -213,12 +213,15 @@
213213
</Button>
214214
<Button x:Name="ExtractMatchesButton" Click="ExtractMatchesButton_Click">
215215
<StackPanel Orientation="Horizontal">
216-
<Image Source="{StaticResource ExtractPicture}" Width="16" Height="16" ToolTip="Extract All Matches (Maintain [Shift] Key down to apply the replacement in the extraction)"/>
216+
<Image Source="{StaticResource ExtractPicture}" Width="16" Height="16" ToolTip="Extract All Matches [Ctrl+E] (Maintain [Shift] Key down to apply the replacement in the extraction)"/>
217217
</StackPanel>
218218
</Button>
219-
<Button x:Name="ReplaceAllButton" Click="ReplaceAllButton_Click" IsEnabled="{Binding TextSourceOn, Converter={converters:ExpressionEvalConverter Expression='binding != RegexTextSource.Excel'}}">
219+
<Button x:Name="ReplaceAllButton"
220+
Click="ReplaceAllButton_Click"
221+
ToolTip="Replace All [Ctrl+R] (Maintain [Shift] Key down to put the result in a new tab)"
222+
IsEnabled="{Binding TextSourceOn, Converter={converters:ExpressionEvalConverter Expression='binding != RegexTextSource.Excel'}}">
220223
<StackPanel Orientation="Horizontal">
221-
<Image Source="{StaticResource ReplacePicture}" Width="16" Height="16" ToolTip="Replace All (Maintain [Ctrl] Key down to put the result in a new tab)"/>
224+
<Image Source="{StaticResource ReplacePicture}" Width="16" Height="16" />
222225
</StackPanel>
223226
</Button>
224227
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />

0 commit comments

Comments
 (0)