| // |
| // Copyright 2020 Comcast Cable Communications Management, LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include "third_party/starboard/rdk/shared/linux_key_mapping.h" |
| |
| #include <core/JSON.h> |
| #include <core/Enumerate.h> |
| |
| #include <linux/input.h> |
| |
| #include "starboard/once.h" |
| |
| #include "third_party/starboard/rdk/shared/log_override.h" |
| |
| using namespace WPEFramework; |
| |
| namespace WPEFramework { |
| |
| ENUM_CONVERSION_HANDLER(SbKeyModifiers); |
| ENUM_CONVERSION_BEGIN(SbKeyModifiers) |
| { kSbKeyModifiersAlt, _TXT("alt") }, |
| { kSbKeyModifiersCtrl, _TXT("ctrl") }, |
| { kSbKeyModifiersMeta, _TXT("meta") }, |
| { kSbKeyModifiersShift, _TXT("shift") }, |
| ENUM_CONVERSION_END(SbKeyModifiers); |
| |
| } |
| |
| namespace third_party { |
| namespace starboard { |
| namespace rdk { |
| namespace shared { |
| |
| namespace { |
| |
| struct KeymappingsData : public Core::JSON::Container { |
| struct KeymappingData : public Core::JSON::Container { |
| struct MappedData : public Core::JSON::Container { |
| MappedData() |
| : Core::JSON::Container() { |
| Init(); |
| } |
| |
| MappedData(const MappedData& other) |
| : Core::JSON::Container() |
| , Keycode(other.Keycode) |
| , Modifiers(other.Modifiers) { |
| Init(); |
| } |
| |
| MappedData& operator=(const MappedData& rhs) { |
| Keycode = rhs.Keycode; |
| Modifiers = rhs.Modifiers; |
| return (*this); |
| } |
| |
| private: |
| void Init() { |
| Add(_T("keycode"), &Keycode); |
| Add(_T("modifiers"), &Modifiers); |
| } |
| |
| public: |
| Core::JSON::DecUInt16 Keycode; |
| Core::JSON::ArrayType<Core::JSON::EnumType<SbKeyModifiers>> Modifiers; |
| }; // struct MappedData |
| |
| KeymappingData() |
| : Core::JSON::Container() { |
| Init(); |
| } |
| |
| KeymappingData(const KeymappingData& other) |
| : Core::JSON::Container() |
| , Keycode(other.Keycode) |
| , Modifiers(other.Modifiers) |
| , Mapped(other.Mapped) { |
| Init(); |
| } |
| |
| KeymappingData& operator=(const KeymappingData& rhs) { |
| Keycode = rhs.Keycode; |
| Modifiers = rhs.Modifiers; |
| Mapped = rhs.Mapped; |
| return (*this); |
| } |
| |
| private: |
| void Init() { |
| Add(_T("keycode"), &Keycode); |
| Add(_T("modifiers"), &Modifiers); |
| Add(_T("mapped"), &Mapped); |
| } |
| |
| public: |
| Core::JSON::DecUInt16 Keycode; |
| Core::JSON::ArrayType<Core::JSON::EnumType<SbKeyModifiers>> Modifiers; |
| MappedData Mapped; |
| }; // struct KeymappingData |
| |
| KeymappingsData() |
| : Core::JSON::Container() { |
| Add(_T("keymappings"), &Keymappings); |
| } |
| KeymappingsData(const KeymappingsData&) = delete; |
| KeymappingsData& operator=(const KeymappingsData&) = delete; |
| |
| Core::JSON::ArrayType<KeymappingData> Keymappings; |
| }; // struct KeymappingsData |
| |
| struct LinuxKeyMappingImpl { |
| |
| struct KeyMapping { |
| uint16_t key_code; |
| SbKeyModifiers modifiers; |
| uint16_t mapped_key_code; |
| SbKeyModifiers mapped_modifiers; |
| }; |
| |
| std::vector<KeyMapping> key_mappings_ = { |
| { KEY_M, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // Menu |
| { KEY_G, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // Guide |
| { KEY_R, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // Record |
| { KEY_U, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // Volume Up |
| { KEY_D, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // Volume Down |
| { KEY_S, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // Stop |
| { KEY_N, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // Favorite |
| { KEY_O, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // OnDemand |
| { KEY_B, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // Replay |
| { KEY_C, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // Search |
| { KEY_E, kSbKeyModifiersCtrl, KEY_UNKNOWN, kSbKeyModifiersNone }, // Exit |
| |
| { KEY_I, kSbKeyModifiersCtrl, KEY_INFO, kSbKeyModifiersNone }, |
| { KEY_Y, kSbKeyModifiersCtrl, KEY_MUTE, kSbKeyModifiersNone }, |
| { KEY_L, kSbKeyModifiersCtrl, KEY_ESC, kSbKeyModifiersNone }, |
| { KEY_F, kSbKeyModifiersCtrl, KEY_FASTFORWARD, kSbKeyModifiersNone }, |
| { KEY_W, kSbKeyModifiersCtrl, KEY_REWIND, kSbKeyModifiersNone }, |
| { KEY_P, kSbKeyModifiersCtrl, KEY_PLAYPAUSE, kSbKeyModifiersNone }, |
| { KEY_0, kSbKeyModifiersCtrl, KEY_RED, kSbKeyModifiersNone }, |
| { KEY_1, kSbKeyModifiersCtrl, KEY_GREEN, kSbKeyModifiersNone }, |
| { KEY_2, kSbKeyModifiersCtrl, KEY_YELLOW, kSbKeyModifiersNone }, |
| { KEY_3, kSbKeyModifiersCtrl, KEY_BLUE, kSbKeyModifiersNone }, |
| { KEY_UP, kSbKeyModifiersCtrl, KEY_CHANNELUP, kSbKeyModifiersNone }, |
| { KEY_DOWN, kSbKeyModifiersCtrl, KEY_CHANNELDOWN, kSbKeyModifiersNone }, |
| |
| { KEY_PAGEDOWN, kSbKeyModifiersNone, KEY_NEXTSONG, kSbKeyModifiersNone }, |
| { KEY_PAGEUP, kSbKeyModifiersNone, KEY_PREVIOUSSONG, kSbKeyModifiersNone }, |
| }; |
| |
| void UpdateKeyMapping( |
| uint16_t key, SbKeyModifiers modifiers, |
| uint16_t mapped_key, SbKeyModifiers mapped_modifiers) { |
| |
| SB_LOG(INFO) << "UpdateKeyMapping: " |
| "key code: " << key << " (" << modifiers << ") " |
| "mapped to: " << mapped_key << " (" << mapped_modifiers << ")"; |
| |
| auto it = std::find_if(key_mappings_.begin(), key_mappings_.end(), [&](const KeyMapping & mapping) { |
| return mapping.key_code == key && mapping.modifiers == modifiers; |
| }); |
| |
| if (it != key_mappings_.end()) { |
| it->mapped_key_code = mapped_key; |
| it->mapped_modifiers = mapped_modifiers; |
| } |
| else { |
| key_mappings_.push_back({key, modifiers, mapped_key, mapped_modifiers}); |
| } |
| } |
| |
| void UpdateKeyMapping(const KeymappingsData &data) { |
| if (!data.Keymappings.IsSet()) { |
| SB_LOG(WARNING) << "No key mappings in config"; |
| return ; |
| } |
| |
| auto convert_modifiers = [](const Core::JSON::ArrayType<Core::JSON::EnumType<SbKeyModifiers>>& modifiers) { |
| uint32_t result = kSbKeyModifiersNone; |
| if (modifiers.IsSet() && !modifiers.IsNull()) { |
| auto it = modifiers.Elements(); |
| while(it.Next()) |
| result |= it.Current().Value(); |
| } |
| return static_cast<SbKeyModifiers>(result); |
| }; |
| |
| auto elms = data.Keymappings.Elements(); |
| while(elms.Next()) { |
| const auto& key_mapping = elms.Current(); |
| if (!key_mapping.Keycode.IsSet() || |
| !key_mapping.Mapped.IsSet() || |
| !key_mapping.Mapped.Keycode.IsSet()) { |
| continue; |
| } |
| uint16_t key_code = key_mapping.Keycode.Value(); |
| SbKeyModifiers key_modifiers = convert_modifiers(key_mapping.Modifiers); |
| uint16_t mapped_key_code = key_mapping.Mapped.Keycode.Value(); |
| SbKeyModifiers mapped_key_modifiers = convert_modifiers(key_mapping.Mapped.Modifiers); |
| UpdateKeyMapping(key_code, key_modifiers, mapped_key_code, mapped_key_modifiers); |
| } |
| } |
| |
| void ReadFromFile(const std::string &filename) { |
| Core::File file{filename}; |
| if (file.Exists() == false) |
| return; |
| SB_LOG(INFO) << "Reading keymapping from file: " << filename; |
| if (file.Open(true) == false) { |
| SB_LOG(WARNING) << "Cannot open key mapping file: " << filename; |
| return; |
| } |
| Core::OptionalType<Core::JSON::Error> error; |
| KeymappingsData data; |
| if (!Core::JSON::IElement::FromFile(file, data, error)) { |
| SB_LOG(ERROR) << "Failed to parse key mapping file(" << filename << "), error: " |
| << (error.IsSet() ? Core::JSON::ErrorDisplayMessage(error.Value()): "Unknown"); |
| return; |
| } |
| UpdateKeyMapping(data); |
| } |
| |
| void MapKeyCodeAndModifiers(uint32_t& key_code, uint32_t& modifiers) { |
| auto it = std::find_if(key_mappings_.begin(), key_mappings_.end(), [&](const KeyMapping & mapping) { |
| return mapping.key_code == key_code && mapping.modifiers == modifiers; |
| }); |
| if (it != key_mappings_.end()) { |
| key_code = it->mapped_key_code; |
| modifiers = it->mapped_modifiers; |
| } |
| } |
| |
| LinuxKeyMappingImpl() { |
| const int kBufferSize = 256; |
| char buffer[kBufferSize]; |
| if (SbSystemGetPath(kSbSystemPathContentDirectory, buffer, kBufferSize)) { |
| ReadFromFile(std::string(buffer).append("/etc/keymapping.json")); |
| } |
| } |
| }; |
| |
| SB_ONCE_INITIALIZE_FUNCTION(LinuxKeyMappingImpl, GetLinuxKeyMapping); |
| |
| } // namespace |
| |
| void LinuxKeyMapping::MapKeyCodeAndModifiers(uint32_t& key_code, uint32_t& modifiers) { |
| GetLinuxKeyMapping()->MapKeyCodeAndModifiers(key_code, modifiers); |
| } |
| |
| } // namespace shared |
| } // namespace rdk |
| } // namespace starboard |
| } // namespace third_party |