Skip to content

Commit 91586ba

Browse files
Key Combinations
1 parent 3204182 commit 91586ba

5 files changed

Lines changed: 133 additions & 21 deletions

File tree

src/utils/helpers.rs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ pub fn resolve_expression(expr: &Expression, state: &mut State) -> Value {
2323
}
2424
Value::Object(object)
2525
}
26-
Expression::Closure { args, body, returns } => {
26+
Expression::Closure {
27+
args,
28+
body,
29+
returns,
30+
} => {
2731
let closure = Function {
2832
args: args.clone(),
2933
body: body.clone(),
@@ -321,6 +325,81 @@ pub fn string_to_keycode(s: &str) -> Option<Key> {
321325
}
322326
}
323327

328+
pub fn keycode_to_string(key: Key) -> String {
329+
use Key::*;
330+
match key {
331+
A => "a".to_string(),
332+
B => "b".to_string(),
333+
C => "c".to_string(),
334+
D => "d".to_string(),
335+
E => "e".to_string(),
336+
F => "f".to_string(),
337+
G => "g".to_string(),
338+
H => "h".to_string(),
339+
I => "i".to_string(),
340+
J => "j".to_string(),
341+
K => "k".to_string(),
342+
L => "l".to_string(),
343+
M => "m".to_string(),
344+
N => "n".to_string(),
345+
O => "o".to_string(),
346+
P => "p".to_string(),
347+
Q => "q".to_string(),
348+
R => "r".to_string(),
349+
S => "s".to_string(),
350+
T => "t".to_string(),
351+
U => "u".to_string(),
352+
V => "v".to_string(),
353+
W => "w".to_string(),
354+
X => "x".to_string(),
355+
Y => "y".to_string(),
356+
Z => "z".to_string(),
357+
358+
Num0 => "0".to_string(),
359+
Num1 => "1".to_string(),
360+
Num2 => "2".to_string(),
361+
Num3 => "3".to_string(),
362+
Num4 => "4".to_string(),
363+
Num5 => "5".to_string(),
364+
Num6 => "6".to_string(),
365+
Num7 => "7".to_string(),
366+
Num8 => "8".to_string(),
367+
Num9 => "9".to_string(),
368+
369+
GraveAccent => "`".to_owned(),
370+
Minus => "-".to_owned(),
371+
Equal => "=".to_owned(),
372+
LeftBracket => "(".to_owned(),
373+
RightBracket => ")".to_owned(),
374+
Backslash => "\\".to_owned(),
375+
Semicolon => ";".to_owned(),
376+
Apostrophe => "'".to_owned(),
377+
Comma => ",".to_owned(),
378+
Period => ".".to_owned(),
379+
Slash => "/".to_owned(),
380+
381+
LeftControl => "lctrl".to_owned(),
382+
RightControl => "rctrl".to_owned(),
383+
LeftShift => "lshift".to_owned(),
384+
RightShift => "rshift".to_owned(),
385+
LeftAlt => "lalt".to_owned(),
386+
RightAlt => "ralt".to_owned(),
387+
LeftSuper => "lsuper".to_owned(),
388+
RightSuper => "rsuper".to_owned(),
389+
Tab => "tab".to_owned(),
390+
Delete => "del".to_owned(),
391+
Backspace => "back".to_owned(),
392+
Left => "left".to_owned(),
393+
Right => "right".to_owned(),
394+
Up => "up".to_owned(),
395+
Down => "down".to_owned(),
396+
Space => "space".to_owned(),
397+
Enter => "enter".to_owned(),
398+
Escape => "escape".to_owned(),
399+
_ => "unknown".to_owned(),
400+
}
401+
}
402+
324403
pub fn draw_line(start: Vec2, end: Vec2, thickness: f32, shader: &ShaderProgram, color: Vec4) {
325404
let direction = (end - start).normalize();
326405
let length = (end - start).length();

src/utils/language.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use std::collections::HashMap;
21
use super::Value;
2+
use std::collections::HashMap;
33

44
// ========================= Tokenizer ========================= \\
55

@@ -307,11 +307,7 @@ impl Expression {
307307
}
308308
Expression::Closure { args, returns, .. } => {
309309
let args_str = args.join(", ");
310-
format!(
311-
"({}) {} {{ ... }}",
312-
args_str,
313-
returns.to_string(),
314-
)
310+
format!("({}) {} {{ ... }}", args_str, returns.to_string(),)
315311
}
316312
Expression::ListMemberAccess { list, index } => {
317313
format!("{}[{}]", list.to_string(), index.to_string())

src/utils/runtime.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ struct ProjectConfig {
6464

6565
#[derive(Debug)]
6666
pub struct InputManager {
67+
key_history: Vec<glfw::Key>,
6768
keys_down: HashSet<glfw::Key>,
6869
keys_pressed: HashSet<glfw::Key>,
6970
keys_released: HashSet<glfw::Key>,
@@ -75,6 +76,7 @@ pub struct InputManager {
7576
impl InputManager {
7677
pub fn new() -> Self {
7778
Self {
79+
key_history: Vec::new(),
7880
keys_down: HashSet::new(),
7981
keys_pressed: HashSet::new(),
8082
keys_released: HashSet::new(),
@@ -101,6 +103,7 @@ impl InputManager {
101103
if !self.keys_down.contains(&key) {
102104
self.keys_pressed.insert(key);
103105
}
106+
self.key_history.push(key);
104107
self.keys_down.insert(key);
105108
}
106109
glfw::Action::Release => {
@@ -130,6 +133,10 @@ impl InputManager {
130133
}
131134
}
132135

136+
pub fn key_history(&self) -> &[glfw::Key] {
137+
&self.key_history
138+
}
139+
133140
pub fn is_key_down(&self, key: glfw::Key) -> bool {
134141
self.keys_down.contains(&key)
135142
}

src/utils/sprite/builtins/builtins.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ pub fn builtins() -> HashMap<String, Callable> {
9797
builtin!(builtins, "switch_costume", |st, ar| looks::switch_costume(st, ar));
9898
builtin!(builtins, "next_costume", |st, _| looks::next_costume(st));
9999
builtin!(builtins, "previous_costume", |st, _| looks::previous_costume(st));
100-
builtin!(builtins,"switch_backdrop",|st, ar| looks::switch_backdrop(st, ar));
100+
builtin!(builtins, "switch_backdrop",|st, ar| looks::switch_backdrop(st, ar));
101101
builtin!(builtins, "next_backdrop", |st, _| looks::next_backdrop(st));
102102
builtin!(builtins, "previous_backdrop", |st, _| looks::previous_backdrop(st));
103103
builtin!(builtins, "set_scale", |st, ar| looks::set_scale(st, ar));
@@ -128,6 +128,8 @@ pub fn builtins() -> HashMap<String, Callable> {
128128
builtin!(builtins, "key_down", |st, ar| events::key_down(st, ar));
129129
builtin!(builtins, "key_pressed", |st, ar| events::key_pressed(st, ar));
130130
builtin!(builtins, "key_released", |st, ar| events::key_released(st, ar));
131+
builtin!(builtins, "last_key", |st, _| events::last_key(st));
132+
builtin!(builtins, "combination_pressed", |st, ar| events::combination_pressed(st, ar));
131133
builtin!(builtins, "mouse_button_down", |st, ar| events::mouse_button_down(st, ar));
132134
builtin!(builtins, "mouse_button_pressed", |st, ar| events::mouse_button_pressed(st, ar));
133135
builtin!(builtins, "mouse_button_released", |st, ar| events::mouse_button_released(st, ar));

src/utils/sprite/builtins/events.rs

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use crate::utils::*;
21
use glam::*;
32

4-
pub fn key_down(state: &State, args: &[Value]) -> Result {
3+
use crate::utils::{State, Value, function, keycode_to_string, string_to_keycode, string_to_mouse};
4+
5+
pub fn key_down(state: &State, args: &[Value]) -> function::Result {
56
if let [Value::String(key)] = args {
67
let key_code = string_to_keycode(key).ok_or(format!("Invalid key code: '{}'", key))?;
78
Ok(Value::Boolean(state.input_manager.is_key_down(key_code)))
@@ -10,7 +11,7 @@ pub fn key_down(state: &State, args: &[Value]) -> Result {
1011
}
1112
}
1213

13-
pub fn key_pressed(state: &State, args: &[Value]) -> Result {
14+
pub fn key_pressed(state: &State, args: &[Value]) -> function::Result {
1415
if let [Value::String(key)] = args {
1516
let key_code = string_to_keycode(key).ok_or(format!("Invalid key code: '{}'", key))?;
1617
Ok(Value::Boolean(state.input_manager.is_key_pressed(key_code)))
@@ -19,7 +20,7 @@ pub fn key_pressed(state: &State, args: &[Value]) -> Result {
1920
}
2021
}
2122

22-
pub fn key_released(state: &State, args: &[Value]) -> Result {
23+
pub fn key_released(state: &State, args: &[Value]) -> function::Result {
2324
if let [Value::String(key)] = args {
2425
let key_code = string_to_keycode(key).ok_or(format!("Invalid key code: '{}'", key))?;
2526
Ok(Value::Boolean(
@@ -30,7 +31,34 @@ pub fn key_released(state: &State, args: &[Value]) -> Result {
3031
}
3132
}
3233

33-
pub fn mouse_button_down(state: &State, args: &[Value]) -> Result {
34+
pub fn last_key(state: &State) -> function::Result {
35+
let key_history = state.input_manager.key_history();
36+
if let Some(key) = key_history.last() {
37+
Ok(Value::String(keycode_to_string(*key)))
38+
} else {
39+
Ok(Value::Null)
40+
}
41+
}
42+
43+
pub fn combination_pressed(state: &State, args: &[Value]) -> function::Result {
44+
let key_codes: Result<Vec<glfw::Key>, _> = args
45+
.iter()
46+
.map(|arg| match arg {
47+
Value::String(s) => string_to_keycode(s).ok_or_else(|| format!("Invalid key: {}", s)),
48+
_ => Err("All arguments must be strings".to_string()),
49+
})
50+
.collect();
51+
52+
let key_codes = match key_codes {
53+
Ok(codes) if !codes.is_empty() => codes,
54+
_ => return Ok(Value::Boolean(false)),
55+
};
56+
57+
let matches = state.input_manager.key_history().ends_with(&key_codes);
58+
Ok(Value::Boolean(matches))
59+
}
60+
61+
pub fn mouse_button_down(state: &State, args: &[Value]) -> function::Result {
3462
if let [Value::String(button)] = args {
3563
let button_code =
3664
string_to_mouse(button).ok_or(format!("Invalid mouse button: '{}'", button))?;
@@ -42,7 +70,7 @@ pub fn mouse_button_down(state: &State, args: &[Value]) -> Result {
4270
}
4371
}
4472

45-
pub fn mouse_button_pressed(state: &State, args: &[Value]) -> Result {
73+
pub fn mouse_button_pressed(state: &State, args: &[Value]) -> function::Result {
4674
if let [Value::String(button)] = args {
4775
let button_code =
4876
string_to_mouse(button).ok_or(format!("Invalid mouse button: '{}'", button))?;
@@ -54,7 +82,7 @@ pub fn mouse_button_pressed(state: &State, args: &[Value]) -> Result {
5482
}
5583
}
5684

57-
pub fn mouse_button_released(state: &State, args: &[Value]) -> Result {
85+
pub fn mouse_button_released(state: &State, args: &[Value]) -> function::Result {
5886
if let [Value::String(button)] = args {
5987
let button_code =
6088
string_to_mouse(button).ok_or(format!("Invalid mouse button: '{}'", button))?;
@@ -66,19 +94,19 @@ pub fn mouse_button_released(state: &State, args: &[Value]) -> Result {
6694
}
6795
}
6896

69-
pub fn mouse_x(state: &State) -> Result {
97+
pub fn mouse_x(state: &State) -> function::Result {
7098
Ok(Value::Number(
7199
state.window.get_cursor_pos().0 as f32 * 2.0 - state.window.get_size().0 as f32,
72100
))
73101
}
74102

75-
pub fn mouse_y(state: &State) -> Result {
103+
pub fn mouse_y(state: &State) -> function::Result {
76104
Ok(Value::Number(
77105
-(state.window.get_cursor_pos().1 as f32 * 2.0 - state.window.get_size().1 as f32),
78106
))
79107
}
80108

81-
pub fn sprite_clicked(state: &State) -> Result {
109+
pub fn sprite_clicked(state: &State) -> function::Result {
82110
if !state
83111
.input_manager
84112
.is_mouse_button_pressed(glfw::MouseButton::Left)
@@ -111,7 +139,7 @@ pub fn sprite_clicked(state: &State) -> Result {
111139
}
112140
}
113141

114-
pub fn is_backdrop(state: &State, args: &[Value]) -> Result {
142+
pub fn is_backdrop(state: &State, args: &[Value]) -> function::Result {
115143
if let [Value::Number(index)] = args {
116144
let backdrop = state.project.stage.backdrop();
117145
if backdrop == *index as usize {
@@ -124,7 +152,7 @@ pub fn is_backdrop(state: &State, args: &[Value]) -> Result {
124152
}
125153
}
126154

127-
pub fn broadcast_id_of(state: &State, args: &[Value]) -> Result {
155+
pub fn broadcast_id_of(state: &State, args: &[Value]) -> function::Result {
128156
if let [Value::String(message)] = args {
129157
if let Some(broadcast) = state.project.get_broadcast(message) {
130158
Ok(Value::Number(broadcast.id as f32))
@@ -136,7 +164,7 @@ pub fn broadcast_id_of(state: &State, args: &[Value]) -> Result {
136164
}
137165
}
138166

139-
pub fn broadcast(state: &mut State, args: &[Value]) -> Result {
167+
pub fn broadcast(state: &mut State, args: &[Value]) -> function::Result {
140168
if let [Value::String(message)] = args {
141169
state.project.broadcast(message.clone());
142170
Ok(Value::Null)

0 commit comments

Comments
 (0)