summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/am/applets/software_keyboard.cpp
blob: 7352f3bdf6a77f936dace430cae977974845f8c8 (plain) (blame)
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
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#include <cstring>
#include "common/assert.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/software_keyboard.h"

namespace Service::AM::Applets {

constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8;
constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4;
constexpr std::size_t DEFAULT_MAX_LENGTH = 500;
constexpr bool INTERACTIVE_STATUS_OK = false;

static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
    KeyboardConfig config, std::u16string initial_text) {
    Core::Frontend::SoftwareKeyboardParameters params{};

    params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
        config.submit_text.data(), config.submit_text.size());
    params.header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
        config.header_text.data(), config.header_text.size());
    params.sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.sub_text.data(),
                                                                       config.sub_text.size());
    params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(),
                                                                         config.guide_text.size());
    params.initial_text = initial_text;
    params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit;
    params.password = static_cast<bool>(config.is_password);
    params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position);
    params.value = static_cast<u8>(config.keyset_disable_bitmask);

    return params;
}

SoftwareKeyboard::SoftwareKeyboard() = default;

SoftwareKeyboard::~SoftwareKeyboard() = default;

void SoftwareKeyboard::Initialize(std::vector<std::shared_ptr<IStorage>> storage_) {
    Applet::Initialize(std::move(storage_));

    ASSERT(storage_stack.size() >= 2);
    const auto& keyboard_config = storage_stack[1]->GetData();
    ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
    std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));

    const auto& work_buffer = storage_stack[2]->GetData();

    if (config.initial_string_size == 0)
        return;

    std::vector<char16_t> string(config.initial_string_size);
    std::memcpy(string.data(), work_buffer.data() + 4, string.size() * 2);
    initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size());
}

bool SoftwareKeyboard::TransactionComplete() const {
    return complete;
}

ResultCode SoftwareKeyboard::GetStatus() const {
    return RESULT_SUCCESS;
}

void SoftwareKeyboard::ReceiveInteractiveData(std::shared_ptr<IStorage> storage) {
    if (complete)
        return;

    const auto data = storage->GetData();
    const auto status = static_cast<bool>(data[0]);

    if (status == INTERACTIVE_STATUS_OK) {
        complete = true;
    } else {
        const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};

        std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
        std::memcpy(string.data(), data.data() + 4, string.size() * 2);
        frontend.SendTextCheckDialog(
            Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()));
    }
}

void SoftwareKeyboard::Execute(AppletStorageProxyFunction out_data,
                               AppletStorageProxyFunction out_interactive_data) {
    if (complete)
        return;

    const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};

    const auto parameters = ConvertToFrontendParameters(config, initial_text);

    const auto res = frontend.GetText(parameters);

    std::vector<u8> output(SWKBD_OUTPUT_BUFFER_SIZE);

    if (res.has_value()) {
        if (config.text_check) {
            const auto size = static_cast<u32>(res->size() * 2 + 4);
            std::memcpy(output.data(), &size, sizeof(u32));
        } else {
            output[0] = 1;
        }

        std::memcpy(output.data() + 4, res->data(),
                    std::min(res->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4));
    } else {
        complete = true;
        out_data(IStorage{output});
        return;
    }

    complete = !config.text_check;

    (complete ? out_data : out_interactive_data)(IStorage{output});
}
} // namespace Service::AM::Applets