控制台程序添加滚轮滑动支持

控制台程序默认只能通过拖动滚动条来查看窗口中打印的内容,操作起来十分不方便。

本文通过多线程技术为控制台窗体添加鼠标滚轮滑动功能。值得注意的是,在有内容输出时,窗口会自动定位到输出的光标处;

这种情况最好是先暂停住主线程,然后再滚动鼠标查看打印的内容,查看完毕后,再继续执行主线程。

首先,需要让控制台程序的屏幕缓冲区高度 > 窗口高度(此时窗口右侧会产生滚动条),否则无需滚动窗口。

下列代码实现了如下功能:

(1)滚动鼠标滑动窗口

(2)按空格键,暂停/继续主线程

#include <windows.h>

/**
* Scroll console window by relative coordinate
*/
static int ScrollByRelativeCoord(int iRows)
{
    CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
    SMALL_RECT srctWindow; 

    // Get the current screen buffer window position.
    HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);

    if (! GetConsoleScreenBufferInfo(hConsoleOutput, &csbiInfo))
    {
        return 0;
    }

    // Check whether the window is too close to the screen buffer top or bottom
    if (csbiInfo.srWindow.Top < iRows)
    {
        iRows = csbiInfo.srWindow.Top;
    }
    else if (csbiInfo.srWindow.Bottom > csbiInfo.dwSize.Y+iRows-1)
    {
        iRows = -1* (csbiInfo.dwSize.Y -1 - csbiInfo.srWindow.Bottom);
    }

    srctWindow.Top =- (SHORT)iRows;     // move top up
    srctWindow.Bottom =- (SHORT)iRows;  // move bottom up
    srctWindow.Left = 0;         // no change
    srctWindow.Right = 0;        // no change 

    if (! SetConsoleWindowInfo(
        hConsoleOutput,          // screen buffer handle
        FALSE,            // relative coordinates
        &srctWindow))     // specifies new location
    {
        return 0;
    }
    return iRows;
}

DWORD WINAPI ConsoleInputEventProc(LPVOID lParam)
{
    // vc6 version sdk don‘t has OpenThread API, need get by call GetProcAddress;
    HANDLE hMainThreadHandle = NULL;
#if _MSC_VER <= 1200
    HMODULE hDll =::LoadLibrary("Kernel32.dll");
    if (hDll)
    {
        typedef HANDLE (__stdcall *OPENTHREAD) (DWORD, BOOL, DWORD);
        OPENTHREAD fnOpenThread = (OPENTHREAD)::GetProcAddress(hDll, "OpenThread");
        if (fnOpenThread)
        {
            hMainThreadHandle = fnOpenThread(THREAD_SUSPEND_RESUME, FALSE, (DWORD)lParam);
        }
    }
#else
    hMainThreadHandle = OpenThread(THREAD_SUSPEND_RESUME, FALSE, (DWORD)lParam);
#endif

    HANDLE hConsoleInput = GetStdHandle(STD_INPUT_HANDLE);

    BOOL bSuspend = FALSE;
    BOOL fContinue = TRUE;
    DWORD dwEvents;
    INPUT_RECORD input;
    while (fContinue &&
        ReadConsoleInput(hConsoleInput, &input, 1, &dwEvents) &&
        dwEvents > 0)
    {
        switch (input.EventType)
        {
        case KEY_EVENT:
            if (input.Event.KeyEvent.wVirtualKeyCode == VK_SPACE)
            {
                if (input.Event.KeyEvent.bKeyDown && hMainThreadHandle != NULL)
                {
                    HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
                    if (bSuspend)
                    {
                        SetConsoleTextAttribute(hConsoleOutput, FOREGROUND_GREEN);
                        printf("Resume MainThread\n");
                        ResumeThread(hMainThreadHandle);
                    }
                    else
                    {
                        SetConsoleTextAttribute(hConsoleOutput, FOREGROUND_RED);
                        printf("Suspend MainThread\n");
                        SuspendThread(hMainThreadHandle);
                    }

                    SetConsoleTextAttribute(hConsoleOutput, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
                    bSuspend = !bSuspend;
                }
            }
        case MOUSE_EVENT:
            if (input.Event.MouseEvent.dwEventFlags==4)// mousewheel
            {
                const int nLine = 5;
                if ((int)input.Event.MouseEvent.dwButtonState>0)// scroll up
                {
                    ScrollByRelativeCoord(nLine);
                }
                else// scroll up
                {
                    ScrollByRelativeCoord(-1*nLine);
                }
            }
            break;
        }
    }

    CloseHandle(hMainThreadHandle);
    return 0;
}

int main(int argc, char* argv[])
{
    CreateThread(NULL, 0, ConsoleInputEventProc, (LPVOID)GetCurrentThreadId(), 0, NULL);

    int nLine = 60;
    while (nLine--)
    {
        printf("Hello World!\n");
        Sleep(1000);
    }

    Sleep(INFINITE);
    return 0;
}
时间: 2024-10-24 22:02:26

控制台程序添加滚轮滑动支持的相关文章

[WPF]为旧版本的应用添加触控支持

之前做WPF开发时曾经遇到这样一个需求:为一个基于 .NET Framework 3.5开发的老旧WPF程序添加触控支持,以便于大屏触控展示. 接手之后发现这是一个大坑. 项目最初的时候完全没考虑过软件架构设计,业务逻辑基本都写在后台代码中,经过两代程序员的开发维护(初代开发者已离职,文档这种东西不存在的),主界面cs代码已经有上万行,各种事件注册的非常杂乱.由于是做给政府部门用的,稳定性很重要,修修补补不断的打补丁,程序已经非常难维护了. 而且不像最新.net框架下的WPF以及UWP开发中,我

Delph控制台(Console)程序添加图标和版权信息

Delphi创建控制台(Console)程序默认是无法添加图标和版权的.经过仔细的对比窗体程序与控制台程序源码,发现窗体程序的工程文中,在uses结束begin开始的地方有一句如下代码:{$R *.res}而控制台程序的工程文件里是没有这句代码的.于是,我就在想是不是我在控制台程序的工程文件里加上如上代码,我们就可以更改图标和添加版权了,说做就开始做,加上如上代码,然后保存,Delphi会自动生成资源文件,如下图:本以为可以就可以编辑图标和版权了,结果发现,版权是可以修改了,但是图标还是无法修改

为 WPF 程序添加 Windows 跳转列表的支持

原文:为 WPF 程序添加 Windows 跳转列表的支持 Windows 跳转列表是自 Windows 7 时代就带来的功能,这一功能是跟随 Windows 7 的任务栏而发布的.当时应用程序要想用上这样的功能需要调用 shell 提供的一些 API. 然而在 WPF 程序中使用 Windows 跳转列表功能非常简单,在 XAML 里面就能完成.本文将介绍如何让你的 WPF 应用支持 Windows 跳转列表功能. 本文内容 一个简单的跳转列表程序 定制跳转列表的功能 一个简单的跳转列表程序

VS2017新建windows控制台程序打印中文乱码问题

最近刚换上VS2017,由于手头又要做个MFC的程序,所以写控制台程序做功能测试,然后发现居然乱码了. 于是用VS2017新建windows控制台应用程序,在main函数种加一句printf("你好");后,运行结果依然乱码 用notapad++打开该文件后,点击菜单栏的编码一项,发现是UTF-8无BOM格式编码,然后改成以ANSI格式编码后 也就是说VS是用UTF-8来编码代码文件的,编译出的程序中字符串也是按照UTF-8编码的,而控制台却是按照ANSI编码来理解的. 打个比方,A用

VC++ GUI桌面程序添加控制台调试输出

VC++ GUI桌面程序添加控制台调试输出 GUI控制台 GUI桌面应用程序添加控制台只需按如下步骤在代码中添加即可: 1. 第一步:引入头文件 #include "stdio.h" 2.第二步:在程序开始部分添加如下代码 AllocConsole(); freopen("CONOUT$", "w", stdout);//开启中文控制台输出支持 3. 第三步:程序结束部分添加 FreeConsole(); //释放 原文地址:https://ww

为Azure Web Site 添加ADFS验证支持之二 在代码里使用ADFS

下面我们来创建一个MVC 5.0的ASP.Net程序,并且将它部署到Azure Web Site上 通过Visual Studio 2015创建Web Project 在选择ASP.net模板的地方,更改验证方式   在选择验证方式时选择"Work And School Accounts",在文本框中填入 1.你公司的ADFS的Metadata的地址,这个地址可以找ADFS的管理员要到,通常如以下形式: https://{youradfs.yourcompany.com}/federa

【控制台程序】一闪而过的基本解决办法

方法1: 直接通过[Ctrl + F5]组合键启动程序: 方法2: 在程序中加上getchar(); 方法3: 先添加对应引用: #include <ctype.h> #include <iostream> system("pause"); //代码中加上这句,系统暂停; 方法4: 通过[cin>>]等待新的输入来实现暂停的作用. [控制台程序]一闪而过的基本解决办法,布布扣,bubuko.com

网上下载的dubbo-admin控制台程序启动报错Bean property &#39;URIType&#39; is not writable

因为linux中使用的是jdk1.8,所以网上直接下载的dubbo-admin.war基本是2.5.4及以下的,如果放入tomcat中启动会报以下错误信息 Caused by: org.springframework.beans.NotWritablePropertyException: Invalid prope rty 'URIType' of bean class [com.alibaba.citrus.service.uribroker.uri.GenericURI Broker]: B

C#控制台程序的参数解析类库 CommandLine简单使用说明

前言 C#开发的控制台程序,默认接收string[] args参数.如果有多个参数需要输入时,可以按照顺序依次输入:但如果有些参数不是必选的,或者有些参数中间需要有空格比如时间“2016-05-18 24:35:00”,处理起来就比较麻烦了.一些常用的命令行工具都会提供指定参数的方式,比如:curl C:\Users\Administrator>curl --helpUsage: curl [options...] <url>Options: (H) means HTTP/HTTPS o