繁体   English   中英

c++ 在控制台“单元格”中获取用户 cursor position

[英]c++ get users cursor position in console "cells"

系统:Windows; 版本 c++23 想要在控制台应用程序中创建一个交互式按钮。 为此,我需要获取用户单击的位置 1) 相对于控制台 window 2) 不是在像素中,而是在控制台单元中。 我尝试过的事情:

using namespace std;
void GetMouseCursorPos(POINT *mC) {
    *mC = POINT{0,0};
    ScreenToClient(GetConsoleWindow(),mC);
    mC->x = mC->x / font.dwFontSize.X;
    mC->y = mC->y / font.dwFontSize.Y;
    system("cls");
    cout << mC->x << " " << mC->y;
}

int main (){
    POINT mCoord;
    while (true){
        SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_MOUSE_INPUT | 
 ENABLE_EXTENDED_FLAGS);
        GetMouseCursorPos(&mCoord);
    }
}

在全屏中总是输出 0 -4
第二次尝试:

using namespace std;
void GetMouseCursorPos(POINT *mC) {
    *mC = POINT{0,0};
    ScreenToClient(GetConsoleWindow(),mC);
    mC->x = mC->x / font.dwFontSize.X;
    mC->y = LONG(mC->y - 22.5) / font.dwFontSize.Y;
    system("cls");
    cout << mC->x << " " << mC->y;
}

int main (){
    POINT mCoord;
    while (true){
        SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_MOUSE_INPUT | 
 ENABLE_EXTENDED_FLAGS);
        GetMouseCursorPos(&mCoord);
    }
}

虽然第二次尝试更好(但仍然不完美)为什么第二次尝试不完美(图)
当你点击红色十字时,你 select 插槽左侧(不是插槽本身)

按钮 class:

using namespace std;

class Button {
public:
    int x;
    int y;
    int height;
    int width;
    string text;
    string text1;
    string text2;
    int color = 7;
    int itemColor = 7;

    string getText() { return text; };

    void setText(string text) { this->text = text; };

    bool isPressed(int mX, int mY) {
        if (mX >= this->x && mX <= this->x + width && mY >= this->y && mY <= this->y + height) {
            return true;
        }
        return false;
    };

    void print() {
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), {static_cast<SHORT>(x + 1), static_cast<SHORT>(y)});
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
        for (int i = 0; i < width - 1; i++) {
            cout << "-";
        }
        for (int i = 0; i < (height - 2); i++) {
            SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),
                                 {static_cast<SHORT>(x), static_cast<SHORT>(y + i + 1)});
            cout << "|";
            SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),
                                 {static_cast<SHORT>(x + width), static_cast<SHORT>(y + i + 1)});
            cout << "|";
        }
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),
                             {static_cast<SHORT>(x + 1), static_cast<SHORT>(y + height - 
1)});
        for (int i = 0; i < width - 1; i++) {
            cout << "-";
        }
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),
                                 {static_cast<SHORT>(x + 1),
                                  static_cast<SHORT>(y + height / 2)});
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
        for (int i = 0; i < width / 2 - text.length() / 2 - 1; i++) {
            cout << " ";
        }
        cout << text;
        for (int i = 0; i < width / 2 - text.length() / 2 - 1; i++) {
            cout << " ";
        }
        if (!text1.empty()) {
            SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),
                                     {static_cast<SHORT>(x + 1),
                                      static_cast<SHORT>(y + height / 2 + 1)});
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
            for (int i = 0; i < width / 2 - text1.length() / 2 - 1; i++) {
                cout << " ";
            }
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), itemColor);
            cout << text1[0];
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
            cout << text1.substr(1);
            for (int i = 0; i < width / 2 - text1.length() / 2 - 1; i++) {
                cout << " ";
            }
        }
        if (!text2.empty()) {
            SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),
                                      {static_cast<SHORT>(x + 1),
                                      static_cast<SHORT>(y + height / 2 - 1)});
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
            for (int i = 0; i < width / 2 - text2.length() / 2 - 1; i++) {
                cout << " ";
            }
            cout << text2;
            for (int i = 0; i < width / 2 - text2.length() / 2 - 1; i++) {
                cout << " ";
            }
        }
    }
};

通过使用参数ENABLE_MOUSE_INPUT SetConsoleMode您可以将控制台设置为报告鼠标事件。 然后可以使用 function ReadConsoleInput读取这些事件。

当读取一个鼠标事件时,你会得到一个MOUSE_EVENT_RECORD结构。 此结构的dwMousePosition成员位于字符单元格坐标中,而不是像素中。

这是一个示例程序:

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
    INPUT_RECORD ir;
    DWORD dwRead;

    //set console to report mouse input events (but nothing else, including keyboard events)
    if ( !SetConsoleMode( hInput, ENABLE_MOUSE_INPUT )  )
    {
        fprintf( stderr, "Error setting console mode!\n" );
        exit( EXIT_FAILURE );
    }

    while ( ReadConsoleInput( hInput, &ir, 1, &dwRead ) && dwRead == 1 )
    {
        //ignore all non-mouse events, except for the key "q", which is a request to end the program
        if ( ir.EventType != MOUSE_EVENT )
        {
            if (
                ir.EventType == KEY_EVENT &&
                ir.Event.KeyEvent.bKeyDown &&
                ir.Event.KeyEvent.uChar.AsciiChar == 'q'
            )
            {
                return 0;
            }
                
            continue;
        }

        //ignore all mouse events which don't involve mouse button presses
        if ( ir.Event.MouseEvent.dwEventFlags != 0 && ir.Event.MouseEvent.dwEventFlags != DOUBLE_CLICK )
            continue;

        //determine whether mouse button was clicked or released
        if ( ir.Event.MouseEvent.dwButtonState != 0 )
            printf( "Mouse button clicked" );
        else
            printf( "Mouse button released" );

        //print coordinates of mouse click/release
        printf(
            " at the following cell coordinates: [%u,%u]\n",
            ir.Event.MouseEvent.dwMousePosition.X,
            ir.Event.MouseEvent.dwMousePosition.Y
        );
        fflush( stdout );
    }

    fprintf( stderr, "Input error!\n" );
}

该程序具有以下 output:

Mouse button clicked at the following cell coordinates: [24,9]
Mouse button released at the following cell coordinates: [24,9]
Mouse button clicked at the following cell coordinates: [46,10]
Mouse button released at the following cell coordinates: [60,12]
Mouse button clicked at the following cell coordinates: [45,17]
Mouse button released at the following cell coordinates: [31,10]

要退出程序,您必须按Q键。

请注意,此程序仅用于演示目的,并未针对性能进行优化。 在性能可能成为问题的适当程序中,使用ReadConsoleInput一次读取多个事件可能会更好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM