get it typing!
This commit is contained in:
parent
2a01c5ff97
commit
c2cc52e391
2 changed files with 137 additions and 78 deletions
|
@ -4,12 +4,14 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use enigo::{Enigo, Key, Keyboard, Settings};
|
use enigo::{Direction, Enigo, Key, Keyboard, Settings};
|
||||||
use midi_keys::{
|
use midi_keys::{
|
||||||
log::load_raw_log,
|
log::load_raw_log,
|
||||||
midi::daemon::Category,
|
midi::daemon::Category,
|
||||||
parser::parse_message,
|
parser::parse_message,
|
||||||
typing::{base_values, encode, midi_to_scale_degree, TypingState},
|
typing::{
|
||||||
|
base_values, encode, midi_to_scale_degree, Keystroke, Modifier, Special, TypingState,
|
||||||
|
},
|
||||||
ui::{display_state_daemon, DisplayQueues, DisplayState},
|
ui::{display_state_daemon, DisplayQueues, DisplayState},
|
||||||
};
|
};
|
||||||
use midir::{MidiInput, MidiInputPort};
|
use midir::{MidiInput, MidiInputPort};
|
||||||
|
@ -37,12 +39,17 @@ fn main() {
|
||||||
println!("started daemon");
|
println!("started daemon");
|
||||||
|
|
||||||
for c in "hello, world".chars() {
|
for c in "hello, world".chars() {
|
||||||
let v = encode(c).unwrap();
|
let v = encode(Keystroke::Char(c)).unwrap();
|
||||||
println!("{c}: {:?} - {:?}", v, base_values(v, 7, 3));
|
println!("{c}: {:?} - {:?}", v, base_values(v, 7, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
for c in "Hello, WORLD!".chars() {
|
for c in "Hello, WORLD!".chars() {
|
||||||
let v = encode(c).unwrap();
|
if c.is_uppercase() {
|
||||||
println!("{c}: {:?} - {:?}", v, base_values(v, 7, 3));
|
let v = encode(Keystroke::Modifier(Modifier::Shift)).unwrap();
|
||||||
|
println!("{c}: {:?} - {:?}", v, base_values(v, 7, 2));
|
||||||
|
}
|
||||||
|
let v = encode(Keystroke::Char(c.to_ascii_lowercase())).unwrap();
|
||||||
|
println!("{c}: {:?} - {:?}", v, base_values(v, 7, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::thread::spawn(move || loop {
|
//std::thread::spawn(move || loop {
|
||||||
|
@ -57,6 +64,7 @@ fn main() {
|
||||||
let mut enigo = Enigo::new(&Settings::default()).unwrap();
|
let mut enigo = Enigo::new(&Settings::default()).unwrap();
|
||||||
|
|
||||||
let mut current_note = None;
|
let mut current_note = None;
|
||||||
|
let mut shift = false;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match ws_recv.recv() {
|
match ws_recv.recv() {
|
||||||
|
@ -87,7 +95,7 @@ fn main() {
|
||||||
None => {
|
None => {
|
||||||
current_note = None;
|
current_note = None;
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
steps += 1;
|
steps += 1;
|
||||||
|
@ -96,17 +104,33 @@ fn main() {
|
||||||
println!("here: {steps}, {scale_degree}, {current_note:?}, {m:?}");
|
println!("here: {steps}, {scale_degree}, {current_note:?}, {m:?}");
|
||||||
|
|
||||||
if steps % 2 == 0 {
|
if steps % 2 == 0 {
|
||||||
if velocity > 20 {
|
|
||||||
state.set_bits(64);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (b, c) = state.emit();
|
let (b, c) = state.emit();
|
||||||
println!("got {b}, {c:?}");
|
println!("got {b}, {c:?}");
|
||||||
|
|
||||||
if let Some(c) = c {
|
if let Some(c) = c {
|
||||||
|
match c {
|
||||||
|
Keystroke::Char(c) => {
|
||||||
|
if shift {
|
||||||
|
println!("well that's a shifty character");
|
||||||
|
let shifted_c = c.to_ascii_uppercase();
|
||||||
|
enigo.text(&format!("{shifted_c}")).unwrap();
|
||||||
|
shift = false;
|
||||||
|
} else {
|
||||||
|
println!("no shifty characters here");
|
||||||
enigo.text(&format!("{c}")).unwrap();
|
enigo.text(&format!("{c}")).unwrap();
|
||||||
} else if b == 120 {
|
}
|
||||||
enigo.key(Key::Backspace, enigo::Direction::Click).unwrap();
|
}
|
||||||
|
Keystroke::Modifier(Modifier::Shift) => {
|
||||||
|
println!("SHIFTY BEHAVIOR");
|
||||||
|
shift = !shift;
|
||||||
|
}
|
||||||
|
Keystroke::Special(Special::CapsLock) => {
|
||||||
|
enigo.key(Key::CapsLock, Direction::Click).unwrap()
|
||||||
|
}
|
||||||
|
Keystroke::Special(Special::Backspace) => {
|
||||||
|
enigo.key(Key::Backspace, Direction::Click).unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,24 +140,6 @@ fn main() {
|
||||||
} else if let Some(_) = note_off {
|
} else if let Some(_) = note_off {
|
||||||
current_note = None;
|
current_note = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if let Some((note, velocity)) = m.note_on_values() {
|
|
||||||
// if let Some(degree) = midi_to_scale_degree(60, note) {
|
|
||||||
// steps += 1;
|
|
||||||
// println!("got degree: {degree}, steps: {steps}, state: {state:?}");
|
|
||||||
// state.enter(degree);
|
|
||||||
|
|
||||||
// if steps % 3 == 0 {
|
|
||||||
// let (b, c) = state.emit();
|
|
||||||
// println!("got {b}, {c:?}");
|
|
||||||
// if let Some(c) = c {
|
|
||||||
// enigo.text(&format!("{c}")).unwrap();
|
|
||||||
// } else if b == 255 {
|
|
||||||
// enigo.key(Key::Backspace, enigo::Direction::Click).unwrap();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
Err(err) => println!("err(ws): {err:?}"),
|
Err(err) => println!("err(ws): {err:?}"),
|
||||||
}
|
}
|
||||||
|
@ -149,6 +155,13 @@ fn main() {
|
||||||
midi_keys::ui::run(state);
|
midi_keys::ui::run(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn press_modifier(keyboard: &mut Enigo, modifier: &Modifier, direction: Direction) {
|
||||||
|
match modifier {
|
||||||
|
Modifier::Shift => keyboard.key(Key::Shift, direction),
|
||||||
|
}
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run() -> Result<()> {
|
pub fn run() -> Result<()> {
|
||||||
let midi_in = MidiInput::new("keyboard")?;
|
let midi_in = MidiInput::new("keyboard")?;
|
||||||
|
|
||||||
|
|
138
src/typing.rs
138
src/typing.rs
|
@ -1,28 +1,31 @@
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct TypingState {
|
pub struct TypingState {
|
||||||
base: u8,
|
base: u32,
|
||||||
current: u8,
|
current: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypingState {
|
impl TypingState {
|
||||||
pub fn new(base: u8) -> TypingState {
|
pub fn new(base: u32) -> TypingState {
|
||||||
TypingState { base, current: 0 }
|
TypingState { base, current: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add the value into the current accumulator.
|
/// Add the value into the current accumulator.
|
||||||
pub fn enter(&mut self, value: u8) {
|
pub fn enter(&mut self, value: u8) {
|
||||||
self.current = self.current.saturating_mul(self.base).saturating_add(value);
|
self.current = self
|
||||||
|
.current
|
||||||
|
.saturating_mul(self.base)
|
||||||
|
.saturating_add(value.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_bits(&mut self, mask: u8) {
|
pub fn set_bits(&mut self, mask: u32) {
|
||||||
self.current |= mask;
|
self.current |= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decode the current accumulator as a character, or None if it's invalid.
|
/// Decode the current accumulator as a keystroke, or None if it's invalid.
|
||||||
/// This resets the accumulator to 0!
|
/// This resets the accumulator to 0!
|
||||||
pub fn emit(&mut self) -> (u8, Option<char>) {
|
pub fn emit(&mut self) -> (u32, Option<Keystroke>) {
|
||||||
let x = self.current;
|
let x = self.current;
|
||||||
let c = decode_alt(x);
|
let c = decode(x);
|
||||||
|
|
||||||
self.current = 0;
|
self.current = 0;
|
||||||
|
|
||||||
|
@ -31,10 +34,11 @@ impl TypingState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Chunks a u8 into a sequence of values in a given base.
|
/// Chunks a u8 into a sequence of values in a given base.
|
||||||
pub fn base_values(mut x: u8, base: u8, len: usize) -> Vec<u8> {
|
pub fn base_values(mut x: u32, base: u32, len: usize) -> Vec<u8> {
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
vals.push(x % base);
|
let digit = x % (base as u32);
|
||||||
|
vals.push(digit as u8);
|
||||||
x = x / base;
|
x = x / base;
|
||||||
}
|
}
|
||||||
vals.reverse();
|
vals.reverse();
|
||||||
|
@ -58,10 +62,66 @@ pub fn midi_to_scale_degree(root: u8, note: u8) -> Option<u8> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum Keystroke {
|
||||||
|
Char(char),
|
||||||
|
Modifier(Modifier),
|
||||||
|
Special(Special),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum Modifier {
|
||||||
|
Shift,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum Special {
|
||||||
|
CapsLock,
|
||||||
|
Backspace,
|
||||||
|
}
|
||||||
|
|
||||||
/// Converts a character to its assigned number for use in text entry. This is
|
/// Converts a character to its assigned number for use in text entry. This is
|
||||||
/// stores them as u8 to keep things simple and fixed length. If we want to
|
/// stores them as u32 to keep things simple and fixed length. If we want to
|
||||||
/// support the full Unicode space, we can have expand this to u32.
|
/// support the full Unicode space, we must expand this to u32.
|
||||||
pub fn encode(c: char) -> Option<u8> {
|
pub fn encode(key: Keystroke) -> Option<u32> {
|
||||||
|
Some(match key {
|
||||||
|
Keystroke::Modifier(Modifier::Shift) => 0,
|
||||||
|
Keystroke::Special(Special::CapsLock) => 1,
|
||||||
|
Keystroke::Special(Special::Backspace) => 2,
|
||||||
|
|
||||||
|
Keystroke::Char(c @ 'a'..='z') => c as u32 - 'a' as u32 + 3,
|
||||||
|
Keystroke::Char(c @ '0'..='9') => c as u32 - '0' as u32 + 29,
|
||||||
|
Keystroke::Char('.') => 39,
|
||||||
|
Keystroke::Char(',') => 40,
|
||||||
|
Keystroke::Char('!') => 41,
|
||||||
|
Keystroke::Char(' ') => 42,
|
||||||
|
Keystroke::Char('\n') => 43,
|
||||||
|
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a number to its corresponding character for use in text entry.
|
||||||
|
/// If a character isn't implemented, it will return None.
|
||||||
|
pub fn decode(x: u32) -> Option<Keystroke> {
|
||||||
|
Some(match x {
|
||||||
|
0 => Keystroke::Modifier(Modifier::Shift),
|
||||||
|
1 => Keystroke::Special(Special::CapsLock),
|
||||||
|
2 => Keystroke::Special(Special::Backspace),
|
||||||
|
|
||||||
|
3..29 => Keystroke::Char(char::from_u32(x - 3 + ('a' as u32))?),
|
||||||
|
29..39 => Keystroke::Char(char::from_u32(x - 29 + ('0' as u32))?),
|
||||||
|
39 => Keystroke::Char('.'),
|
||||||
|
40 => Keystroke::Char(','),
|
||||||
|
41 => Keystroke::Char('!'),
|
||||||
|
42 => Keystroke::Char(' '),
|
||||||
|
43 => Keystroke::Char('\n'),
|
||||||
|
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode_old(c: char) -> Option<u8> {
|
||||||
Some(match c {
|
Some(match c {
|
||||||
'a'..='z' => c as u8 - 'a' as u8,
|
'a'..='z' => c as u8 - 'a' as u8,
|
||||||
'A'..='Z' => c as u8 - 'A' as u8 + 26,
|
'A'..='Z' => c as u8 - 'A' as u8 + 26,
|
||||||
|
@ -76,7 +136,7 @@ pub fn encode(c: char) -> Option<u8> {
|
||||||
|
|
||||||
/// Converts a number to its corresponding character for use in text entry.
|
/// Converts a number to its corresponding character for use in text entry.
|
||||||
/// If a character isn't implemented, it will return None.
|
/// If a character isn't implemented, it will return None.
|
||||||
pub fn decode(x: u8) -> Option<char> {
|
pub fn decode_old(x: u8) -> Option<char> {
|
||||||
let c = match x {
|
let c = match x {
|
||||||
0..=25 => 'a' as u8 + x,
|
0..=25 => 'a' as u8 + x,
|
||||||
26..=51 => 'A' as u8 + x - 26,
|
26..=51 => 'A' as u8 + x - 26,
|
||||||
|
@ -107,58 +167,44 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encodes_lowercase() {
|
fn encodes_lowercase() {
|
||||||
assert_eq!(encode('a'), Some(0));
|
assert_eq!(encode(Keystroke::Char('a')), Some(3));
|
||||||
assert_eq!(encode('b'), Some(1));
|
assert_eq!(encode(Keystroke::Char('b')), Some(4));
|
||||||
assert_eq!(encode('z'), Some(25));
|
assert_eq!(encode(Keystroke::Char('z')), Some(28));
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn encodes_uppercase() {
|
|
||||||
assert_eq!(encode('A'), Some(26));
|
|
||||||
assert_eq!(encode('B'), Some(27));
|
|
||||||
assert_eq!(encode('Z'), Some(51));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encodes_numbers() {
|
fn encodes_numbers() {
|
||||||
assert_eq!(encode('0'), Some(52));
|
assert_eq!(encode(Keystroke::Char('0')), Some(29));
|
||||||
assert_eq!(encode('1'), Some(53));
|
assert_eq!(encode(Keystroke::Char('1')), Some(30));
|
||||||
assert_eq!(encode('9'), Some(61));
|
assert_eq!(encode(Keystroke::Char('9')), Some(38));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encodes_punctuation() {
|
fn encodes_punctuation() {
|
||||||
assert_eq!(encode('.'), Some(62));
|
assert_eq!(encode(Keystroke::Char('.')), Some(39));
|
||||||
assert_eq!(encode(','), Some(63));
|
assert_eq!(encode(Keystroke::Char(',')), Some(40));
|
||||||
assert_eq!(encode('!'), Some(64));
|
assert_eq!(encode(Keystroke::Char('!')), Some(41));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decodes_lowercase() {
|
fn decodes_lowercase() {
|
||||||
assert_eq!(decode(0), Some('a'));
|
assert_eq!(decode(3), Some(Keystroke::Char('a')));
|
||||||
assert_eq!(decode(1), Some('b'));
|
assert_eq!(decode(4), Some(Keystroke::Char('b')));
|
||||||
assert_eq!(decode(25), Some('z'));
|
assert_eq!(decode(28), Some(Keystroke::Char('z')));
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn decodes_uppercase() {
|
|
||||||
assert_eq!(decode(26), Some('A'));
|
|
||||||
assert_eq!(decode(27), Some('B'));
|
|
||||||
assert_eq!(decode(51), Some('Z'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decodes_numbers() {
|
fn decodes_numbers() {
|
||||||
assert_eq!(decode(52), Some('0'));
|
assert_eq!(decode(29), Some(Keystroke::Char('0')));
|
||||||
assert_eq!(decode(53), Some('1'));
|
assert_eq!(decode(30), Some(Keystroke::Char('1')));
|
||||||
assert_eq!(decode(61), Some('9'));
|
assert_eq!(decode(38), Some(Keystroke::Char('9')));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decodes_punctuation() {
|
fn decodes_punctuation() {
|
||||||
assert_eq!(decode(62), Some('.'));
|
assert_eq!(decode(39), Some(Keystroke::Char('.')));
|
||||||
assert_eq!(decode(63), Some(','));
|
assert_eq!(decode(40), Some(Keystroke::Char(',')));
|
||||||
assert_eq!(decode(64), Some('!'));
|
assert_eq!(decode(41), Some(Keystroke::Char('!')));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue