卡尔一键放技能--dota

news/2024/9/30 0:20:47/

源地址:

http://linger.devhub.com/blog/754274--dota/

可执行程序和源代码下载地址:http://download.csdn.net/detail/linger2012liu/4029003

卡尔一键放技能

     突然间想试试用卡尔这个英雄,毕竟这个英雄技能多比较爽,但不好的是技能太多转换起来好麻烦好难记,所以有个一键放技能的工具就好了。

       其实这个原理跟dota改键精灵的是一样的,都是利用windows挂钩技术,首先设置好键盘钩子,然后捕获键盘消息,再调用自己写的发送按键消息的函数,即可一键切换技能。

举个例子吧,比如卡尔的“急速冷却”这个技能,原本是按QQQR来切换,再加上Y来释放,比如我们想用数字键“1”来一键释放这个技能,那么就在捕获了用户按下“1”这个键之后,想魔兽3这个窗体发送QQQRY几个按键消息,

SendMessage(childWnd, WM_KEYDOWN, 'Q', 0);

            SendMessage(childWnd, WM_KEYUP, 'Q', 0);

            SendMessage(childWnd, WM_KEYDOWN, 'Q', 0);

            SendMessage(childWnd, WM_KEYUP, 'Q', 0);

            SendMessage(childWnd, WM_KEYDOWN, 'Q', 0);

            SendMessage(childWnd, WM_KEYUP, 'Q', 0);

            SendMessage(childWnd, WM_KEYDOWN, 'R', 0);

            SendMessage(childWnd, WM_KEYUP, 'R', 0);

            Thread.Sleep(300);//有时候不延迟一点会无法释放技能的

            SendMessage(childWnd, WM_KEYDOWN, 'Y', 0);

            SendMessage(childWnd, WM_KEYUP, 'Y', 0);

       当然在这之前要设置钩子,大约如下

              using (System.Diagnostics.Process curProcess = System.Diagnostics.Process.GetCurrentProcess())

              using (System.Diagnostics.ProcessModule curModule = curProcess.MainModule)

              hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle(curModule.ModuleName), 0);

SetWindowsHookEx的第一个参数为要截获的消息类型,这里肯定是键盘消息啊,第二个参数为截获到消息后的回调函数,第三个参数为回调函数所在dll或exe的模块的句柄,这里是本执行程序的句柄,第四个为关联的线程id(这个不是很懂,不过知道的是系统钩子设置为0即可)。

       然后回调函数做的事就是根据用户按下的键而决定向魔兽3发送什么按键消息。

       刚开始有点坑爹,本来我打算先用c语言写个控制台程序实现一键放技能的功能,但是貌似控制台程序有个缺点,就是它会尽可能快的结束这个程序的运行,就是它按着main函数运行,一般很快就到return 了,一return程序就不工作了,它不会像窗体程序那样在等待消息。我试过用system(“pause”)让main函数阻塞在那里,但回调函数还是不起效即不会工作。还试过在main函数里面设置一个while的死循环,在里面输出点什么或者向记事本发送几个字符,有时截获到消息有时又没有。哎,总之,对windows的消息机制还不是很懂,解决不了。最后还是用窗体程序做吧。

       后来用wpf做了,其中发现一个很有趣的事情。就是用到CallNextHookEx,网上声明这个函数的一般的方法都是将第四个参数声明为int或者Int32的,但我观察到一个现象就是对于同一个函数,很多人用的时候声明有时候不一样的,特别是参数类型,但的确都是可行的,我就纳闷了,于是结合几篇文章,瞎搞了一下,就是把第四个参数类型设为自己定义的结构体,没想到竟然可以,声明如下       public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, ref KeyboardHookStruct lParam);

其中[StructLayout(LayoutKind.Sequential)]

        public struct KeyboardHookStruct

        {

            public int vkCode;//键盘虚拟码

            public int scanCode;//扫描码

            public int flags;

            public int time;

            public int dwExtraInfo;

        }

真不是很懂windows api的调用是怎样子的啊,看来有时间要研究一下这个问题。

贴一下源代码吧(用wpf写的):

xaml:

 

<Window x:Class="Carl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="卡尔一键释放技能-linger" Height="700" Width="525"
Loaded="Window_Loaded"
Left="100"
Top="30"
Icon="icon.ico"
Deactivated="Window_Deactivated"
>
<Window.Background>
<ImageBrush ImageSource="carl.jpg" />
</Window.Background>
<ScrollViewer>
<StackPanel >
<Button Width="100" Margin="30" Click="Button_Click">应用</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Margin="0,0,50,0" 
Foreground="Red"
FontSize="15">
按键</TextBlock>
<TextBlock
Foreground="Red"
FontSize="15">技能</TextBlock>
</StackPanel>
<StackPanel Name="main">
<!--
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Width="50" Height="20" MaxLength="1" Margin="20">
</TextBox>
<ComboBox Name="cb" Width="100" Height="20"> 
<ComboBoxItem>急速冷却</ComboBoxItem>
<ComboBoxItem>浑沌陨石</ComboBoxItem>
<ComboBoxItem>超震声波</ComboBoxItem>
<ComboBoxItem>强袭飓风</ComboBoxItem>
<ComboBoxItem>熔炉精灵</ComboBoxItem>
<ComboBoxItem>冰墙</ComboBoxItem>
<ComboBoxItem>电磁脉冲</ComboBoxItem>
<ComboBoxItem>幽灵漫步</ComboBoxItem>
<ComboBoxItem>阳炎冲击</ComboBoxItem>
<ComboBoxItem>灵动迅捷</ComboBoxItem>
</ComboBox>
</StackPanel>-->
</StackPanel>
</StackPanel>
</ScrollViewer>
</Window>
<Window x:Class="Carl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="卡尔一键释放技能-linger" Height="700" Width="525"
Loaded="Window_Loaded"
Left="100"
Top="30"
Icon="icon.ico"
Deactivated="Window_Deactivated"
>
<Window.Background>
<ImageBrush ImageSource="carl.jpg" />
</Window.Background>
<ScrollViewer>
<StackPanel >
<Button Width="100" Margin="30" Click="Button_Click">应用</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Margin="0,0,50,0" 
Foreground="Red"
FontSize="15">
按键</TextBlock>
<TextBlock
Foreground="Red"
FontSize="15">技能</TextBlock>
</StackPanel>
<StackPanel Name="main">
<!--
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Width="50" Height="20" MaxLength="1" Margin="20">
</TextBox>
<ComboBox Name="cb" Width="100" Height="20"> 
<ComboBoxItem>急速冷却</ComboBoxItem>
<ComboBoxItem>浑沌陨石</ComboBoxItem>
<ComboBoxItem>超震声波</ComboBoxItem>
<ComboBoxItem>强袭飓风</ComboBoxItem>
<ComboBoxItem>熔炉精灵</ComboBoxItem>
<ComboBoxItem>冰墙</ComboBoxItem>
<ComboBoxItem>电磁脉冲</ComboBoxItem>
<ComboBoxItem>幽灵漫步</ComboBoxItem>
<ComboBoxItem>阳炎冲击</ComboBoxItem>
<ComboBoxItem>灵动迅捷</ComboBoxItem>
</ComboBox>
</StackPanel>-->
</StackPanel>
</StackPanel>
</ScrollViewer>
</Window>
<Window x:Class="Carl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="卡尔一键释放技能-linger" Height="700" Width="525"
Loaded="Window_Loaded"
Left="100"
Top="30"
Icon="icon.ico"
Deactivated="Window_Deactivated"
>
<Window.Background>
<ImageBrush ImageSource="carl.jpg" />
</Window.Background>
<ScrollViewer>
<StackPanel >
<Button Width="100" Margin="30" Click="Button_Click">应用</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Margin="0,0,50,0" 
Foreground="Red"
FontSize="15">
按键</TextBlock>
<TextBlock
Foreground="Red"
FontSize="15">技能</TextBlock>
</StackPanel>
<StackPanel Name="main">
<!--
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Width="50" Height="20" MaxLength="1" Margin="20">
</TextBox>
<ComboBox Name="cb" Width="100" Height="20"> 
<ComboBoxItem>急速冷却</ComboBoxItem>
<ComboBoxItem>浑沌陨石</ComboBoxItem>
<ComboBoxItem>超震声波</ComboBoxItem>
<ComboBoxItem>强袭飓风</ComboBoxItem>
<ComboBoxItem>熔炉精灵</ComboBoxItem>
<ComboBoxItem>冰墙</ComboBoxItem>
<ComboBoxItem>电磁脉冲</ComboBoxItem>
<ComboBoxItem>幽灵漫步</ComboBoxItem>
<ComboBoxItem>阳炎冲击</ComboBoxItem>
<ComboBoxItem>灵动迅捷</ComboBoxItem>
</ComboBox>
</StackPanel>-->
</StackPanel>
</StackPanel>
</ScrollViewer>
</Window>
<Window x:Class="Carl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="卡尔一键释放技能-linger" Height="700" Width="525"
Loaded="Window_Loaded"
Left="100"
Top="30"
Icon="icon.ico"
Deactivated="Window_Deactivated"
>
<Window.Background>
<ImageBrush ImageSource="carl.jpg" />
</Window.Background>
<ScrollViewer>
<StackPanel >
<Button Width="100" Margin="30" Click="Button_Click">应用</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Margin="0,0,50,0" 
Foreground="Red"
FontSize="15">
按键</TextBlock>
<TextBlock
Foreground="Red"
FontSize="15">技能</TextBlock>
</StackPanel>
<StackPanel Name="main">
<!--
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<TextBox Width="50" Height="20" MaxLength="1" Margin="20">
</TextBox>
<ComboBox Name="cb" Width="100" Height="20"> 
<ComboBoxItem>急速冷却</ComboBoxItem>
<ComboBoxItem>浑沌陨石</ComboBoxItem>
<ComboBoxItem>超震声波</ComboBoxItem>
<ComboBoxItem>强袭飓风</ComboBoxItem>
<ComboBoxItem>熔炉精灵</ComboBoxItem>
<ComboBoxItem>冰墙</ComboBoxItem>
<ComboBoxItem>电磁脉冲</ComboBoxItem>
<ComboBoxItem>幽灵漫步</ComboBoxItem>
<ComboBoxItem>阳炎冲击</ComboBoxItem>
<ComboBoxItem>灵动迅捷</ComboBoxItem>
</ComboBox>
</StackPanel>-->
</StackPanel>
</StackPanel>
</ScrollViewer>
</Window>
c#:using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
using System.Runtime.InteropServices;
using System.Threading;
namespace Carl
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
//using System.Runtime.InteropServices;记得添加
[DllImport("USER32.DLL")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.DLL")]
public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
//安装钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
//下一个钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, ref KeyboardHookStruct lParam);
//卸载钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
public delegate int HookProc(int nCode, Int32 wParam,ref KeyboardHookStruct lParam);
HookProc KeyboardHookProcedure;
public const int WH_KEYBOARD_LL = 13;
const int WM_CHAR = 0x102;
const int  WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
IntPtr npWnd, childWnd;
static int hKeyboardHook = 0;
[StructLayout(LayoutKind.Sequential)]
public struct KeyboardHookStruct
{
public int vkCode;//表示一个1到254间的虚拟键盘码
public int scanCode;//表示硬件扫描码
public int flags;
public int time;
public int dwExtraInfo;
}
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 10;i++ )
addNew();
ht = new Hashtable();
init(0, "1", "急速冷却");
init(1, "2", "浑沌陨石");
init(2, "3", "超震声波");
init(3, "4", "强袭飓风");
init(4, "5", "熔炉精灵");
init(5, "6", "冰墙");
init(6, "7", "电磁脉冲");
init(7, "8", "幽灵漫步");
init(8, "9", "阳炎冲击");
init(9, "0", "灵动迅捷");
}
void updateKeyValue()
{
ColdSnap = (char)(ht["急速冷却"].ToString().ToCharArray())[0];
ChaosMeteor = toVcode("浑沌陨石");
DefeaningBlast = toVcode("超震声波");
Tornado = toVcode("强袭飓风");
ForgedSpirit = toVcode("熔炉精灵");
IceWall = toVcode("冰墙");
EMP = toVcode("电磁脉冲");
GhostWalk = toVcode("幽灵漫步");
SunStrike = toVcode("阳炎冲击");
Alacrity = toVcode("灵动迅捷");
}
char toVcode(string str)
{
char ch =  (char)(ht[str].ToString().ToCharArray())[0];
//小写还要转成大写
if(ch >= 'a' && ch <='z')
ch = (char)(ch - 'a' +'A');
return ch;
}
void init(int index,string key,string tec)
{
StackPanel sp = (StackPanel)main.Children[index];
ComboBox cbb = (ComboBox)sp.Children[1];
TextBox tbb = (TextBox)sp.Children[0];
tbb.Text = key;
cbb.SelectedValue = tec;
ht.Add((cbb.SelectedItem).ToString(),tbb.Text);
}
void addNew()
{
StackPanel sp = new StackPanel();
sp.Orientation = Orientation.Horizontal;
sp.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
TextBox tb = new TextBox();
tb.Width = 50;
tb.Height = 20;
tb.Margin = new Thickness(20);
tb.MaxLength = 1;
sp.Children.Add(tb);
ComboBox cb2 = new ComboBox();
cb2.Width = 100;
cb2.Height = 20;
//原来下面添加的字符串不是ComboxItem
cb2.Items.Add("急速冷却");
cb2.Items.Add("浑沌陨石");
cb2.Items.Add("超震声波");
cb2.Items.Add("强袭飓风");
cb2.Items.Add("熔炉精灵");
cb2.Items.Add("冰墙");
cb2.Items.Add("电磁脉冲");
cb2.Items.Add("幽灵漫步");
cb2.Items.Add("阳炎冲击");
cb2.Items.Add("灵动迅捷");
sp.Children.Add(cb2);
main.Children.Add(sp);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//npWnd = FindWindow("notepad", null);//刚开始用记事本作为测试
//  if (npWnd == IntPtr.Zero)
// {
//     MessageBox.Show("找不到窗口");
//    return;
//}
//  childWnd = FindWindowEx(npWnd, IntPtr.Zero, "Edit", null);
childWnd = FindWindow(null, "Warcraft III");
if (childWnd == IntPtr.Zero)
{
MessageBox.Show("魔兽3未启动,设置失败");
return;
}
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
using (System.Diagnostics.Process curProcess = System.Diagnostics.Process.GetCurrentProcess())
using (System.Diagnostics.ProcessModule curModule = curProcess.MainModule)
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle(curModule.ModuleName), 0);
}
//冰 Q    雷W     火E
//急速冷却 (Y)  技能组合:QQQ+R    ColdSnap  = 1
// 浑沌陨石 (D)   技能组合:EEW+R   ChaosMeteor =2 
//超震声波 (B)   技能组合:QWE+R   DefeaningBlast =3 
//强袭飓风 (X)   技能组合:WWQ+R    Tornado  =4 
//熔炉精灵 (F)  技能组合:EEQ+R    ForgedSpirit  =5 
//冰墙 (G)  技能组合:QQE+R        IceWall  =6 
//电磁脉冲 (C)   技能组合:WWW+R   EMP  =7
//幽灵漫步 (V)   技能组合:QQW+R   GhostWalk  =8
//阳炎冲击 (T)  技能组合:EEE+R     SunStrike  =9
//灵动迅捷 (Z)  技能组合:WWE+R   Alacrity  = 0
Hashtable ht = new Hashtable();
//用户输入决定哪个键对应哪个技能,比如用户  "急速冷却"  对应于 i键
//则令  ColdSnap等于 ht["急速冷却"] = i的虚拟码
//以下是默认值
int ColdSnap = '1';
int ChaosMeteor = '2';
int DefeaningBlast = '3';
int Tornado = '4';
int ForgedSpirit = '5';
int IceWall = '6';
int EMP = '7';
int GhostWalk = '8';
int SunStrike = '9';
int Alacrity = '0';
void RunAlacrity()
{ //WWE+R   Z
Run('W', 'W', 'E', 'R', 'Z');
}
void RunSunStrike()
{ //EEE+R  T
Run('E', 'E', 'E', 'R', 'T');
}
void RunGhostWalk()
{ //QQW+R  V
Run('Q', 'Q', 'W', 'R', 'V');
}
void RunEMP()
{ //WWW+R   C
Run('W', 'W', 'W', 'R', 'C');
}
void RunIceWall()
{ //QQE+R  G
Run('Q', 'Q', 'E', 'R', 'G');
}
void RunForgedSpirit()
{ //EEQ+R   F
Run('E', 'E', 'Q', 'R', 'F');
}
void RunTornado()
{//WWQ+R  X
Run('W', 'W', 'Q', 'R', 'X');
}
void RunDefeaningBlast()
{ //QWE+R B
Run('Q', 'W', 'E', 'R', 'B');
}
void RunChaosMeteor()
{//EEW+R
Run('E','E','W','R','D');          
}
void RunColdSnap()
{
SendMessage(childWnd, WM_KEYDOWN, 'Q', 0);
SendMessage(childWnd, WM_KEYUP, 'Q', 0);
SendMessage(childWnd, WM_KEYDOWN, 'Q', 0);
SendMessage(childWnd, WM_KEYUP, 'Q', 0);
SendMessage(childWnd, WM_KEYDOWN, 'Q', 0);
SendMessage(childWnd, WM_KEYUP, 'Q', 0);
SendMessage(childWnd, WM_KEYDOWN, 'R', 0);
SendMessage(childWnd, WM_KEYUP, 'R', 0);
Thread.Sleep(300);
SendMessage(childWnd, WM_KEYDOWN, 'Y', 0);
SendMessage(childWnd, WM_KEYUP, 'Y', 0);
/*
SendMessage(childWnd, WM_CHAR, 'Q', 0);
SendMessage(childWnd, WM_CHAR, 'Q', 0);
SendMessage(childWnd, WM_CHAR, 'Q', 0);
SendMessage(childWnd, WM_CHAR, 'R', 0);
SendMessage(childWnd, WM_CHAR, 'Y', 0);*/
}
void Run(int a, int b, int c, int d, int e)
{
SendMessage(childWnd, WM_KEYDOWN, a, 0);
SendMessage(childWnd, WM_KEYUP, a, 0);
SendMessage(childWnd, WM_KEYDOWN, b, 0);
SendMessage(childWnd, WM_KEYUP, b, 0);
SendMessage(childWnd, WM_KEYDOWN, c, 0);
SendMessage(childWnd, WM_KEYUP, c, 0);
SendMessage(childWnd, WM_KEYDOWN, d, 0);
SendMessage(childWnd, WM_KEYUP, d, 0);
Thread.Sleep(300);
SendMessage(childWnd, WM_KEYDOWN, e, 0);
SendMessage(childWnd, WM_KEYUP, e, 0);
}
private int KeyboardHookProc(int nCode, Int32 wParam, ref KeyboardHookStruct lParam)
{
// MessageBox.Show("截获到消息");
// if (wParam == WM_KEYDOWN)
//   MessageBox.Show(lParam.vkCode.ToString());
//为何我这里验证-号的虚拟码是189呢,算了不用这个了
if (wParam == WM_KEYDOWN &&enable)//可以识别小a了
{
if (lParam.vkCode == ColdSnap)
{
RunColdSnap();
}
else if (lParam.vkCode == ChaosMeteor)
{
RunChaosMeteor();
}
else if (DefeaningBlast == lParam.vkCode)
RunDefeaningBlast();
else if (Tornado == lParam.vkCode)
RunTornado();
else if (ForgedSpirit == lParam.vkCode)
RunForgedSpirit();
else if (IceWall == lParam.vkCode)
RunIceWall();
else if (EMP == lParam.vkCode)
RunEMP();
else if (GhostWalk == lParam.vkCode)
RunGhostWalk();
else if (SunStrike == lParam.vkCode)
RunSunStrike();
else if (Alacrity == lParam.vkCode)
RunAlacrity();
else
return CallNextHookEx(hKeyboardHook, nCode, wParam, ref lParam);
return 1;
//根据返回值的范围决定是否继续传播
//以下方法是可行的
//返回1阻止消息继续传播
//返回0消息继续传播
}
//交给下一个钩子处理消息
return CallNextHookEx(hKeyboardHook, nCode, wParam,ref lParam);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
childWnd = FindWindow(null, "Warcraft III");
if (childWnd == IntPtr.Zero)
{
MessageBox.Show("魔兽3未启动,设置失败");
return;
}
ht.Clear();
foreach(StackPanel sp in main.Children)
{
ComboBox cbb = (ComboBox)sp.Children[1];
TextBox tbb = (TextBox)sp.Children[0];
if (null != cbb.SelectedItem && tbb.Text != null)
{
// ht.Add(tbb.Text, (cbb.SelectedItem).ToString());
ht.Add((cbb.SelectedItem).ToString(), tbb.Text);
// MessageBox.Show(tbb.Text + ((ComboBoxItem)cbb.SelectedItem).ToString());
//MessageBox.Show( (cbb.SelectedItem).ToString());
}
}
updateKeyValue();
}
bool enable = false;//因为是系统钩子,所以避免挂钩本程序的按键
private void Window_Deactivated(object sender, EventArgs e)
{
enable = true;//失去焦点时再起效
}
}
}


http://www.ppmy.cn/news/526904.html

相关文章

基于钩子的改键

玩dota时候&#xff0c;大多的人会使用改建精灵&#xff0c;在网上找了找资料&#xff0c;发现这个其实不难编&#xff0c;于是自己实现了一个。 首先&#xff0c;要了解什么是钩子&#xff08;HOOK&#xff0c;彼得潘里的虎克船长就是这个&#xff09;。我们都知道在windows程…

dota是java中的_用java开发dota英雄最华丽的技能(实例讲解)

爱java 爱dota&#xff0c;突发奇想想用java开发dota操作最华丽的英雄之一的卡尔的技能&#xff0c;因为本人系小白&#xff0c;代码不足的地方还请包涵&#xff0c;有同样爱好的同学欢迎一起研究学习。 先把我的代码呈上 import java.util.*; public class TestDotakaer{ publ…

dota是java中的_用java开发dota英雄最华丽的技能

爱java 爱dota&#xff0c;突发奇想想用dota操作最华丽的英雄之一的卡尔的技能&#xff0c;因为本人系小白&#xff0c;代码不足的地方还请包涵&#xff0c;有同样爱好的同学欢迎一起研究学习。 先把我的代码呈上 import java.util.*; public class TestDotakaer{ public stati…

dota2 自定义官方服务器,DOTA2官网更新:服务器扩容 首部官方漫画发布

DOTA2全新宣传画 随着GamsCom的临近&#xff0c;更多DOTA2的截图也相继流出&#xff0c;身为主策划之一的IceFrog也曝光了DOTA2的全新原画。 http://img3.cache.netease.com/photo/0031/2011-08-15/7BG5AVI44NQF0031.jpg http://img4.cache.netease.com/photo/0031/2011-08-15/…

一个简易的dota改键助手

那年,刚开始玩dota的时候, 发现物品栏的快捷键太不好按鸟(集中在小键盘的数字键)。于是各种改键工具应运而生,像最经典的warkey, 不知不觉就用了好多年。如今,各种改键工具越来越强大了, 支持各种,甚至是喊话什么的~不过最经典的warkey,实际上只是简单的键盘映射, …

【Linux】VNC xfc4安装指导

1.xfce4软件介绍 Xfce是一个自由软件&#xff0c;运行在类Unix操作系统 (如Linux、FreeBSD 和 Solaris)上&#xff0c;提供轻量级桌面环境。 Xfce快速、轻量&#xff0c;界面美观和对用户友好。 Xfce由独立的软件组件构成&#xff0c;可根据需要单独使用或者组合在一起提供计算…

嵌入式VNC远程桌面配置终极指南

伙计们&#xff0c;终极指南在手&#xff0c;小赞点起来哦&#xff01; 1.开发板VNC服务器安装 #1.终端输入如下指令安装tightvncserver sudo apt-get install tightvncserver#2.终端输入下方指令初次运行vncserver vncserver#3.之后会提示输入密码&#xff08;两次&#xff…

局域网中Openstack的VNC安全配置

局域网中Openstack的VNC安全配置 1.前言 Openstack虚拟机的VNC是通过开启计算节点5900-5999端口来实现网页显示的&#xff0c;当外人知道计算节点的IP地址后可以通过VNC端口访问到所有的虚拟机&#xff0c;非常的不安全&#xff0c;其中为了防止出现虚拟机被攻击的情况&#…