mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
Applications: Add new KeyboardMapper application
New editing app for keymap files.
This commit is contained in:
parent
92d03931d6
commit
d3578fdf9b
Notes:
sideshowbarker
2024-07-19 05:51:48 +09:00
Author: https://github.com/asliturk Commit: https://github.com/SerenityOS/serenity/commit/d3578fdf9b8 Pull-request: https://github.com/SerenityOS/serenity/pull/2455 Reviewed-by: https://github.com/JonArcherII Reviewed-by: https://github.com/awesomekling Reviewed-by: https://github.com/bugaevc
8 changed files with 702 additions and 0 deletions
|
@ -9,6 +9,7 @@ add_subdirectory(FontEditor)
|
|||
add_subdirectory(Help)
|
||||
add_subdirectory(HexEditor)
|
||||
add_subdirectory(IRCClient)
|
||||
add_subdirectory(KeyboardMapper)
|
||||
add_subdirectory(Piano)
|
||||
add_subdirectory(PixelPaint)
|
||||
add_subdirectory(QuickShow)
|
||||
|
|
8
Applications/KeyboardMapper/CMakeLists.txt
Normal file
8
Applications/KeyboardMapper/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
set(SOURCES
|
||||
KeyboardMapperWidget.cpp
|
||||
KeyButton.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
serenity_bin(KeyboardMapper)
|
||||
target_link_libraries(KeyboardMapper LibGUI LibKeyboard)
|
68
Applications/KeyboardMapper/KeyButton.cpp
Normal file
68
Applications/KeyboardMapper/KeyButton.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "KeyButton.h"
|
||||
#include <LibGUI/Button.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGfx/Font.h>
|
||||
#include <LibGfx/Palette.h>
|
||||
|
||||
KeyButton::~KeyButton()
|
||||
{
|
||||
}
|
||||
|
||||
void KeyButton::paint_event(GUI::PaintEvent& event)
|
||||
{
|
||||
GUI::Painter painter(*this);
|
||||
painter.add_clip_rect(event.rect());
|
||||
|
||||
auto content_rect = rect().shrunken(5, 5);
|
||||
auto& font = this->font();
|
||||
|
||||
Gfx::StylePainter::paint_button(painter, rect(), palette(), Gfx::ButtonStyle::Normal, is_being_pressed(), is_hovered(), is_checked(), true);
|
||||
|
||||
if (m_pressed)
|
||||
painter.fill_rect(content_rect, Color::Cyan);
|
||||
else if (!is_enabled())
|
||||
painter.fill_rect(content_rect, Color::from_rgb(0x8C7272));
|
||||
|
||||
if (!text().is_empty()) {
|
||||
Gfx::Rect text_rect { 0, 0, font.width(text()), font.glyph_height() };
|
||||
text_rect.align_within(content_rect, Gfx::TextAlignment::Center);
|
||||
|
||||
auto clipped_rect = rect().intersected(this->rect());
|
||||
|
||||
painter.draw_text(clipped_rect, text(), font, Gfx::TextAlignment::Center, palette().button_text(), Gfx::TextElision::Right);
|
||||
if (is_focused())
|
||||
painter.draw_rect(clipped_rect.inflated(6, 4), palette().focus_outline());
|
||||
}
|
||||
}
|
||||
|
||||
void KeyButton::click(unsigned)
|
||||
{
|
||||
if (on_click)
|
||||
on_click();
|
||||
}
|
47
Applications/KeyboardMapper/KeyButton.h
Normal file
47
Applications/KeyboardMapper/KeyButton.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGUI/AbstractButton.h>
|
||||
|
||||
class KeyButton : public GUI::AbstractButton {
|
||||
C_OBJECT(KeyButton)
|
||||
|
||||
public:
|
||||
virtual ~KeyButton() override;
|
||||
|
||||
void set_pressed(bool value) { m_pressed = value; }
|
||||
|
||||
Function<void()> on_click;
|
||||
|
||||
protected:
|
||||
virtual void click(unsigned modifiers = 0) override;
|
||||
virtual void paint_event(GUI::PaintEvent&) override;
|
||||
|
||||
private:
|
||||
bool m_pressed { false };
|
||||
};
|
115
Applications/KeyboardMapper/KeyPositions.h
Normal file
115
Applications/KeyboardMapper/KeyPositions.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/String.h>
|
||||
|
||||
struct KeyPosition {
|
||||
u32 scancode;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
bool enabled;
|
||||
int map_index;
|
||||
AK::String name;
|
||||
};
|
||||
|
||||
#define KEY_COUNT 63
|
||||
|
||||
struct KeyPosition keys[KEY_COUNT] = {
|
||||
[ 0] = { 0, 0, 0, 0, 0, false, 0, ""},
|
||||
|
||||
[ 1] = { 0x29, 0, 0, 50, 50, true, 41, "`"},
|
||||
[ 2] = { 0x02, 51, 0, 50, 50, true, 2, "1"},
|
||||
[ 3] = { 0x03, 102, 0, 50, 50, true, 3, "2"},
|
||||
[ 4] = { 0x04, 153, 0, 50, 50, true, 4, "3"},
|
||||
[ 5] = { 0x05, 204, 0, 50, 50, true, 5, "4"},
|
||||
[ 6] = { 0x06, 255, 0, 50, 50, true, 6, "5"},
|
||||
[ 7] = { 0x07, 306, 0, 50, 50, true, 7, "6"},
|
||||
[ 8] = { 0x08, 357, 0, 50, 50, true, 8, "7"},
|
||||
[ 9] = { 0x09, 408, 0, 50, 50, true, 9, "8"},
|
||||
[10] = { 0x0A, 459, 0, 50, 50, true, 10, "9"},
|
||||
[11] = { 0x0B, 510, 0, 50, 50, true, 11, "0"},
|
||||
[12] = { 0x0C, 561, 0, 50, 50, true, 12, "-"},
|
||||
[13] = { 0x0D, 612, 0, 50, 50, true, 13, "="},
|
||||
[14] = { 0x0E, 663, 0, 100, 50, false, 0, "back space"},
|
||||
|
||||
|
||||
[15] = { 0x0F, 0, 52, 76, 50, false, 0, "tab"},
|
||||
[16] = { 0x10, 77, 52, 50, 50, true, 16, "q"},
|
||||
[17] = { 0x11, 128, 52, 50, 50, true, 17, "w"},
|
||||
[18] = { 0x12, 179, 52, 50, 50, true, 18, "e"},
|
||||
[19] = { 0x13, 230, 52, 50, 50, true, 19, "r"},
|
||||
[20] = { 0x14, 281, 52, 50, 50, true, 20, "t"},
|
||||
[21] = { 0x15, 332, 52, 50, 50, true, 21, "y"},
|
||||
[22] = { 0x16, 383, 52, 50, 50, true, 22, "u"},
|
||||
[23] = { 0x17, 434, 52, 50, 50, true, 23, "ı"},
|
||||
[24] = { 0x18, 485, 52, 50, 50, true, 24, "o"},
|
||||
[25] = { 0x19, 536, 52, 50, 50, true, 25, "p"},
|
||||
[26] = { 0x1A, 587, 52, 50, 50, true, 26, "["},
|
||||
[27] = { 0x1B, 638, 52, 50, 50, true, 27, "]"},
|
||||
[28] = { 0x1C, 689, 52, 74, 50, false, 0, "enter"},
|
||||
|
||||
|
||||
[29] = { 0x3A, 0, 104, 101, 50, false, 0, "caps lock"},
|
||||
[30] = { 0x1E, 103, 104, 50, 50, true, 30, "a"},
|
||||
[31] = { 0x1F, 154, 104, 50, 50, true, 31, "s"},
|
||||
[32] = { 0x20, 205, 104, 50, 50, true, 32, "d"},
|
||||
[33] = { 0x21, 256, 104, 50, 50, true, 33, "f"},
|
||||
[34] = { 0x22, 307, 104, 50, 50, true, 34, "g"},
|
||||
[35] = { 0x23, 358, 104, 50, 50, true, 35, "h"},
|
||||
[36] = { 0x24, 409, 104, 50, 50, true, 36, "j"},
|
||||
[37] = { 0x25, 460, 104, 50, 50, true, 37, "k"},
|
||||
[38] = { 0x26, 511, 104, 50, 50, true, 38, "l"},
|
||||
[39] = { 0x27, 562, 104, 50, 50, true, 39, ";"},
|
||||
[40] = { 0x28, 614, 104, 50, 50, true, 40, "\""},
|
||||
[41] = { 0x2B, 665, 104, 50, 50, true, 43, "\\"},
|
||||
|
||||
|
||||
|
||||
[42] = { 0x2A, 0, 156, 76, 50, false, 0, "left shift"},
|
||||
[43] = { 0x56, 77, 156, 50, 50, true, 86, "\\"},
|
||||
[44] = { 0x2C, 128, 156, 50, 50, true, 44, "z"},
|
||||
[45] = { 0x2D, 179, 156, 50, 50, true, 45, "x"},
|
||||
[46] = { 0x2E, 230, 156, 50, 50, true, 46, "c"},
|
||||
[47] = { 0x2F, 281, 156, 50, 50, true, 47, "v"},
|
||||
[48] = { 0x30, 332, 156, 50, 50, true, 48, "b"},
|
||||
[49] = { 0x31, 383, 156, 50, 50, true, 49, "n"},
|
||||
[50] = { 0x32, 434, 156, 50, 50, true, 50, "m"},
|
||||
[51] = { 0x33, 485, 156, 50, 50, true, 51, ","},
|
||||
[52] = { 0x34, 536, 156, 50, 50, true, 52, "."},
|
||||
[53] = { 0x35, 587, 156, 50, 50, true, 53, "/"},
|
||||
[54] = { 0x36, 638, 156, 125, 50, false, 0, "right shift"},
|
||||
|
||||
[55] = { 0x1D, 0, 208, 76, 50, false, 0, "left ctrl"},
|
||||
[56] = {0xE05B, 77, 208, 50, 50, false, 0, "left\nsuper"},
|
||||
[57] = { 0x38, 128, 208, 50, 50, false, 0, "alt"},
|
||||
[58] = { 0x39, 179, 208, 356, 50, false, 0, "space"},
|
||||
[59] = {0xE038, 536, 208, 50, 50, false, 0, "alt gr"},
|
||||
[60] = {0xE05C, 587, 208, 50, 50, false, 0, "right\nsuper"},
|
||||
[61] = {0xE05D, 638, 208, 50, 50, false, 0, "menu"},
|
||||
[62] = {0xE01D, 689, 208, 74, 50, false, 0, "right ctrl"}
|
||||
};
|
289
Applications/KeyboardMapper/KeyboardMapperWidget.cpp
Normal file
289
Applications/KeyboardMapper/KeyboardMapperWidget.cpp
Normal file
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "KeyboardMapperWidget.h"
|
||||
#include "KeyPositions.h"
|
||||
#include <LibCore/File.h>
|
||||
#include <LibGUI/BoxLayout.h>
|
||||
#include <LibGUI/InputBox.h>
|
||||
#include <LibGUI/MessageBox.h>
|
||||
#include <LibGUI/RadioButton.h>
|
||||
#include <LibKeyboard/CharacterMapFile.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
KeyboardMapperWidget::KeyboardMapperWidget()
|
||||
{
|
||||
create_frame();
|
||||
}
|
||||
|
||||
KeyboardMapperWidget::~KeyboardMapperWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void KeyboardMapperWidget::create_frame()
|
||||
{
|
||||
set_fill_with_background_color(true);
|
||||
set_layout<GUI::VerticalBoxLayout>();
|
||||
set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fill);
|
||||
layout()->set_margins({ 4, 4, 4, 4 });
|
||||
|
||||
auto& main_widget = add<GUI::Widget>();
|
||||
main_widget.set_relative_rect(0, 0, 200, 200);
|
||||
|
||||
m_keys.resize(KEY_COUNT);
|
||||
|
||||
for (unsigned i = 0; i < KEY_COUNT; i++) {
|
||||
Gfx::Rect rect = { keys[i].x, keys[i].y, keys[i].width, keys[i].height };
|
||||
|
||||
auto& tmp_button = main_widget.add<KeyButton>();
|
||||
tmp_button.set_relative_rect(rect);
|
||||
tmp_button.set_text(keys[i].name);
|
||||
tmp_button.set_enabled(keys[i].enabled);
|
||||
|
||||
tmp_button.on_click = [&]() {
|
||||
auto input_box = GUI::InputBox::construct("New Character:", "Select Character", window());
|
||||
if (input_box->exec() == GUI::InputBox::ExecOK) {
|
||||
auto value = input_box->text_value();
|
||||
|
||||
int i = m_keys.find_first_index(&tmp_button).value_or(0);
|
||||
ASSERT(i > 0);
|
||||
|
||||
auto index = keys[i].map_index;
|
||||
ASSERT(index > 0);
|
||||
|
||||
tmp_button.set_text(value);
|
||||
char* map;
|
||||
|
||||
if (m_current_map_name == "map") {
|
||||
map = m_character_map.map;
|
||||
} else if (m_current_map_name == "shift_map") {
|
||||
map = m_character_map.shift_map;
|
||||
} else if (m_current_map_name == "alt_map") {
|
||||
map = m_character_map.alt_map;
|
||||
} else if (m_current_map_name == "altgr_map") {
|
||||
map = m_character_map.altgr_map;
|
||||
} else {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
if (value.length() == 0)
|
||||
map[index] = '\0'; // Empty string
|
||||
else
|
||||
map[index] = value[0];
|
||||
|
||||
m_modified = true;
|
||||
update_window_title();
|
||||
}
|
||||
};
|
||||
|
||||
m_keys.insert(i, &tmp_button);
|
||||
}
|
||||
|
||||
// Action Buttons
|
||||
auto& bottom_widget = add<GUI::Widget>();
|
||||
bottom_widget.set_layout<GUI::HorizontalBoxLayout>();
|
||||
bottom_widget.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed);
|
||||
bottom_widget.set_preferred_size(0, 40);
|
||||
|
||||
// Map Selection
|
||||
m_map_group = bottom_widget.add<GUI::Widget>();
|
||||
m_map_group->set_layout<GUI::HorizontalBoxLayout>();
|
||||
m_map_group->set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill);
|
||||
m_map_group->set_preferred_size(250, 0);
|
||||
|
||||
auto& radio_map = m_map_group->add<GUI::RadioButton>("Default");
|
||||
radio_map.set_name("map");
|
||||
radio_map.on_checked = [&](bool) {
|
||||
set_current_map("map");
|
||||
};
|
||||
auto& radio_shift = m_map_group->add<GUI::RadioButton>("Shift");
|
||||
radio_shift.set_name("shift_map");
|
||||
radio_shift.on_checked = [&](bool) {
|
||||
set_current_map("shift_map");
|
||||
};
|
||||
auto& radio_altgr = m_map_group->add<GUI::RadioButton>("AltGr");
|
||||
radio_altgr.set_name("altgr_map");
|
||||
radio_altgr.on_checked = [&](bool) {
|
||||
set_current_map("altgr_map");
|
||||
};
|
||||
auto& radio_alt = m_map_group->add<GUI::RadioButton>("Alt");
|
||||
radio_alt.set_name("alt_map");
|
||||
radio_alt.on_checked = [&](bool) {
|
||||
set_current_map("alt_map");
|
||||
};
|
||||
|
||||
bottom_widget.layout()->add_spacer();
|
||||
|
||||
auto& ok_button = bottom_widget.add<GUI::Button>();
|
||||
ok_button.set_text("Save");
|
||||
ok_button.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill);
|
||||
ok_button.set_preferred_size(80, 0);
|
||||
ok_button.on_click = [this](auto) {
|
||||
save();
|
||||
};
|
||||
}
|
||||
|
||||
void KeyboardMapperWidget::load_from_file(String file_name)
|
||||
{
|
||||
auto result = Keyboard::CharacterMapFile::load_from_file(file_name);
|
||||
if (!result.has_value()) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
m_file_name = file_name;
|
||||
m_character_map = result.value();
|
||||
set_current_map("map");
|
||||
|
||||
for (Widget* widget : m_map_group->child_widgets()) {
|
||||
auto radio_button = (GUI::RadioButton*)widget;
|
||||
radio_button->set_checked(radio_button->name() == "map");
|
||||
}
|
||||
|
||||
update_window_title();
|
||||
}
|
||||
|
||||
void KeyboardMapperWidget::save()
|
||||
{
|
||||
save_to_file(m_file_name);
|
||||
}
|
||||
|
||||
void KeyboardMapperWidget::save_to_file(const StringView& file_name)
|
||||
{
|
||||
JsonObject map_json;
|
||||
|
||||
auto add_array = [&](String name, char* values) {
|
||||
JsonArray items;
|
||||
for (int i = 0; i < 90; i++) {
|
||||
AK::StringBuilder sb;
|
||||
sb.append(values[i]);
|
||||
|
||||
JsonValue val(sb.to_string());
|
||||
items.append(move(val));
|
||||
}
|
||||
map_json.set(name, move(items));
|
||||
};
|
||||
|
||||
add_array("map", m_character_map.map);
|
||||
add_array("shift_map", m_character_map.shift_map);
|
||||
add_array("alt_map", m_character_map.alt_map);
|
||||
add_array("altgr_map", m_character_map.altgr_map);
|
||||
|
||||
// Write to file.
|
||||
String file_content = map_json.to_string();
|
||||
|
||||
auto file = Core::File::construct(file_name);
|
||||
file->open(Core::IODevice::WriteOnly);
|
||||
if (!file->is_open()) {
|
||||
StringBuilder sb;
|
||||
sb.append("Failed to open ");
|
||||
sb.append(file_name);
|
||||
sb.append(" for write. Error: ");
|
||||
sb.append(file->error_string());
|
||||
|
||||
GUI::MessageBox::show(sb.to_string(), "Error", GUI::MessageBox::Type::Error, GUI::MessageBox::InputType::OK, window());
|
||||
return;
|
||||
}
|
||||
|
||||
bool result = file->write(file_content);
|
||||
if (!result) {
|
||||
int error_number = errno;
|
||||
StringBuilder sb;
|
||||
sb.append("Unable to save file. Error: ");
|
||||
sb.append(strerror(error_number));
|
||||
|
||||
GUI::MessageBox::show(sb.to_string(), "Error", GUI::MessageBox::Type::Error, GUI::MessageBox::InputType::OK, window());
|
||||
return;
|
||||
}
|
||||
|
||||
m_modified = false;
|
||||
m_file_name = file_name;
|
||||
update_window_title();
|
||||
}
|
||||
|
||||
void KeyboardMapperWidget::keydown_event(GUI::KeyEvent& event)
|
||||
{
|
||||
for (int i = 0; i < KEY_COUNT; i++) {
|
||||
auto& tmp_button = m_keys.at(i);
|
||||
tmp_button->set_pressed(keys[i].scancode == event.scancode());
|
||||
tmp_button->update();
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardMapperWidget::keyup_event(GUI::KeyEvent& event)
|
||||
{
|
||||
for (int i = 0; i < KEY_COUNT; i++) {
|
||||
if (keys[i].scancode == event.scancode()) {
|
||||
auto& tmp_button = m_keys.at(i);
|
||||
tmp_button->set_pressed(false);
|
||||
tmp_button->update();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardMapperWidget::set_current_map(const String current_map)
|
||||
{
|
||||
m_current_map_name = current_map;
|
||||
char* map;
|
||||
|
||||
if (m_current_map_name == "map") {
|
||||
map = m_character_map.map;
|
||||
} else if (m_current_map_name == "shift_map") {
|
||||
map = m_character_map.shift_map;
|
||||
} else if (m_current_map_name == "alt_map") {
|
||||
map = m_character_map.alt_map;
|
||||
} else if (m_current_map_name == "altgr_map") {
|
||||
map = m_character_map.altgr_map;
|
||||
} else {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
for (unsigned k = 0; k < KEY_COUNT; k++) {
|
||||
auto index = keys[k].map_index;
|
||||
if (index == 0)
|
||||
continue;
|
||||
|
||||
AK::StringBuilder sb;
|
||||
sb.append(map[index]);
|
||||
|
||||
m_keys.at(k)->set_text(sb.to_string());
|
||||
}
|
||||
|
||||
this->update();
|
||||
}
|
||||
|
||||
void KeyboardMapperWidget::update_window_title()
|
||||
{
|
||||
StringBuilder sb;
|
||||
sb.append(m_file_name);
|
||||
if (m_modified)
|
||||
sb.append(" (*)");
|
||||
sb.append(" - KeyboardMapper");
|
||||
|
||||
window()->set_title(sb.to_string());
|
||||
}
|
60
Applications/KeyboardMapper/KeyboardMapperWidget.h
Normal file
60
Applications/KeyboardMapper/KeyboardMapperWidget.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KeyButton.h"
|
||||
#include <LibGUI/Button.h>
|
||||
#include <LibKeyboard/CharacterMapData.h>
|
||||
|
||||
class KeyboardMapperWidget : public GUI::Widget {
|
||||
C_OBJECT(KeyboardMapperWidget)
|
||||
|
||||
public:
|
||||
KeyboardMapperWidget();
|
||||
virtual ~KeyboardMapperWidget() override;
|
||||
|
||||
void create_frame();
|
||||
void load_from_file(const String);
|
||||
void save();
|
||||
void save_to_file(const StringView&);
|
||||
|
||||
protected:
|
||||
virtual void keydown_event(GUI::KeyEvent&) override;
|
||||
virtual void keyup_event(GUI::KeyEvent&) override;
|
||||
|
||||
void set_current_map(const String);
|
||||
void update_window_title();
|
||||
|
||||
private:
|
||||
Vector<KeyButton*> m_keys;
|
||||
RefPtr<GUI::Widget> m_map_group;
|
||||
|
||||
String m_file_name;
|
||||
Keyboard::CharacterMapData m_character_map;
|
||||
String m_current_map_name;
|
||||
bool m_modified { false };
|
||||
};
|
114
Applications/KeyboardMapper/main.cpp
Normal file
114
Applications/KeyboardMapper/main.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "KeyboardMapperWidget.h"
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibGUI/AboutDialog.h>
|
||||
#include <LibGUI/Action.h>
|
||||
#include <LibGUI/Application.h>
|
||||
#include <LibGUI/FilePicker.h>
|
||||
#include <LibGUI/Icon.h>
|
||||
#include <LibGUI/Menu.h>
|
||||
#include <LibGUI/MenuBar.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* path = nullptr;
|
||||
Core::ArgsParser args_parser;
|
||||
args_parser.add_positional_argument(path, "Keyboard character mapping file.", "file", Core::ArgsParser::Required::No);
|
||||
args_parser.parse(argc, argv);
|
||||
|
||||
GUI::Application app(argc, argv);
|
||||
|
||||
auto app_icon = GUI::Icon::default_icon("app-keyboard-mapper");
|
||||
|
||||
auto window = GUI::Window::construct();
|
||||
window->set_title("KeyboardMapper");
|
||||
window->set_icon(app_icon.bitmap_for_size(16));
|
||||
window->set_main_widget<KeyboardMapperWidget>();
|
||||
window->resize(775, 315);
|
||||
window->move_to(50, 50);
|
||||
window->set_resizable(false);
|
||||
window->show();
|
||||
|
||||
auto keyboard_mapper_widget = (KeyboardMapperWidget*)window->main_widget();
|
||||
if (path != nullptr) {
|
||||
keyboard_mapper_widget->load_from_file(path);
|
||||
} else {
|
||||
keyboard_mapper_widget->load_from_file("/res/keymaps/en.json");
|
||||
}
|
||||
|
||||
// Actions
|
||||
auto open_action = GUI::CommonActions::make_open_action(
|
||||
[&](auto&) {
|
||||
Optional<String> path = GUI::FilePicker::get_open_filepath("Open");
|
||||
if (path.has_value()) {
|
||||
keyboard_mapper_widget->load_from_file(path.value());
|
||||
}
|
||||
});
|
||||
|
||||
auto save_action = GUI::CommonActions::make_save_action(
|
||||
[&](auto&) {
|
||||
keyboard_mapper_widget->save();
|
||||
});
|
||||
|
||||
auto save_as_action = GUI::Action::create("Save as...", { Mod_Ctrl | Mod_Shift, Key_S }, Gfx::Bitmap::load_from_file("/res/icons/16x16/save.png"),
|
||||
[&](auto&) {
|
||||
String m_name = "Unnamed";
|
||||
Optional<String> save_path = GUI::FilePicker::get_save_filepath(m_name, "json");
|
||||
if (!save_path.has_value())
|
||||
return;
|
||||
|
||||
keyboard_mapper_widget->save_to_file(save_path.value());
|
||||
});
|
||||
|
||||
auto quit_action = GUI::CommonActions::make_quit_action(
|
||||
[&](auto&) {
|
||||
app.quit();
|
||||
});
|
||||
|
||||
auto about_action = GUI::Action::create("About",
|
||||
[&](auto&) {
|
||||
GUI::AboutDialog::show("KeyboardMapper", app_icon.bitmap_for_size(32), window);
|
||||
});
|
||||
|
||||
// Menu
|
||||
auto menubar = GUI::MenuBar::construct();
|
||||
|
||||
auto& app_menu = menubar->add_menu("KeyboardMapper");
|
||||
app_menu.add_action(open_action);
|
||||
app_menu.add_action(save_action);
|
||||
app_menu.add_action(save_as_action);
|
||||
app_menu.add_separator();
|
||||
app_menu.add_action(quit_action);
|
||||
|
||||
auto& help_menu = menubar->add_menu("Help");
|
||||
help_menu.add_action(about_action);
|
||||
|
||||
app.set_menubar(move(menubar));
|
||||
|
||||
return app.exec();
|
||||
}
|
Loading…
Reference in a new issue