テンキー押下でWin32アプリのウインドウをキャプチャする。ただしUWPアプリはキャプチャできない。
Revision | 213 (tree) |
---|---|
Time | 2023-04-04 23:05:52 |
Author | hor931101jp |
(empty log message)
@@ -0,0 +1,956 @@ | ||
1 | +/***********************************************************//*! | |
2 | + * @brief メインウインドウ処理 | |
3 | + **************************************************************/ | |
4 | + | |
5 | +using System; | |
6 | +using System.IO; | |
7 | +using System.Collections.Generic; | |
8 | +using System.ComponentModel; | |
9 | +using System.Data; | |
10 | +using System.Drawing; | |
11 | +using System.Linq; | |
12 | +using System.Text; | |
13 | +using System.Threading.Tasks; | |
14 | +using System.Windows.Forms; | |
15 | +using System.Runtime.InteropServices; | |
16 | +using static TenKeyCapture.ClassMyCommon; | |
17 | +using static TenKeyCapture.ClassConfig; | |
18 | +using System.Collections.Concurrent; | |
19 | +using static System.Console; | |
20 | + | |
21 | +namespace TenKeyCapture | |
22 | +{ | |
23 | + /// <summary> | |
24 | + /// メインウインドウのフォーム | |
25 | + /// </summary> | |
26 | + public partial class FormMain : Form | |
27 | + { | |
28 | + private static string PreCSVString = ""; | |
29 | + | |
30 | + [DllImport("user32.dll")] | |
31 | + private static extern IntPtr FindWindowEx(IntPtr hWnd, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); | |
32 | + | |
33 | + // EnumWindowsから呼び出されるコールバック関数WNDENUMPROCのデリゲート | |
34 | + public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lparam); | |
35 | + | |
36 | + [DllImport("user32.dll")] | |
37 | + [return: MarshalAs(UnmanagedType.Bool)] | |
38 | + public extern static bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lparam); //可視判定 | |
39 | + | |
40 | + [DllImport("user32")] | |
41 | + private static extern bool IsWindowVisible(IntPtr hWnd); | |
42 | + | |
43 | + [DllImport("user32", CharSet = CharSet.Auto)] | |
44 | + private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); | |
45 | + | |
46 | + [DllImport("user32", CharSet = CharSet.Auto)] | |
47 | + private static extern int GetWindow(IntPtr hWnd, UInt32 wCmd); | |
48 | + | |
49 | + //public const UInt32 GW_OWNER = 4; | |
50 | + | |
51 | + [StructLayout(LayoutKind.Sequential)] | |
52 | + private struct RECT | |
53 | + { | |
54 | + public int left; | |
55 | + public int top; | |
56 | + public int right; | |
57 | + public int bottom; | |
58 | + } | |
59 | + | |
60 | + [DllImport("user32.dll")] | |
61 | + private static extern int GetWindowRect(IntPtr hwnd, ref RECT lpRect); | |
62 | + | |
63 | + [DllImport("User32.dll")] | |
64 | + private extern static bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags); | |
65 | + | |
66 | + /// <summary>キーボードフック処理インスタンス</summary> | |
67 | + private KeyboardHooker KeyboardHooker1; | |
68 | + | |
69 | + /// <summary>テンキーが押された時の対応するコマンドを格納するインスタンス</summary> | |
70 | + private static ClassTenKeyConfig CurrentTenkeyConfig; | |
71 | + | |
72 | + /// <summary>キャプチャタスクスレッド</summary> | |
73 | + public Task CaptureThread; | |
74 | + | |
75 | + /// <summary> | |
76 | + /// コンストラクタ | |
77 | + /// </summary> | |
78 | + public FormMain() | |
79 | + { | |
80 | + InitializeComponent(); | |
81 | + } | |
82 | + | |
83 | + /// <summary> | |
84 | + /// 終了時の処理 | |
85 | + /// </summary> | |
86 | + /// <param name="sender">未使用。イベントを発生させたオブジェクト</param> | |
87 | + /// <param name="e">未使用。イベントのオプション</param> | |
88 | + private void FormMain_FormClosing(object sender, FormClosingEventArgs e) | |
89 | + { | |
90 | + //! ウインドウポップアップ | |
91 | + Visible = true; | |
92 | + WindowState = FormWindowState.Normal; | |
93 | + TopMost = true; | |
94 | + | |
95 | + Log.Put("終了"); | |
96 | + //! ログを保存する | |
97 | + Log.Save(); | |
98 | + CSV.Save(); | |
99 | + } | |
100 | + | |
101 | + /// <summary> | |
102 | + /// フォームロード時の処理 | |
103 | + /// </summary> | |
104 | + /// <param name="sender">未使用。イベントを発生させたオブジェクト</param> | |
105 | + /// <param name="e">未使用。イベントのオプション</param> | |
106 | + private void FormMain_Load(object sender, EventArgs e) | |
107 | + { | |
108 | + //多重起動チェック | |
109 | + //Process.GetProcessesByName メソッド | |
110 | + //指定したプロセス名を共有するリモートコンピュータ上の | |
111 | + //すべてのプロセスリソースに関連付けます。 | |
112 | + string pn = System.Diagnostics.Process.GetCurrentProcess().ProcessName; //Process.ProcessName プロパティ(プロセスの名前を取得します) | |
113 | + if (System.Diagnostics.Process.GetProcessesByName(pn).GetUpperBound(0) > 0) | |
114 | + { | |
115 | + //! 多重起動しているならばエラーメッセージ表示して終了。 | |
116 | + MessageBox.Show("すでに起動しています。", TITLE + " エラーメッセージ", | |
117 | + MessageBoxButtons.OK, | |
118 | + MessageBoxIcon.Error); | |
119 | + Environment.Exit(0); | |
120 | + } | |
121 | + | |
122 | + frmMain = this; | |
123 | + FormControlBoxCustomize(frmMain); | |
124 | + frmMain.Text = TITLE + " " + VERSION; | |
125 | + Log = new ClassLog(this.textBox1); | |
126 | + | |
127 | + notifyIcon1.Text = TITLE + " " + VERSION; | |
128 | + notifyIcon1.Visible = true; | |
129 | + | |
130 | + //! iniファイルから設定を読み出す | |
131 | + Config.Load(); | |
132 | + | |
133 | + Log.Put("タスクトレイにアイコンを登録しました。"); | |
134 | + | |
135 | + Popup(); | |
136 | + | |
137 | + NowTime = DateTime.Now; | |
138 | + | |
139 | + //! データフォルダ作成 | |
140 | + System.IO.Directory.CreateDirectory(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\"); | |
141 | + | |
142 | + //! ナムロックONにする | |
143 | + SetNumLock(true); | |
144 | + | |
145 | + //! キーボードフック処理インスタンス | |
146 | + KeyboardHooker1 = new KeyboardHooker(); | |
147 | + | |
148 | + //! キャプチャタスク起動 | |
149 | + Task t = CaptureTask(); | |
150 | + Log.Put("キャプチャタスク生成しました。"); | |
151 | + //! サウンドタスク起動 | |
152 | + Task t2 = SoundTask(); | |
153 | + Log.Put("サウンドタスク生成しました。"); | |
154 | + | |
155 | + //! 起動時はウインドウを短時間最前面にもってくる | |
156 | + Show(); | |
157 | + TopMost = true; | |
158 | + WaitTickCount(100); | |
159 | + TopMost = false; | |
160 | + Log.Put("起動完了しました。"); | |
161 | + | |
162 | + button1.PerformClick(); | |
163 | + | |
164 | + Log.Save(); | |
165 | + | |
166 | + } | |
167 | + | |
168 | + /// <summary> | |
169 | + /// Aboutボタンを押された時の処理 | |
170 | + /// オープニングメッセージをログに表示する | |
171 | + /// 設定を表示する | |
172 | + /// サウンドテストを行う | |
173 | + /// </summary> | |
174 | + /// <param name="sender">未使用。イベントを発生させたオブジェクト</param> | |
175 | + /// <param name="e">未使用。イベントのオプション</param> | |
176 | + private async void button1_Click(object sender, EventArgs e) | |
177 | + { | |
178 | + Log.Add("------------------------------------------------------\r\n"); | |
179 | + Log.Add(TITLE + " " + VERSION); | |
180 | + Log.Add(OPENING_MSG); | |
181 | + Log.Put("------------------------------------------------------\r\n"); | |
182 | + | |
183 | + Config.Show(); | |
184 | + | |
185 | + Log.Put("シャッター音のサウンドテストを行います。"); | |
186 | + await Task.Delay(200); | |
187 | + bool addSuccess = SoundQue.TryAdd(true, System.Threading.Timeout.Infinite); | |
188 | + await Task.Delay(500); | |
189 | + Log.Put("ビープ音のサウンドテストを行います。"); | |
190 | + await Task.Delay(200); | |
191 | + addSuccess = SoundQue.TryAdd(false, System.Threading.Timeout.Infinite); | |
192 | + Log.Save(); | |
193 | + } | |
194 | + | |
195 | + /// <summary> | |
196 | + /// Clear Log ボタンを押された時の処理 ログの表示をクリアする | |
197 | + /// </summary> | |
198 | + /// <param name="sender">sender 未使用。イベントを発生させたオブジェクト</param> | |
199 | + /// <param name="e">未使用。イベントのオプション</param> | |
200 | + private void button2_Click(object sender, EventArgs e) | |
201 | + { | |
202 | + Log.Clear(); | |
203 | + Log.Save(); | |
204 | + } | |
205 | + | |
206 | + /// <summary> | |
207 | + /// Data Folder ボタンを押された時の処理 | |
208 | + /// </summary> | |
209 | + /// <param name="sender">未使用。イベントを発生させたオブジェクト</param> | |
210 | + /// <param name="e">未使用。イベントのオプション</param> | |
211 | + private void button3_Click(object sender, EventArgs e) | |
212 | + { | |
213 | + //! データフォルダ作成(ユーザーが消してしまった場合に備えて) | |
214 | + System.IO.Directory.CreateDirectory(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\"); | |
215 | + | |
216 | + //! データフォルダを開く | |
217 | + System.Diagnostics.Process.Start(AppFolder() + "\\" + NowTime.ToString("yyMMdd")); | |
218 | + | |
219 | + Log.Save(); | |
220 | + } | |
221 | + | |
222 | + /// <summary> | |
223 | + /// Quit ボタンを押された時の処理 プログラム終了 | |
224 | + /// </summary> | |
225 | + /// <param name="sender">未使用。イベントを発生させたオブジェクト</param> | |
226 | + /// <param name="e">未使用。イベントのオプション</param> | |
227 | + private void button4_Click(object sender, EventArgs e) | |
228 | + { | |
229 | + Close(); | |
230 | + } | |
231 | + | |
232 | + /// <summary> | |
233 | + /// メインウインドウの最小化時にウインドウを非表示にする | |
234 | + /// </summary> | |
235 | + /// <param name="sender">未使用。イベントを発生させたオブジェクト</param> | |
236 | + /// <param name="e">未使用。イベントのオプション</param> | |
237 | + private void FormMain_Resize(object sender, EventArgs e) | |
238 | + { | |
239 | + if (WindowState == FormWindowState.Minimized) | |
240 | + { | |
241 | + Visible = false; | |
242 | + } | |
243 | + } | |
244 | + | |
245 | + /// <summary> | |
246 | + /// メインウインドウをポップアップする | |
247 | + /// </summary> | |
248 | + private void Popup() | |
249 | + { | |
250 | + Visible = true; | |
251 | + WindowState = FormWindowState.Normal; | |
252 | + //! 短時間かならずトップに表示 | |
253 | + TopMost = true; | |
254 | + WaitTickCount(100); | |
255 | + TopMost = false; | |
256 | + //! 最新ログを表示 | |
257 | + Log.Put(""); | |
258 | + Log.Save(); | |
259 | + } | |
260 | + | |
261 | + /// <summary> | |
262 | + /// タスクトレイアイコンをダブルクリックされたらメインウインドウをポップアップする | |
263 | + /// </summary> | |
264 | + /// <param name="sender">未使用。イベントを発生させたオブジェクト</param> | |
265 | + /// <param name="e">未使用。イベントのオプション</param> | |
266 | + private void notifyIcon1_DoubleClick(object sender, EventArgs e) | |
267 | + { | |
268 | + Popup(); | |
269 | + } | |
270 | + | |
271 | + /// <summary> | |
272 | + /// タスクトレイアイコンメニュの TenKeyCaputer Open をクリックされたときの処理 | |
273 | + /// </summary> | |
274 | + /// <param name="sender">未使用。イベントを発生させたオブジェクト</param> | |
275 | + /// <param name="e">未使用。イベントのオプション</param> | |
276 | + private void tenKeyCaptureOpenToolStripMenuItem_Click(object sender, EventArgs e) | |
277 | + { | |
278 | + Popup(); | |
279 | + } | |
280 | + | |
281 | + /// <summary> | |
282 | + /// タスクトレイアイコンメニュの TenKeyCaputer Open をクリックされたときの処理 | |
283 | + /// </summary> | |
284 | + /// <param name="sender">未使用。イベントを発生させたオブジェクト</param> | |
285 | + /// <param name="e">未使用。イベントのオプション</param> | |
286 | + private void dataFolderToolStripMenuItem_Click(object sender, EventArgs e) | |
287 | + { | |
288 | + //! データフォルダ作成(ユーザーが消してしまった場合に備えて) | |
289 | + System.IO.Directory.CreateDirectory(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\"); | |
290 | + | |
291 | + //! データフォルダを開く | |
292 | + System.Diagnostics.Process.Start(AppFolder() + "\\" + NowTime.ToString("yyMMdd")); | |
293 | + } | |
294 | + | |
295 | + /// <summary> | |
296 | + /// タスクトレイアイコンのメニューからQuitを選択された時の処理 | |
297 | + /// メインウインドウをトップに表示。 | |
298 | + /// </summary> | |
299 | + /// <param name="sender">未使用。イベントを発生させたオブジェクト</param> | |
300 | + /// <param name="e">未使用。イベントのオプション</param> | |
301 | + private void quitToolStripMenuItem_Click(object sender, EventArgs e) | |
302 | + { | |
303 | + Popup(); | |
304 | + Close(); | |
305 | + } | |
306 | + | |
307 | + [DllImport("user32.dll")] | |
308 | + private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo); | |
309 | + | |
310 | + public const byte VK_NUMLOCK = 0x90; | |
311 | + | |
312 | + //public const uint KEYEVENTF_EXTENDEDKEY = 1; | |
313 | + public const int KEYEVENTF_KEYUP = 0x2; | |
314 | + | |
315 | + /// <summary> | |
316 | + /// NumLock状態を変更する | |
317 | + /// </summary> | |
318 | + /// <param name="bOnOffFlag">true=ナムロックON false=ナムロックオフ</param> | |
319 | + private void SetNumLock(Boolean bOnOffFlag) | |
320 | + { | |
321 | + if (Control.IsKeyLocked(Keys.NumLock) != bOnOffFlag) | |
322 | + { | |
323 | + keybd_event(VK_NUMLOCK, 0x45, 0, 0); | |
324 | + keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_KEYUP, 0); | |
325 | + if (bOnOffFlag) | |
326 | + { | |
327 | + Log.Put("NumLock を ON にしました。"); | |
328 | + } | |
329 | + else | |
330 | + { | |
331 | + Log.Put("NumLock を OFF にしました。"); | |
332 | + } | |
333 | + } | |
334 | + } | |
335 | + | |
336 | + /// <summary> | |
337 | + /// キーに応じてWAVファイルを再生するタスク 無限ループ処理 | |
338 | + /// </summary> | |
339 | + /// <returns></returns> | |
340 | + private async Task SoundTask() | |
341 | + { | |
342 | + try | |
343 | + { | |
344 | + System.Media.SoundPlayer player_shutter = new System.Media.SoundPlayer(AppFolder() + "\\" + "shutter.wav"); | |
345 | + System.Media.SoundPlayer player_beep = new System.Media.SoundPlayer(AppFolder() + "\\" + "beep.wav"); | |
346 | + Log.Put("サウンドタスク開始しました。"); | |
347 | + for (; ; ) | |
348 | + { | |
349 | + await Task.Delay(1); | |
350 | + try | |
351 | + { | |
352 | + if (SoundQue.Count > 0) | |
353 | + { | |
354 | + player_shutter.Stop(); | |
355 | + player_beep.Stop(); | |
356 | + Boolean outdata; | |
357 | + bool takeSuccess = SoundQue.TryTake(out outdata, System.Threading.Timeout.Infinite); | |
358 | + if (outdata == true) | |
359 | + { | |
360 | + player_shutter.Play(); | |
361 | + } | |
362 | + else | |
363 | + { | |
364 | + player_beep.Play(); | |
365 | + } | |
366 | + await Task.Delay(250);//最低でもこれだけは鳴らす時間を確保する | |
367 | + } | |
368 | + } | |
369 | + catch (Exception e) | |
370 | + { | |
371 | + Log.Put("SoundTask():Exception" + e.Message); | |
372 | + } | |
373 | + } | |
374 | + } | |
375 | + catch (Exception e) | |
376 | + { | |
377 | + Log.Put("SoundTask():Exception" + e.Message); | |
378 | + } | |
379 | + } | |
380 | + | |
381 | + /// <summary> | |
382 | + /// キャプチャタスク 無限ループ処理 | |
383 | + /// </summary> | |
384 | + /// <returns></returns> | |
385 | + private async Task CaptureTask() | |
386 | + { | |
387 | + Int64 LastTickCount = Environment.TickCount; | |
388 | + Log.Put("キャプチャタスク開始しました。"); | |
389 | + | |
390 | + for (; ; ) | |
391 | + { | |
392 | + await Task.Delay(1); //非ブロッキング API 呼び出し | |
393 | + | |
394 | + if (KeyQue.Count > 0) | |
395 | + { | |
396 | + LastTickCount = Environment.TickCount; | |
397 | + uint KeyCode; | |
398 | + // キューからキーデータを取り出す | |
399 | + bool takeSuccess = KeyQue.TryTake(out KeyCode, System.Threading.Timeout.Infinite); | |
400 | + | |
401 | + try | |
402 | + { | |
403 | + //Log.Put("KeyCode = " + KeyCode); | |
404 | + CurrentTenkeyConfig = null; | |
405 | + | |
406 | + switch (KeyCode) | |
407 | + { | |
408 | + case 96: | |
409 | + CurrentTenkeyConfig = | |
410 | + (from p in TenKeyConfig | |
411 | + where p.KeyCode == "T0" | |
412 | + select p).Single(); | |
413 | + break; | |
414 | + | |
415 | + case 97: | |
416 | + CurrentTenkeyConfig = | |
417 | + (from p in TenKeyConfig | |
418 | + where p.KeyCode == "T1" | |
419 | + select p).Single(); | |
420 | + break; | |
421 | + | |
422 | + case 98: | |
423 | + CurrentTenkeyConfig = | |
424 | + (from p in TenKeyConfig | |
425 | + where p.KeyCode == "T2" | |
426 | + select p).Single(); | |
427 | + break; | |
428 | + | |
429 | + case 99: | |
430 | + CurrentTenkeyConfig = | |
431 | + (from p in TenKeyConfig | |
432 | + where p.KeyCode == "T3" | |
433 | + select p).Single(); | |
434 | + break; | |
435 | + | |
436 | + case 100: | |
437 | + CurrentTenkeyConfig = | |
438 | + (from p in TenKeyConfig | |
439 | + where p.KeyCode == "T4" | |
440 | + select p).Single(); | |
441 | + break; | |
442 | + | |
443 | + case 101: | |
444 | + CurrentTenkeyConfig = | |
445 | + (from p in TenKeyConfig | |
446 | + where p.KeyCode == "T5" | |
447 | + select p).Single(); | |
448 | + break; | |
449 | + | |
450 | + case 102: | |
451 | + CurrentTenkeyConfig = | |
452 | + (from p in TenKeyConfig | |
453 | + where p.KeyCode == "T6" | |
454 | + select p).Single(); | |
455 | + break; | |
456 | + | |
457 | + case 103: | |
458 | + CurrentTenkeyConfig = | |
459 | + (from p in TenKeyConfig | |
460 | + where p.KeyCode == "T7" | |
461 | + select p).Single(); | |
462 | + break; | |
463 | + | |
464 | + case 104: | |
465 | + CurrentTenkeyConfig = | |
466 | + (from p in TenKeyConfig | |
467 | + where p.KeyCode == "T8" | |
468 | + select p).Single(); | |
469 | + break; | |
470 | + | |
471 | + case 105: | |
472 | + CurrentTenkeyConfig = | |
473 | + (from p in TenKeyConfig | |
474 | + where p.KeyCode == "T9" | |
475 | + select p).Single(); | |
476 | + break; | |
477 | + | |
478 | + case 106: | |
479 | + CurrentTenkeyConfig = | |
480 | + (from p in TenKeyConfig | |
481 | + where p.KeyCode == "Tastah" | |
482 | + select p).Single(); | |
483 | + break; | |
484 | + | |
485 | + case 107: | |
486 | + CurrentTenkeyConfig = | |
487 | + (from p in TenKeyConfig | |
488 | + where p.KeyCode == "Tplus" | |
489 | + select p).Single(); | |
490 | + break; | |
491 | + | |
492 | + case 108: | |
493 | + //なし | |
494 | + break; | |
495 | + | |
496 | + case 109: | |
497 | + CurrentTenkeyConfig = | |
498 | + (from p in TenKeyConfig | |
499 | + where p.KeyCode == "Tminus" | |
500 | + select p).Single(); | |
501 | + break; | |
502 | + | |
503 | + case 110: | |
504 | + CurrentTenkeyConfig = | |
505 | + (from p in TenKeyConfig | |
506 | + where p.KeyCode == "Tdot" | |
507 | + select p).Single(); | |
508 | + break; | |
509 | + | |
510 | + case 111: | |
511 | + CurrentTenkeyConfig = | |
512 | + (from p in TenKeyConfig | |
513 | + where p.KeyCode == "Tslash" | |
514 | + select p).Single(); | |
515 | + break; | |
516 | + | |
517 | + default: | |
518 | + break; | |
519 | + } | |
520 | + | |
521 | + if (CurrentTenkeyConfig != null) | |
522 | + { | |
523 | + if (CurrentTenkeyConfig.RollBack == true) | |
524 | + { | |
525 | + CSV.RollBack(); | |
526 | + CaptureRollBack(); | |
527 | + Log.Put("最後の保存データを一つ削除しました。"); | |
528 | + } | |
529 | + else | |
530 | + { | |
531 | + Log.Put(CurrentTenkeyConfig.CSVString.Replace("\r\n", "")); | |
532 | + if (CurrentTenkeyConfig.CaptureFlag == true) | |
533 | + { | |
534 | + NowTime = DateTime.Now; | |
535 | + CaptureWindows(); | |
536 | + CSV.Add("\r\n"); | |
537 | + } | |
538 | + //Log.Put(CurrentTenkeyConfig.KeyCode); | |
539 | + | |
540 | + CSV.Add(CurrentTenkeyConfig.CSVString); | |
541 | + PreCSVString = CurrentTenkeyConfig.CSVString; | |
542 | + } | |
543 | + bool addSuccess = SoundQue.TryAdd(CurrentTenkeyConfig.CaptureFlag, System.Threading.Timeout.Infinite); | |
544 | + } | |
545 | + } | |
546 | + catch (Exception e) | |
547 | + { | |
548 | + Log.Put("CaptureTask():Exception" + e.Message); | |
549 | + } | |
550 | + } | |
551 | + if (Environment.TickCount - LastTickCount < 5000) | |
552 | + { | |
553 | + ; | |
554 | + } | |
555 | + else | |
556 | + { | |
557 | + try | |
558 | + { | |
559 | + SetNumLock(true); | |
560 | + //Log.Put("loop"); | |
561 | + //TaskLoopCount = 0; | |
562 | + Log.Save(); | |
563 | + CSV.Save(); | |
564 | + } | |
565 | + catch (Exception e) | |
566 | + { | |
567 | + Log.Put("CaptureTask():Exception2" + e.Message); | |
568 | + } | |
569 | + NowTime = DateTime.Now; | |
570 | + } | |
571 | + } | |
572 | + } | |
573 | + | |
574 | + /// <summary> | |
575 | + /// 二つのファイルの最終書き込み日時を取得して比較するメソッド | |
576 | + /// </summary> | |
577 | + private int CompareLastWriteTime(string fileX, string fileY) | |
578 | + { | |
579 | + return DateTime.Compare(File.GetLastWriteTime(fileX), File.GetLastWriteTime(fileY)); | |
580 | + } | |
581 | + | |
582 | + /// <summary> | |
583 | + /// キャプチャしたPNGファイルの中で最も新しいグループを一つ削除する | |
584 | + /// </summary> | |
585 | + private void CaptureRollBack() | |
586 | + { | |
587 | + //pngファイルをすべて取得する | |
588 | + var di = new DirectoryInfo(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\"); | |
589 | + var files = di.GetFiles("*.png", SearchOption.AllDirectories); | |
590 | + //pngファイルが一つもなければ終了 | |
591 | + if (files.Length <= 0) | |
592 | + { | |
593 | + return; | |
594 | + } | |
595 | + var filenames = files.Select(x => x.FullName).ToArray(); | |
596 | + | |
597 | + //ファイルの更新日時でソート | |
598 | + Array.Sort(filenames, CompareLastWriteTime); | |
599 | + | |
600 | + //フルパスからファイル名の部分だけをとりだす | |
601 | + var lastfilename = Path.GetFileName(filenames.Last()); | |
602 | + | |
603 | + if (lastfilename == "") | |
604 | + { | |
605 | + return; | |
606 | + } | |
607 | + | |
608 | + //プリフィクス yyMMdd_HHmmssfff 16文字をとりだす | |
609 | + var prefix = Left(lastfilename, 16); | |
610 | + | |
611 | + files = di.GetFiles(prefix + "*.png", SearchOption.AllDirectories); | |
612 | + filenames = files.Select(x => x.FullName).ToArray(); | |
613 | + foreach (var x in filenames) | |
614 | + { | |
615 | + File.Delete(x); | |
616 | + } | |
617 | + } | |
618 | + | |
619 | + /// <summary> | |
620 | + /// UWPアプリのウインドウがEnumWindowsでつかまらないので代用としてFindWindowExを使用する | |
621 | + /// </summary> | |
622 | + /// <param name="lpEnumFunc"></param> | |
623 | + /// <param name="lParam"></param> | |
624 | + private void EnumWindowsWithUWP(EnumWindowsDelegate lpEnumFunc, IntPtr lParam) | |
625 | + { | |
626 | + var hwList = new List<IntPtr>(); | |
627 | + IntPtr childWindow = IntPtr.Zero; | |
628 | + int i = 0; | |
629 | + | |
630 | + while (i < 1000) | |
631 | + { | |
632 | + i++; | |
633 | + childWindow = FindWindowEx(IntPtr.Zero, childWindow, null, null); | |
634 | + if (childWindow == null) | |
635 | + { | |
636 | + return; | |
637 | + } | |
638 | + | |
639 | + if (hwList.Contains(childWindow)) | |
640 | + { | |
641 | + continue; | |
642 | + } | |
643 | + else | |
644 | + { | |
645 | + hwList.Add(childWindow); | |
646 | + } | |
647 | + | |
648 | + if (!lpEnumFunc(childWindow, lParam)) | |
649 | + { | |
650 | + return; | |
651 | + } | |
652 | + } | |
653 | + } | |
654 | + | |
655 | + /// <summary> | |
656 | + /// ウインドウのキャプチャし、最後にスクリーンショットをキャプチャする | |
657 | + /// </summary> | |
658 | + private void CaptureWindows() | |
659 | + { | |
660 | + //! 保存用のデータフォルダが存在しなければ作成 | |
661 | + System.IO.Directory.CreateDirectory(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\"); | |
662 | + //! ウィンドウを列挙し、コールバック関数内で各ウインドウのキャプチャを行う | |
663 | + try | |
664 | + { | |
665 | + //EnumWindows(new EnumWindowsDelegate(EnumWindowCallBack), IntPtr.Zero); | |
666 | + EnumWindowsWithUWP(new EnumWindowsDelegate(EnumWindowCallBack), IntPtr.Zero); | |
667 | + } | |
668 | + catch (Exception e) | |
669 | + { | |
670 | + } | |
671 | + | |
672 | + //デスクトップをキャプチャする | |
673 | + // Bitmapの作成 | |
674 | + Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); | |
675 | + //Graphicsの作成 | |
676 | + Graphics g = Graphics.FromImage(bmp); | |
677 | + //画面全体をコピーする | |
678 | + g.CopyFromScreen(new Point(0, 0), new Point(0, 0), bmp.Size); | |
679 | + //解放 | |
680 | + g.Dispose(); | |
681 | + | |
682 | + var pngfilename = NowTime.ToString("yyMMdd_HHmmssfff") + "_" | |
683 | + + CurrentTenkeyConfig.CSVString.Replace("\r\n", "").Replace(",", "") + "_" | |
684 | + + "screen_00000000_.png"; | |
685 | + | |
686 | + //ファイル名やフォルダ名として不適切な文字を除去してPNGファイル名とする。 | |
687 | + var invalidChars = System.IO.Path.GetInvalidFileNameChars(); | |
688 | + pngfilename = string.Concat(pngfilename.ToString().Where(c => !invalidChars.Contains(c))); | |
689 | + bmp.Save(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\" + pngfilename, System.Drawing.Imaging.ImageFormat.Png); | |
690 | + } | |
691 | + | |
692 | + //public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lparam); | |
693 | + | |
694 | + //[DllImport("user32.dll")] | |
695 | + //[return: MarshalAs(UnmanagedType.Bool)] | |
696 | + //public extern static bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lparam); | |
697 | + | |
698 | + //[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
699 | + //private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); | |
700 | + | |
701 | + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
702 | + private static extern int GetWindowTextLength(IntPtr hWnd); | |
703 | + | |
704 | + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
705 | + private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); | |
706 | + | |
707 | + //[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | |
708 | + //private static extern Boolean IsWindowVisible(IntPtr hWnd); | |
709 | + | |
710 | + [System.Runtime.InteropServices.DllImport("User32.dll")] | |
711 | + private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect); | |
712 | + | |
713 | + // GetDpiForMonitorが返したDPIの種類 | |
714 | + private enum MonitorDpiType | |
715 | + { Effective, Angular, Raw, Default = Effective } | |
716 | + | |
717 | + // MonitorFromWindowが返したディスプレイの種類 | |
718 | + public enum MonitorDefaultTo { Null, Primary, Nearest } | |
719 | + | |
720 | + // ウィンドウハンドルから、そのウィンドウが乗っているディスプレイハンドルを取得 | |
721 | + [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] | |
722 | + private static extern IntPtr MonitorFromWindow(IntPtr hwnd, MonitorDefaultTo dwFlags); | |
723 | + | |
724 | + // ディスプレイハンドルからDPIを取得 | |
725 | + [DllImport("SHCore.dll", CharSet = CharSet.Unicode, PreserveSig = false)] | |
726 | + private static extern void GetDpiForMonitor(IntPtr hmonitor, MonitorDpiType dpiType, ref uint dpiX, ref uint dpiY); | |
727 | + | |
728 | + private static Boolean EnumWindowCallBack(IntPtr hWnd, IntPtr lparam) | |
729 | + { | |
730 | + //visibleでないなら即リターン | |
731 | + if (!IsWindowVisible(hWnd)) | |
732 | + { | |
733 | + return true; | |
734 | + } | |
735 | + | |
736 | + //ウィンドウのタイトルの長さが0以下なら即リターン | |
737 | + int textLen = GetWindowTextLength(hWnd); | |
738 | + if (textLen <= 0) | |
739 | + { | |
740 | + return true; | |
741 | + } | |
742 | + | |
743 | + //ウィンドウのタイトルを取得する | |
744 | + StringBuilder tsb = new StringBuilder(textLen + 1); | |
745 | + GetWindowText(hWnd, tsb, tsb.Capacity); | |
746 | + if (tsb.ToString().Length <= 0) | |
747 | + { | |
748 | + return true; | |
749 | + } | |
750 | + //Log.Put("tsb:" + tsb.ToString()); | |
751 | + | |
752 | + //ウィンドウのタイトルの中にキャプチャしないウインドウタイトルキーワードが含まれているか確認する | |
753 | + foreach (string str in ClassConfig.IgnoreWindowTitles) | |
754 | + { | |
755 | + if (tsb.ToString().IndexOf(str) >= 0) | |
756 | + { | |
757 | + //Log.Put("WindowTitle が " + str + " と一致したのでキャプチャ処理スキップします"); | |
758 | + return true; | |
759 | + } | |
760 | + } | |
761 | + | |
762 | + //ウィンドウのクラス名を取得する | |
763 | + StringBuilder csb = new StringBuilder(256); | |
764 | + GetClassName(hWnd, csb, csb.Capacity); | |
765 | + if (csb.ToString().Length <= 0) | |
766 | + { | |
767 | + return true; | |
768 | + } | |
769 | + //Log.Put("csb:" + csb.ToString()); | |
770 | + | |
771 | + try | |
772 | + { | |
773 | + RECT gWB = new RECT(); ; | |
774 | + if (hWnd.Equals(System.IntPtr.Zero)) | |
775 | + { | |
776 | + return true; | |
777 | + } | |
778 | + else | |
779 | + { | |
780 | +#if true | |
781 | + GetWindowRect(hWnd, ref gWB); | |
782 | + if ((gWB.right - gWB.left) < 100 || (gWB.bottom - gWB.top) < 100) | |
783 | + { | |
784 | + return true; | |
785 | + } | |
786 | +#if false | |
787 | + if (gWB.right < -100 || gWB.bottom < -100) | |
788 | + { | |
789 | + return true; | |
790 | + } | |
791 | +#endif | |
792 | + //Log.Put("----------"); | |
793 | + //Log.Put("タイトル,ハンドル:" + tsb.ToString() + "_" + (((UInt64)hWnd).ToString("x"))); | |
794 | + //Log.Put("left,right,top,bottom:" + gWB.left.ToString() + "," + gWB.right.ToString() + "," + gWB.top.ToString() + "," + gWB.bottom.ToString()); | |
795 | + | |
796 | + // ウィンドウが乗っているディスプレイのハンドルを取得する | |
797 | + var hmonitor = MonitorFromWindow(hWnd, MonitorDefaultTo.Nearest); | |
798 | + | |
799 | + // ディスプレイのDPIを取得する | |
800 | + uint dpiX = 96; | |
801 | + uint dpiY = 96; | |
802 | + GetDpiForMonitor(hmonitor, MonitorDpiType.Default, ref dpiX, ref dpiY); | |
803 | + | |
804 | + float scaleX = dpiX / 96; | |
805 | + float scaleY = dpiY / 96; | |
806 | + var width = (int)(scaleX * (float)(gWB.right - gWB.left)); | |
807 | + var height = (int)(scaleY * (float)(gWB.bottom - gWB.top)); | |
808 | + | |
809 | + using (Bitmap img = new Bitmap(width, height)) | |
810 | + using (Graphics memg = Graphics.FromImage(img)) | |
811 | + { | |
812 | + IntPtr dc = memg.GetHdc(); | |
813 | + | |
814 | + PrintWindow(hWnd, dc, 0); | |
815 | + memg.ReleaseHdc(dc); | |
816 | + //SetAlpha(img, 255); | |
817 | + | |
818 | +#if false | |
819 | + img.Save(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\" | |
820 | + + NowTime.ToString("yyMMdd_HHmmssfff") + "_" | |
821 | + + Tcommand.Replace("[capture]", "").Split(',')[0] + "_" | |
822 | + + tsb.ToString() + "_" | |
823 | + + ((UInt64)hWnd).ToString("X8") | |
824 | + + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg); | |
825 | +#endif | |
826 | +#if false | |
827 | + img.Save(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\" | |
828 | + + NowTime.ToString("yyMMdd_HHmmssfff") + "_" | |
829 | + + Tcommand.Replace("[capture]", "").Split(',')[0] + "_" | |
830 | + + tsb.ToString() + "_" | |
831 | + + ((UInt64)hWnd).ToString("X8") | |
832 | + + ".gif", System.Drawing.Imaging.ImageFormat.Gif); | |
833 | +#endif | |
834 | +#if false | |
835 | + //Format32bppRgb 透明色ありのPNGフォーマット | |
836 | + img.Save(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\" | |
837 | + + NowTime.ToString("yyMMdd_HHmmssfff") + "_" | |
838 | + + Tcommand.Replace("[capture]", "").Split(',')[0] + "_" | |
839 | + + tsb.ToString() + "_" | |
840 | + + ((UInt64)hWnd).ToString("X8") | |
841 | + + ".png", System.Drawing.Imaging.ImageFormat.Png); | |
842 | +#endif | |
843 | + //Format24bppRgb 透明色なしのPNGフォーマット | |
844 | + Rectangle cloneRect = new Rectangle(0, 0, img.Width, img.Height); | |
845 | + Bitmap cloneimg = img.Clone(cloneRect, System.Drawing.Imaging.PixelFormat.Format24bppRgb); | |
846 | + | |
847 | + if (BmpHasColor(cloneimg) == false) | |
848 | + { | |
849 | + //Log.Put("ウインドウ " + tsb.ToString() + " のキャプチャをスキップします。"); | |
850 | + return true; | |
851 | + } | |
852 | + var pngfilename = NowTime.ToString("yyMMdd_HHmmssfff") + "_" | |
853 | + + CurrentTenkeyConfig.CSVString.Replace("\r\n", "").Replace(",", "") + "_" | |
854 | + + tsb.ToString() + "_" | |
855 | + + ((UInt64)hWnd).ToString("X8") | |
856 | + + "_.png"; | |
857 | + | |
858 | + //ファイル名やフォルダ名として不適切な文字を除去してPNGファイル名とする。 | |
859 | + var invalidChars = System.IO.Path.GetInvalidFileNameChars(); | |
860 | + pngfilename = string.Concat(pngfilename.ToString().Where(c => !invalidChars.Contains(c))); | |
861 | + | |
862 | + cloneimg.Save(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\" + pngfilename, System.Drawing.Imaging.ImageFormat.Png); | |
863 | + } | |
864 | +#endif | |
865 | +#if false | |
866 | + GetWindowRect(hWnd, ref gWB); | |
867 | + if ((gWB.right - gWB.left) < 100 || (gWB.bottom - gWB.top) < 100) | |
868 | + { | |
869 | + return true; | |
870 | + } | |
871 | + | |
872 | + RECT rec = new RECT(); | |
873 | + var size = GetClientRect(hWnd, out rec); | |
874 | + | |
875 | + //Log.Put("----------"); | |
876 | + Log.Put("タイトル,ハンドル:" + tsb.ToString() + "_" + (((UInt64)hWnd).ToString("x"))); | |
877 | + //Log.Put("left,right,top,bottom:" + gWB.left.ToString() + "," + gWB.right.ToString() + "," + gWB.top.ToString() + "," + gWB.bottom.ToString()); | |
878 | + | |
879 | + //using (Bitmap img = new Bitmap(gWB.right - gWB.left, gWB.bottom - gWB.top)) | |
880 | + using (Bitmap img = new Bitmap(rec.right - rec.left, rec.bottom)) | |
881 | + using (Graphics memg = Graphics.FromImage(img)) | |
882 | + { | |
883 | + IntPtr dc = memg.GetHdc(); | |
884 | + | |
885 | + PrintWindow(hWnd, dc, 0); | |
886 | + //PrintWindow(hWnd, dc, 1); | |
887 | + memg.ReleaseHdc(dc); | |
888 | + //SetAlpha(img, 255); | |
889 | + //Format24bppRgb 透明色なしのPNGフォーマット | |
890 | + Rectangle cloneRect = new Rectangle(0, 0, img.Width, img.Height); | |
891 | + Bitmap cloneimg = img.Clone(cloneRect, System.Drawing.Imaging.PixelFormat.Format24bppRgb); | |
892 | + | |
893 | + if (BmpHasColor(cloneimg) == false) | |
894 | + { | |
895 | + Log.Put("カラー判定: false ウインドウ " + tsb.ToString() + " のキャプチャをスキップします。"); | |
896 | + //return true; | |
897 | + } | |
898 | + var pngfilename = NowTime.ToString("yyMMdd_HHmmssfff") + "_" | |
899 | + + CurrentTenkeyConfig.CSVString.Replace("\r\n", "").Replace(",", "") + "_" | |
900 | + + tsb.ToString() + "_" | |
901 | + + ((UInt64)hWnd).ToString("X8") | |
902 | + + "_.png"; | |
903 | + | |
904 | + //ファイル名やフォルダ名として不適切な文字を除去してPNGファイル名とする。 | |
905 | + var invalidChars = System.IO.Path.GetInvalidFileNameChars(); | |
906 | + pngfilename = string.Concat(pngfilename.ToString().Where(c => !invalidChars.Contains(c))); | |
907 | + | |
908 | + //cloneimg.Save(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\" + pngfilename, System.Drawing.Imaging.ImageFormat.Png); | |
909 | + img.Save(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\" + pngfilename, System.Drawing.Imaging.ImageFormat.Png); | |
910 | + | |
911 | + Log.Put("保存: " + pngfilename); | |
912 | + } | |
913 | +#endif | |
914 | + } | |
915 | + } | |
916 | + catch (Exception e) | |
917 | + { | |
918 | + Log.Put("EnuWindowCallBack():Exception " + e.Message); | |
919 | + Log.Put("EnuWindowCallBack():tsb " + tsb.ToString()); | |
920 | + } | |
921 | + return true; | |
922 | + } | |
923 | + | |
924 | +#if false | |
925 | + /***********************************************************//*! | |
926 | + * @brief αチャンネルを指定する | |
927 | + * @param[in] bmp αチャンネルを指定するビットマップデータ | |
928 | + * @param[in] alpha αチャンネル値 0:完全透過~255:完全不透過 | |
929 | + **************************************************************/ | |
930 | + public static void SetAlpha(Bitmap bmp, byte alpha) | |
931 | + { | |
932 | + if (bmp == null) throw new ArgumentNullException("bmp"); | |
933 | + | |
934 | + var data = bmp.LockBits( | |
935 | + new Rectangle(0, 0, bmp.Width, bmp.Height), | |
936 | + System.Drawing.Imaging.ImageLockMode.ReadWrite, | |
937 | + System.Drawing.Imaging.PixelFormat.Format32bppArgb); | |
938 | + | |
939 | + var line = data.Scan0; | |
940 | + var eof = line + data.Height * data.Stride; | |
941 | + while (line != eof) | |
942 | + { | |
943 | + var pixelAlpha = line + 3; | |
944 | + var eol = pixelAlpha + data.Width * 4; | |
945 | + while (pixelAlpha != eol) | |
946 | + { | |
947 | + Marshal.WriteByte(pixelAlpha, alpha); | |
948 | + pixelAlpha += 4; | |
949 | + } | |
950 | + line += data.Stride; | |
951 | + } | |
952 | + bmp.UnlockBits(data); | |
953 | + } | |
954 | +#endif | |
955 | + } | |
956 | +} | |
\ No newline at end of file |
@@ -0,0 +1,235 @@ | ||
1 | +/***********************************************************//*! | |
2 | + * @brief 共通部品 | |
3 | + **************************************************************/ | |
4 | + | |
5 | +using System; | |
6 | +using System.Collections.Generic; | |
7 | +using System.Linq; | |
8 | +using System.Text; | |
9 | +using System.Threading.Tasks; | |
10 | +using System.Windows; | |
11 | +using System.Windows.Forms; | |
12 | +using System.Collections.Concurrent; | |
13 | +using static System.Console; | |
14 | + | |
15 | +namespace TenKeyCapture | |
16 | +{ | |
17 | + /// <summary> | |
18 | + /// 共通部品クラス よく使う処理とかオブジェクトを定義 | |
19 | + /// </summary> | |
20 | + internal class ClassMyCommon | |
21 | + { | |
22 | + //! プログラムのタイトル | |
23 | + public const string TITLE = "TenKeyCapture"; | |
24 | + | |
25 | + //! プログラムのバージョン | |
26 | + public const string VERSION = "01.03-200226"; | |
27 | + | |
28 | + //! プログラム開始時の表示メッセージ | |
29 | + public const string OPENING_MSG | |
30 | + = "Programmed by S.Hori\r\n" | |
31 | + + "\r\n" | |
32 | + + "下記のWEBサイトから最新版を入手できます。\r\n" | |
33 | + + "https://osdn.net/users/hor931101jp/pf/02 \r\n" | |
34 | + + "下記のSVNリポジトリからソースコードをチェックアウトできます。\r\n" | |
35 | + + "svn://svn.pf.osdn.net/h/ho/hor931101jp/02/tags \r\n"; | |
36 | + | |
37 | + //! メインフォームのインスタンス | |
38 | + public static Form frmMain; | |
39 | + | |
40 | + //!設定用インスタンス宣言と生成 | |
41 | + public static ClassConfig Config = new ClassConfig(); | |
42 | + | |
43 | + //! ログの管理インスタンス | |
44 | + public static ClassLog Log; | |
45 | + | |
46 | + //! CSVの管理インスタンス | |
47 | + public static ClassCSV CSV = new ClassCSV(); | |
48 | + | |
49 | + //! キーボードの設定管理インスタンス | |
50 | + public static ClassTenKeyConfig[] TenKeyConfig = { | |
51 | + new ClassTenKeyConfig("T0"), | |
52 | + new ClassTenKeyConfig("T1"), | |
53 | + new ClassTenKeyConfig("T2"), | |
54 | + new ClassTenKeyConfig("T3"), | |
55 | + new ClassTenKeyConfig("T4"), | |
56 | + new ClassTenKeyConfig("T5"), | |
57 | + new ClassTenKeyConfig("T6"), | |
58 | + new ClassTenKeyConfig("T7"), | |
59 | + new ClassTenKeyConfig("T8"), | |
60 | + new ClassTenKeyConfig("T9"), | |
61 | + new ClassTenKeyConfig("Tslash"), | |
62 | + new ClassTenKeyConfig("Tastah"), | |
63 | + new ClassTenKeyConfig("Tminus"), | |
64 | + new ClassTenKeyConfig("Tplus"), | |
65 | + new ClassTenKeyConfig("Tdot"), | |
66 | + }; | |
67 | + | |
68 | + //! 現在時刻格納変数 | |
69 | + public static DateTime NowTime = DateTime.Now; | |
70 | + | |
71 | + //! サウンドリクエストのキュー(trueならキャプチャ音 falseならBEEP音) | |
72 | + public static BlockingCollection<Boolean> SoundQue = new BlockingCollection<Boolean>(); | |
73 | + | |
74 | + //! キーコードを格納するキュー | |
75 | + public static BlockingCollection<uint> KeyQue = new BlockingCollection<uint>(); | |
76 | + | |
77 | + /// <summary> | |
78 | + /// Application.DoEventsとThread.Sleepをしながら待機 | |
79 | + /// </summary> | |
80 | + /// <param name="WaitTime">待ち時間[ms]</param> | |
81 | + static public void WaitTickCount(Int32 WaitTime) | |
82 | + { | |
83 | + Int64 StartTickCount = Environment.TickCount; | |
84 | + Int64 NowTickCount; | |
85 | + do | |
86 | + { | |
87 | + Application.DoEvents(); | |
88 | + System.Threading.Thread.Sleep(1); | |
89 | + NowTickCount = Environment.TickCount; | |
90 | + } | |
91 | + while ((NowTickCount - StartTickCount) < WaitTime); | |
92 | + } | |
93 | + | |
94 | + [System.Runtime.InteropServices.DllImport("user32.dll")] | |
95 | + private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); | |
96 | + | |
97 | + [System.Runtime.InteropServices.DllImport("user32.dll")] | |
98 | + private static extern bool DrawMenuBar(IntPtr hWnd); | |
99 | + | |
100 | + [System.Runtime.InteropServices.DllImport("user32.dll")] | |
101 | + private static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags); | |
102 | + | |
103 | + /// <summary> | |
104 | + /// フォームの右上ボタンと左上メニューのカスタマイズ | |
105 | + /// フォーム右上ボタンのうち[x]ボタンを無効化する。左上メニューの[閉じる]を消去 | |
106 | + /// </summary> | |
107 | + /// <param name="f">対象とするフォーム</param> | |
108 | + public static void FormControlBoxCustomize(Form f) | |
109 | + { | |
110 | + //const uint SC_SIZE = 0xF000; //システムメニューの「サイズ変更」 | |
111 | + //const uint SC_MOVE = 0xF010; //システムメニューの「移動」 | |
112 | + //const uint SC_MINIMIZE = 0xF020; //システムメニューの「最小化」 | |
113 | + //const uint SC_MAXIMIZE = 0xF030; //システムメニューの「最大化」 | |
114 | + const uint SC_CLOSE = 0xF060; //システムメニューの「閉じる」 | |
115 | + //const uint SC_RESTORE = 0xF120; //システムメニューの「元のサイズに戻す」 | |
116 | + const uint MF_BYCOMMAND = 0x0; //メニュー項目指定 | |
117 | + const uint MF_BYPOSITION = 0x400; //ポジション指定 | |
118 | + //const uint MF_ENABLED = 0x0; //有効化 | |
119 | + //const uint MF_GRAYED = 0x1; //無効化 | |
120 | + //const uint MF_DISABLED = 0x2; //半無効化(見かけ上有効) | |
121 | + bool DUMMY; | |
122 | + | |
123 | + //「区切り線」の削除 | |
124 | + DUMMY = RemoveMenu(GetSystemMenu(f.Handle, false), 5, MF_BYPOSITION); | |
125 | + //「閉じる」の削除 + xボタンの無効化 | |
126 | + DUMMY = RemoveMenu(GetSystemMenu(f.Handle, false), SC_CLOSE, MF_BYCOMMAND); | |
127 | + //描画(変更を反映) | |
128 | + DUMMY = DrawMenuBar(f.Handle); | |
129 | + } | |
130 | + | |
131 | + /// <summary> | |
132 | + /// 自身の exe ファイルの存在するフォルダを返す | |
133 | + /// </summary> | |
134 | + /// <returns>自身の exe ファイルの存在するフォルダパス 最後に '\' なし</returns> | |
135 | + public static string AppFolder() | |
136 | + { | |
137 | + return System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); | |
138 | + } | |
139 | + | |
140 | + /// <summary> | |
141 | + /// 文字列を渡して先頭から指定した長さだけの文字列を切り出して返す | |
142 | + /// BASICに昔からある Left$ 関数 | |
143 | + /// </summary> | |
144 | + /// <param name="str">文字列</param> | |
145 | + /// <param name="len">長さ</param> | |
146 | + /// <returns>切り出した文字列</returns> | |
147 | + public static string Left(string str, int len) | |
148 | + { | |
149 | + if (len < 0) | |
150 | + { | |
151 | + throw new ArgumentException("引数'len'は0以上でなければなりません。"); | |
152 | + } | |
153 | + if (str == null) | |
154 | + { | |
155 | + return ""; | |
156 | + } | |
157 | + if (str.Length <= len) | |
158 | + { | |
159 | + return str; | |
160 | + } | |
161 | + return str.Substring(0, len); | |
162 | + } | |
163 | + | |
164 | + /// <summary> | |
165 | + /// 文字列の末尾から指定した長さの文字列を取得する | |
166 | + /// BASICに昔からある Right$ 関数 | |
167 | + /// </summary> | |
168 | + /// <param name="str">文字列</param> | |
169 | + /// <param name="len">長さ</param> | |
170 | + /// <returns>切り出した文字列</returns> | |
171 | + public static string Right(string str, int len) | |
172 | + { | |
173 | + if (len < 0) | |
174 | + { | |
175 | + throw new ArgumentException("引数'len'は0以上でなければなりません。"); | |
176 | + } | |
177 | + if (str == null) | |
178 | + { | |
179 | + return ""; | |
180 | + } | |
181 | + if (str.Length <= len) | |
182 | + { | |
183 | + return str; | |
184 | + } | |
185 | + return str.Substring(str.Length - len, len); | |
186 | + } | |
187 | + | |
188 | + /// <summary> | |
189 | + /// Bitmapが真っ黒でないか判定する | |
190 | + /// </summary> | |
191 | + /// <param name="bmp">bitmapデータ</param> | |
192 | + /// <returns>true ちゃんとした色がある。 false 真っ黒</returns> | |
193 | + public static Boolean BmpHasColor(System.Drawing.Bitmap bmp) | |
194 | + { | |
195 | + var retval = false; | |
196 | + | |
197 | + //ビットマップデータをアンマネージ配列にコピーしてから処理する | |
198 | + System.Drawing.Imaging.BitmapData data = bmp.LockBits( | |
199 | + new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), | |
200 | + System.Drawing.Imaging.ImageLockMode.ReadWrite, | |
201 | + System.Drawing.Imaging.PixelFormat.Format32bppArgb); | |
202 | + byte[] buf = new byte[bmp.Width * bmp.Height * 4]; | |
203 | + System.Runtime.InteropServices.Marshal.Copy(data.Scan0, buf, 0, buf.Length); | |
204 | + | |
205 | + //取得したBMPが真っ黒かどうか確認する。ただしすべてのピクセルを確認すると時間かかるので、skiplenだけスキップして100箇所のみ確認する。 | |
206 | + var skiplen = ((UInt32)(buf.Length / 100)) & 0xfffffffc - 4; //skiplenは4の倍数でなければならない | |
207 | + if (skiplen < 0) skiplen = 0; | |
208 | + | |
209 | + for (UInt32 i = 0; i < buf.Length;) | |
210 | + { | |
211 | + //黒であれば R=G=B=0 Alpha=Don't Care | |
212 | + if (buf[i++] != 0) | |
213 | + { | |
214 | + retval = true; | |
215 | + break; | |
216 | + } | |
217 | + if (buf[i++] != 0) | |
218 | + { | |
219 | + retval = true; | |
220 | + break; | |
221 | + } | |
222 | + if (buf[i++] != 0) | |
223 | + { | |
224 | + retval = true; | |
225 | + break; | |
226 | + } | |
227 | + i++; | |
228 | + i += skiplen; | |
229 | + } | |
230 | + bmp.UnlockBits(data); | |
231 | + | |
232 | + return retval; | |
233 | + } | |
234 | + } | |
235 | +} | |
\ No newline at end of file |
@@ -0,0 +1,72 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> | |
3 | + <assemblyIdentity version="1.0.0.0" name="MyApplication.app" /> | |
4 | + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> | |
5 | + <security> | |
6 | + <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> | |
7 | + <!-- UAC マニフェスト オプション | |
8 | + Windows のユーザー アカウント制御のレベルを変更するには、 | |
9 | + requestedExecutionLevel ノードを以下のいずれかで置換します。 | |
10 | + | |
11 | + <requestedExecutionLevel level="asInvoker" uiAccess="false" /> | |
12 | + <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> | |
13 | + <requestedExecutionLevel level="highestAvailable" uiAccess="false" /> | |
14 | + | |
15 | + requestedExecutionLevel 要素を指定すると、ファイルおよびレジストリの仮想化が無効にされます。 | |
16 | + アプリケーションが下位互換性を保つためにこの仮想化を要求する場合、この要素を | |
17 | + 削除します。 | |
18 | + --> | |
19 | + <requestedExecutionLevel level="asInvoker" uiAccess="false" /> | |
20 | + </requestedPrivileges> | |
21 | + </security> | |
22 | + </trustInfo> | |
23 | + | |
24 | + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> | |
25 | + <application> | |
26 | + <!-- このアプリケーションがテストされ、動作するよう設計された Windows バージョンの | |
27 | + 一覧。適切な要素をコメント解除すると、最も互換性のある環境を Windows が | |
28 | + 自動的に選択します。--> | |
29 | + | |
30 | + <!-- Windows Vista --> | |
31 | + <!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />--> | |
32 | + | |
33 | + <!-- Windows 7 --> | |
34 | + <!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />--> | |
35 | + | |
36 | + <!-- Windows 8 --> | |
37 | + <!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />--> | |
38 | + | |
39 | + <!-- Windows 8.1 --> | |
40 | + <!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />--> | |
41 | + | |
42 | + <!-- Windows 10 --> | |
43 | + <!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />--> | |
44 | + </application> | |
45 | + </compatibility> | |
46 | + | |
47 | + <!-- アプリケーションが DPI 対応であり、それ以上の DPI で Windows によって自動的にスケーリングされないことを | |
48 | + 示します。Windows Presentation Foundation (WPF) アプリケーションは自動的に DPI に対応し、オプトインする必要は | |
49 | + ありません。さらに、この設定にオプトインする .NET Framework 4.6 を対象とする Windows Forms アプリケーションは、 | |
50 | + app.config ファイルで 'EnableWindowsFormsHighDpiAutoResizing' 設定を 'true' に設定する必要があります。--> | |
51 | + | |
52 | + <application xmlns="urn:schemas-microsoft-com:asm.v3"> | |
53 | + <windowsSettings> | |
54 | + <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">per monitor</dpiAware> | |
55 | + </windowsSettings> | |
56 | + </application> | |
57 | + | |
58 | + <!-- Windows のコモン コントロールとダイアログのテーマを有効にします (Windows XP 以降) --> | |
59 | + <!-- | |
60 | + <dependency> | |
61 | + <dependentAssembly> | |
62 | + <assemblyIdentity | |
63 | + type="win32" | |
64 | + name="Microsoft.Windows.Common-Controls" | |
65 | + version="6.0.0.0" | |
66 | + processorArchitecture="*" | |
67 | + publicKeyToken="6595b64144ccf1df" | |
68 | + language="*" /> | |
69 | + </dependentAssembly> | |
70 | + </dependency> | |
71 | + --> | |
72 | +</assembly> | |
\ No newline at end of file |
@@ -0,0 +1,127 @@ | ||
1 | +using System; | |
2 | +using System.IO; | |
3 | +using System.Collections.Generic; | |
4 | +using System.Linq; | |
5 | +using System.Text; | |
6 | +using System.Threading.Tasks; | |
7 | +using static TenKeyCapture.ClassMyCommon; | |
8 | + | |
9 | +namespace TenKeyCapture | |
10 | +{ | |
11 | + /// <summary> | |
12 | + /// CSVクラス CSVを管理する | |
13 | + /// </summary> | |
14 | + internal class ClassCSV | |
15 | + { | |
16 | + ///<summary>CSVファイル保存用の文字列を確保する</summary> | |
17 | + private string _ShadowBuf = ""; | |
18 | + | |
19 | + /// <summary> | |
20 | + /// CSVに保存する文字列を一時的に文字列に保存する。 | |
21 | + /// </summary> | |
22 | + /// <param name="stradd">テンキーに設定された文字列</param> | |
23 | + public void Add(string stradd) | |
24 | + { | |
25 | + //! 改行 [CR][LF] 0D 0A があったときはタイムスタンプを追加 | |
26 | + string straddCSV = stradd.Replace("\r\n", NowTime.ToString("\r\nHH:mm:ss,")); | |
27 | + | |
28 | + _ShadowBuf += straddCSV; | |
29 | + //Log.Put("CSVadd() " + straddCSV); | |
30 | + } | |
31 | + | |
32 | + /// <summary> | |
33 | + /// CSV最後の一行削除 | |
34 | + /// </summary> | |
35 | + public void RollBack() | |
36 | + { | |
37 | + string str = ""; | |
38 | + try | |
39 | + { | |
40 | + //! 読み込み | |
41 | + using (var sr = new StreamReader( | |
42 | + AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\" + NowTime.ToString("yyMMdd") + ".csv" | |
43 | + , Encoding.GetEncoding("shift_jis") | |
44 | + ) | |
45 | + ) | |
46 | + { | |
47 | + str = sr.ReadToEnd(); | |
48 | + } | |
49 | + } | |
50 | + catch (Exception ex) | |
51 | + { | |
52 | + //Log.Put(ex.Message); | |
53 | + } | |
54 | + | |
55 | + str += _ShadowBuf; | |
56 | + if (str.Length <= 0) | |
57 | + { | |
58 | + return; | |
59 | + } | |
60 | + | |
61 | + string[] sep = { "\r\n" };//Separater | |
62 | + string[] arr = str.Split(sep, StringSplitOptions.None); | |
63 | + | |
64 | + str = arr[0]; | |
65 | + for (int i = 1; i < (arr.Length - 1); i++) | |
66 | + { | |
67 | + str += "\r\n" + arr[i]; | |
68 | + } | |
69 | + | |
70 | + //! 上書きモードで書き込み | |
71 | + using (StreamWriter sw = new StreamWriter( | |
72 | + AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\" + NowTime.ToString("yyMMdd") + ".csv", | |
73 | + false, | |
74 | + Encoding.GetEncoding("shift_jis") | |
75 | + ) | |
76 | + ) | |
77 | + { | |
78 | + sw.Write(str); | |
79 | + } | |
80 | + _ShadowBuf = ""; | |
81 | + } | |
82 | + | |
83 | + /// <summary>CSVファイル保存失敗したときの時刻</summary> | |
84 | + private static Int64 ErrorTickCount = 0; | |
85 | + | |
86 | + /// <summary> | |
87 | + /// CSVに保存 | |
88 | + /// </summary> | |
89 | + public void Save() | |
90 | + { | |
91 | + if (_ShadowBuf.Length == 0) | |
92 | + { | |
93 | + return; | |
94 | + } | |
95 | + //Log.Put("CSV.Save()"); | |
96 | + | |
97 | + //CSVファイル保存失敗したときは10秒間は保存しない。 | |
98 | + if ((Environment.TickCount - ErrorTickCount) < 10000) | |
99 | + { | |
100 | + return; | |
101 | + } | |
102 | + | |
103 | + try | |
104 | + { | |
105 | + //! データフォルダ作成(ユーザーが消してしまった場合に備えて) | |
106 | + Directory.CreateDirectory(AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\"); | |
107 | + | |
108 | + //! 追記モードで書き込み | |
109 | + using (StreamWriter sw = new StreamWriter( | |
110 | + AppFolder() + "\\" + NowTime.ToString("yyMMdd") + "\\" + NowTime.ToString("yyMMdd") + ".csv", | |
111 | + true, | |
112 | + Encoding.GetEncoding("shift_jis") | |
113 | + ) | |
114 | + ) | |
115 | + { | |
116 | + sw.Write(_ShadowBuf); | |
117 | + } | |
118 | + _ShadowBuf = ""; | |
119 | + } | |
120 | + catch (Exception e) | |
121 | + { | |
122 | + Log.Put("CSVファイルの保存に失敗しました。" + e.Message); | |
123 | + ErrorTickCount = Environment.TickCount; | |
124 | + } | |
125 | + } | |
126 | + } | |
127 | +} | |
\ No newline at end of file |
@@ -0,0 +1,299 @@ | ||
1 | +/***********************************************************//*! | |
2 | + * @brief 設定管理 | |
3 | + **************************************************************/ | |
4 | + | |
5 | +using System; | |
6 | +using System.IO; | |
7 | +using System.Collections.Generic; | |
8 | +using System.Linq; | |
9 | +using System.Text; | |
10 | +using System.Threading.Tasks; | |
11 | +using static TenKeyCapture.ClassMyCommon; | |
12 | +using System.Xml.Linq; | |
13 | + | |
14 | +namespace TenKeyCapture | |
15 | +{ | |
16 | + /// <summary> | |
17 | + /// キーボード設定管理クラス | |
18 | + /// </summary> | |
19 | + internal class ClassTenKeyConfig | |
20 | + { | |
21 | + /// <summary>キーが押された時にCSVに記入する文字列</summary> | |
22 | + public string CSVString; | |
23 | + | |
24 | + /// <summary>キーが押された時にキャプチャするかどうかのフラグ</summary> | |
25 | + public Boolean CaptureFlag; | |
26 | + | |
27 | + /// <summary>キーの識別文字列</summary> | |
28 | + public string KeyCode; | |
29 | + | |
30 | + /// <summary>キーが押された時に直前のキー入力をキャンセルするかどうかのフラグ</summary> | |
31 | + public Boolean RollBack; | |
32 | + | |
33 | + /// <summary> | |
34 | + /// コンストラクタ キーボード設定管理クラス | |
35 | + /// </summary> | |
36 | + /// <param name="SetKeyCode">キー識別用コード</param> | |
37 | + public ClassTenKeyConfig(string SetKeyCode) | |
38 | + { | |
39 | + KeyCode = SetKeyCode; | |
40 | + CSVString = "\r\n"; | |
41 | + CaptureFlag = true; | |
42 | + RollBack = false; | |
43 | + } | |
44 | + } | |
45 | + | |
46 | + /// <summary> | |
47 | + /// 設定管理クラス | |
48 | + /// </summary> | |
49 | + internal class ClassConfig | |
50 | + { | |
51 | + /// <summary>設定データ格納ファイル名(フルパス付き)</summary> | |
52 | + private string APPini = AppFolder() + "\\" + TITLE + ".ini"; | |
53 | + | |
54 | + /// <summary>デバッグフラグ</summary> | |
55 | + public Int16 DebugFlag = 0; | |
56 | + | |
57 | + /// <summary>ウインドウタイトルに下記の文字列が含まれていた場合キャプチャ対象外となる</summary> | |
58 | + public static string[] IgnoreWindowTitles = { "" }; | |
59 | + | |
60 | + /// <summary> | |
61 | + /// 設定xmlファイルから設定データ読み出し | |
62 | + /// </summary> | |
63 | + public void Load() | |
64 | + { | |
65 | + try | |
66 | + { | |
67 | + //! INIファイルがあるか判定する。なければ初期値でINIファイルを生成する。 | |
68 | + if (!File.Exists(APPini)) | |
69 | + { | |
70 | + SaveIni(); | |
71 | + } | |
72 | + | |
73 | + // INIファイルを読みだす。 | |
74 | + var xmlsource = XDocument.Load(APPini); | |
75 | + | |
76 | + //Log.Put("App.ini LOAD" + "\r\n" + xmlsource + "\r\n"); | |
77 | + | |
78 | + var skip = false; | |
79 | + | |
80 | + // INIファイルの中身を解釈する | |
81 | + foreach (ClassTenKeyConfig c in TenKeyConfig) | |
82 | + { | |
83 | + var Element1 = (from p in xmlsource.Elements("APPini").Elements("TenKeyConfig") | |
84 | + where p.Element("KeyCode").Value == c.KeyCode | |
85 | + select p).Single(); | |
86 | + if (Element1 != null) | |
87 | + { | |
88 | + string xmlvalue; | |
89 | + try | |
90 | + { | |
91 | + xmlvalue = Element1.Element("CSVString").Value; | |
92 | + c.CSVString = xmlvalue; | |
93 | + } | |
94 | + catch (Exception e) | |
95 | + { | |
96 | + Log.Put(c.KeyCode + ".CSVString の読込をスキップしました。"); | |
97 | + skip = true; | |
98 | + } | |
99 | + | |
100 | + try | |
101 | + { | |
102 | + xmlvalue = Element1.Element("CaptureFlag").Value; | |
103 | + c.CaptureFlag = Convert.ToBoolean(xmlvalue); | |
104 | + } | |
105 | + catch (Exception e) | |
106 | + { | |
107 | + Log.Put(c.KeyCode + ".CaptureFlag の読込をスキップしました。"); | |
108 | + skip = true; | |
109 | + } | |
110 | + | |
111 | + try | |
112 | + { | |
113 | + xmlvalue = Element1.Element("RollBack").Value; | |
114 | + c.RollBack = Convert.ToBoolean(xmlvalue); | |
115 | + } | |
116 | + catch (Exception e) | |
117 | + { | |
118 | + Log.Put(c.KeyCode + ".RollBack の読込をスキップしました。"); | |
119 | + skip = true; | |
120 | + } | |
121 | + } | |
122 | + } | |
123 | + | |
124 | + var Element2 = (from p in xmlsource.Elements("APPini").Elements("IgnoreWindowTitles") | |
125 | + select p).Single(); | |
126 | + IgnoreWindowTitles = Element2.Value.Split(','); | |
127 | + | |
128 | + //読み込みがスキップした場合は現状の設定でConfig.iniを生成する。 | |
129 | + if (skip) | |
130 | + { | |
131 | + Config.Save(); | |
132 | + } | |
133 | + } | |
134 | + catch (Exception ex) | |
135 | + { | |
136 | + Log.Put("Error:Config.Load()"); | |
137 | + Log.Put("ex.Message\r\n" + ex.Message); | |
138 | + Log.Put("ex.StacTrace\r\n" + ex.StackTrace); | |
139 | + } | |
140 | + } | |
141 | + | |
142 | + /// <summary> | |
143 | + /// 設定データ表示 | |
144 | + /// </summary> | |
145 | + public void Show() | |
146 | + { | |
147 | + // 読み出した結果を表示 | |
148 | + Log.Put("設定は以下の通りです。"); | |
149 | + foreach (ClassTenKeyConfig c in TenKeyConfig) | |
150 | + { | |
151 | + Log.Put(c.KeyCode); | |
152 | + Log.Put("RollBack = " + c.RollBack); | |
153 | + Log.Put("CaptureFlag = " + c.CaptureFlag); | |
154 | + Log.Put("CSVString = " + c.CSVString); | |
155 | + c.CSVString = c.CSVString.Replace("\\n", "\r\n"); | |
156 | + } | |
157 | + | |
158 | + // IgnoreWindowTitles配列内のデータをすべてカンマ区切りで連結する | |
159 | + Log.Put("IgnoreWindowTitle = \"" + string.Join(",", IgnoreWindowTitles) + "\""); | |
160 | + } | |
161 | + | |
162 | + /// <summary> | |
163 | + /// xmlファイルへ設定データのを書き込み | |
164 | + /// </summary> | |
165 | + public void Save() | |
166 | + { | |
167 | + var XDoc = new XDocument( | |
168 | + new XDeclaration("1.0", "utf-8", "true") | |
169 | + , new XComment("[重要]このファイルを編集する前に必ず TenKeyCapture を終了させてください。") | |
170 | + ); | |
171 | + | |
172 | + var APPini_element = new XElement("APPini"); | |
173 | + APPini_element.Add(new XElement("APPini_VERSION", "01.10")); | |
174 | + | |
175 | + foreach (var x in TenKeyConfig) | |
176 | + { | |
177 | + // W3C勧告によるとXMLファイル内での改行コードは \n であるべきらしいので変換する。 | |
178 | + var xCSVString = x.CSVString.Replace("\r\n", @"\n"); | |
179 | + | |
180 | + APPini_element.Add( | |
181 | + new XElement("TenKeyConfig", | |
182 | + new XElement("KeyCode", x.KeyCode), | |
183 | + new XElement("CSVString", xCSVString), | |
184 | + new XElement("RollBack", x.RollBack), | |
185 | + new XElement("CaptureFlag", x.CaptureFlag) | |
186 | + ) | |
187 | + ); | |
188 | + } | |
189 | + APPini_element.Add(new XElement("IgnoreWindowTitles", string.Join(",", IgnoreWindowTitles))); | |
190 | + XDoc.Add(APPini_element); | |
191 | + XDoc.Save(APPini); | |
192 | + } | |
193 | + | |
194 | + /// <summary> | |
195 | + /// xmlファイルへ設定データの初期値を書き込み | |
196 | + /// </summary> | |
197 | + public void SaveIni() | |
198 | + { | |
199 | + var XDoc = new XDocument(new XDeclaration("1.0", "utf-8", "true"), | |
200 | + new XComment("[重要]このファイルを編集する前に必ず TenKeyCapture を終了させてください。"), | |
201 | + new XElement("APPini", | |
202 | + new XElement("APPini_VERSION", "01.10"), | |
203 | + new XElement("TenKeyConfig", | |
204 | + new XElement("KeyCode", "T0"), | |
205 | + new XElement("CSVString", "静止物,"), | |
206 | + new XElement("RollBack", false), | |
207 | + new XElement("CaptureFlag", false) | |
208 | + ), | |
209 | + new XElement("TenKeyConfig", | |
210 | + new XElement("KeyCode", "T1"), | |
211 | + new XElement("CSVString", "左後,,,"), | |
212 | + new XElement("RollBack", false), | |
213 | + new XElement("CaptureFlag", true) | |
214 | + ), | |
215 | + new XElement("TenKeyConfig", | |
216 | + new XElement("KeyCode", "T2"), | |
217 | + new XElement("CSVString", "真後,,,"), | |
218 | + new XElement("RollBack", false), | |
219 | + new XElement("CaptureFlag", true) | |
220 | + ), | |
221 | + new XElement("TenKeyConfig", | |
222 | + new XElement("KeyCode", "T3"), | |
223 | + new XElement("CSVString", "右後,,,"), | |
224 | + new XElement("RollBack", false), | |
225 | + new XElement("CaptureFlag", true) | |
226 | + ), | |
227 | + new XElement("TenKeyConfig", | |
228 | + new XElement("KeyCode", "T4"), | |
229 | + new XElement("CSVString", "真左,,,"), | |
230 | + new XElement("RollBack", false), | |
231 | + new XElement("CaptureFlag", true) | |
232 | + ), | |
233 | + new XElement("TenKeyConfig", | |
234 | + new XElement("KeyCode", "T5"), | |
235 | + new XElement("CSVString", ""), | |
236 | + new XElement("RollBack", true), | |
237 | + new XElement("CaptureFlag", false) | |
238 | + ), | |
239 | + new XElement("TenKeyConfig", | |
240 | + new XElement("KeyCode", "T6"), | |
241 | + new XElement("CSVString", "真右,,,"), | |
242 | + new XElement("RollBack", false), | |
243 | + new XElement("CaptureFlag", true) | |
244 | + ), | |
245 | + new XElement("TenKeyConfig", | |
246 | + new XElement("KeyCode", "T7"), | |
247 | + new XElement("CSVString", "左前,,,"), | |
248 | + new XElement("RollBack", false), | |
249 | + new XElement("CaptureFlag", true) | |
250 | + ), | |
251 | + new XElement("TenKeyConfig", | |
252 | + new XElement("KeyCode", "T8"), | |
253 | + new XElement("CSVString", "正面,,,"), | |
254 | + new XElement("RollBack", false), | |
255 | + new XElement("CaptureFlag", true) | |
256 | + ), | |
257 | + new XElement("TenKeyConfig", | |
258 | + new XElement("KeyCode", "T9"), | |
259 | + new XElement("CSVString", "右前,,,"), | |
260 | + new XElement("RollBack", false), | |
261 | + new XElement("CaptureFlag", true) | |
262 | + ), | |
263 | + new XElement("TenKeyConfig", | |
264 | + new XElement("KeyCode", "Tslash"), | |
265 | + new XElement("CSVString", "人・自転車,"), | |
266 | + new XElement("RollBack", false), | |
267 | + new XElement("CaptureFlag", false) | |
268 | + ), | |
269 | + new XElement("TenKeyConfig", | |
270 | + new XElement("KeyCode", "Tastah"), | |
271 | + new XElement("CSVString", "バイク,"), | |
272 | + new XElement("RollBack", false), | |
273 | + new XElement("CaptureFlag", false) | |
274 | + ), | |
275 | + new XElement("TenKeyConfig", | |
276 | + new XElement("KeyCode", "Tminus"), | |
277 | + new XElement("CSVString", "車,"), | |
278 | + new XElement("RollBack", false), | |
279 | + new XElement("CaptureFlag", false) | |
280 | + ), | |
281 | + new XElement("TenKeyConfig", | |
282 | + new XElement("KeyCode", "Tplus"), | |
283 | + new XElement("CSVString", "大型車,"), | |
284 | + new XElement("RollBack", false), | |
285 | + new XElement("CaptureFlag", false) | |
286 | + ), | |
287 | + new XElement("TenKeyConfig", | |
288 | + new XElement("KeyCode", "Tdot"), | |
289 | + new XElement("CSVString", "不明,"), | |
290 | + new XElement("RollBack", false), | |
291 | + new XElement("CaptureFlag", false) | |
292 | + ), | |
293 | + new XElement("IgnoreWindowTitles", "Program Manager,フォト,シェル,設定,テレビ") | |
294 | + ) | |
295 | + ); | |
296 | + XDoc.Save(APPini); | |
297 | + } | |
298 | + } | |
299 | +} | |
\ No newline at end of file |
@@ -0,0 +1,173 @@ | ||
1 | +/***********************************************************//*! | |
2 | + * @brief ログ処理 | |
3 | + **************************************************************/ | |
4 | + | |
5 | +using System; | |
6 | +using System.Collections.Generic; | |
7 | +using System.Linq; | |
8 | +using System.Text; | |
9 | +using System.Threading.Tasks; | |
10 | +using System.Windows.Forms; | |
11 | +using System.IO; | |
12 | +using static TenKeyCapture.ClassMyCommon; | |
13 | + | |
14 | +namespace TenKeyCapture | |
15 | +{ | |
16 | + /// <summary> | |
17 | + /// ログクラス ログを管理する | |
18 | + /// </summary> | |
19 | + internal class ClassLog | |
20 | + { | |
21 | + /// <summary> ログを保存するフルパス付ファイル名</summary> | |
22 | + private string LogFileName; | |
23 | + | |
24 | + /// <summary> ファイル保存用のログ文字列を確保する</summary> | |
25 | + private string _ShadowBuf; | |
26 | + | |
27 | + /// <summary> ログ表示用テキストボックス</summary> | |
28 | + private TextBox _LogTextBox; | |
29 | + | |
30 | + /// <summary> | |
31 | + /// コンストラクタ | |
32 | + /// </summary> | |
33 | + /// <param name="LogTextBox">ログ表示用のテキストボックス</param> | |
34 | + public ClassLog(TextBox LogTextBox) | |
35 | + { | |
36 | + _LogTextBox = LogTextBox; | |
37 | + _LogTextBox.Text = ""; | |
38 | + _ShadowBuf = ""; | |
39 | + LogFileName = ClassMyCommon.AppFolder() + "\\" + ClassMyCommon.TITLE | |
40 | + + "Log" + System.DateTime.Now.ToString("yyMMdd") + ".txt"; | |
41 | + } | |
42 | + | |
43 | + /// <summary> | |
44 | + /// 他のスレッドからコールする為のデリゲート | |
45 | + /// </summary> | |
46 | + /// <param name="stradd">ログへ追加する文字列</param> | |
47 | + private delegate void Add_Callback(string stradd); | |
48 | + | |
49 | + /// <summary> | |
50 | + /// ログに文字列を追加する ログの表示は更新スクロールされない | |
51 | + /// </summary> | |
52 | + /// <param name="stradd">ログへ追加する文字列</param> | |
53 | + public void Add(string stradd) | |
54 | + { | |
55 | + if (stradd == "") | |
56 | + { | |
57 | + //! 文字列がカラなら即終了 | |
58 | + return; | |
59 | + } | |
60 | + | |
61 | + if (_LogTextBox.InvokeRequired) | |
62 | + { | |
63 | + //! 別スレッドから呼び出された場合デリゲートからコールバックさせる | |
64 | + _LogTextBox.Invoke(new Add_Callback(Add), stradd); | |
65 | + return; | |
66 | + } | |
67 | + | |
68 | + //! 表示されている古いログは削除する | |
69 | + DeleteOld(); | |
70 | + | |
71 | + // タイムスタンプ文字列を生成 | |
72 | + string TimeStamp = System.DateTime.Now.ToString("MM/dd HH:mm:ss : "); | |
73 | + // ログ追加文字列の先頭にタイムスタンプを追加 | |
74 | + stradd = TimeStamp + stradd; | |
75 | + | |
76 | + // ログ追加文字列の最後尾に "\r\n" があった場合は、いったん削除する | |
77 | + if (stradd.Substring(stradd.Length - "\r\n".Length, "\r\n".Length) == "\r\n") | |
78 | + { | |
79 | + stradd = stradd.Substring(0, stradd.Length - "\r\n".Length); | |
80 | + } | |
81 | + | |
82 | + // ログ追加文字列の中に "\r\n" があった場合は、"\r\n+タイムスタンプ" に置換する | |
83 | + stradd = stradd.Replace("\r\n", "\r\n" + TimeStamp); | |
84 | + | |
85 | + // ログ追加文字列の最後尾に "\r\n" を追加 | |
86 | + stradd += "\r\n"; | |
87 | + | |
88 | + // 加工したログ追加文字列を保存用文字列とテキストボックスへ追加 | |
89 | + _LogTextBox.Text += stradd; | |
90 | + _ShadowBuf += stradd; | |
91 | + } | |
92 | + | |
93 | + /// <summary> | |
94 | + /// 他のスレッドからコールする為のデリゲート | |
95 | + /// </summary> | |
96 | + /// <param name="stradd">ログへ追加する文字列</param> | |
97 | + private delegate void Put_Callback(string stradd); | |
98 | + | |
99 | + /// <summary> | |
100 | + /// ログに文字列を追加しログ表示を最下行へ強制スクロールする | |
101 | + /// </summary> | |
102 | + /// <param name="stradd">ログへ追加する文字列</param> | |
103 | + public void Put(string stradd) | |
104 | + { | |
105 | + if (_LogTextBox.InvokeRequired) | |
106 | + { | |
107 | + //! 別スレッドから呼び出された場合デリゲートからコールバックさせる | |
108 | + _LogTextBox.Invoke(new Put_Callback(Put), stradd); | |
109 | + return; | |
110 | + } | |
111 | + | |
112 | + // ログ追加 | |
113 | + Add(stradd); | |
114 | + | |
115 | + // ログ表示を最下行へスクロールする。 | |
116 | + _LogTextBox.SelectionStart = _LogTextBox.Text.Length; | |
117 | + _LogTextBox.ScrollToCaret(); | |
118 | + } | |
119 | + | |
120 | + /// <summary> | |
121 | + /// ログにデバッグ用文字列を追加 | |
122 | + /// </summary> | |
123 | + /// <param name="stradd">ログへ追加する文字列</param> | |
124 | + public void DebugPut(string stradd) | |
125 | + { | |
126 | +#if false | |
127 | + Put(stradd); | |
128 | +#endif | |
129 | + } | |
130 | + | |
131 | + /// <summary> | |
132 | + /// ログをファイルに保存 | |
133 | + /// </summary> | |
134 | + public void Save() | |
135 | + { | |
136 | + if (_ShadowBuf.Length <= 0) | |
137 | + { | |
138 | + return; | |
139 | + } | |
140 | + using (StreamWriter sw = new StreamWriter( | |
141 | + LogFileName, | |
142 | + true, | |
143 | + Encoding.GetEncoding("UTF-8"))) | |
144 | + { | |
145 | + // ファイルへの書き込み | |
146 | + sw.Write(_ShadowBuf); | |
147 | + _ShadowBuf = ""; | |
148 | + } | |
149 | + } | |
150 | + | |
151 | + /// <summary> | |
152 | + /// ログ表示部から古いログを削除 | |
153 | + /// 削除されるのは表示部のみ。保存用文字列からは削除しない。 | |
154 | + /// </summary> | |
155 | + private void DeleteOld() | |
156 | + { | |
157 | + //! ログ表示量が MaxLength-1024 より大きくなったら破棄する | |
158 | + if (_LogTextBox.Text.Length > (_LogTextBox.MaxLength - 1024)) | |
159 | + { | |
160 | + _LogTextBox.Text = _LogTextBox.Text.Substring(_LogTextBox.MaxLength / 2); | |
161 | + } | |
162 | + } | |
163 | + | |
164 | + /// <summary> | |
165 | + /// ログ表示部からログをすべて削除 | |
166 | + /// 削除されるのはログ表示のみ。ログ保存用文字列からは削除しない。 | |
167 | + /// </summary> | |
168 | + public void Clear() | |
169 | + { | |
170 | + _LogTextBox.Text = ""; | |
171 | + } | |
172 | + } | |
173 | +} | |
\ No newline at end of file |
@@ -0,0 +1,180 @@ | ||
1 | +namespace TenKeyCapture | |
2 | +{ | |
3 | + partial class FormMain | |
4 | + { | |
5 | + /// <summary> | |
6 | + /// 必要なデザイナー変数です。 | |
7 | + /// </summary> | |
8 | + private System.ComponentModel.IContainer components = null; | |
9 | + | |
10 | + /// <summary> | |
11 | + /// 使用中のリソースをすべてクリーンアップします。 | |
12 | + /// </summary> | |
13 | + /// <param name="disposing">マネージ リソースを破棄する場合は true を指定し、その他の場合は false を指定します。</param> | |
14 | + protected override void Dispose(bool disposing) | |
15 | + { | |
16 | + if (disposing && (components != null)) | |
17 | + { | |
18 | + components.Dispose(); | |
19 | + } | |
20 | + base.Dispose(disposing); | |
21 | + } | |
22 | + | |
23 | + #region Windows フォーム デザイナーで生成されたコード | |
24 | + | |
25 | + /// <summary> | |
26 | + /// デザイナー サポートに必要なメソッドです。このメソッドの内容を | |
27 | + /// コード エディターで変更しないでください。 | |
28 | + /// </summary> | |
29 | + private void InitializeComponent() | |
30 | + { | |
31 | + this.components = new System.ComponentModel.Container(); | |
32 | + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain)); | |
33 | + this.textBox1 = new System.Windows.Forms.TextBox(); | |
34 | + this.button1 = new System.Windows.Forms.Button(); | |
35 | + this.button2 = new System.Windows.Forms.Button(); | |
36 | + this.button3 = new System.Windows.Forms.Button(); | |
37 | + this.button4 = new System.Windows.Forms.Button(); | |
38 | + this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components); | |
39 | + this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); | |
40 | + this.tenKeyCaptureOpenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |
41 | + this.dataFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |
42 | + this.quitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); | |
43 | + this.contextMenuStrip1.SuspendLayout(); | |
44 | + this.SuspendLayout(); | |
45 | + // | |
46 | + // textBox1 | |
47 | + // | |
48 | + this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | |
49 | + | System.Windows.Forms.AnchorStyles.Left) | |
50 | + | System.Windows.Forms.AnchorStyles.Right))); | |
51 | + this.textBox1.Location = new System.Drawing.Point(12, 12); | |
52 | + this.textBox1.Multiline = true; | |
53 | + this.textBox1.Name = "textBox1"; | |
54 | + this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both; | |
55 | + this.textBox1.Size = new System.Drawing.Size(510, 190); | |
56 | + this.textBox1.TabIndex = 0; | |
57 | + this.textBox1.WordWrap = false; | |
58 | + // | |
59 | + // button1 | |
60 | + // | |
61 | + this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); | |
62 | + this.button1.Location = new System.Drawing.Point(12, 219); | |
63 | + this.button1.Name = "button1"; | |
64 | + this.button1.Size = new System.Drawing.Size(110, 30); | |
65 | + this.button1.TabIndex = 1; | |
66 | + this.button1.Text = "About"; | |
67 | + this.button1.UseVisualStyleBackColor = true; | |
68 | + this.button1.Click += new System.EventHandler(this.button1_Click); | |
69 | + // | |
70 | + // button2 | |
71 | + // | |
72 | + this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); | |
73 | + this.button2.Location = new System.Drawing.Point(128, 219); | |
74 | + this.button2.Name = "button2"; | |
75 | + this.button2.Size = new System.Drawing.Size(110, 30); | |
76 | + this.button2.TabIndex = 2; | |
77 | + this.button2.Text = "Clear Log"; | |
78 | + this.button2.UseVisualStyleBackColor = true; | |
79 | + this.button2.Click += new System.EventHandler(this.button2_Click); | |
80 | + // | |
81 | + // button3 | |
82 | + // | |
83 | + this.button3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | |
84 | + | System.Windows.Forms.AnchorStyles.Right))); | |
85 | + this.button3.Location = new System.Drawing.Point(244, 219); | |
86 | + this.button3.Name = "button3"; | |
87 | + this.button3.Size = new System.Drawing.Size(162, 30); | |
88 | + this.button3.TabIndex = 3; | |
89 | + this.button3.Text = "Data Folder"; | |
90 | + this.button3.UseVisualStyleBackColor = true; | |
91 | + this.button3.Click += new System.EventHandler(this.button3_Click); | |
92 | + // | |
93 | + // button4 | |
94 | + // | |
95 | + this.button4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); | |
96 | + this.button4.Location = new System.Drawing.Point(412, 219); | |
97 | + this.button4.Name = "button4"; | |
98 | + this.button4.Size = new System.Drawing.Size(110, 30); | |
99 | + this.button4.TabIndex = 4; | |
100 | + this.button4.Text = "Quit"; | |
101 | + this.button4.UseVisualStyleBackColor = true; | |
102 | + this.button4.Click += new System.EventHandler(this.button4_Click); | |
103 | + // | |
104 | + // notifyIcon1 | |
105 | + // | |
106 | + this.notifyIcon1.ContextMenuStrip = this.contextMenuStrip1; | |
107 | + this.notifyIcon1.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon1.Icon"))); | |
108 | + this.notifyIcon1.Text = "notifyIcon1"; | |
109 | + this.notifyIcon1.Visible = true; | |
110 | + this.notifyIcon1.DoubleClick += new System.EventHandler(this.notifyIcon1_DoubleClick); | |
111 | + // | |
112 | + // contextMenuStrip1 | |
113 | + // | |
114 | + this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { | |
115 | + this.tenKeyCaptureOpenToolStripMenuItem, | |
116 | + this.dataFolderToolStripMenuItem, | |
117 | + this.quitToolStripMenuItem}); | |
118 | + this.contextMenuStrip1.Name = "contextMenuStrip1"; | |
119 | + this.contextMenuStrip1.Size = new System.Drawing.Size(185, 70); | |
120 | + // | |
121 | + // tenKeyCaptureOpenToolStripMenuItem | |
122 | + // | |
123 | + this.tenKeyCaptureOpenToolStripMenuItem.Name = "tenKeyCaptureOpenToolStripMenuItem"; | |
124 | + this.tenKeyCaptureOpenToolStripMenuItem.Size = new System.Drawing.Size(184, 22); | |
125 | + this.tenKeyCaptureOpenToolStripMenuItem.Text = "TenKeyCapture Open"; | |
126 | + this.tenKeyCaptureOpenToolStripMenuItem.Click += new System.EventHandler(this.tenKeyCaptureOpenToolStripMenuItem_Click); | |
127 | + // | |
128 | + // dataFolderToolStripMenuItem | |
129 | + // | |
130 | + this.dataFolderToolStripMenuItem.Name = "dataFolderToolStripMenuItem"; | |
131 | + this.dataFolderToolStripMenuItem.Size = new System.Drawing.Size(184, 22); | |
132 | + this.dataFolderToolStripMenuItem.Text = "Data Folder"; | |
133 | + this.dataFolderToolStripMenuItem.Click += new System.EventHandler(this.dataFolderToolStripMenuItem_Click); | |
134 | + // | |
135 | + // quitToolStripMenuItem | |
136 | + // | |
137 | + this.quitToolStripMenuItem.Name = "quitToolStripMenuItem"; | |
138 | + this.quitToolStripMenuItem.Size = new System.Drawing.Size(184, 22); | |
139 | + this.quitToolStripMenuItem.Text = "Quit"; | |
140 | + this.quitToolStripMenuItem.Click += new System.EventHandler(this.quitToolStripMenuItem_Click); | |
141 | + // | |
142 | + // FormMain | |
143 | + // | |
144 | + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); | |
145 | + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; | |
146 | + this.ClientSize = new System.Drawing.Size(534, 261); | |
147 | + this.Controls.Add(this.button4); | |
148 | + this.Controls.Add(this.button3); | |
149 | + this.Controls.Add(this.button2); | |
150 | + this.Controls.Add(this.button1); | |
151 | + this.Controls.Add(this.textBox1); | |
152 | + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); | |
153 | + this.MinimumSize = new System.Drawing.Size(550, 300); | |
154 | + this.Name = "FormMain"; | |
155 | + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; | |
156 | + this.Text = "TenKeyCapture"; | |
157 | + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormMain_FormClosing); | |
158 | + this.Load += new System.EventHandler(this.FormMain_Load); | |
159 | + this.Resize += new System.EventHandler(this.FormMain_Resize); | |
160 | + this.contextMenuStrip1.ResumeLayout(false); | |
161 | + this.ResumeLayout(false); | |
162 | + this.PerformLayout(); | |
163 | + | |
164 | + } | |
165 | + | |
166 | + #endregion | |
167 | + | |
168 | + private System.Windows.Forms.TextBox textBox1; | |
169 | + private System.Windows.Forms.Button button1; | |
170 | + private System.Windows.Forms.Button button2; | |
171 | + private System.Windows.Forms.Button button3; | |
172 | + private System.Windows.Forms.Button button4; | |
173 | + private System.Windows.Forms.NotifyIcon notifyIcon1; | |
174 | + private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; | |
175 | + private System.Windows.Forms.ToolStripMenuItem tenKeyCaptureOpenToolStripMenuItem; | |
176 | + private System.Windows.Forms.ToolStripMenuItem dataFolderToolStripMenuItem; | |
177 | + private System.Windows.Forms.ToolStripMenuItem quitToolStripMenuItem; | |
178 | + } | |
179 | +} | |
180 | + |
@@ -0,0 +1,121 @@ | ||
1 | +/***********************************************************//*! | |
2 | + * @brief キーボードフック処理 | |
3 | + | |
4 | + **************************************************************/using System; | |
5 | +using System.Collections.Generic; | |
6 | +using System.Linq; | |
7 | +using System.Text; | |
8 | +using System.Threading.Tasks; | |
9 | +using System.Windows.Forms; | |
10 | +using System.Runtime.InteropServices; | |
11 | +using static TenKeyCapture.ClassMyCommon; | |
12 | + | |
13 | +namespace TenKeyCapture | |
14 | +{ | |
15 | + /// <summary> | |
16 | + /// キーボードフック処理クラス | |
17 | + /// </summary> | |
18 | + internal class KeyboardHooker | |
19 | + { | |
20 | + private const uint WM_KEYDOWN = 0x100; | |
21 | + private const uint WM_KEYUP = 0x101; | |
22 | + private const int WH_KEYBOARD_LL = 13; | |
23 | + private static IntPtr hHook; | |
24 | + | |
25 | + private Callback hookproc; | |
26 | + | |
27 | + /// <summary> | |
28 | + /// コンストラクタ | |
29 | + /// </summary> | |
30 | + public KeyboardHooker() | |
31 | + { | |
32 | + hookproc = KeybordHookProc; | |
33 | + hHook = SetWindowsHookEx(WH_KEYBOARD_LL, hookproc, GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), 0); | |
34 | + if (hHook == null) | |
35 | + { | |
36 | + Log.Put("SetWindowsHookEx Failed"); | |
37 | + } | |
38 | + } | |
39 | + | |
40 | + public delegate IntPtr Callback(int nCode, IntPtr msg, IntPtr s); | |
41 | + | |
42 | + [DllImport("user32.dll")] | |
43 | + public static extern IntPtr SetWindowsHookEx(int idHook, Callback lpfn, IntPtr hMod, uint dwThreadId); | |
44 | + | |
45 | + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] | |
46 | + public static extern IntPtr GetModuleHandle(string lpModuleName); | |
47 | + | |
48 | + [DllImport("user32.dll")] | |
49 | + public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr msg, IntPtr s); | |
50 | + | |
51 | + [DllImport("user32.dll")] | |
52 | + [return: MarshalAs(UnmanagedType.Bool)] | |
53 | + public static extern bool UnhookWindowsHookEx(IntPtr hhk); | |
54 | + | |
55 | + [StructLayout(LayoutKind.Sequential)] | |
56 | + private struct KeyboardLLHookStruct | |
57 | + { | |
58 | + public uint vkCode; | |
59 | + public uint scanCode; | |
60 | + public uint flags; | |
61 | + public uint time; | |
62 | + public IntPtr dwExtraInfo; | |
63 | + } | |
64 | + | |
65 | + /// <summary> | |
66 | + /// キーボードフック処理 | |
67 | + /// </summary> | |
68 | + /// <param name="nCode">キーコード</param> | |
69 | + /// <param name="msg">イベントメッセージ</param> | |
70 | + /// <param name="s"></param> | |
71 | + /// <returns></returns> | |
72 | + private static IntPtr KeybordHookProc(int nCode, IntPtr msg, IntPtr s) | |
73 | + { | |
74 | + if (nCode < 0) | |
75 | + { | |
76 | + return CallNextHookEx(hHook, nCode, msg, s); | |
77 | + } | |
78 | + | |
79 | + KeyboardLLHookStruct hookStruct = new KeyboardLLHookStruct(); | |
80 | + | |
81 | + hookStruct = (KeyboardLLHookStruct)Marshal.PtrToStructure(s, typeof(KeyboardLLHookStruct)); | |
82 | + | |
83 | + uint vkCode = hookStruct.vkCode; | |
84 | + | |
85 | + if (msg == new IntPtr(WM_KEYDOWN)) | |
86 | + { | |
87 | + vkCode = hookStruct.vkCode; | |
88 | + if (vkCode >= 96 && 111 >= vkCode) | |
89 | + { | |
90 | + // キューへキーデータを投入する(ロック不要) | |
91 | + bool addSuccess = KeyQue.TryAdd(vkCode, System.Threading.Timeout.Infinite); | |
92 | + | |
93 | + return new IntPtr(1); | |
94 | + } | |
95 | + } | |
96 | + | |
97 | + if (msg == new IntPtr(WM_KEYUP)) | |
98 | + { | |
99 | + vkCode = hookStruct.vkCode; | |
100 | + | |
101 | + if (vkCode >= 96 && 111 >= vkCode) | |
102 | + { | |
103 | + return new IntPtr(1); | |
104 | + } | |
105 | + } | |
106 | + | |
107 | + return CallNextHookEx(hHook, nCode, msg, s); | |
108 | + } | |
109 | + | |
110 | + /// <summary> | |
111 | + /// | |
112 | + /// </summary> | |
113 | + public void Dispose() | |
114 | + { | |
115 | + Boolean ret = UnhookWindowsHookEx(hHook); | |
116 | + if (ret.Equals(false)) | |
117 | + { | |
118 | + } | |
119 | + } | |
120 | + } | |
121 | +} | |
\ No newline at end of file |
@@ -0,0 +1,22 @@ | ||
1 | +using System; | |
2 | +using System.Collections.Generic; | |
3 | +using System.Linq; | |
4 | +using System.Threading.Tasks; | |
5 | +using System.Windows.Forms; | |
6 | + | |
7 | +namespace TenKeyCapture | |
8 | +{ | |
9 | + static class Program | |
10 | + { | |
11 | + /// <summary> | |
12 | + /// アプリケーションのメイン エントリ ポイントです。 | |
13 | + /// </summary> | |
14 | + [STAThread] | |
15 | + static void Main() | |
16 | + { | |
17 | + Application.EnableVisualStyles(); | |
18 | + Application.SetCompatibleTextRenderingDefault(false); | |
19 | + Application.Run(new FormMain()); | |
20 | + } | |
21 | + } | |
22 | +} |
@@ -0,0 +1,36 @@ | ||
1 | +using System.Reflection; | |
2 | +using System.Runtime.CompilerServices; | |
3 | +using System.Runtime.InteropServices; | |
4 | + | |
5 | +// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 | |
6 | +// アセンブリに関連付けられている情報を変更するには、 | |
7 | +// これらの属性値を変更してください。 | |
8 | +[assembly: AssemblyTitle("TenKeyCapture")] | |
9 | +[assembly: AssemblyDescription("")] | |
10 | +[assembly: AssemblyConfiguration("")] | |
11 | +[assembly: AssemblyCompany("")] | |
12 | +[assembly: AssemblyProduct("TenKeyCapture")] | |
13 | +[assembly: AssemblyCopyright("Copyright © 2018")] | |
14 | +[assembly: AssemblyTrademark("")] | |
15 | +[assembly: AssemblyCulture("")] | |
16 | + | |
17 | +// ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから | |
18 | +// 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、 | |
19 | +// その型の ComVisible 属性を true に設定してください。 | |
20 | +[assembly: ComVisible(false)] | |
21 | + | |
22 | +// このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります | |
23 | +[assembly: Guid("e9742bad-8414-44a2-80c2-b047ca268dcf")] | |
24 | + | |
25 | +// アセンブリのバージョン情報は次の 4 つの値で構成されています: | |
26 | +// | |
27 | +// メジャー バージョン | |
28 | +// マイナー バージョン | |
29 | +// ビルド番号 | |
30 | +// Revision | |
31 | +// | |
32 | +// すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます | |
33 | +// 既定値にすることができます: | |
34 | +// [assembly: AssemblyVersion("1.0.*")] | |
35 | +[assembly: AssemblyVersion("1.0.0.0")] | |
36 | +[assembly: AssemblyFileVersion("1.0.0.0")] |
@@ -0,0 +1,63 @@ | ||
1 | +//------------------------------------------------------------------------------ | |
2 | +// <auto-generated> | |
3 | +// このコードはツールによって生成されました。 | |
4 | +// ランタイム バージョン:4.0.30319.42000 | |
5 | +// | |
6 | +// このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 | |
7 | +// コードが再生成されるときに損失したりします。 | |
8 | +// </auto-generated> | |
9 | +//------------------------------------------------------------------------------ | |
10 | + | |
11 | +namespace TenKeyCapture.Properties { | |
12 | + using System; | |
13 | + | |
14 | + | |
15 | + /// <summary> | |
16 | + /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。 | |
17 | + /// </summary> | |
18 | + // このクラスは StronglyTypedResourceBuilder クラスが ResGen | |
19 | + // または Visual Studio のようなツールを使用して自動生成されました。 | |
20 | + // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に | |
21 | + // ResGen を実行し直すか、または VS プロジェクトをビルドし直します。 | |
22 | + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] | |
23 | + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |
24 | + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |
25 | + internal class Resources { | |
26 | + | |
27 | + private static global::System.Resources.ResourceManager resourceMan; | |
28 | + | |
29 | + private static global::System.Globalization.CultureInfo resourceCulture; | |
30 | + | |
31 | + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] | |
32 | + internal Resources() { | |
33 | + } | |
34 | + | |
35 | + /// <summary> | |
36 | + /// このクラスで使用されているキャッシュされた ResourceManager インスタンスを返します。 | |
37 | + /// </summary> | |
38 | + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |
39 | + internal static global::System.Resources.ResourceManager ResourceManager { | |
40 | + get { | |
41 | + if (object.ReferenceEquals(resourceMan, null)) { | |
42 | + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TenKeyCapture.Properties.Resources", typeof(Resources).Assembly); | |
43 | + resourceMan = temp; | |
44 | + } | |
45 | + return resourceMan; | |
46 | + } | |
47 | + } | |
48 | + | |
49 | + /// <summary> | |
50 | + /// 厳密に型指定されたこのリソース クラスを使用して、すべての検索リソースに対し、 | |
51 | + /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。 | |
52 | + /// </summary> | |
53 | + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |
54 | + internal static global::System.Globalization.CultureInfo Culture { | |
55 | + get { | |
56 | + return resourceCulture; | |
57 | + } | |
58 | + set { | |
59 | + resourceCulture = value; | |
60 | + } | |
61 | + } | |
62 | + } | |
63 | +} |
@@ -0,0 +1,26 @@ | ||
1 | +//------------------------------------------------------------------------------ | |
2 | +// <auto-generated> | |
3 | +// このコードはツールによって生成されました。 | |
4 | +// ランタイム バージョン:4.0.30319.42000 | |
5 | +// | |
6 | +// このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 | |
7 | +// コードが再生成されるときに損失したりします。 | |
8 | +// </auto-generated> | |
9 | +//------------------------------------------------------------------------------ | |
10 | + | |
11 | +namespace TenKeyCapture.Properties { | |
12 | + | |
13 | + | |
14 | + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |
15 | + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.3.0.0")] | |
16 | + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { | |
17 | + | |
18 | + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); | |
19 | + | |
20 | + public static Settings Default { | |
21 | + get { | |
22 | + return defaultInstance; | |
23 | + } | |
24 | + } | |
25 | + } | |
26 | +} |