mirror of
https://github.com/miracle-wm-org/miracle-wm.git
synced 2024-11-27 00:11:40 +03:00
feature: custom actions
This commit is contained in:
parent
c6dbc2c402
commit
d6abbe57e1
45
USERGUIDE.md
45
USERGUIDE.md
@ -1,7 +1,7 @@
|
||||
> This user manual will keep up to date with the current state of the project.
|
||||
> Please note that the information in here is likely to change with future release.
|
||||
|
||||
# Default Key Commands
|
||||
# Built-in Key Commands
|
||||
- `meta + enter`: Open new terminal
|
||||
- `meta + h`: Switch current lane to horizontal layout mode
|
||||
- `meta + v`: Switch current lane to vertical layout mode
|
||||
@ -30,10 +30,12 @@
|
||||
- Window CANNOT be resized or moved with the pointer
|
||||
|
||||
# Configuration File
|
||||
|
||||
## Location
|
||||
The configuration file will be written blank the first time that you start the compositor. The file is named `miracle-wm.yaml`
|
||||
and it is written to your config directory, most likely at `~/.config/miracle-wm.yaml`.
|
||||
|
||||
## Data Types
|
||||
## Types
|
||||
First, let's define some reoccurring data types in the configuration file:
|
||||
|
||||
- `ModifierKey`: represents a modifier to be used in conjunction with another key press (e.g. Ctrl + Alt + Delete; Ctrl and Alt would be modifiers)
|
||||
@ -89,19 +91,40 @@ First, let's define some reoccurring data types in the configuration file:
|
||||
};
|
||||
```
|
||||
|
||||
## Configuration Definition
|
||||
- `CustomAction`: defines a custom action to execute when the provided keybind is inputted.
|
||||
```c++
|
||||
struct CustomAction
|
||||
{
|
||||
// Action to execute
|
||||
command: String
|
||||
|
||||
// Action will fire based on this key event
|
||||
action: "up" | "down" | "repeat" | "modifiers";
|
||||
|
||||
// Modifiers required for the action to trigger
|
||||
modifiers: Modifier[];
|
||||
|
||||
// Name of the keycode that the action should respond to.
|
||||
// See https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
|
||||
// for the list of available keycodes (e.g. KEY_ENTER, KEY_Z, etc.)
|
||||
key: KeyCodeName;
|
||||
};
|
||||
```
|
||||
|
||||
## Definition
|
||||
With those types defined, the following table defines the allowed key/value pairs:
|
||||
|
||||
| Key | Default | Type | Description |
|
||||
|--------------------------|---------|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| action_key | `meta` | `Modifier` | The default key that is used to initate any action. |
|
||||
| default_action_overrides | `[]` | `DefaultActionOverride[]` | A list overrides to apply to built-in actions. Actions may be overridden more than once and will respond to multiple key combinations as a result. Defining at least one override disables the default action defined in [Default Key Commands](#default-key-commands) |
|
||||
| gap_size_x | 10 | `int` | Size of the gaps in pixels horizontally between windows | |
|
||||
| gap_size_y | 10 | `int` | Size of the gaps in pixels vertically between windows | |
|
||||
| startup_apps | [] | `String[]` | List of applications to be started when the compositor starts |
|
||||
| custom_actions | [] | `CustomAction[]` | A list of custom applications that I user can execute. These actions always have precedence over built-in actions. |
|
||||
| gap_size_x | 10 | `int` | Size of the gaps in pixels horizontally between windows | |
|
||||
| gap_size_y | 10 | `int` | Size of the gaps in pixels vertically between windows | |
|
||||
| startup_apps | [] | `String[]` | List of applications to be started when the compositor starts |
|
||||
|
||||
|
||||
## Example Configuration
|
||||
## Example
|
||||
```yaml
|
||||
action_key: alt # Set the primary action key to alt
|
||||
default_action_overrides:
|
||||
@ -111,6 +134,14 @@ default_action_overrides:
|
||||
- ctrl
|
||||
- shift
|
||||
key: KEY_ENTER
|
||||
|
||||
custom_actions: # Set meta + D to open wofi
|
||||
- command: wofi --show=drun
|
||||
action: down
|
||||
modifiers:
|
||||
- primary
|
||||
key: KEY_D
|
||||
|
||||
gap_size_x: 20
|
||||
gap_size_y: 20
|
||||
startup_apps:
|
||||
|
@ -377,6 +377,95 @@ MiracleConfig::MiracleConfig()
|
||||
key_commands[i].push_back(default_key_commands[i]);
|
||||
}
|
||||
|
||||
// Custom actions
|
||||
if (config["custom_actions"])
|
||||
{
|
||||
auto const custom_actions = config["custom_actions"];
|
||||
if (!custom_actions.IsSequence())
|
||||
{
|
||||
mir::log_error("custom_actions: value must be an array");
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto i = 0; i < custom_actions.size(); i++)
|
||||
{
|
||||
auto sub_node = custom_actions[i];
|
||||
if (!sub_node["command"])
|
||||
{
|
||||
mir::log_error("custom_actions: missing command");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sub_node["action"])
|
||||
{
|
||||
mir::log_error("custom_actions: missing action");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sub_node["modifiers"])
|
||||
{
|
||||
mir::log_error("custom_actions: missing modifiers");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sub_node["key"])
|
||||
{
|
||||
mir::log_error("custom_actions: missing key");
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Copy & paste here
|
||||
auto command = sub_node["command"].as<std::string>();
|
||||
auto action = sub_node["action"].as<std::string>();
|
||||
MirKeyboardAction keyboard_action;
|
||||
if (action == "up")
|
||||
keyboard_action = MirKeyboardAction::mir_keyboard_action_up;
|
||||
else if (action == "down")
|
||||
keyboard_action = MirKeyboardAction::mir_keyboard_action_down;
|
||||
else if (action == "repeat")
|
||||
keyboard_action = MirKeyboardAction::mir_keyboard_action_repeat;
|
||||
else if (action == "modifiers")
|
||||
keyboard_action = MirKeyboardAction::mir_keyboard_action_modifiers;
|
||||
else {
|
||||
mir::log_error("custom_actions: Unknown keyboard action: %s", action.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
auto key = sub_node["key"].as<std::string>();
|
||||
auto code = libevdev_event_code_from_name(EV_KEY,
|
||||
key.c_str()); //https://stackoverflow.com/questions/32059363/is-there-a-way-to-get-the-evdev-keycode-from-a-string
|
||||
if (code < 0)
|
||||
{
|
||||
mir::log_error(
|
||||
"custom_actions: Unknown keyboard code in configuration: %s. See the linux kernel for allowed codes: https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h",
|
||||
key.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
auto modifiers_node = sub_node["modifiers"];
|
||||
|
||||
if (!modifiers_node.IsSequence())
|
||||
{
|
||||
mir::log_error("custom_actions: Provided modifiers is not an array");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint modifiers = 0;
|
||||
for (auto j = 0; j < modifiers_node.size(); j++)
|
||||
{
|
||||
auto modifier = modifiers_node[j].as<std::string>();
|
||||
modifiers = modifiers | parse_modifier(modifier);
|
||||
}
|
||||
|
||||
custom_key_commands.push_back({
|
||||
keyboard_action,
|
||||
modifiers,
|
||||
code,
|
||||
command
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Gap sizes
|
||||
if (config["gap_size_x"])
|
||||
{
|
||||
@ -445,6 +534,29 @@ MirInputEventModifier MiracleConfig::get_input_event_modifier() const
|
||||
return (MirInputEventModifier)primary_modifier;
|
||||
}
|
||||
|
||||
CustomKeyCommand const*
|
||||
MiracleConfig::matches_custom_key_command(MirKeyboardAction action, int scan_code, unsigned int modifiers) const
|
||||
{
|
||||
// TODO: Copy & paste
|
||||
for (auto const& command : custom_key_commands)
|
||||
{
|
||||
if (action != command.action)
|
||||
continue;
|
||||
|
||||
auto command_modifiers = command.modifiers;
|
||||
if (command_modifiers & miracle_input_event_modifier_default)
|
||||
command_modifiers = command_modifiers & ~miracle_input_event_modifier_default | get_input_event_modifier();
|
||||
|
||||
if (command_modifiers != modifiers)
|
||||
continue;
|
||||
|
||||
if (scan_code == command.key)
|
||||
return &command;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DefaultKeyCommand MiracleConfig::matches_key_command(MirKeyboardAction action, int scan_code, unsigned int modifiers) const
|
||||
{
|
||||
for (int i = 0; i < DefaultKeyCommand::MAX; i++)
|
||||
|
@ -57,6 +57,11 @@ struct KeyCommand
|
||||
int key;
|
||||
};
|
||||
|
||||
struct CustomKeyCommand : KeyCommand
|
||||
{
|
||||
std::string command;
|
||||
};
|
||||
|
||||
typedef std::vector<KeyCommand> KeyCommandList;
|
||||
|
||||
class MiracleConfig
|
||||
@ -64,6 +69,7 @@ class MiracleConfig
|
||||
public:
|
||||
MiracleConfig();
|
||||
[[nodiscard]] MirInputEventModifier get_input_event_modifier() const;
|
||||
CustomKeyCommand const* matches_custom_key_command(MirKeyboardAction action, int scan_code, unsigned int modifiers) const;
|
||||
[[nodiscard]] DefaultKeyCommand matches_key_command(MirKeyboardAction action, int scan_code, unsigned int modifiers) const;
|
||||
[[nodiscard]] int get_gap_size_x() const;
|
||||
[[nodiscard]] int get_gap_size_y() const;
|
||||
@ -74,6 +80,8 @@ private:
|
||||
|
||||
static const uint miracle_input_event_modifier_default = 1 << 18;
|
||||
uint primary_modifier = mir_input_event_modifier_meta;
|
||||
|
||||
std::vector<CustomKeyCommand> custom_key_commands;
|
||||
KeyCommandList key_commands[DefaultKeyCommand::MAX];
|
||||
|
||||
int gap_size_x = 10;
|
||||
|
@ -92,6 +92,13 @@ bool MiracleWindowManagementPolicy::handle_keyboard_event(MirKeyboardEvent const
|
||||
auto const scan_code = miral::toolkit::mir_keyboard_event_scan_code(event);
|
||||
auto const modifiers = miral::toolkit::mir_keyboard_event_modifiers(event) & MODIFIER_MASK;
|
||||
|
||||
auto custom_key_command = config.matches_custom_key_command(action, scan_code, modifiers);
|
||||
if (custom_key_command != nullptr)
|
||||
{
|
||||
external_client_launcher.launch(custom_key_command->command);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto key_command = config.matches_key_command(action, scan_code, modifiers);
|
||||
if (key_command == DefaultKeyCommand::MAX)
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user