注册 登录
编程论坛 C# 论坛

如何实现快捷键功能

蚕头燕尾 发布于 2015-08-25 14:12, 2634 次点击
问题是基于C#代码的,不知道发在哪里,就放在这个版块了。

要求实现全局快捷键,而且是单键,不是组合键。比如Space、A-Z等等。

1.非全局的组合快捷键(实现方法参见:http://blog.

2.非全局单键(不知道怎么实现)

3.全局组合键(同样参见上链接)

4.全局单键(我的问题)

10 回复
#2
TonyDeng2015-08-25 14:49
KeyDown是冒泡事件
#3
TonyDeng2015-08-25 14:54
下面的程序,不论在何处按键,都会在上面的TextBlock中显示按下的键名,哪怕光标在TextBox中亦如此。

只有本站会员才能查看附件,请 登录
#4
TonyDeng2015-08-25 14:57
程序代码:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas."
        xmlns:x="http://schemas."
        xmlns:d="http://schemas."
        xmlns:mc="http://schemas."
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        WindowStartupLocation="CenterScreen"
        KeyDown="Window_KeyDown"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="139,87,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="194,175,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>

    </Grid>
</Window>


程序代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            textBlock.Text = e.Key.ToString();
        }
    }
}
#5
蚕头燕尾2015-08-25 22:16
这段代码我看不太懂,我写的是winForm代码

我运行了一下程序,似乎并没有什么反应?

这是程序运行界面:
只有本站会员才能查看附件,请 登录
#6
蚕头燕尾2015-08-25 22:27
从你的叙述:不论在何处按键,都会在上面的TextBlock中显示按下的键名
我感觉有点鼠标追踪的意思(我听说钩子可以这样做,因为我C#刚接触,还未仔细看钩子是什么)

我听说钩子用来做全局快捷键挺方便,且暂不用这种办法。

我还是挺想知道这样做为什么不行的,下面是我的代码:
1.HotKey类的定义
程序代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Windows.Forms;  

namespace Hangman_Steven
{
    class HotKey
    {
        //如果函数执行成功,返回值不为0。  
        
//如果函数执行失败,返回值为0。要得到扩展错误信息,调用GetLastError。  
        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool RegisterHotKey(
            IntPtr hWnd,                 //要定义热键的窗口的句柄  
            int id,                      //定义热键ID(不能与其它ID重复)            
            KeyModifiers fsModifiers,    //标识热键是否在按Alt、Ctrl、Shift、Windows等键时才会生效  
            Keys vk                      //定义热键的内容  
            );

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool RegisterHotKey(
            IntPtr hWnd,
            int id,
            Keys vk
            );

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool UnregisterHotKey(
            IntPtr hWnd,                 //要取消热键的窗口的句柄  
            int id                       //要取消热键的ID  
            );

        //定义了辅助键的名称(将数字转变为字符以便于记忆,也可去除此枚举而直接使用数值)  
        [Flags()]
        public enum KeyModifiers
        {
            None = 0,
            Alt = 1,
            Ctrl = 2,
            Shift = 4,
            WindowsKey = 8
        }
    }
}



2.调用

HotKey.RegisterHotKey(Handle, 101, HotKey.KeyModifiers.Shift, Keys.A);//定义Shift+A


我幻想着可以这样调用

HotKey.RegisterHotKey(Handle, 101, Keys.A);


所以我在HotKey类的定义中重载了RegisterHotKey函数(具体见定义代码)。但是实践证明:

HotKey.RegisterHotKey(Handle, 101, Keys.A);

这样定义的快捷键并不起作用。

PS:快捷键功能定义函数(部分代码)
程序代码:


 /// 监视Windows消息,重载WndProc方法,用于实现热键响应
        protected override void WndProc(ref Message m)
        {
            const int WM_HOTKEY = 0x0312;
            //按快捷键  
            switch (m.Msg)
            {
                case WM_HOTKEY:
                    switch (m.WParam.ToInt32())
                    {
                        case 101:
                            //这里写具体的函数内容
                            break;
#7
蚕头燕尾2015-08-25 22:34
我想知道为什么我的代码原来那样是对的,为什么不能那样重载声明,简而言之,就是:这一切是怎么回事?

#8
TonyDeng2015-08-25 22:44
我写的是WPF
#9
TonyDeng2015-08-25 22:57
我上面2楼说了,在WPF中,KeyDown事件是冒泡的:事件首先在焦点控件内触发,被焦点控件处理过后,事件会向上冒泡,即由上层控件捕获,不管上层控件处理与否,都继续向上冒,直至最高层的容器即窗体(Window)。在这种机制中,捕获全局按键成为可能,只要由Window的KeyDown事件处理代码处理该键即可。

在WinForms中,用钩子的办法,需要首先由窗体捕获键盘按键事件,再决定是否向下传送,这里与WPF的方向相反。向下传送并不难,难在由最顶层控件捕获事件之后,要知道整个窗体的控件传递链路,才能向下传递到焦点控件中,这要你自己维护。要么你窗体直接拦截了事,不再向下传,但那不现实,因为有些按键是你不需要的,那必须仍由焦点控件去处理,而这个时候你传不下去了。

解决的办法:自己维护窗体的控件树!具体地说,是Windows消息处理的轮询必须是有顺序的,首先应由Form接收,依次向下。你原来的对,恐怕是因为控件少,当窗体空控件布局复杂时,就失效了。我是不写WinForms程序的,接下去就帮不了你啦。

[ 本帖最后由 TonyDeng 于 2015-8-25 23:03 编辑 ]
#10
wmf20142015-08-26 08:45
c#的窗体不知道有没有keypriview属性,该属性为true,则只要焦点在窗体中任何一个控件里都可以捕获键盘事件并送到需要的控件里显示,如果焦点不在本窗体,则只有消息钩子了。
#11
TonyDeng2015-08-26 11:52
其实试图在全局级设置单键快捷键是不现实的,那只会带来混乱。不说某些控件会阻塞消息,单是要在每一个控件上都写一个按键事件处理代码就够你受了。人家系统设计快捷键功能,都是采用平时小概率用到的按键组合,目的就是回避与多数控件的冲突,现在倒好,反过来,试图使用最普遍的单键,最终实现不了,也属正常。
1