1
1
using System ;
2
2
using System . Collections . Generic ;
3
+ using System . Drawing ;
4
+ using System . IO ;
3
5
using System . Linq ;
4
6
using System . Text ;
7
+ using System . Threading ;
5
8
using System . Threading . Tasks ;
6
9
using System . Windows ;
7
10
using System . Windows . Controls ;
14
17
15
18
namespace RawInput . Touchpad
16
19
{
17
- public partial class MainWindow : Window
18
- {
19
- public bool TouchpadExists
20
- {
21
- get { return ( bool ) GetValue ( TouchpadExistsProperty ) ; }
22
- set { SetValue ( TouchpadExistsProperty , value ) ; }
23
- }
24
- public static readonly DependencyProperty TouchpadExistsProperty =
25
- DependencyProperty . Register ( "TouchpadExists" , typeof ( bool ) , typeof ( MainWindow ) , new PropertyMetadata ( false ) ) ;
26
-
27
- public string TouchpadContacts
28
- {
29
- get { return ( string ) GetValue ( TouchpadContactsProperty ) ; }
30
- set { SetValue ( TouchpadContactsProperty , value ) ; }
31
- }
32
- public static readonly DependencyProperty TouchpadContactsProperty =
33
- DependencyProperty . Register ( "TouchpadContacts" , typeof ( string ) , typeof ( MainWindow ) , new PropertyMetadata ( null ) ) ;
34
-
35
- public MainWindow ( )
36
- {
37
- InitializeComponent ( ) ;
38
- }
39
-
40
- private HwndSource _targetSource ;
41
- private readonly List < string > _log = new ( ) ;
42
-
43
- protected override void OnSourceInitialized ( EventArgs e )
44
- {
45
- base . OnSourceInitialized ( e ) ;
46
-
47
- _targetSource = PresentationSource . FromVisual ( this ) as HwndSource ;
48
- _targetSource ? . AddHook ( WndProc ) ;
49
-
50
- TouchpadExists = TouchpadHelper . Exists ( ) ;
51
-
52
- _log . Add ( $ "Precision touchpad exists: { TouchpadExists } ") ;
53
-
54
- if ( TouchpadExists )
55
- {
56
- var success = TouchpadHelper . RegisterInput ( _targetSource . Handle ) ;
57
-
58
- _log . Add ( $ "Precision touchpad registered: { success } ") ;
59
- }
60
- }
61
-
62
- private IntPtr WndProc ( IntPtr hwnd , int msg , IntPtr wParam , IntPtr lParam , ref bool handled )
63
- {
64
- switch ( msg )
65
- {
66
- case TouchpadHelper . WM_INPUT :
67
- var contacts = TouchpadHelper . ParseInput ( lParam ) ;
68
- TouchpadContacts = string . Join ( Environment . NewLine , contacts . Select ( x => x . ToString ( ) ) ) ;
69
-
70
- _log . Add ( "---" ) ;
71
- _log . Add ( TouchpadContacts ) ;
72
- break ;
73
- }
74
- return IntPtr . Zero ;
75
- }
76
-
77
- private void Copy_Click ( object sender , RoutedEventArgs e )
78
- {
79
- Clipboard . SetText ( string . Join ( Environment . NewLine , _log ) ) ;
80
- }
81
- }
82
- }
20
+ public partial class MainWindow : Window
21
+ {
22
+ [ System . Runtime . InteropServices . DllImport ( "user32.dll" ) ]
23
+ static extern bool DestroyIcon ( IntPtr handle ) ;
24
+
25
+ public bool TouchpadExists
26
+ {
27
+ get { return ( bool ) GetValue ( TouchpadExistsProperty ) ; }
28
+ set { SetValue ( TouchpadExistsProperty , value ) ; }
29
+ }
30
+
31
+ public static readonly DependencyProperty TouchpadExistsProperty =
32
+ DependencyProperty . Register (
33
+ "TouchpadExists" ,
34
+ typeof ( bool ) ,
35
+ typeof ( MainWindow ) ,
36
+ new PropertyMetadata ( false )
37
+ ) ;
38
+
39
+ public string TouchpadContacts
40
+ {
41
+ get { return ( string ) GetValue ( TouchpadContactsProperty ) ; }
42
+ set { SetValue ( TouchpadContactsProperty , value ) ; }
43
+ }
44
+
45
+ public static readonly DependencyProperty TouchpadContactsProperty =
46
+ DependencyProperty . Register (
47
+ "TouchpadContacts" ,
48
+ typeof ( string ) ,
49
+ typeof ( MainWindow ) ,
50
+ new PropertyMetadata ( null )
51
+ ) ;
52
+
53
+ // reference to tray icon
54
+ private System . Windows . Forms . NotifyIcon _notifyIcon ;
55
+
56
+ // tracks if touch is showing, used to avoid updating the icon if it is already correct
57
+ private int _touchesShowing = 0 ;
58
+
59
+ // when was the last touch event received
60
+ private long _lastTouchTime = 0 ;
61
+
62
+ // timer to expire last touch event to detect when no one is touching the track pad anymore
63
+ private Timer _touchTimer ;
64
+
65
+ // list of all received touch events
66
+ private readonly List < string > _log = new ( ) ;
67
+
68
+ public MainWindow ( )
69
+ {
70
+ InitializeComponent ( ) ;
71
+
72
+ // add tray icon
73
+ _notifyIcon = new System . Windows . Forms . NotifyIcon
74
+ {
75
+ Text = "Touchpad Monitor" ,
76
+ Visible = true ,
77
+ } ;
78
+ SetIconState ( System . Drawing . Color . Red , ' ' ) ;
79
+ // restore window on tray icon click
80
+ _notifyIcon . Click += ( s , e ) => RestoreWindow ( ) ;
81
+ // keep window on top when showing
82
+ Topmost = true ;
83
+ // start window in bottom right corner
84
+ var workingArea = SystemParameters . WorkArea ;
85
+ Left = workingArea . Width - Width ;
86
+ Top = workingArea . Height - Height ;
87
+ // start timer to track expired touches
88
+ _touchTimer = new Timer ( TouchTimerCallback , null , 0 , 50 ) ;
89
+ }
90
+
91
+ protected override void OnClosed ( EventArgs e )
92
+ {
93
+ base . OnClosed ( e ) ;
94
+
95
+ _notifyIcon . Dispose ( ) ;
96
+ }
97
+
98
+ protected override void OnStateChanged ( EventArgs e )
99
+ {
100
+ base . OnStateChanged ( e ) ;
101
+
102
+ if ( WindowState == WindowState . Minimized )
103
+ {
104
+ Hide ( ) ;
105
+ _notifyIcon . Visible = true ;
106
+ }
107
+ }
108
+
109
+ protected override void OnSourceInitialized ( EventArgs e )
110
+ {
111
+ base . OnSourceInitialized ( e ) ;
112
+
113
+ var targetSource = PresentationSource . FromVisual ( this ) as HwndSource ;
114
+ targetSource ? . AddHook ( WndProc ) ;
115
+
116
+ TouchpadExists = TouchpadHelper . Exists ( ) ;
117
+
118
+ _log . Add ( $ "Precision touchpad exists: { TouchpadExists } ") ;
119
+
120
+ if ( TouchpadExists )
121
+ {
122
+ var success = TouchpadHelper . RegisterInput ( targetSource . Handle ) ;
123
+
124
+ _log . Add ( $ "Precision touchpad registered: { success } ") ;
125
+ }
126
+
127
+ Visibility = Visibility . Hidden ;
128
+ }
129
+
130
+ private IntPtr WndProc ( IntPtr hwnd , int msg , IntPtr wParam , IntPtr lParam , ref bool handled )
131
+ {
132
+ switch ( msg )
133
+ {
134
+ case TouchpadHelper . WM_INPUT :
135
+ var contacts = TouchpadHelper . ParseInput ( lParam ) ;
136
+ _lastTouchTime = DateTimeOffset . UtcNow . ToUnixTimeMilliseconds ( ) ;
137
+ TouchpadContacts = string . Join (
138
+ Environment . NewLine ,
139
+ contacts . Select ( x => x . ToString ( ) )
140
+ ) ;
141
+
142
+ var touchCount = contacts . Length ;
143
+
144
+ if ( touchCount != _touchesShowing )
145
+ {
146
+ _touchesShowing = touchCount ;
147
+ Background = new SolidColorBrush (
148
+ System . Windows . Media . Color . FromRgb ( 144 , 238 , 144 )
149
+ ) ;
150
+ SetIconState ( System . Drawing . Color . Green , touchCount . ToString ( ) . ToCharArray ( ) [ 0 ] ) ;
151
+ }
152
+
153
+ _log . Add ( "---" ) ;
154
+ _log . Add ( TouchpadContacts ) ;
155
+ break ;
156
+ }
157
+ return IntPtr . Zero ;
158
+ }
159
+
160
+ private void Copy_Click ( object sender , RoutedEventArgs e )
161
+ {
162
+ Clipboard . SetText ( string . Join ( Environment . NewLine , _log ) ) ;
163
+ }
164
+
165
+ private void TouchTimerCallback ( object state )
166
+ {
167
+ var now = DateTimeOffset . UtcNow . ToUnixTimeMilliseconds ( ) ;
168
+ if ( now - _lastTouchTime > 100 && _touchesShowing > 0 )
169
+ {
170
+ Dispatcher . Invoke ( ( ) =>
171
+ {
172
+ _touchesShowing = 0 ;
173
+ TouchpadContacts = "" ;
174
+ Background = new SolidColorBrush (
175
+ System . Windows . Media . Color . FromRgb ( 238 , 144 , 144 )
176
+ ) ;
177
+ SetIconState ( System . Drawing . Color . Red , ' ' ) ;
178
+ } ) ;
179
+ }
180
+ }
181
+
182
+ private void RestoreWindow ( )
183
+ {
184
+ Show ( ) ;
185
+ WindowState = WindowState . Normal ;
186
+ Activate ( ) ;
187
+ _notifyIcon . Visible = false ;
188
+ }
189
+
190
+ private void SetIconState ( System . Drawing . Color color , char label )
191
+ {
192
+ using ( var icon = CreateCircleIcon ( color , label ) )
193
+ {
194
+ _notifyIcon . Icon = icon ;
195
+ DestroyIcon ( icon . Handle ) ;
196
+ }
197
+ }
198
+
199
+ private static Icon CreateCircleIcon ( System . Drawing . Color color , char character )
200
+ {
201
+ int size = 32 ;
202
+ using ( var bitmap = new Bitmap ( size , size ) )
203
+ {
204
+ using ( var graphics = Graphics . FromImage ( bitmap ) )
205
+ {
206
+ graphics . Clear ( System . Drawing . Color . Transparent ) ;
207
+
208
+ // Draw the circle with the specified color
209
+ using ( var brush = new SolidBrush ( color ) )
210
+ {
211
+ graphics . FillEllipse ( brush , 0 , 0 , size , size ) ;
212
+ }
213
+
214
+ // Set up the font and brush for the character
215
+ using var font = new Font ( System . Drawing . FontFamily . GenericSansSerif , 6 , System . Drawing . FontStyle . Bold ) ;
216
+ using var textBrush = new SolidBrush ( System . Drawing . Color . White ) ;
217
+ // Measure the size of the character to center it
218
+ SizeF textSize = graphics . MeasureString ( character . ToString ( ) , font ) ;
219
+
220
+ // Calculate the position to center the character
221
+ float x = ( size - textSize . Width ) / 2 ;
222
+ float y = ( size - textSize . Height ) / 2 ;
223
+
224
+ // Draw the character centered on the circle
225
+ graphics . DrawString ( character . ToString ( ) , font , textBrush , x , y ) ;
226
+ }
227
+
228
+ IntPtr hIcon = bitmap . GetHicon ( ) ;
229
+ return System . Drawing . Icon . FromHandle ( hIcon ) ;
230
+ }
231
+ }
232
+
233
+ }
234
+ }
0 commit comments