当前位置:C++技术网 > 资讯 > 键盘方向键控制鼠标光标移动,并智能调节速度和绘制速度曲线

键盘方向键控制鼠标光标移动,并智能调节速度和绘制速度曲线

更新时间:2016-01-10 23:22:20浏览次数:1+次

    为了支持键盘操作光标,我们对键盘光标键的上下左右四个按键的消息进行处理。按照光标键的方向来移动鼠标光标。如果一次移动一个像素,那么效率就会太低了。而如果让移动的间距太大,又太不精确了。

    所以,我们采用自动调节速度的方式来调整移动光标的速度。为了让速度的变化更加直观,我们绘制了速度走势曲线图,如下图所示:

周期性调整光标的移动速度

【周期性调整光标的移动速度】
    从速度走势图中可以看出,总体上速度是呈周期性的变化。速度走势图中显示的是每次移动的距离,自然,移动的距离越大,速度越大。
    这个效果的实现,分为键盘光标的响应、鼠标光标的移动、智能调整速度和绘制速度曲线四部分。
    键盘光标的响应:
    在WM_KEYDOWN消息中,对比wParam携带的虚拟键码,即可对四个光标键进行响应。
    鼠标光标的移动:
    要说鼠标光标的移动,实际上就是设置鼠标光标的位置。透过现象看本质,移动光标就是不同的改变光标,随着时间的推移,在视觉上就形成了动感,就是光标移动的效果。我们使用函数SetCursorPos函数,传入xy坐标值即可设置。鼠标光标的坐标是屏幕坐标,不过我们对此并不关心。我们是实现的基于相对当前鼠标光标位置的移动。所以我们要获取当前光标的位置,调用函数GetCursorPos,并用POINT结构体变量来接受获得的光标位置的坐标。
    智能调整速度:
    其实我们就是利用数学的线程方程实现z=ax+y。我们累计y的值,然后当y到达21的时候,就增加x的值,也就是增加斜率,也就是加速变大的效果。这样速度会越来越快。当速度加速度到达了6的时候,然后开始递减加速度,降低速度的加速度。这里就是起一个演示的作用。你可以自己实现更多的速度控制。为了制造更多的随机的速度走势,我们在斜率x和y上都做了随机值。但是总体上,还是这个方程式的曲线走势。
    绘制速度曲线:
    移动的间距每次都会存入STL的vector容器,然后在WM_PAINT消息时绘制出来。所以在每次按下光标键移动鼠标光标的时候,就通知客户区重绘,即调用InvalidateRect。不过我们不需要客户区擦除背景,因为之前的速度曲线是重复的,没必要擦除,所以InvalidateRect第三个参数设置为FALSE。我们将vector容器中的移动的间距取出来轴y坐标,以i为x轴坐标,坐标系是客户区坐标系,所以是倒立的。然后就从原点不停的划线,连接各个点,即可形成走势曲线。

    如果你不想要这样的走势曲线,而想画成柱状图那样的曲线,只要每次将直线的起始点移动到客户区的顶部即可。柱状图如下图所示:

使用树状图来代替走势图

【使用树状图来代替走势图】
    下面是完整的代码:
#include "windows.h"
#include <tchar.h>
#include <vector>
using namespace std;
TCHAR tip[]=_T("C++技术网www.cjjjs.com");
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    static int iAcc = 0;
    static int iAcc2 = 0;
    static int step=0;
    static vector<int> speedlist;
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;
    switch (message)
    {
        case WM_KEYDOWN:
            {
                POINT pt;
                GetCursorPos(&pt);

                //移动速度自动调节

                iAcc2++;//累计iAcc2
                step=iAcc*rand()%3+iAcc2+rand()%10;//移动的幅度计算
                if (iAcc2>20)
                {
                    //Acc2累计到20,则加速一级
                    iAcc++;//线性加速一级
                    iAcc2=0;//重新计数
                }
                if (iAcc>5)
                {
                    //如果速度太快,控制速度,回归速度
                    iAcc--;//线性递减
                }
                speedlist.push_back(step);
                switch(wParam)
                {
                case VK_UP:
                    pt.y += -step;
                    break;
                case VK_DOWN:
                    pt.y += step;
                    break;
                case VK_LEFT:
                    pt.x += -step;
                    break;
                case VK_RIGHT:
                    pt.x += step;
                    break;
                }
                SetCursorPos(pt.x,pt.y);//设置光标位置
            }
            InvalidateRect(hwnd,NULL,FALSE);
            return 0;
        case WM_PAINT:
            hdc = BeginPaint(hwnd,&ps);
            GetClientRect(hwnd,&rect);
            for (int i=0;i<speedlist.size();i++)
            {
                MoveToEx(hdc,i*2,0,NULL);//去掉注释,可以形成柱状图
                LineTo(hdc,i*2,speedlist[i]*5);
            }

            EndPaint(hwnd,&ps);
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
        break;//跳出到默认处理
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
    TCHAR ClassName[] = _T("MyClass");
    TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
    WNDCLASS wndClass;
    wndClass.cbClsExtra=0;
    wndClass.cbWndExtra=0;
    wndClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndClass.hInstance = hInstance;
    wndClass.lpfnWndProc = WinProc;
    wndClass.lpszClassName = ClassName;
    wndClass.lpszMenuName=NULL;
    wndClass.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;

    if(!RegisterClass(&wndClass))return 0;
    HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,350,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}