Skip to content

Commit

Permalink
Multiple changes
Browse files Browse the repository at this point in the history
- #686 Experiment with a new mouse target
- Fix error when learning and loading some special keyboard keys on macOS
- Improve target control logging to include error
  • Loading branch information
helgoboss committed Sep 20, 2022
1 parent 0c030c4 commit 8d8e358
Show file tree
Hide file tree
Showing 23 changed files with 2,080 additions and 172 deletions.
242 changes: 229 additions & 13 deletions Cargo.lock

Large diffs are not rendered by default.

126 changes: 126 additions & 0 deletions api/src/persistence/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize};
#[derive(PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind")]
pub enum Target {
Mouse(MouseTarget),
LastTouched(LastTouchedTarget),
AutomationModeOverride(AutomationModeOverrideTarget),
ReaperAction(ReaperActionTarget),
Expand Down Expand Up @@ -99,6 +100,14 @@ impl Default for TargetUnit {
}
}

#[derive(Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct MouseTarget {
#[serde(flatten)]
pub commons: TargetCommons,
pub action: MouseAction,
}

#[derive(Eq, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct LastTouchedTarget {
Expand Down Expand Up @@ -395,6 +404,123 @@ impl Default for TrackToolAction {
}
}

#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind")]
pub enum MouseAction {
/// Mouse position on the given axis.
///
/// Control:
///
/// - Move by (using relative control value)
/// - Move to (use absolute control value)
/// - Move to absolute coordinates before clicking (2 mappings for moving, 1 for clicking)
///
/// Feedback:
///
/// - Reflect position of the mouse cursor
///
/// Future extension possibilities:
///
/// - Canvas: Relative to all screens, current screen, REAPER window or focused window
/// - Pixel density: Take pixel density into account
Move { axis: Axis },
/// Like [`Self::Move`] but automatically presses a button while moving and releases it
/// when the move is finished.
///
/// Future extension possibilities:
///
/// - Timeout: Set time when to release button
Drag { axis: Axis, button: MouseButton },
/// Button state.
///
/// Control:
///
/// - Press and release a mouse button
/// - Press a mouse button and keep it pressed (press-only filter)
/// - Just release a mouse button (release-only filter, e.g. for manual drag control)
///
/// Feedback:
///
/// - Whether the button is down or up
///
/// Future extension possibilities:
///
/// - Click or double-click a mouse button (press and immediate release, this could be a generic
/// "Glue" option because it could be useful for other on/off targets as well).
Click { button: MouseButton },
/// Scroll wheel.
///
/// Control:
///
/// - Invoke scroll wheel
///
/// Feedback: None
Scroll,
}

impl Default for MouseAction {
fn default() -> Self {
Self::Move {
axis: Default::default(),
}
}
}

#[derive(
Copy,
Clone,
Eq,
PartialEq,
Debug,
Serialize,
Deserialize,
JsonSchema,
derive_more::Display,
enum_iterator::IntoEnumIterator,
num_enum::TryFromPrimitive,
num_enum::IntoPrimitive,
)]
#[repr(usize)]
pub enum Axis {
#[display(fmt = "X (horizontal)")]
X,
#[display(fmt = "Y (vertical)")]
Y,
}

impl Default for Axis {
fn default() -> Self {
Self::X
}
}

#[derive(
Copy,
Clone,
Eq,
PartialEq,
Debug,
Serialize,
Deserialize,
JsonSchema,
derive_more::Display,
enum_iterator::IntoEnumIterator,
num_enum::TryFromPrimitive,
num_enum::IntoPrimitive,
)]
#[repr(usize)]
pub enum MouseButton {
Left,
Middle,
Right,
}

impl Default for MouseButton {
fn default() -> Self {
Self::Left
}
}

#[derive(Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct TrackVisibilityTarget {
Expand Down
3 changes: 3 additions & 0 deletions main/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ realearn-dialogs = { path = "../dialogs" }
either = "1.8.0"
# For reading preset directories recursively
walkdir = "2"
# For the mouse target
mouse-rs = "0.4.2"
enigo = "0.0.14"

[target.'cfg(windows)'.dependencies]
# For detecting the Windows version (to determine whether special charactes can be displayed)
Expand Down
122 changes: 118 additions & 4 deletions main/src/application/target_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use crate::domain::{
UnresolvedFxOnlineTarget, UnresolvedFxOpenTarget, UnresolvedFxParameterTarget,
UnresolvedFxParameterTouchStateTarget, UnresolvedFxPresetTarget, UnresolvedFxToolTarget,
UnresolvedGoToBookmarkTarget, UnresolvedLastTouchedTarget, UnresolvedLoadFxSnapshotTarget,
UnresolvedLoadMappingSnapshotTarget, UnresolvedMidiSendTarget,
UnresolvedLoadMappingSnapshotTarget, UnresolvedMidiSendTarget, UnresolvedMouseTarget,
UnresolvedNavigateWithinGroupTarget, UnresolvedOscSendTarget, UnresolvedPlayrateTarget,
UnresolvedReaperTarget, UnresolvedRouteAutomationModeTarget, UnresolvedRouteMonoTarget,
UnresolvedRouteMuteTarget, UnresolvedRoutePanTarget, UnresolvedRoutePhaseTarget,
Expand All @@ -58,11 +58,11 @@ use crate::domain::ui_util::format_tags_as_csv;
use playtime_api::persistence::{ClipPlayStartTiming, ClipPlayStopTiming};
use playtime_clip_engine::main::ClipTransportOptions;
use realearn_api::persistence::{
ClipColumnAction, ClipColumnDescriptor, ClipColumnTrackContext, ClipManagementAction,
Axis, ClipColumnAction, ClipColumnDescriptor, ClipColumnTrackContext, ClipManagementAction,
ClipMatrixAction, ClipRowAction, ClipRowDescriptor, ClipSlotDescriptor, ClipTransportAction,
FxChainDescriptor, FxDescriptorCommons, FxToolAction, MappingSnapshotDescForLoad,
MappingSnapshotDescForTake, MonitoringMode, SeekBehavior, TrackDescriptorCommons, TrackFxChain,
TrackToolAction,
MappingSnapshotDescForTake, MonitoringMode, MouseAction, MouseButton, SeekBehavior,
TrackDescriptorCommons, TrackFxChain, TrackToolAction,
};
use reaper_medium::{
AutomationMode, BookmarkId, GlobalAutomationModeOverride, InputMonitoringMode, TrackArea,
Expand Down Expand Up @@ -137,6 +137,9 @@ pub enum TargetCommand {
SetOscArgTypeTag(OscTypeTag),
SetOscArgValueRange(Interval<f64>),
SetOscDevId(Option<OscDeviceId>),
SetMouseActionType(MouseActionType),
SetAxis(Axis),
SetMouseButton(MouseButton),
SetClipSlot(ClipSlotDescriptor),
SetClipColumn(ClipColumnDescriptor),
SetClipRow(ClipRowDescriptor),
Expand Down Expand Up @@ -228,6 +231,9 @@ pub enum TargetProp {
OscArgTypeTag,
OscArgValueRange,
OscDevId,
MouseActionType,
Axis,
MouseButton,
ClipSlot,
ClipColumn,
ClipRow,
Expand Down Expand Up @@ -515,6 +521,18 @@ impl<'a> Change<'a> for TargetModel {
self.osc_dev_id = v;
One(P::OscDevId)
}
C::SetMouseActionType(v) => {
self.mouse_action_type = v;
One(P::MouseActionType)
}
C::SetAxis(v) => {
self.axis = v;
One(P::Axis)
}
C::SetMouseButton(v) => {
self.mouse_button = v;
One(P::MouseButton)
}
C::SetPollForFeedback(v) => {
self.poll_for_feedback = v;
One(P::PollForFeedback)
Expand Down Expand Up @@ -702,6 +720,10 @@ pub struct TargetModel {
osc_arg_type_tag: OscTypeTag,
osc_arg_value_range: Interval<f64>,
osc_dev_id: Option<OscDeviceId>,
// # For mouse target
mouse_action_type: MouseActionType,
axis: Axis,
mouse_button: MouseButton,
// # For clip targets
clip_slot: ClipSlotDescriptor,
clip_column: ClipColumnDescriptor,
Expand Down Expand Up @@ -794,6 +816,9 @@ impl Default for TargetModel {
osc_arg_type_tag: Default::default(),
osc_arg_value_range: DEFAULT_OSC_ARG_VALUE_RANGE,
osc_dev_id: None,
mouse_action_type: Default::default(),
axis: Default::default(),
mouse_button: Default::default(),
poll_for_feedback: true,
tags: Default::default(),
mapping_snapshot_type_for_load: MappingSnapshotTypeForLoad::Initial,
Expand Down Expand Up @@ -959,6 +984,18 @@ impl TargetModel {
self.transport_action
}

pub fn mouse_action_type(&self) -> MouseActionType {
self.mouse_action_type
}

pub fn axis(&self) -> Axis {
self.axis
}

pub fn mouse_button(&self) -> MouseButton {
self.mouse_button
}

pub fn any_on_parameter(&self) -> AnyOnParameter {
self.any_on_parameter
}
Expand Down Expand Up @@ -2059,6 +2096,9 @@ impl TargetModel {
Reaper => {
use ReaperTargetType::*;
let target = match self.r#type {
Mouse => UnresolvedReaperTarget::Mouse(UnresolvedMouseTarget {
action: self.mouse_action(),
}),
Action => UnresolvedReaperTarget::Action(UnresolvedActionTarget {
action: self.resolved_action()?,
invocation_type: self.action_invocation_type,
Expand Down Expand Up @@ -2441,6 +2481,41 @@ impl TargetModel {
))
}

pub fn mouse_action(&self) -> MouseAction {
match self.mouse_action_type {
MouseActionType::Move => MouseAction::Move { axis: self.axis },
MouseActionType::Drag => MouseAction::Drag {
axis: self.axis,
button: self.mouse_button,
},
MouseActionType::Click => MouseAction::Click {
button: self.mouse_button,
},
MouseActionType::Scroll => MouseAction::Scroll,
}
}

pub fn set_mouse_action_without_notification(&mut self, mouse_action: MouseAction) {
match mouse_action {
MouseAction::Move { axis } => {
self.mouse_action_type = MouseActionType::Move;
self.axis = axis;
}
MouseAction::Drag { axis, button } => {
self.mouse_action_type = MouseActionType::Drag;
self.axis = axis;
self.mouse_button = button;
}
MouseAction::Click { button } => {
self.mouse_action_type = MouseActionType::Click;
self.mouse_button = button;
}
MouseAction::Scroll => {
self.mouse_action_type = MouseActionType::Scroll;
}
}
}

pub fn with_context<'a>(
&'a self,
context: ExtendedProcessorContext<'a>,
Expand All @@ -2453,6 +2528,20 @@ impl TargetModel {
}
}

pub fn supports_mouse_axis(&self) -> bool {
matches!(
self.mouse_action_type,
MouseActionType::Move | MouseActionType::Drag
)
}

pub fn supports_mouse_button(&self) -> bool {
matches!(
self.mouse_action_type,
MouseActionType::Drag | MouseActionType::Click
)
}

pub fn supports_track(&self) -> bool {
let target_type = self.r#type;
if !target_type.supports_track() {
Expand Down Expand Up @@ -4109,3 +4198,28 @@ fn convert_monitoring_mode_to_realearn(monitoring_mode: InputMonitoringMode) ->
InputMonitoringMode::Unknown(_) => MonitoringMode::Off,
}
}

#[derive(
Copy,
Clone,
Eq,
PartialEq,
Debug,
derive_more::Display,
enum_iterator::IntoEnumIterator,
num_enum::TryFromPrimitive,
num_enum::IntoPrimitive,
)]
#[repr(usize)]
pub enum MouseActionType {
Move,
Drag,
Click,
Scroll,
}

impl Default for MouseActionType {
fn default() -> Self {
Self::Move
}
}
4 changes: 2 additions & 2 deletions main/src/domain/key_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ impl Keystroke {
Some(NonPortable(PortabilityIssue::Other))
}
// Characters
k => match k.get() {
b'A'..=b'Z' | b'0'..=b'9' => Some(Portable),
k => match u8::try_from(k.get()) {
Ok(b'A'..=b'Z' | b'0'..=b'9') => Some(Portable),
// Other basic characters don't qualify as explicitly portable.
_ => None,
},
Expand Down
Loading

0 comments on commit 8d8e358

Please sign in to comment.