mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-26 00:28:11 +08:00
Move layouts definitions to backend and fix Firefox overlay scrollbars (#647)
* Fix two-axis scrollbars in scrollable regions on Firefox * Move Document Mode dropdown to the backend; and related code cleanup * Port the Layer Tree options bar layout to the backend * Port the tool shelf to the backend * Clean up initialization and wasm wrapper * Fix crash * Fix missing document bar * Remove unused functions in api.rs * Code review * Tool initalisation * Remove some frontend functions * Initalise -> Init so en-US/GB doesn't have to matter :) * Remove blend_mode and opacity from LayerPanelEntry Co-authored-by: 0hypercube <0hypercube@gmail.com>
This commit is contained in:
co-authored by
0hypercube
parent
95435d8bf1
commit
a8f09da5a2
+18
-102
@@ -2,17 +2,13 @@
|
||||
// It serves as a thin wrapper over the editor backend API that relies
|
||||
// on the dispatcher messaging system and more complex Rust data types.
|
||||
|
||||
use crate::helpers::Error;
|
||||
use crate::type_translators::{translate_blend_mode, translate_key, translate_tool_type};
|
||||
use crate::helpers::{translate_key, Error};
|
||||
use crate::{EDITOR_HAS_CRASHED, EDITOR_INSTANCES, JS_EDITOR_HANDLES};
|
||||
|
||||
use editor::consts::{FILE_SAVE_SUFFIX, GRAPHITE_DOCUMENT_VERSION};
|
||||
use editor::input::input_preprocessor::ModifierKeys;
|
||||
use editor::input::mouse::{EditorMouseState, ScrollDelta, ViewportBounds};
|
||||
use editor::message_prelude::*;
|
||||
use editor::misc::EditorError;
|
||||
use editor::viewport_tools::tool::ToolType;
|
||||
use editor::viewport_tools::tools;
|
||||
use editor::Color;
|
||||
use editor::Editor;
|
||||
use editor::LayerId;
|
||||
@@ -96,19 +92,6 @@ impl JsEditorHandle {
|
||||
self.dispatch(WorkspaceMessage::NodeGraphToggleVisibility);
|
||||
}
|
||||
|
||||
/// Modify the currently selected tool in the document state store
|
||||
pub fn select_tool(&self, tool: String) -> Result<(), JsValue> {
|
||||
match translate_tool_type(&tool) {
|
||||
Some(tool_type) => {
|
||||
let message = ToolMessage::ActivateTool { tool_type };
|
||||
self.dispatch(message);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
None => Err(Error::new(&format!("Couldn't select {} because it was not recognized as a valid tool", tool)).into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Update layout of a given UI
|
||||
pub fn update_layout(&self, layout_target: JsValue, widget_id: u64, value: JsValue) -> Result<(), JsValue> {
|
||||
match (from_value(layout_target), from_value(value)) {
|
||||
@@ -121,29 +104,6 @@ impl JsEditorHandle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a message to a given tool
|
||||
pub fn send_tool_message(&self, tool: String, message: &JsValue) -> Result<(), JsValue> {
|
||||
let tool_message = match translate_tool_type(&tool) {
|
||||
Some(tool) => match tool {
|
||||
ToolType::Select => match serde_wasm_bindgen::from_value::<tools::select_tool::SelectToolMessage>(message.clone()) {
|
||||
Ok(select_message) => Ok(ToolMessage::Select(select_message)),
|
||||
Err(err) => Err(Error::new(&format!("Invalid message for {}: {}", tool, err)).into()),
|
||||
},
|
||||
_ => Err(Error::new(&format!("Tool message sending not implemented for {}", tool)).into()),
|
||||
},
|
||||
None => Err(Error::new(&format!("Couldn't send message for {} because it was not recognized as a valid tool", tool)).into()),
|
||||
};
|
||||
|
||||
match tool_message {
|
||||
Ok(message) => {
|
||||
self.dispatch(message);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_document(&self, document_id: u64) {
|
||||
let message = PortfolioMessage::SelectDocument { document_id };
|
||||
self.dispatch(message);
|
||||
@@ -442,12 +402,6 @@ impl JsEditorHandle {
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Delete all selected layers
|
||||
pub fn delete_selected_layers(&self) {
|
||||
let message = DocumentMessage::DeleteSelectedLayers;
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Reorder selected layer
|
||||
pub fn reorder_selected_layers(&self, relative_index_offset: isize) {
|
||||
let message = DocumentMessage::ReorderSelectedLayers { relative_index_offset };
|
||||
@@ -470,25 +424,6 @@ impl JsEditorHandle {
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Set the blend mode for the selected layers
|
||||
pub fn set_blend_mode_for_selected_layers(&self, blend_mode_svg_style_name: String) -> Result<(), JsValue> {
|
||||
if let Some(blend_mode) = translate_blend_mode(blend_mode_svg_style_name.as_str()) {
|
||||
let message = DocumentMessage::SetBlendModeForSelectedLayers { blend_mode };
|
||||
self.dispatch(message);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(&EditorError::Misc("UnknownBlendMode".to_string()).to_string()).into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the opacity for the selected layers
|
||||
pub fn set_opacity_for_selected_layers(&self, opacity_percent: f64) {
|
||||
let opacity = opacity_percent / 100.;
|
||||
let message = DocumentMessage::SetOpacityForSelectedLayers { opacity };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Export the document
|
||||
pub fn export_document(&self) {
|
||||
let message = DialogMessage::RequestExportDialog;
|
||||
@@ -507,13 +442,6 @@ impl JsEditorHandle {
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Update the list of selected layers. The layer paths have to be stored in one array and are separated by LayerId::MAX
|
||||
pub fn select_layers(&self, paths: Vec<LayerId>) {
|
||||
let replacement_selected_layers = paths.split(|id| *id == LayerId::MAX).map(|path| path.to_vec()).collect();
|
||||
let message = DocumentMessage::SetSelectedLayers { replacement_selected_layers };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Sends the blob url generated by js
|
||||
pub fn set_image_blob_url(&self, path: Vec<LayerId>, blob_url: String, width: f64, height: f64) {
|
||||
let dimensions = (width, height);
|
||||
@@ -540,29 +468,14 @@ impl JsEditorHandle {
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Renames a layer from the layer list
|
||||
pub fn rename_layer(&self, layer_path: Vec<LayerId>, new_name: String) {
|
||||
let message = DocumentMessage::RenameLayer { layer_path, new_name };
|
||||
// TODO: Replace with initialization system, issue #524
|
||||
pub fn init_app(&self) {
|
||||
let message = PortfolioMessage::UpdateDocumentWidgets;
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Deletes a layer from the layer list
|
||||
pub fn delete_layer(&self, layer_path: Vec<LayerId>) {
|
||||
let message = DocumentMessage::DeleteLayer { layer_path };
|
||||
let message = ToolMessage::InitTools;
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
/// Creates an empty folder at the document root
|
||||
pub fn create_empty_folder(&self) {
|
||||
let message = DocumentMessage::CreateEmptyFolder { container_path: vec![] };
|
||||
self.dispatch(message);
|
||||
}
|
||||
|
||||
// TODO(mfish33): Replace with initialization system Issue:#524
|
||||
pub fn init_document_bar(&self) {
|
||||
let message = PortfolioMessage::UpdateDocumentBar;
|
||||
self.dispatch(message)
|
||||
}
|
||||
}
|
||||
|
||||
// Needed to make JsEditorHandle functions pub to rust. Do not fully
|
||||
@@ -579,10 +492,11 @@ impl Drop for JsEditorHandle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Access a handle to WASM memory
|
||||
/// Set the random seed used by the editor by calling this from JS upon initialization.
|
||||
/// This is necessary because WASM doesn't have a random number generator.
|
||||
#[wasm_bindgen]
|
||||
pub fn wasm_memory() -> JsValue {
|
||||
wasm_bindgen::memory()
|
||||
pub fn set_random_seed(seed: u64) {
|
||||
editor::communication::set_uuid_seed(seed)
|
||||
}
|
||||
|
||||
/// Intentionally panic for debugging purposes
|
||||
@@ -591,17 +505,24 @@ pub fn intentional_panic() {
|
||||
panic!();
|
||||
}
|
||||
|
||||
/// Get the constant FILE_SAVE_SUFFIX
|
||||
/// Access a handle to WASM memory
|
||||
#[wasm_bindgen]
|
||||
pub fn wasm_memory() -> JsValue {
|
||||
wasm_bindgen::memory()
|
||||
}
|
||||
|
||||
/// Get the constant `FILE_SAVE_SUFFIX`
|
||||
#[wasm_bindgen]
|
||||
pub fn file_save_suffix() -> String {
|
||||
FILE_SAVE_SUFFIX.into()
|
||||
}
|
||||
|
||||
/// Get the constant FILE_SAVE_SUFFIX
|
||||
/// Get the constant `GRAPHITE_DOCUMENT_VERSION`
|
||||
#[wasm_bindgen]
|
||||
pub fn graphite_version() -> String {
|
||||
GRAPHITE_DOCUMENT_VERSION.to_string()
|
||||
}
|
||||
|
||||
/// Get the constant `i32::MAX`
|
||||
#[wasm_bindgen]
|
||||
pub fn i32_max() -> i32 {
|
||||
@@ -613,8 +534,3 @@ pub fn i32_max() -> i32 {
|
||||
pub fn i32_min() -> i32 {
|
||||
i32::MIN
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn set_random_seed(seed: u64) {
|
||||
editor::communication::set_uuid_seed(seed)
|
||||
}
|
||||
|
||||
+129
-11
@@ -1,5 +1,27 @@
|
||||
use crate::JS_EDITOR_HANDLES;
|
||||
|
||||
use editor::{input::keyboard::Key, message_prelude::FrontendMessage};
|
||||
|
||||
use std::panic;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
/// When a panic occurs, notify the user and log the error to the JS console before the backend dies
|
||||
pub fn panic_hook(info: &panic::PanicInfo) {
|
||||
let panic_info = info.to_string();
|
||||
let title = "The editor crashed — sorry about that".to_string();
|
||||
let description = "An internal error occurred. Reload the editor to continue. Please report this by filing an issue on GitHub.".to_string();
|
||||
log::error!("{}", info);
|
||||
JS_EDITOR_HANDLES.with(|instances| {
|
||||
instances.borrow_mut().values_mut().for_each(|instance| {
|
||||
instance.handle_response_rust_proxy(FrontendMessage::DisplayDialogPanic {
|
||||
panic_info: panic_info.clone(),
|
||||
title: title.clone(),
|
||||
description: description.clone(),
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/// The JavaScript `Error` type
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
@@ -10,15 +32,111 @@ extern "C" {
|
||||
pub fn new(msg: &str) -> Error;
|
||||
}
|
||||
|
||||
/// Takes a string and matches it to its equivalently-named enum variant (useful for simple type translations)
|
||||
macro_rules! match_string_to_enum {
|
||||
(match ($e:expr) {$($var:ident),* $(,)?}) => {
|
||||
match $e {
|
||||
$(
|
||||
stringify!($var) => Some($var),
|
||||
)*
|
||||
_ => None
|
||||
}
|
||||
};
|
||||
/// Logging to the JS console
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(msg: &str, format: &str);
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn info(msg: &str, format: &str);
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn warn(msg: &str, format: &str);
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn error(msg: &str, format: &str);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WasmLog;
|
||||
|
||||
impl log::Log for WasmLog {
|
||||
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||
metadata.level() <= log::Level::Info
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
let (log, name, color): (fn(&str, &str), &str, &str) = match record.level() {
|
||||
log::Level::Trace => (log, "trace", "color:plum"),
|
||||
log::Level::Debug => (log, "debug", "color:cyan"),
|
||||
log::Level::Warn => (warn, "warn", "color:goldenrod"),
|
||||
log::Level::Info => (info, "info", "color:mediumseagreen"),
|
||||
log::Level::Error => (error, "error", "color:red"),
|
||||
};
|
||||
let msg = &format!("%c{}\t{}", name, record.args());
|
||||
log(msg, color)
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
/// Translate a keyboard key from its JS name to its Rust `Key` enum
|
||||
pub fn translate_key(name: &str) -> Key {
|
||||
use Key::*;
|
||||
|
||||
log::trace!("Key event received: {}", name);
|
||||
|
||||
match name.to_lowercase().as_str() {
|
||||
"a" => KeyA,
|
||||
"b" => KeyB,
|
||||
"c" => KeyC,
|
||||
"d" => KeyD,
|
||||
"e" => KeyE,
|
||||
"f" => KeyF,
|
||||
"g" => KeyG,
|
||||
"h" => KeyH,
|
||||
"i" => KeyI,
|
||||
"j" => KeyJ,
|
||||
"k" => KeyK,
|
||||
"l" => KeyL,
|
||||
"m" => KeyM,
|
||||
"n" => KeyN,
|
||||
"o" => KeyO,
|
||||
"p" => KeyP,
|
||||
"q" => KeyQ,
|
||||
"r" => KeyR,
|
||||
"s" => KeyS,
|
||||
"t" => KeyT,
|
||||
"u" => KeyU,
|
||||
"v" => KeyV,
|
||||
"w" => KeyW,
|
||||
"x" => KeyX,
|
||||
"y" => KeyY,
|
||||
"z" => KeyZ,
|
||||
"0" => Key0,
|
||||
"1" => Key1,
|
||||
"2" => Key2,
|
||||
"3" => Key3,
|
||||
"4" => Key4,
|
||||
"5" => Key5,
|
||||
"6" => Key6,
|
||||
"7" => Key7,
|
||||
"8" => Key8,
|
||||
"9" => Key9,
|
||||
"enter" => KeyEnter,
|
||||
"=" => KeyEquals,
|
||||
"+" => KeyPlus,
|
||||
"-" => KeyMinus,
|
||||
"shift" => KeyShift,
|
||||
// When using linux + chrome + the neo keyboard layout, the shift key is recognized as caps
|
||||
"capslock" => KeyShift,
|
||||
" " => KeySpace,
|
||||
"control" => KeyControl,
|
||||
"delete" => KeyDelete,
|
||||
"backspace" => KeyBackspace,
|
||||
"alt" => KeyAlt,
|
||||
"escape" => KeyEscape,
|
||||
"tab" => KeyTab,
|
||||
"arrowup" => KeyArrowUp,
|
||||
"arrowdown" => KeyArrowDown,
|
||||
"arrowleft" => KeyArrowLeft,
|
||||
"arrowright" => KeyArrowRight,
|
||||
"[" => KeyLeftBracket,
|
||||
"]" => KeyRightBracket,
|
||||
"{" => KeyLeftCurlyBracket,
|
||||
"}" => KeyRightCurlyBracket,
|
||||
"pageup" => KeyPageUp,
|
||||
"pagedown" => KeyPageDown,
|
||||
"," => KeyComma,
|
||||
"." => KeyPeriod,
|
||||
_ => UnknownKey,
|
||||
}
|
||||
}
|
||||
pub(crate) use match_string_to_enum;
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
pub mod api;
|
||||
pub mod helpers;
|
||||
pub mod logging;
|
||||
pub mod type_translators;
|
||||
|
||||
use editor::message_prelude::*;
|
||||
|
||||
use logging::WasmLog;
|
||||
use helpers::{panic_hook, WasmLog};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::panic;
|
||||
@@ -20,7 +16,7 @@ thread_local! {
|
||||
pub static JS_EDITOR_HANDLES: RefCell<HashMap<u64, api::JsEditorHandle>> = RefCell::new(HashMap::new());
|
||||
}
|
||||
|
||||
// Initialize the backend
|
||||
/// Initialize the backend
|
||||
#[wasm_bindgen(start)]
|
||||
pub fn init() {
|
||||
panic::set_hook(Box::new(panic_hook));
|
||||
@@ -28,20 +24,3 @@ pub fn init() {
|
||||
log::set_logger(&LOGGER).expect("Failed to set logger");
|
||||
log::set_max_level(log::LevelFilter::Debug);
|
||||
}
|
||||
|
||||
// When a panic occurs, close up shop before the backend dies
|
||||
fn panic_hook(info: &panic::PanicInfo) {
|
||||
let panic_info = info.to_string();
|
||||
let title = "The editor crashed — sorry about that".to_string();
|
||||
let description = "An internal error occurred. Reload the editor to continue. Please report this by filing an issue on GitHub.".to_string();
|
||||
log::error!("{}", info);
|
||||
JS_EDITOR_HANDLES.with(|instances| {
|
||||
instances.borrow_mut().values_mut().for_each(|instance| {
|
||||
instance.handle_response_rust_proxy(FrontendMessage::DisplayDialogPanic {
|
||||
panic_info: panic_info.clone(),
|
||||
title: title.clone(),
|
||||
description: description.clone(),
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(msg: &str, format: &str);
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn info(msg: &str, format: &str);
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn warn(msg: &str, format: &str);
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn error(msg: &str, format: &str);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct WasmLog;
|
||||
|
||||
impl log::Log for WasmLog {
|
||||
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||
metadata.level() <= log::Level::Info
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
let (log, name, color): (fn(&str, &str), &str, &str) = match record.level() {
|
||||
log::Level::Trace => (log, "trace", "color:plum"),
|
||||
log::Level::Debug => (log, "debug", "color:cyan"),
|
||||
log::Level::Warn => (warn, "warn", "color:goldenrod"),
|
||||
log::Level::Info => (info, "info", "color:mediumseagreen"),
|
||||
log::Level::Error => (error, "error", "color:red"),
|
||||
};
|
||||
let msg = &format!("%c{}\t{}", name, record.args());
|
||||
log(msg, color)
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
use crate::helpers::match_string_to_enum;
|
||||
|
||||
use editor::input::keyboard::Key;
|
||||
use editor::viewport_tools::tool::ToolType;
|
||||
use graphene::layers::blend_mode::BlendMode;
|
||||
|
||||
pub fn translate_tool_type(name: &str) -> Option<ToolType> {
|
||||
use ToolType::*;
|
||||
|
||||
match_string_to_enum!(match (name) {
|
||||
Select,
|
||||
Artboard,
|
||||
Navigate,
|
||||
Eyedropper,
|
||||
Text,
|
||||
Fill,
|
||||
Gradient,
|
||||
Brush,
|
||||
Heal,
|
||||
Clone,
|
||||
Patch,
|
||||
Detail,
|
||||
Relight,
|
||||
Path,
|
||||
Pen,
|
||||
Freehand,
|
||||
Spline,
|
||||
Line,
|
||||
Rectangle,
|
||||
Ellipse,
|
||||
Shape
|
||||
})
|
||||
}
|
||||
|
||||
pub fn translate_blend_mode(blend_mode_svg_style_name: &str) -> Option<BlendMode> {
|
||||
use BlendMode::*;
|
||||
|
||||
let blend_mode = match blend_mode_svg_style_name {
|
||||
"Normal" => Normal,
|
||||
"Multiply" => Multiply,
|
||||
"Darken" => Darken,
|
||||
"ColorBurn" => ColorBurn,
|
||||
"Screen" => Screen,
|
||||
"Lighten" => Lighten,
|
||||
"ColorDodge" => ColorDodge,
|
||||
"Overlay" => Overlay,
|
||||
"SoftLight" => SoftLight,
|
||||
"HardLight" => HardLight,
|
||||
"Difference" => Difference,
|
||||
"Exclusion" => Exclusion,
|
||||
"Hue" => Hue,
|
||||
"Saturation" => Saturation,
|
||||
"Color" => Color,
|
||||
"Luminosity" => Luminosity,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(blend_mode)
|
||||
}
|
||||
|
||||
pub fn translate_key(name: &str) -> Key {
|
||||
use Key::*;
|
||||
|
||||
log::trace!("Key event received: {}", name);
|
||||
|
||||
match name.to_lowercase().as_str() {
|
||||
"a" => KeyA,
|
||||
"b" => KeyB,
|
||||
"c" => KeyC,
|
||||
"d" => KeyD,
|
||||
"e" => KeyE,
|
||||
"f" => KeyF,
|
||||
"g" => KeyG,
|
||||
"h" => KeyH,
|
||||
"i" => KeyI,
|
||||
"j" => KeyJ,
|
||||
"k" => KeyK,
|
||||
"l" => KeyL,
|
||||
"m" => KeyM,
|
||||
"n" => KeyN,
|
||||
"o" => KeyO,
|
||||
"p" => KeyP,
|
||||
"q" => KeyQ,
|
||||
"r" => KeyR,
|
||||
"s" => KeyS,
|
||||
"t" => KeyT,
|
||||
"u" => KeyU,
|
||||
"v" => KeyV,
|
||||
"w" => KeyW,
|
||||
"x" => KeyX,
|
||||
"y" => KeyY,
|
||||
"z" => KeyZ,
|
||||
"0" => Key0,
|
||||
"1" => Key1,
|
||||
"2" => Key2,
|
||||
"3" => Key3,
|
||||
"4" => Key4,
|
||||
"5" => Key5,
|
||||
"6" => Key6,
|
||||
"7" => Key7,
|
||||
"8" => Key8,
|
||||
"9" => Key9,
|
||||
"enter" => KeyEnter,
|
||||
"=" => KeyEquals,
|
||||
"+" => KeyPlus,
|
||||
"-" => KeyMinus,
|
||||
"shift" => KeyShift,
|
||||
// When using linux + chrome + the neo keyboard layout, the shift key is recognized as caps
|
||||
"capslock" => KeyShift,
|
||||
" " => KeySpace,
|
||||
"control" => KeyControl,
|
||||
"delete" => KeyDelete,
|
||||
"backspace" => KeyBackspace,
|
||||
"alt" => KeyAlt,
|
||||
"escape" => KeyEscape,
|
||||
"tab" => KeyTab,
|
||||
"arrowup" => KeyArrowUp,
|
||||
"arrowdown" => KeyArrowDown,
|
||||
"arrowleft" => KeyArrowLeft,
|
||||
"arrowright" => KeyArrowRight,
|
||||
"[" => KeyLeftBracket,
|
||||
"]" => KeyRightBracket,
|
||||
"{" => KeyLeftCurlyBracket,
|
||||
"}" => KeyRightCurlyBracket,
|
||||
"pageup" => KeyPageUp,
|
||||
"pagedown" => KeyPageDown,
|
||||
"," => KeyComma,
|
||||
"." => KeyPeriod,
|
||||
_ => UnknownKey,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user