~aleteoryx/muditaos

ref: 2695cc830472190ce1401869bb67f5506a3e17e6 muditaos/module-gui/gui/input/Translator.hpp -rw-r--r-- 4.2 KiB
2695cc83 — piotrleniec-mudita [DW-31] Add commit message format checking on CI (#1201) 5 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include "InputEvent.hpp"
#include "Profile.hpp"
#include "bsp/keyboard/key_codes.hpp"
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <common_data/RawKey.hpp>
#include <vfs.hpp>

namespace gui
{

    // TODO if neccessary `custom` keymap can be added her
    enum class Keymaps
    {
        ABC,
        abc,
        digit,
    };

    class KeyBaseTranslation
    {
      public:
        // previous pressed key (only for pressed keys), used for shortpress and longpress
        RawKey prev_key_press = {};
        // was previous key released? used for longpress only
        bool prev_key_released = true;
        // did previous key already timed out (and send longpress as a result)
        bool prev_key_timedout = false;
        InputEvent set(RawKey key);
        /// timeout keypress (only press) - returns true on timeout'ed keypress
        bool timeout(uint32_t time);
    };

    /// KeyPress translator
    /// simplest 1:1 keys handling, used when application needs simplest key parsing possible
    /// no keys behaviour analysis done here - just mapping
    class KeyInputSimpleTranslation : public KeyBaseTranslation
    {
      public:
        /// translate incomming key
        InputEvent translate(RawKey key);
        /// translate timeout - simulate key release
        InputEvent translate(uint32_t timeout);
    };

    /// translator using & switching KeyMaps for use per widget basis ,called for selected widget, per widget basis
    class KeyInputMappedTranslation : public KeyBaseTranslation
    {
        uint32_t times = 0;

      public:
        bool setProfile(std::string profileName);
        uint32_t handle(RawKey key, const std::string &keymap);
        uint32_t getTimes()
        {
            return times;
        }
    };

    /// profiles cache - load once for all
    class Profiles
    {
      private:
        const char *profilesFolder                   = "assets/profiles";
        std::map<std::string, gui::Profile> profiles = {};

        void loadProfile(const std::string &filepath)
        {
            LOG_INFO("Load profile: %s", filepath.c_str());
            auto p = Profile(filepath);
            if (p.getName() != std::string()) {
                profiles.insert({p.getName(), std::move(p)});
            }
        }

        std::vector<std::string> getProfilesList(std::string ext)
        {
            std::vector<std::string> profileFiles;
            LOG_INFO("Scanning %s profiles folder: %s", ext.c_str(), profilesFolder);
            auto dirList = vfs.listdir(profilesFolder, ext);

            for (vfs::DirectoryEntry ent : dirList) {
                if (ent.attributes != vfs::FileAttributes::Directory) {
                    profileFiles.push_back(std::string(profilesFolder) + "/" + ent.fileName);
                }
            }

            LOG_INFO("Total number of profiles: %u", static_cast<unsigned int>(profileFiles.size()));
            return profileFiles;
        }

        void init()
        {
            std::vector<std::string> profileFiles = getProfilesList(".kprof");
            for (std::string mapName : profileFiles) {
                if (std::size(mapName)) {
                    loadProfile(mapName);
                }
            }
            if (std::size(profiles) == 0) {
                LOG_ERROR("No keyboard profiles loaded");
            }
        }
        Profile empty;

      public:
        static Profiles &get()
        {
            static Profiles *p;
            if (p == nullptr) {
                p = new Profiles();
                p->init();
            }
            return *p;
        }

        static Profile &get(const std::string &name)
        {
            // if profile not in profile map -> load
            if (std::size(name) == 0) {
                LOG_ERROR("Request for non existend profile: %s", name.c_str());
                return get().empty;
            }
            if (get().profiles.find(name) == get().profiles.end()) {
                get().loadProfile(name);
            }
            return get().profiles[name];
        }
    };

} /* namespace gui */