SDL2无法捕获控制台键盘事件?

问题描述 投票:1回答:1

TL; DR

我正在尝试在自己的C ++程序中捕获键盘事件(更具体地说,是Ctrl + c命令)。我正在尝试通过SDL2中的通用键盘按键来进行此操作。

END TL; DR

我在SO和Internet上找到了涉及使用SDL2处理键盘事件的链接。我这里列出了一些。

https://stackoverflow.com/questions/28105533/sdl2-joystick-dont-capture-pressed-event
https://lazyfoo.net/tutorials/SDL/04_key_presses/index.php
http://www.cplusplus.com/forum/windows/182214/
http://gigi.nullneuron.net/gigilabs/handling-keyboard-and-mouse-events-in-sdl2/

我认为引起问题的主要问题是,我同时也在使用Xbox风格的操纵杆。捕获操纵杆事件没有任何问题。我已经做了很长时间了。我在尝试使键盘上的任何东西引发事件时遇到问题。我尝试过if(event.type == SDL_KEYDOWN),然后检查它是哪个键,但是似乎什么也没返回。我觉得我需要定义一些宏来允许这样做,因为我一直在互联网上找到相同的解决方案。

我已经包含了我目前正在运行的整个脚本。


#include <boost/thread.hpp>
// Time library
#include <chrono>
// vector data structure
#include <vector>
// Thread-safe base variables
#include <atomic>
// std::cout
#include <iostream>
// Joystick library
#include <SDL2/SDL.h>
// Counters for printing
std::atomic_int printcounter{ 0 };
// This is every 3 * 1000 milliseconds
const int printer = 300;
// If an event is found, allow for printing.
std::atomic_bool eventupdate{ false };
// This function converts the raw joystick axis from the SDL library to proper double precision floating-point values.
double intToDouble(int input)
{
    return (double) input / 32767.0 ;
}
// Prevent joystick values from going outside the physical limit
double clamp(double input)
{
    return (input < -1.0) ? -1.0 : ( (input > 1.0) ? 1.0 : input);
}
// SDL library joystick deadband
const int JOYSTICK_DEAD_ZONE = 5000;
// These are the raw read in values from the joystick in XInput (XBox) mode.
//Normalized direction
int leftX = 0;
int leftY = 0;
int rightX = 0;
int rightY = 0;
int leftTrigger  = -32768;
int rightTrigger = -32768;
// Button array
uint buttons[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// Tbe pov hat is only 4 bits - 1, 2, 4, 8
int povhat = 0;
// These are the rectified joystick values
double leftstickx = 0;
double leftsticky = 0;
double rightstickx = 0;
double rightsticky = 0;
double lefttrigger = 0;
double righttrigger = 0;
// These are the rectified boolean buttons
bool leftstickbut = false;
bool rightstickbut = false;
bool xbutton = false;
bool ybutton = false;
bool abutton = false;
bool bbutton = false;
bool rightbut = false;
bool leftbut = false;
bool startbut = false;
bool backbut = false;
bool centbut = false;

// This is the boolean that controls running the robot.
std::atomic_bool quitrobot{false};
// Joystick values
static double joyvalues[6] = { 0, 0, 0, 0, 0, 0};
static bool joybuttons[11] = { false };
// Sleep function
void wait(int milliseconds)
{
    boost::this_thread::sleep_for(boost::chrono::milliseconds{milliseconds});
}
// Now the main code
int main(int argc, char** argv)
{
    // Now the robot goes through the looping code until a quit flag is set to true
    while ( ! quitrobot)
    {
        // Now we look for an Xbox-style joystick
        std::cout << "Looking for gamepad..." << std::endl;
        while(true)
        {
            // Now the program waits until an Xbox-style joystick is plugged in.
            // resetting SDL makes things more stable
            SDL_Quit();
            // restart SDL with the expectation that a jostick is required.
            SDL_Init(SDL_INIT_JOYSTICK);
            // SDL_HINT_GRAB_KEYBOARD
            // check for a joystick
            int res = SDL_NumJoysticks();
            if (res > 0) { break; } // Here a joystick has been detected.
            if (res < 0)
            {
                std::cout << "Joystick detection error: " << std::to_string(res) << std::endl;
            }
            // we don't want the program running super fast when detecting hardware.
            wait(20);
        }
        // Now we check to make sure that the joystick is valid.
        // Open the joystick for reading and store its handle in the joy variable
        SDL_Joystick *joy = SDL_JoystickOpen(0);
        if (joy == NULL) {
            /* back to top of while loop */
            continue;
        }
        // Get information about the joystick
        const char *name = SDL_JoystickName(joy);
        const int num_axes = SDL_JoystickNumAxes(joy);
        const int num_buttons = SDL_JoystickNumButtons(joy);
        const int num_hats = SDL_JoystickNumHats(joy);
        printf("Now reading from joystick '%s' with:\n"
            "%d axes\n"
            "%d buttons\n"
            "%d hats\n\n",
            name,
            num_axes,
            num_buttons,
            num_hats);
        /* I'm using a logitech F350 wireless in X mode.
        If num axis is 4, then gamepad is in D mode, so neutral drive and wait for X mode.
        [SAFETY] This means 'D' becomes our robot-disable button.
        This can be removed if that's not the goal. */
        if (num_axes < 5) {
            /* back to top of while loop */
            continue;
        }
        // This is the read joystick and drive robot loop.
        while(true)
        {
            // poll for disconnects or bad things
            SDL_Event e;
            if (SDL_PollEvent(&e)) {
                // SDL generated quit command
                if (e.type == SDL_QUIT) { break; }
                // Checking for Ctrl+c on the keyboard
                // SDL_Keymod modstates = SDL_GetModState();
                // if (modstates & KMOD_CTRL)
                // {
                    // One of the Ctrl keys are being held down
                    // std::cout << "Pressed Ctrl key." << std::endl;
                // }
                if(e.key.keysym.scancode == SDLK_RCTRL || e.key.keysym.scancode == SDLK_LCTRL || SDL_SCANCODE_RCTRL == e.key.keysym.scancode || e.key.keysym.scancode == SDL_SCANCODE_LCTRL)
                {
                    std::cout << "Pressed QQQQ." << std::endl;
                }
                if (e.type == SDL_KEYDOWN)
                {
                    switch(e.key.keysym.sym){ 
                        case SDLK_UP: 
                            std::cout << "Pressed up." << std::endl;
                            break; 
                        case SDLK_RCTRL: 
                            std::cout << "Pressed up." << std::endl;
                            break; 
                        case SDLK_LCTRL: 
                            std::cout << "Pressed up." << std::endl;
                            break; 
                    }
                    // Select surfaces based on key press
                    switch( e.key.keysym.sym )
                    {
                        case SDLK_UP:
                            std::cout << "Pressed Up." << std::endl;
                        break;

                        case SDLK_DOWN:
                            std::cout << "Pressed Up." << std::endl;
                        break;

                        case SDLK_LEFT:
                            std::cout << "Pressed Up." << std::endl;
                        break;

                        case SDLK_RIGHT:
                            std::cout << "Pressed Up." << std::endl;
                        break;
                    }
                    std::cout << "Pressed blah di blah blah please print me." << std::endl;
                }
                // Checking which joystick event occured
                if (e.jdevice.type == SDL_JOYDEVICEREMOVED) { break; }
                // Since joystick is not erroring out, we can 
                else if( e.type == SDL_JOYAXISMOTION )
                {
                    //Motion on controller 0
                    if( e.jaxis.which == 0 )
                    {
                        // event happened
                        eventupdate = true;
                        // Left X axis 
                        if( e.jaxis.axis == 0 )
                        {
                            // dead zone check
                            if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
                            {
                                leftX = 0;
                            }
                            else
                            {
                                leftX = e.jaxis.value;
                            }
                        }
                        // Right Y axis
                        else if( e.jaxis.axis == 1 )
                        {
                            // dead zone check
                            if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
                            {
                                leftY = 0;
                            }
                            else
                            {
                                leftY = e.jaxis.value;
                            }
                        }
                        // Left trigger
                        else if ( e.jaxis.axis == 2 )
                        {
                            // dead zone check
                            if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
                            {
                                leftTrigger = 0;
                            }
                            else
                            {
                                leftTrigger = e.jaxis.value;
                            }
                        }
                        // Right X axis
                        else if( e.jaxis.axis == 3 )
                        {
                            // dead zone check
                            if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
                            {
                                rightX = 0;
                            }
                            else
                            {
                                rightX = e.jaxis.value;
                            }
                        }
                        // Right Y axis
                        else if( e.jaxis.axis == 4 )
                        {
                            // dead zone check
                            if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
                            {
                                rightY = 0;
                            }
                            else
                            {
                                rightY = e.jaxis.value;
                            }
                        }
                        // Right trigger
                        else if( e.jaxis.axis == 5 )
                        {
                            // dead zone check
                            if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
                            {
                                rightTrigger = 0;
                            }
                            else
                            {
                                rightTrigger = e.jaxis.value;
                            }
                        }
                    }
                }
                else if ( e.type == SDL_JOYBUTTONUP || e.type == SDL_JOYBUTTONDOWN )
                {

                    // now we are looking for button events.
                    if (e.jbutton.which == 0)
                    {
                        // event happened
                        eventupdate = true;
                        // buttons[e.jbutton.button] = e.jbutton.state;
                        if (e.jbutton.button == 0)
                        {
                            buttons[0] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 1)
                        {
                            buttons[1] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 2)
                        {
                            buttons[2] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 3)
                        {
                            buttons[3] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 4)
                        {
                            buttons[4] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 5)
                        {
                            buttons[5] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 6)
                        {
                            buttons[6] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 7)
                        {
                            buttons[7] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 8)
                        {
                            buttons[8] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 9)
                        {
                            buttons[9] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 10)
                        {
                            buttons[10] = e.jbutton.state;
                        }
                        if (e.jbutton.button == 11)
                        {
                            buttons[11] = e.jbutton.state;
                        }
                    }
                }
                else if ( e.type == SDL_JOYHATMOTION)
                {
                    if (e.jhat.which == 0)
                    {
                        // event happened
                        eventupdate = true;
                        povhat = e.jhat.value;
                    }
                }
            }

            // Now that we have read in the values directly from the joystick we need top convert the values properly.
            leftstickx = clamp(intToDouble(leftX));
            leftsticky = clamp(intToDouble(leftY));
            rightstickx = clamp(intToDouble(rightX));
            rightsticky = clamp(intToDouble(rightY));
            lefttrigger = clamp(intToDouble(leftTrigger));
            righttrigger = clamp(intToDouble(rightTrigger));
            // rectify the buttons to become boolean values instead of integers.
            abutton = buttons[0] > 0;
            bbutton = buttons[1] > 0;
            xbutton = buttons[2] > 0;
            ybutton = buttons[3] > 0;
            //
            rightbut = buttons[4] > 0;
            leftbut  = buttons[5] > 0;
            //
            centbut = buttons[8] > 0;
            startbut = buttons[7] > 0;
            backbut = buttons[6] > 0;
            //
            leftstickbut = buttons[9] > 0;
            rightstickbut = buttons[10] > 0;

            // Transfer axis to the array.
            joyvalues[0] = leftstickx;
            joyvalues[1] = leftsticky;
            joyvalues[2] = rightstickx;
            joyvalues[3] = rightsticky;
            joyvalues[4] = lefttrigger;
            joyvalues[5] = righttrigger;
            // We are using the "B" button to quit the program
            if (bbutton)
            {
                quitrobot = true;
                std::cout << "Shutting down program." << std::endl;
                break;
            }
            if (eventupdate)                    
            {
                // This section of code is meant for running code that happens when SDL has detected an event.
                // This code section can be used for something else as well.
                if (e.key.keysym.sym == SDL_SCANCODE_RCTRL || e.key.keysym.sym == SDL_SCANCODE_LCTRL || e.key.keysym.sym == SDLK_LCTRL || e.key.keysym.sym == SDLK_RCTRL)
                {
                    std::cout << "SDL Event: Ctrl pressed.\n" << std::endl;
                }
                // Simply print the event
                eventupdate = false;
            } else {}
            if ( ! (printcounter = ((printcounter + 1) % printer)))
            {
                // const Uint8 *state = SDL_GetKeyboardState(NULL);
                // if (state[SDL_SCANCODE_RETURN]) {
                //     printf("<RETURN> is pressed.\n");
                // }
            }
            // Sleep the program for a short bit
            wait(5);
        }
        // Reset SDL since the robot is no longer being actuated.
        SDL_JoystickClose(joy);
        // We get here only if the joystick has been disconnected.
        std::cout << "Gamepad disconnected.\n" << std::endl;
    }
    // The program then completes. 
    return 0;
}



巨大的代码块中最重要的部分是第129至179行。我在尝试使键捕获正常工作时更加愚弄,但是我没有得到响应。其他地方都是操纵杆读数的逻辑(这对我来说是完美无缺的)。对于程序员可用的所有宏,我一直都在参考link。我无法捕获左控制按钮或右控制按钮。我也一直在尝试踢脚的方向键,但是这些键都没有用。我知道在进行测试时,还会有其他代码片段的残留。经过我的所有测试,我只是不确定如何捕获任何键盘键,更不用说Ctrl+c我不需要的打印语句都不会打印。

我能够使用库存GUI管理器和窗口管理器在Ubuntu 1804 LTS上运行代码。我感觉到该问题也可能与操作系统有关,即不允许SDL2捕获键盘,但我不知道该怎么做才能仅允许SDL2使用键盘或某些键。

由于我已经成功使用了平台专用的信号中断,所以我尝试不使用平台专用的代码。我的目标是简单地使按下的键某种组合导致程序终止。我认为,由于SDL2可以访问键盘上的所有键,因此我应该能够简单地>

TL; DR我正在尝试在自己的C ++程序中捕获键盘事件(更具体地说,是Ctrl + c命令)。我正在通过SDL2中的通用键盘按键来尝试此操作。 END TL;我发现了DR ...

c++ linux sdl-2
1个回答
0
投票

除非您要从stdin中读取键盘输入,否则需要打开一个窗口并将其聚焦以获取SDL中的键事件。这是一个示例(请注意,对SDL_Init的调用使用SDL_INIT_VIDEO,并且其中包含一些用于渲染背景和处理调整大小事件的代码)。

#include <iostream>
#include <SDL2/SDL.h>


int main(int argc, char** argv)
{
    if (SDL_Init(SDL_INIT_VIDEO) < 0) { // also initialises the events subsystem
        std::cout << "Failed to init SDL.\n";
        return -1;
    }

    SDL_Window *window = SDL_CreateWindow(
        "Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 
        680, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);

    if(!window) {
        std::cout << "Failed to create window.\n";
        return -1;
    }

    // Create renderer and select the color for drawing. 
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255);

    while(true)
    {
        // Clear the entire screen and present.
        SDL_RenderClear(renderer);
        SDL_RenderPresent(renderer);

        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_QUIT) {
                SDL_Quit();
                return 0;
            }

            if(event.type == SDL_WINDOWEVENT) {
                if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
                    int width = event.window.data1;
                    int height = event.window.data2;
                    std::cout << "resize event: " << width << "," << height << std::endl;
                }
            }            

            if (event.type == SDL_KEYDOWN) {
                int key = event.key.keysym.sym;
                if (key == SDLK_ESCAPE) {
                    SDL_Quit();
                    return 0;
                }

                std::cout << "key event: " << key << std::endl; 
            }
        }
    }

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.