1: unit CHMain;
2:
3: interface
4:
5: uses
6: Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7: Dialogs, StdCtrls, ShellAPI, Generics.Collections, Menus, ExtCtrls, ImgList, Imm; {引用泛型单元}
8:
9: const
10: cControlR : array[1..26, 1..3] of Char =
11: ( ('y','f','w'),
12: ('u','e','r'),
13: ('i','r','w'),
14: ('o','e','w'),
15: ('p','q','w'),
16: ('h','e','f'),
17: ('j','d','f'),
18: ('k','f','s'),
19: ('l','d','s'),
20: ('z','a','s'),
21: ('n','b','v'),
22: ('x','b','c'),
23: ('m','c','v'),
24:
25: ('y','w','f'),
26: ('u','r','e'),
27: ('i','w','r'),
28: ('o','w','e'),
29: ('p','w','q'),
30: ('h','f','e'),
31: ('j','f','d'),
32: ('k','s','f'),
33: ('l','s','d'),
34: ('z','s','a'),
35: ('n','v','b'),
36: ('x','c','b'),
37: ('m','v','c'));
38:
39: cControlL : array[1..26, 1..3] of Char =
40: ( ('q','o','p'),
41: ('w','i','o'),
42: ('e','o','u'),
43: ('r','i','u'),
44: ('t','j','o'),
45: ('a','l','z'),
46: ('s','k','l'),
47: ('d','j','l'),
48: ('f','j','k'),
49: ('g','i','j'),
50: ('c','m','x'),
51: ('v','m','n'),
52: ('b','n','x'),
53:
54: ('q','p','o'),
55: ('w','o','i'),
56: ('e','u','o'),
57: ('r','u','i'),
58: ('t','o','j'),
59: ('a','z','l'),
60: ('s','l','k'),
61: ('d','l','j'),
62: ('f','k','j'),
63: ('g','j','i'),
64: ('c','x','m'),
65: ('v','n','m'),
66: ('b','x','n')
67: );
68: ConstIID = 100;
69: WMMouseMsg = WM_USER + 1;
70:
71: type
72: PKBDLLHOOKSTRUCT = ^KBDLLHOOKSTRUCT;
73: TZoomAction = (zaMinimize, zaMaximize);
74:
75: KBDLLHOOKSTRUCT = record
76: vkCode: DWORD;
77: ScanCode: DWORD;
78: Flags: DWORD;
79: Time: DWORD;
80: dwExtraInfo: DWORD;
81: end;
82:
83: type
84: TfmMain = class(TForm)
85: btnRun: TButton;
86: pmMenu: TPopupMenu;
87: N1: TMenuItem;
88: N2: TMenuItem;
89: N3: TMenuItem;
90: N4: TMenuItem;
91: N5: TMenuItem;
92: N6: TMenuItem;
93: N7: TMenuItem;
94: icoB: TTrayIcon;
95: icoR: TTrayIcon;
96: procedure btnRunClick(Sender: TObject);
97: procedure FormCreate(Sender: TObject);
98: procedure N5Click(Sender: TObject);
99: procedure N1Click(Sender: TObject);
100: procedure N4Click(Sender: TObject);
101: procedure N3Click(Sender: TObject);
102: procedure FormClose(Sender: TObject; var Action: TCloseAction);
103: procedure pmMenuPopup(Sender: TObject);
104: procedure N2Click(Sender: TObject);
105: private
106: { Private declarations }
107: procedure WMSysCommand(var Message: TMessage); message WM_SYSCOMMAND;
108: procedure MouseMessage(var Msg: TMessage); message wmMouseMsg;
109: procedure HotyKey(var msg:TMessage);message WM_HOTKEY;
110: procedure ShowMenu;
111: public
112: { Public declarations }
113: end;
114:
115: var
116: fmMain: TfmMain;
117: Hook: HHOOK;
118: iFr, iTo, cFrCharR, cToCharR, cFrCharL, cToCharL: TList<Integer>;
119: hSemaphore: THandle; {信号对象的句柄}
120: UpiFr: TRTLCriticalSection; //临界区
121: vaSysNtida :TnotifyIconDataA;
122:
123:
124: implementation
125: var
126: HotKey_AltQ1, HotKey_ShiftZ, HotKey_AltQ, Hotkey_CtrlAltM, Hotkey_CtrlAltN, HotKey_ShiftX: Integer ; //快捷键
127:
128: {$R *.dfm}
129:
130: function HookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
131: const
132: _KeyPressMask=$80000000;//键盘掩码常量
133: var
134: p: PKBDLLHOOKSTRUCT;
135: iIsZM: Boolean;
136: hIMCa : HIMC;
137: fdwConversion, fdwSentence: DWord;
138: str: TScreen;
139: rPos: TPoint;
140: begin
141: If nCode < 0 Then //根据SDK说明,若iCode小于0,调用CallNextHookEx并返回
142: begin
143: Result:=CallNextHookEx(hook, nCode, wParam, lParam);
144: Exit;
145: end;
146:
147: iIsZM := False;
148: if nCode = HC_ACTION then
149: begin
150: p:= PKBDLLHOOKSTRUCT(Lparam);
151: if p^.dwExtraInfo=1 then
152: begin
153: Result:= CallNextHookEx(hook,nCode,WParam,LParam);
154: Exit;
155: end;
156: if False
157: or (GetKeyState(VK_CONTROL) >=0)
158: or ( (p^.vkCode=191) or (p^.vkCode=220) ) //(GetKeyState(VK_SHIFT) >=0) or
159: then
160: case WParam of
161: WM_KEYDOWN, WM_SYSKEYDOWN:
162: begin
163: p:= PKBDLLHOOKSTRUCT(Lparam);
164: if False
165: or ((p^.vkCode>=65) and (p^.vkCode<=90))
166: or ((p^.vkCode>=97) and (p^.vkCode<=122))
167: then
168: begin
169: iIsZM := True;
170: if iFr.IndexOf(p^.vkCode)>=0 then
171: else
172: iFr.Add(p^.vkCode);
173: keybd_event(0, 0, 0, 0);
174: keybd_event(0, 0, KEYEVENTF_KEYUP, 0);
175: end
176: else
177: if True
178: and (p^.vkCode=32)
179: and (iFr.Count> 0) then
180: begin
181: iIsZM := True;
182: while iFr.Count> 0 do
183: begin
184: iTo.Add(iFr.Items[0]);
185: iFr.Delete(0);
186: end;
187: iTo.Add(32);
188: keybd_event(0, 0, 0, 0);
189: keybd_event(0, 0, KEYEVENTF_KEYUP, 0);
190: ReleaseSemaphore(hSemaphore, 1, nil);
191: end
192: else
193: if (p^.vkCode=191) then
194: begin
195: str := TScreen.Create(nil);
196: GetCurSorPos(rPos);
197: hIMCa := ImmGetContext(WindowFromPoint(rPos));
198: //
199: ImmGetConversionStatus(hIMCa, fdwConversion, fdwSentence);
200: if True
201: and (Trim(str.DefaultIme)<> '')
202: and ((fdwConversion and IME_CMODE_SYMBOL)> 0)
203: and (GetKeyState(VK_SHIFT) <0)
204: and (GetKeyState(VK_CAPITAL) >=0)
205: then
206: begin
207: keybd_event(Ord(Char(191)), 0, 0, 1);
208: keybd_event(Ord(Char(191)), 0, KEYEVENTF_KEYUP, 1);
209: Exit;
210: end
211: else
212: if True
213: and ((fdwConversion and IME_CMODE_SYMBOL)> 0)
214: and (GetKeyState(VK_SHIFT) >=0)
215: and (GetKeyState(VK_CAPITAL) =0)
216: then
217: begin
218: iIsZM := True;
219: SendMessage(WindowFromPoint(rPos), WM_IME_CHAR, 0, 0);
220: SendMessage(WindowFromPoint(rPos), WM_IME_CHAR, word('/'), 0);
221: SendMessage(WindowFromPoint(rPos), WM_IME_CHAR, 32, 0);
222: keybd_event(0, 0, 0, 0);
223: keybd_event(0, 0, KEYEVENTF_KEYUP, 0);
224: end
225: else
226: begin
227: //
228: end;
229: end
230: else
231: if (p^.vkCode=220) then
232: begin
233: str := TScreen.Create(nil);
234: GetCurSorPos(rPos);
235: hIMCa := ImmGetContext(WindowFromPoint(rPos));
236: //
237: ImmGetConversionStatus(hIMCa, fdwConversion, fdwSentence);
238: if True
239: and (Trim(str.DefaultIme)<> '')
240: and ((fdwConversion and IME_CMODE_SYMBOL)> 0)
241: and (GetKeyState(VK_SHIFT) <0)
242: and (GetKeyState(VK_CAPITAL) >=0)
243: then
244: begin
245: keybd_event(Ord(Char(220)), 0, 0, 1);
246: keybd_event(Ord(Char(220)), 0, KEYEVENTF_KEYUP, 1);
247: Exit;
248: end
249: else
250: if True
251: and ((fdwConversion and IME_CMODE_SYMBOL)> 0)
252: and (GetKeyState(VK_SHIFT) >=0)
253: and (GetKeyState(VK_CAPITAL) =0)
254: then
255: begin
256: iIsZM := True;
257: SendMessage(WindowFromPoint(rPos), WM_IME_CHAR, 0, 0);
258: SendMessage(WindowFromPoint(rPos), WM_IME_CHAR, word('\'), 0);
259: SendMessage(WindowFromPoint(rPos), WM_IME_CHAR, 32, 0);
260: keybd_event(0, 0, 0, 0);
261: keybd_event(0, 0, KEYEVENTF_KEYUP, 0);
262: end
263: else
264: begin
265: //
266: end;
267: end;
268: end;
269:
270: WM_KEYUP, WM_SYSKEYUP:
271: begin
272: p := PKBDLLHOOKSTRUCT(Lparam);
273: if False
274: or ((p^.vkCode>=65) and (p^.vkCode<=90))
275: or ((p^.vkCode>=97) and (p^.vkCode<=122))
276: then
277: begin
278: iIsZM := True;
279: if iFr.IndexOf(p^.vkCode)>=0 then
280: begin
281: iTo.Add(p^.vkCode);
282: iFr.Delete(iFr.IndexOf(p^.vkCode));
283: if (ifr.Count=0) and (iTo.Count>0) then
284: ReleaseSemaphore(hSemaphore, 1, nil);
285: end;
286: end
287: else
288: begin
289: //..
290: end;
291: end;
292: end;
293: end;
294:
295: if iIsZM = True then
296: Result:= 1
297: else
298: Result:= CallNextHookEx(hook, nCode, WParam, LParam);
299: end;
300:
301: function LoadListThread(p: Pointer): DWORD; stdcall;
302: var
303: i1, i2, ia, itmp: Integer;
304: procedure VisualChar(iChar: Integer);
305: begin
306: keybd_event(Ord(Char(iChar)), 0, 0, 1);
307: keybd_event(Ord(Char(iChar)), 0, KEYEVENTF_KEYUP, 1);
308: end;
309: begin
310: while True do
311: begin
312: if WaitForSingleObject(hSemaphore, INFINITE) = WAIT_OBJECT_0 then
313: begin
314: i2 := 0;
315: while i2< iTo.Count do
316: begin
317: for i1 := i2+ 1 to iTo.Count - 1 do
318: begin
319: ia := cFrCharR.IndexOf(iTo[i2]* 256+ iTo[i1]);
320: if ia>=0 then
321: begin
322: VisualChar(cToCharR[ia]);
323: iTo.Delete(i2);
324: iTo.Delete(i1- 1);
325: Break;
326: end;
327: end;
328:
329: itmp := 0;
330: for i1 := i2+ 1 to iTo.Count - 1 do
331: begin
332: ia := cFrCharL.IndexOf(iTo[i2]* 256+ iTo[i1]);
333: if ia>=0 then
334: begin
335: itmp := iTo[i2 +1];
336: iTo[i2 +1] := iTo[i1];
337: iTo[i1] := itmp;
338: i2 := i2+ 2;
339: Break;
340: end;
341: end;
342: i2 := i2+ 1;
343: end;
344:
345: i1 := 0;
346: i2 := iTo.Count-1;
347: while True do
348: begin
349: if i1> i2 then
350: Break;
351: if i2>i1 then
352: begin
353: ia := cFrCharL.IndexOf(iTo[i1]* 256+ iTo[i1+1]);
354: if ia>=0 then
355: begin
356: i1 := i1+ 2;
357: Continue;
358: end;
359: end;
360: if cToCharL.IndexOf(iTo[i1])>=0 then
361: begin
362: VisualChar(iTo[i1]);
363: iTo.Delete(i1);
364: i2 := i2-1;
365: end
366: else
367: i1 := i1+ 1;
368: end;
369:
370: i1 := 0;
371: i2 := iTo.Count-1;
372: while True do
373: begin
374: if i1> i2 then
375: Break;
376: if i2>i1 then
377: begin
378: ia := cFrCharL.IndexOf(iTo[i1]* 256+ iTo[i1+1]);
379: if ia>=0 then
380: begin
381: VisualChar(cToCharL[ia]);
382: i1 := i1+ 2;
383: Continue;
384: end;
385: end;
386: VisualChar(iTo[i1]);
387: i1 := i1+ 1;
388: end;
389: end;
390:
391: while iTo.Count>0 do
392: begin
393: iTo.Clear;
394: end;
395: end;
396: end;
397:
398: function SetHook: Boolean; stdcall;
399: begin
400: if hook <> 0 then
401: begin
402: Result:= False;
403: Exit;
404: end;
405: hook:= SetWindowsHookEx(13, @HookProc, HINSTANCE, 0);
406: Result:= hook <> 0;
407: end;
408:
409: function DelHook: Boolean; stdcall;
410: begin
411: if hook <> 0 then
412: begin
413: UnhookWindowshookEx(hook);
414: hook:= 0;
415: end;
416: Result:= hook = 0;
417: end;
418:
419: procedure SetHotKey(Handle: HWnd);
420: begin
421: Hotkey_CtrlAltM :=GlobalAddAtom('Hotkey_CtrlAltM');
422: RegisterHotKey(handle, Hotkey_CtrlAltM, MOD_ALT or MOD_CONTROL,$4D);//Ctrl+Alt+M
423:
424: Hotkey_CtrlAltM :=GlobalAddAtom('Hotkey_CtrlAltN');
425: RegisterHotKey(handle, Hotkey_CtrlAltM, MOD_ALT or MOD_CONTROL,$4E);//Ctrl+Alt+N
426:
427: HotKey_AltQ1 :=GlobalAddAtom('HotKey_AltQ1');
428: RegisterHotKey(handle, HotKey_AltQ1, MOD_ALT ,$71);//Alt+A
429:
430: HotKey_ShiftZ :=GlobalAddAtom('HotKey_ShiftZ');
431: RegisterHotKey(handle, HotKey_ShiftZ, MOD_SHIFT ,$5A);//Shift+z
432:
433: HotKey_ShiftX :=GlobalAddAtom('HotKey_ShiftX');
434: RegisterHotKey(handle, HotKey_ShiftZ, MOD_SHIFT ,$58);//Shift+X
435:
436: HotKey_AltQ :=GlobalAddAtom('HotKey_AltQ');
437: RegisterHotKey(handle, HotKey_AltQ, MOD_ALT ,$51);//Alt+Q
438: end;
439:
440: procedure DelHotKey(Handle: HWnd);
441: begin
442: UnRegisterHotKey(handle, HotKey_AltQ1);
443: UnRegisterHotKey(handle, HotKey_ShiftZ);
444: UnRegisterHotKey(handle, HotKey_ShiftX);
445: UnRegisterHotKey(handle, HotKey_AltQ);
446: UnRegisterHotKey(handle, Hotkey_CtrlAltM);
447: end;
448:
449: procedure ZoomEffect(Handle: HWnd; theOperation: TZoomAction);
450: var
451: rcStart: TRect;
452: rcEnd: TRect;
453: rcTray: TRect;
454: hwndTray : hWnd;
455: hwndChild: hWnd;
456: begin
457: Exit;
458: { Find the system tray area bounding rectangle }
459: hwndTray := FindWindow('Shell_TrayWnd', nil);
460: hwndChild := FindWindowEx(hwndTray, 0, 'TrayNotifyWnd', nil);
461: GetWindowRect(hwndChild, rcTray);
462: { Check for minimize/maximize and swap start/end}
463: if theOperation = zaMinimize then
464: begin
465: GetWindowRect(Handle, rcStart);
466: rcEnd := rcTray;
467: end
468: else
469: begin
470: GetWindowRect(Handle, rcEnd);
471: rcStart := rcTray;
472: end;
473: DrawAnimatedRects(Handle, IDANI_CAPTION, rcStart, rcEnd)
474: end;
475:
476: procedure SetSysNtida(Handle: HWnd; iType: Integer=-1);
477: var
478: aa: Ticon;
479: begin
480: vaSysNtida.cbSize := SizeOf(tnotifyicondataa);
481: vaSysNtida.Wnd := Handle;
482: vaSysNtida.uID := ConstIID;
483: vaSysNtida.uFlags := NIF_ICON + NIF_TIP + NIF_MESSAGE;
484: vaSysNtida.uCallbackMessage := WMMouseMsg;
485: vaSysNtida.hIcon := Application.Icon.handle;
486: if hook= 0 then
487: vaSysNtida.hIcon := fmMain.icoB.Icon.Handle
488: else
489: vaSysNtida.hIcon := fmMain.icoR.Icon.Handle;
490: vaSysNtida.szTip := 'ComboKeys';
491: if vaSysNtida.uVersion=1 then
492: Shell_NotifyIconA(NIM_MODIFY, @vaSysNtida)
493: else
494: Shell_NotifyIconA(NIM_ADD, @vaSysNtida);
495: vaSysNtida.uVersion := 1;
496: if iType=0 then
497: begin
498: ShowWindow(Handle, SW_HIDE);
499: ShowWindow(Application.Handle, SW_HIDE);
500: ZoomEffect(Handle, zaMinimize);
501: end
502: else
503: if iType=1 then
504: begin
505: ShowWindow(Handle, SW_SHOW);
506: end
507: else
508: if iType=-2 then
509: begin
510: vaSysNtida.uFlags := NIF_ICON + NIF_TIP + NIF_MESSAGE;
511: Shell_NotifyIconA(NIM_DELETE, @vaSysNtida);
512: end;
513: end;
514:
515: procedure TfmMain.btnRunClick(Sender: TObject);
516: begin
517: if hook = 0 then
518: SetHook
519: else
520: DelHook;
521: pmMenuPopup(nil);
522: end;
523:
524:
525:
526: procedure TfmMain.FormClose(Sender: TObject; var Action: TCloseAction);
527: begin
528: DelHotKey(Self.Handle);
529: SetSysNtida(Self.Handle, -2);
530: end;
531:
532: procedure TfmMain.FormCreate(Sender: TObject);
533: var
534: ID: DWORD;
535: i: Integer;
536: begin
537: SetSysNtida(Handle);
538: iFr := TList<Integer>.Create;
539: iTo := TList<Integer>.Create;
540:
541: cFrCharR := TList<Integer>.Create;
542: cToCharR := TList<Integer>.Create;
543: cFrCharL := TList<Integer>.Create;
544: cToCharL := TList<Integer>.Create;
545: SetHotKey(Self.Handle);
546: for I := Low(cControlR) to High(cControlR) do
547: begin
548: cFrCharR.Add((Ord(cControlR[i][2])-32)*256+Ord(cControlR[i][3])-32);
549: cToCharR.Add(Ord(cControlR[i][1])-32);
550: end;
551: for I := Low(cControlL) to High(cControlL) do
552: begin
553: cFrCharL.Add((Ord(cControlL[i][2])-32)*256+Ord(cControlL[i][3])-32);
554: cToCharL.Add(Ord(cControlL[i][1])-32);
555: end;
556: CloseHandle(hSemaphore);
557: hSemaphore := CreateSemaphore(nil, 0, 1, nil);
558: CreateThread(nil, 0, @LoadListThread, nil, 0, ID);
559: end;
560:
561: procedure TfmMain.ShowMenu;
562: var
563: P: TPoint;
564: begin
565: GetCursorPos(P);
566: pmMenu.Popup(P.X, P.Y);
567: end;
568:
569: procedure TfmMain.MouseMessage(var Msg: TMessage);
570: begin
571: if (msg.LParam = WM_LBUTTONDBLCLK) then
572: SetSysNtida(Handle, 1)
573: else
574: if (msg.LParam = WM_RBUTTONUP) then
575: begin
576: ShowMenu;
577: end;
578: end;
579:
580: procedure TfmMain.N1Click(Sender: TObject);
581: begin
582: btnRun.Click;
583: end;
584:
585: procedure TfmMain.N2Click(Sender: TObject);
586: begin
587: btnRun.Click;
588: end;
589:
590: procedure TfmMain.N3Click(Sender: TObject);
591: begin
592: if IsWindowVisible(self.Handle) then
593: SendMessage(Handle, WM_SYSCOMMAND,SC_ICON,0)
594: else
595: SendMessage(Handle, wmMouseMsg, 0, WM_LBUTTONDBLCLK);
596: end;
597:
598: procedure TfmMain.N4Click(Sender: TObject);
599: begin
600: if IsWindowVisible(self.Handle) then
601: SendMessage(Handle, WM_SYSCOMMAND,SC_ICON,0)
602: else
603: SendMessage(Handle, wmMouseMsg, 0, WM_LBUTTONDBLCLK);
604: end;
605:
606: procedure TfmMain.N5Click(Sender: TObject);
607: begin
608: Close;
609: end;
610:
611: procedure TfmMain.pmMenuPopup(Sender: TObject);
612: begin
613: N4.Enabled := IsWindowVisible(self.Handle);
614: N3.Enabled := not IsWindowVisible(self.Handle);
615:
616: N1.Enabled := hook= 0;
617: N2.Enabled := hook<> 0;
618: if N1.Enabled then
619: btnRun.Caption := 'Run'
620: else
621: btnRun.Caption := 'Break';
622: SetSysNtida(Handle, 1);
623: end;
624:
625: procedure TfmMain.WMSysCommand(var Message: TMessage);
626: begin
627: if Message.WParam = SC_ICON then
628: SetSysNtida(Handle, 0)
629: else
630: DefWindowProc(Self.Handle, Message.Msg, Message.WParam, Message.LParam);
631: end;
632:
633: procedure TfmMain.HotyKey(var msg: TMessage);
634: begin
635: if False
636: or ((msg.LParamHi=$5A) and (msg.LParamLo=MOD_SHIFT))
637: or ((msg.LParamHi=$71) and (msg.LParamLo=MOD_ALT))
638: or ((msg.LParamHi=$71) and (msg.LParamLo=MOD_ALT)) then
639: begin
640: if IsWindowVisible(self.Handle) then
641: SendMessage(Handle, WM_SYSCOMMAND,SC_ICON,0)
642: else
643: SendMessage(Handle, wmMouseMsg, 0, WM_LBUTTONDBLCLK);
644: end
645: else
646: if False
647: or ((msg.LParamHi=$58) and (msg.LParamLo=MOD_SHIFT)) then
648: begin
649: //SetSysNtida(Handle, 0);
650: ShowMenu;
651: end
652: else
653: if (msg.LParamHi=$4D) and (msg.LParamLo=MOD_ALT or MOD_CONTROL) then //MOD_ALT or MOD_CONTROL, $53)
654: begin
655: ShellExecute(Handle, 'open', PChar('msnmsgr'), nil, nil ,SW_SHOWNORMAL);//记事本
656: end
657: else
658: if (msg.LParamHi=$4E) and (msg.LParamLo=MOD_ALT or MOD_CONTROL) then //MOD_ALT or MOD_CONTROL, $53)
659: begin
660: ShellExecute(Handle, 'open', PChar('Notepad'), nil, nil ,SW_SHOWNORMAL);//记事本
661: end;
662: end ;
663:
664: end.