[Delphi版]罗技无限灵貂,驱动程序补丁-实现真正的多媒体播放器!附QQ图标伪装程序
██████████ QQ图标伪装程序
将 QQ 聊天窗口的标题栏中的 “与 某某 聊天” 变成 “我的文档 某某”,而且聊天窗口的图标变成 Word 文档的图标,托盘中的图标在不同状态时也变成其它图标:例如在线=网络驱动器、离开=软盘驱动器、隐身=硬盘驱动器、离线=断开网络驱动器。
变图标不需要编程,修改 QQ2004 的 QQRes.Dll 文件即可。
██████████ 罗技无限灵貂,驱动程序补丁-实现真正的多媒体播放器
罗技无限灵貂是罗技公司推出的一款多功能无线鼠标,英文名称叫做“Logitech Media Player”,顾名思义-多媒体遥控器。
该款鼠标最大的特色就是嵌入了众多的功能键,除滚轮外,另有8个键。其中侧面的两个键在罗技众多的中高档鼠标都已配备,功能主要是上下浏览;顶部的六个键组成多媒体键区,包括:“Media、Play/Pause、Forward、Backward、+、-”。此外,滚轮可进行十字导航,即多了左右浏览功能。
但在实际使用中,多媒体键的功能实在有限,以我的标准看来,根本发挥不了遥控器的作用!为什么这么说呢?
我钟爱使用的媒体播放器是MPC(MS Windows Media Player Classic),它短小精悍、启动快、占资源少、快捷键丰富,用鼠标、键盘操作起来十分简单。
下面针对 MPC 说说灵貂的缺憾:
播放/暂停 点击左键或 Space 即可,左键就在鼠标上,因此 Play/Pause 键就多余了;
下一个/上一个 点击 PgUp/PgDown 即可,虽然鼠标上对应的是 Forward/Backward,但我们在看一个电影或者视频片断的时候,有多少机会能在中途去看上一个或者下一个文件呢?即使针对超过10分钟的视频文件,看完一个,手工去点击下一个文件也不是很费事的工作么,因此这两个键也就多余了。
罗技提供的最新驱动程序并未提供上述三个键的自定义功能,因此为了充分地利用上鼠标上的众多功能键,我只好在 QQ 图标程序中加入了新的代码来实现这三个键的自定义功能,并且还可以在不同的应用程序中令同一个鼠标键实现不同的自定义功能。
利用官方的驱动设置程序设置:
Media 键的功能为组合键:Ctrl+F4,缩放的功能为关闭程序(效率十分高)。
之后的程序可以实现如下功能(主要是组合键):
◎MPC
向上浏览:前进10秒;向下浏览:倒退10秒。
◎ACDSee
Play/Pause:Ctrl+Del;Forward:Alt+C;Backward:Alt+M。
◎ACD FotoCanvas
Play/Pause:Ctrl+S;Forward:Shift+A;Backward:Shift+S。
◎NetCaptor
Play/Pause:Ctrl+Shift+S;Foward:F3;Backward:F2。
◎UltraEdit
Play/Pause:Ctrl+S;Foward:Ctrl+Shift+F6;Backward:Ctrl+F6。
最后我要鄙视一下罗技无限灵貂驱动程序的开发人员!
鼠标驱动的核心功能在于对鼠标传来的位移信号的换算与处理,还有诸如各种按键的定义、加速度的处理等问题,但这些相对于移动信号的处理与分析来说只是小问题,在这一方面的程序编制并不存在功能上的技术困难。既然你们作出了那么多中高档的鼠标,尤其是我花了360人民币买的这款灵貂,为何不再多敲些代码,把多媒体键区的几个键也加入自定义功能。毕竟计算机不是电视、录音机、VCD机、DVD机、组合音响…,多媒体功能只是计算机的一部分功能,多数人还是要用它来做其它很多游泳的事情的,如果能在更多的应用软件中让每个键都实现自定义功能,那么以它目前不到400元的价格和为数众多的鼠标键,绝对是一款超值的鼠标!
██████████ Delphi 代码如下,其中只有MPC用到了钩子,因为在媒体播放软件中,多媒体键区的键及两个侧键产生的消息都被罗技的驱动钩子给拐跑了,所以要自己编个全局钩子提前把消息拦住,让罗技的钩子钩不到我需要的消息。
//▓▓▓▓▓▓▓▓▓ ReTitle.dpr
program ReTitle;
uses
Forms,
SysUtils,
Windows,
Unit1 in 'Unit1.pas' {f},
DlgDebug_U in 'DlgDebug_U.pas' {dlgDebug};
{$R *.res}
begin
Application.Initialize;
//调试状态
dbg := findCmdLineSwitch('debug', ['/', '-'], true);
if dbg then with dlgDebug do begin
dlgDebug := TDlgDebug.Create(Application); Show;
Left := GetSystemMetrics(SM_CXSCREEN)-Width ;
Top := GetSystemMetrics(SM_CYSCREEN)-Height-60;
end;
Application.CreateForm(Tf, f);
Application.Run;
end.
//▓▓▓▓▓▓▓▓▓ Unit1.pas
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, DlgDebug_U;
type
Tf = class(TForm)
Tmr: TTimer;
procedure FormCreate(Sender: TObject);
procedure TmrTimer(Sender: TObject);
procedure WndProc(var Message: TMessage); override;
private
{ Private declarations }
hFocus: HWND;
Buf: array[0..1024] of Char;
sTitle: string;
procedure GetMousePosHwndAndClassName(Sender : TPoint);
function replacing(s,source,target:string):string;
//罗技无限灵貂
procedure Down(VK: byte);
procedure UP (VK: byte);
procedure Key1(VK1 : byte);
procedure Key2(VK1, VK2 : byte);
procedure Key3(VK1, VK2, VK3: byte);
public
{ Public declarations }
end;
var
f: Tf;
const
LOGITECH = $0319;
PLAY_PAUSE = $E0000;
PLAY_LEFT = $C0000;
PLAY_RIGHT = $B0000;
implementation
procedure EnableWheelHook ; stdcall; external 'HookPrj.dll';
procedure DisableWheelHook; stdcall; external 'HookPrj.dll';
{$R *.dfm}
procedure Tf.FormCreate(Sender: TObject);//█████████████ 界面初始化
begin
FormStyle := fsStayOnTop;
Height:=0;
Width:=0;
Hide;
Tmr.Interval := 50;
ShowWindow(Application.Handle, SW_HIDE);
SetWindowLong(Application.Handle, GWL_EXSTYLE,
GetWindowLong(Application.handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW AND NOT WS_EX_APPWINDOW);
EnableWheelHook;//罗技灵貂蓝色侧键,WM_MouseWheel 消息钩子
end;
procedure Tf.GetMousePosHwndAndClassName(Sender: TPoint);//███ 伪装标题栏
var hWnd: THandle;
aTitle: array [0..255] of char;
str:string;
begin
hWnd := WindowFromPoint(Sender);
if boolean(GetWindowText(hWnd, aTitle, 256)) then begin
str := string(aTitle);
if ((pos('与',str)>0) and (pos('聊天中',str)>0)) then begin
str:=replacing(str, ' 聊天中', '');
str:=replacing(str, '与', '我的文档');
SetWindowText(hWnd,pchar(str));
end;
if ((pos('群 -',str)>0) or (pos('高级群 -',str)>0)) then begin
str:=replacing(str, '群 -', '我的信件');
str:=replacing(str, '高级', '');
SetWindowText(hWnd,pchar(str));
end;
//聊天室
if pos('QQ 聊天室', str)>0 then begin
str := 'Microsoft Visual C++ 6.2';
SetWindowText(hWnd,pchar(str));
end;
//MSN
if pos(' - 对话', str)>0 then begin
str := replacing(str, ' - 对话', '工作文档');
SetWindowText(hWnd,pchar(str));
end;
end;
end;
procedure Tf.TmrTimer(Sender: TObject);//████████████▌定时器
var rPos: TPoint;
begin
if boolean(GetCursorPos(rPos)) then GetMousePosHwndAndClassName(rPos);
end;
function Tf.replacing(s,source,target:string):string;//█████ 替换字符串
var site, strlen: integer;
begin
site:=pos(source,s);
strlen:=length(source);
delete(s,site,strlen);
insert(target,s,site);
result:=s;
end;
procedure Tf.WndProc(var Message: TMessage);////███████▌罗技无限灵貂
begin with Message do begin
inherited;
//如果不是多媒体键区的中右侧三个键按下,则退出
IF NOT( (Msg=LOGITECH) and ((lParam=PLAY_PAUSE)or(lParam=PLAY_LEFT)or(lParam=PLAY_RIGHT)) ) THEN exit;
hFocus := GetForegroundWindow;
GetWindowText(hFocus, buf, 1024);
sTitle := string(buf);
deb(sTitle);
//ACDSee
if (pos('ACDSee', sTitle)>0) and (pos('5.0', sTitle)>0) and (Msg=LOGITECH) then case lParam of
PLAY_PAUSE: Key2(VK_Control, VK_Delete);//Ctrl+Del
PLAY_LEFT : Key2(VK_Menu , ord('M') );//Alt+M
PLAY_RIGHT: Key2(VK_Menu , Ord('C') );//Alt+C
end;
if (pos('ACD', sTitle)>0) and (pos('FotoCanvas', sTitle)>0) and (Msg=LOGITECH) then case lParam of
PLAY_PAUSE: Key2(VK_Control, ord('S'));//Ctrl+S
PLAY_LEFT : Key2(VK_Shift , ord('S'));//Shift+S
PLAY_RIGHT: Key2(VK_Shift , Ord('A'));//Shift+A
end;
//NetCaptor
if (pos('NetCaptor', sTitle)>0) and (Msg=LOGITECH) then case lParam of
PLAY_PAUSE: Key3(VK_Control, VK_Shift, ord('S'));//Ctrl+Shift+S
PLAY_LEFT : Key1(VK_F2);
PLAY_RIGHT: Key1(VK_F3);
end;
//UltraEdit
if (pos('UltraEdit-32', sTitle)>0) and (Msg=LOGITECH) then case lParam of
PLAY_PAUSE: Key2(VK_Control, ord('S'));//Ctrl+S
PLAY_LEFT : Key2(VK_Control, VK_F6 );//Ctrl+F6
PLAY_RIGHT: Key3(VK_Control, VK_Shift, VK_F6);//Ctrl+Shift+F6
end;
end; end;
procedure Tf.Down(VK: byte); begin keybd_event(VK, MapVirtualKey(VK, 0), 0, 0); end;
procedure Tf.UP (VK: byte); begin keybd_event(VK, MapVirtualKey(VK, 0), KEYEVENTF_KEYUp, 0); end;
procedure Tf.Key1(VK1: byte); begin
Down(VK1);
Up (VK1);
end;
procedure Tf.Key2(VK1, VK2: byte); begin
Down(VK1);
Down(VK2);
Up (VK2);
Up (VK1);
end;
procedure Tf.Key3(VK1, VK2, VK3: byte); begin
Down(VK1);
Down(VK2);
Down(VK3);
Up (VK3);
Up (VK2);
Up (VK1);
end;
end.
//▓▓▓▓▓▓▓▓▓ DlgDebug_U.pas
{*******************************************************************************
程序中用来显示调试信息的非模态对话框
2005/02
*******************************************************************************}
unit DlgDebug_U; interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
procedure deb(theMsg: string); overload;//Debug 信息
procedure deb(theMsg: integer);overload;
procedure deb(const theStr: string; const Args: array of const); overload;
type
TdlgDebug = class(TForm)
re: TRichEdit;
procedure mmKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
indent: byte;
selColor: TColor;
procedure TimeLine;
end;
var dlgDebug: TdlgDebug;
dbg: Boolean;
implementation
{$R *.dfm}
procedure TdlgDebug.mmKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if Key=VK_SPACE then begin
re.Tag := integer( not boolean(re.Tag) );
//mm.Tag := integer( not boolean(mm.Tag) );
//if boolean(mm.Tag) then Red.Suspend
//else Red.Resume;
end;
end;
procedure deb(theMsg: string); begin
if not dbg then exit;
with dlgDebug do begin//Debug 信息
TimeLine;
re.SelAttributes.Color := selColor;
re.paragraph.FirstIndent := indent;
re.Lines.Add(theMsg);
//mm.Lines.Add(theMsg);
end;
end;
procedure deb(theMsg: integer);
begin
if not dbg then exit;
with dlgDebug do begin//Debug 信息
TimeLine;
re.SelAttributes.Color := selColor;
re.paragraph.FirstIndent := indent;
re.Lines.Add(intToStr(theMsg));
//mm.Lines.Add(intToStr(theMsg));
end;
end;
procedure deb(const theStr: string; const Args: array of const); overload;
begin
if not dbg then exit;
with dlgDebug do begin//Debug 信息
TimeLine;
re.SelAttributes.Color := selColor;
re.paragraph.FirstIndent := indent;
re.Lines.Add(format(theStr, Args));
//mm.Lines.Add(format(theStr, Args));
end;
end;
procedure TdlgDebug.TimeLine;
begin with re do begin
paragraph.FirstIndent := 0;
SelAttributes.Color := clRed;
lines.Add(formatDateTime(LongTimeFormat, now));
end; end;
procedure TdlgDebug.FormCreate(Sender: TObject);
begin
indent := 10;
selColor := clYellow;
end;
end.
//▓▓▓▓▓▓▓▓▓ HookPrj.dpr
library HookPrj;
uses
SysUtils,
Classes,
Hook_U in 'Hook_U.pas';
exports
EnableWheelHook ,
DisableWheelHook;
begin
end.
//▓▓▓▓▓▓▓▓▓ Hook_U.pas
unit Hook_U; interface
uses Windows,Messages, SysUtils, dialogs;
var HK: HHOOK;//钩子的句柄值
hFocus: HWnd;
buf: array [0..1024] of char;
sTitle: string;
iC: byte;
zDelta: short;
function WheelHookProc(Code: Integer; WParam: Longint; Msg: Longint): LRESULT; stdcall;
function EnableWheelHook : Boolean; stdcall; export;
function DisableWheelHook: Boolean; stdcall; export;
implementation
//██████████████████████████████████▌处理钩子
function WheelHookProc(Code: Integer; WParam: Longint;Msg:Longint): LRESULT; stdcall;
begin
zDelta := short(HiWord(PMsg(Msg)^.wParam));
if (Code=HC_ACTION) and (PMsg(Msg)^.Message=WM_MOUSEWHEEL) and (abs(zDelta)>200) then begin
hFocus := GetForegroundWindow;
GetWindowText(hFocus, buf, 1024);
sTitle := string(buf);
if ( pos('mplayerc', sTitle)>0 )or( pos('Media Player Classic', sTitle)>0 ) then begin
inc(iC);
//按一次蓝色侧键产生两条消息,二合一处理的话相当于快进1次,即5秒,
//都处理的话相当于快进2次,即10秒
//if (iC mod 2)=0 then begin
keybd_event(VK_Control, MapVirtualKey(VK_Control, 0), 0, 0); //CTRL Down
if zDelta>200 then begin
keybd_event(VK_Right, MapVirtualKey(VK_Right, 0), 0, 0); //RIGHT Down
keybd_event(VK_Right, MapVirtualKey(VK_Right, 0), KEYEVENTF_KEYUP, 0);//RIGHT Up
end else begin
keybd_event(VK_Left , MapVirtualKey(VK_Left , 0), 0, 0); //LEFT Down
keybd_event(VK_Left , MapVirtualKey(VK_Left , 0), KEYEVENTF_KEYUP, 0);//LEFT Up
end;
keybd_event(VK_Control, MapVirtualKey(VK_Control, 0), KEYEVENTF_KEYUP, 0);//CTRL Up
//end;
PMsg(Msg)^.Message := 0;//因为侧键消息已经本地处理过了,不必再交给其它线程处理
end else Result := CallNextHookEx(HK, Code, WParam, Longint(@Msg));//如果不是MPC,则向下传递
end else Result := CallNextHookEx(HK, Code, WParam, Longint(@Msg));//如果不是两个蓝色侧键则向下传递
end;
function EnableWheelHook: Boolean; stdcall; export;//█████████ 加载钩子
begin
if HK=0 then begin
HK := SetWindowsHookEx(WH_GETMESSAGE, @WheelHookProc, Hinstance, 0);
Result := True;
end else Result := False;
end;
function DisableWheelHook: Boolean; stdcall; export;//████████▌卸载钩子
begin
if HK<>0 then begin
UnHookWindowsHookEx(HK);
HK := 0;
Result := True;
end else Result := False;
end;
end.
QQ:7995.7944(薪丝路)
E-Mail:gg7853@163.com