自制按键显示的程序

本文介绍了如何使用SFML库开发一个简单的按键显示程序,通过捕捉键盘事件,实时显示用户输入的字符。程序设计注重简洁,仅处理A-Z字母、Ctrl、Esc和特殊键,并在按键间隔超过1秒时清空内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自制按键显示的程序

0. 介绍

在看一些 up 主讲解 vim/emacs 等软件的界面操作时,使用了显示按键的软件。

据说蒋炎炎讲课用的是自己写的,一度以为很神奇。 现在我们用 SFML 手搓一个极其简陋的 demo 版本。

1. 界面设计

不需要复杂界面, 不需要托管图标, 不需要隐藏窗口, 不需要动态变化的窗口。

就弄一个长条形的窗口即可。 不考虑多行显示。

清除内容: 每当用户超过1秒没有输入内容, 或者本次输入内容和上次输入相差了1秒以上, 就清空以前的内容。

如果连续两次按下的按键,在1秒之内, 那么追加内容。 判断1秒, 是通过判断60帧来决定的, 因为我设定了 fps=60.

2. 代码

严格说,用 SFML 的 text 显示输入文本,不是特别合适, 比如可能只需要一次渲染而不是每个字符渲染一次。 但是没关系, 原型设计,20分钟写出代码验证想法。

关于键盘按键的表示:看一下官方 tutorial 文档,以及 SFML 源代码中 include/SFML/Window/keyboard.hpp . 简单起见我只处理了A-Z的字符, 以及Ctrl, Esc, [ 和 ].

#include <iostream>
#include <vector>
#include <iterator>
#include <SFML/Graphics.hpp>

int main()
{
    constexpr int win_width = 800;
    constexpr int win_height = 200;
    const std::string title = "show typed keys - SFML";
    sf::RenderWindow window(sf::VideoMode(win_width, win_height), title);
    window.setFramerateLimit(60);

    sf::Font font;
    const std::string asset_dir = "../../games/Resources";
    if (!font.loadFromFile(asset_dir + "/Arial.ttf"))
    {
        std::cerr << "failed to load font\n";
        return 1;
    }

    std::vector<std::string> keys;
    int frame_index = 0;
    int prev_press_frame = 0;
    while (window.isOpen())
    {
        int press_frame = -1;
        sf::Event event;
        std::vector<std::string> cur_keys;
        while (window.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed: window.close(); break;
            case sf::Event::KeyReleased: // see include/SFML/Window/Keyboard.hpp for ref
                if (event.key.code >= sf::Keyboard::Key::A && event.key.code <= sf::Keyboard::Key::Z)
                {
                    std::string key(1, 'A' + (event.key.code - sf::Keyboard::Key::A));
                    cur_keys.push_back(key);
                }
                if (event.key.code == sf::Keyboard::Key::Space) cur_keys.push_back(" ");
                if (event.key.code == sf::Keyboard::Key::LControl) cur_keys.push_back("Ctrl");
                if (event.key.code == sf::Keyboard::Key::RControl) cur_keys.push_back("Ctrl");
                if (event.key.code == sf::Keyboard::Key::Escape) cur_keys.push_back("Esc");
                if (event.key.code == sf::Keyboard::Key::LBracket) cur_keys.push_back("[");
                if (event.key.code == sf::Keyboard::Key::RBracket) cur_keys.push_back("]");
                press_frame = frame_index;
                break;
            default:
                break;
            }
        }
        window.clear();

        printf("[debug] frame_index=%d, press_frame=%d, prev_press_frame=%d\n",
            frame_index, press_frame, prev_press_frame
        );
        if (cur_keys.size() > 0)
        {
            if (press_frame - prev_press_frame >= 60)
            {
                keys.clear();
                keys = cur_keys;
            }
            else
            {
                std::copy(cur_keys.begin(), cur_keys.end(), std::back_inserter(keys));
            }
            prev_press_frame = press_frame;
        }
        else if (cur_keys.size() == 0)
        {
            if (frame_index - prev_press_frame >= 60)
            {
                keys.clear();
                frame_index = 0;
                prev_press_frame = 0;
            }
        }

        std::string content = "";
        for (int i = 0; i < keys.size(); i++)
        {
            content = content + keys[i];
        }

        sf::Text text;
        text.setFont(font);
        text.setString(content);
        text.setCharacterSize(30);
        text.setFillColor(sf::Color::White);
        text.setPosition(20, 20);
        window.draw(text);

        window.display();

        frame_index++;
    }

    return 0;
}

3. 效果

请添加图片描述

4. 总结

由于先前几篇的练习, 对 SFML 有了基本的使用经验的情况下, 对于显示按键的实现能够快速上手。 主要思考点在于,怎样显示按键内容, 怎样清空内容。 通过判断相邻两次按键的时间差,大于1秒就清空, 否则保持原内容。 通过使用 switch case 语句,简化了 A-Z 的26个字母的判断。

这是一个非常简陋的 demo, 有时间的话可以做改进:

  • 界面改进: 显示多行, 把空格显示为 |-| 的字符
  • 框架库的更换: 使用 GUI 库,例如 imgui 作为替代
  • 添加托盘:需要为每个操作系统分别适配

References

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值