mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
Add touch pressure information for touch events on iOS (#1090)
* Add touch pressure information for touch events on iOS * Add a variant for calibrated touch pressure
This commit is contained in:
parent
8e73287646
commit
1366dc326a
|
@ -22,6 +22,7 @@
|
||||||
- On iOS, add `set_prefers_status_bar_hidden` extension function instead of
|
- On iOS, add `set_prefers_status_bar_hidden` extension function instead of
|
||||||
hijacking `set_decorations` for this purpose.
|
hijacking `set_decorations` for this purpose.
|
||||||
- On macOS and iOS, corrected the auto trait impls of `EventLoopProxy`.
|
- On macOS and iOS, corrected the auto trait impls of `EventLoopProxy`.
|
||||||
|
- On iOS, add touch pressure information for touch events.
|
||||||
|
|
||||||
# 0.20.0 Alpha 2 (2019-07-09)
|
# 0.20.0 Alpha 2 (2019-07-09)
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,7 @@ If your PR makes notable changes to Winit's features, please update this section
|
||||||
- **Cursor grab**: Locking the cursor so it cannot exit the client area of a window.
|
- **Cursor grab**: Locking the cursor so it cannot exit the client area of a window.
|
||||||
- **Cursor icon**: Changing the cursor icon, or hiding the cursor.
|
- **Cursor icon**: Changing the cursor icon, or hiding the cursor.
|
||||||
- **Touch events**: Single-touch events.
|
- **Touch events**: Single-touch events.
|
||||||
|
- **Touch pressure**: Touch events contain information about the amount of force being applied.
|
||||||
- **Multitouch**: Multi-touch events, including cancellation of a gesture.
|
- **Multitouch**: Multi-touch events, including cancellation of a gesture.
|
||||||
- **Keyboard events**: Properly processing keyboard events using the user-specified keymap and
|
- **Keyboard events**: Properly processing keyboard events using the user-specified keymap and
|
||||||
translating keypresses into UTF-8 characters, handling dead keys and IMEs.
|
translating keypresses into UTF-8 characters, handling dead keys and IMEs.
|
||||||
|
@ -192,6 +193,7 @@ Legend:
|
||||||
|Cursor grab |✔️ |▢[#165] |▢[#242] |❌[#306] |**N/A**|**N/A**|✔️ |
|
|Cursor grab |✔️ |▢[#165] |▢[#242] |❌[#306] |**N/A**|**N/A**|✔️ |
|
||||||
|Cursor icon |✔️ |✔️ |✔️ |❌[#306] |**N/A**|**N/A**|❌ |
|
|Cursor icon |✔️ |✔️ |✔️ |❌[#306] |**N/A**|**N/A**|❌ |
|
||||||
|Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |✔️ |
|
|Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |✔️ |
|
||||||
|
|Touch pressure |❌ |❌ |❌ |❌ |❌ |✔️ |❌ |
|
||||||
|Multitouch |✔️ |❌ |✔️ |✔️ |❓ |✔️ |❌ |
|
|Multitouch |✔️ |❌ |✔️ |✔️ |❓ |✔️ |❌ |
|
||||||
|Keyboard events |✔️ |✔️ |✔️ |✔️ |❓ |❌ |✔️ |
|
|Keyboard events |✔️ |✔️ |✔️ |✔️ |❓ |❌ |✔️ |
|
||||||
|Drag & Drop |▢[#720] |▢[#720] |▢[#720] |❌[#306] |**N/A**|**N/A**|❓ |
|
|Drag & Drop |▢[#720] |▢[#720] |▢[#720] |❌[#306] |**N/A**|**N/A**|❓ |
|
||||||
|
|
88
src/event.rs
88
src/event.rs
|
@ -303,30 +303,94 @@ pub enum TouchPhase {
|
||||||
Cancelled,
|
Cancelled,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents touch event
|
/// Represents a touch event
|
||||||
///
|
///
|
||||||
/// Every time user touches screen new Start event with some finger id is generated.
|
/// Every time the user touches the screen, a new `Start` event with an unique
|
||||||
/// When the finger is removed from the screen End event with same id is generated.
|
/// identifier for the finger is generated. When the finger is lifted, an `End`
|
||||||
|
/// event is generated with the same finger id.
|
||||||
///
|
///
|
||||||
/// For every id there will be at least 2 events with phases Start and End (or Cancelled).
|
/// After a `Start` event has been emitted, there may be zero or more `Move`
|
||||||
/// There may be 0 or more Move events.
|
/// events when the finger is moved or the touch pressure changes.
|
||||||
///
|
///
|
||||||
|
/// The finger id may be reused by the system after an `End` event. The user
|
||||||
|
/// should assume that a new `Start` event received with the same id has nothing
|
||||||
|
/// to do with the old finger and is a new finger.
|
||||||
///
|
///
|
||||||
/// Depending on platform implementation id may or may not be reused by system after End event.
|
/// A `Cancelled` event is emitted when the system has canceled tracking this
|
||||||
///
|
/// touch, such as when the window loses focus, or on iOS if the user moves the
|
||||||
/// Gesture regonizer using this event should assume that Start event received with same id
|
/// device against their face.
|
||||||
/// as previously received End event is a new finger and has nothing to do with an old one.
|
|
||||||
///
|
|
||||||
/// Touch may be cancelled if for example window lost focus.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct Touch {
|
pub struct Touch {
|
||||||
pub device_id: DeviceId,
|
pub device_id: DeviceId,
|
||||||
pub phase: TouchPhase,
|
pub phase: TouchPhase,
|
||||||
pub location: LogicalPosition,
|
pub location: LogicalPosition,
|
||||||
/// unique identifier of a finger.
|
/// Describes how hard the screen was pressed. May be `None` if the platform
|
||||||
|
/// does not support pressure sensitivity.
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// - Only available on **iOS**.
|
||||||
|
pub force: Option<Force>,
|
||||||
|
/// Unique identifier of a finger.
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describes the force of a touch event
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum Force {
|
||||||
|
/// On iOS, the force is calibrated so that the same number corresponds to
|
||||||
|
/// roughly the same amount of pressure on the screen regardless of the
|
||||||
|
/// device.
|
||||||
|
Calibrated {
|
||||||
|
/// The force of the touch, where a value of 1.0 represents the force of
|
||||||
|
/// an average touch (predetermined by the system, not user-specific).
|
||||||
|
///
|
||||||
|
/// The force reported by Apple Pencil is measured along the axis of the
|
||||||
|
/// pencil. If you want a force perpendicular to the device, you need to
|
||||||
|
/// calculate this value using the `altitude_angle` value.
|
||||||
|
force: f64,
|
||||||
|
/// The maximum possible force for a touch.
|
||||||
|
///
|
||||||
|
/// The value of this field is sufficiently high to provide a wide
|
||||||
|
/// dynamic range for values of the `force` field.
|
||||||
|
max_possible_force: f64,
|
||||||
|
/// The altitude (in radians) of the stylus.
|
||||||
|
///
|
||||||
|
/// A value of 0 radians indicates that the stylus is parallel to the
|
||||||
|
/// surface. The value of this property is Pi/2 when the stylus is
|
||||||
|
/// perpendicular to the surface.
|
||||||
|
altitude_angle: Option<f64>,
|
||||||
|
},
|
||||||
|
/// If the platform reports the force as normalized, we have no way of
|
||||||
|
/// knowing how much pressure 1.0 corresponds to – we know it's the maximum
|
||||||
|
/// amount of force, but as to how much force, you might either have to
|
||||||
|
/// press really really hard, or not hard at all, depending on the device.
|
||||||
|
Normalized(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Force {
|
||||||
|
/// Returns the force normalized to the range between 0.0 and 1.0 inclusive.
|
||||||
|
/// Instead of normalizing the force, you should prefer to handle
|
||||||
|
/// `Force::Calibrated` so that the amount of force the user has to apply is
|
||||||
|
/// consistent across devices.
|
||||||
|
pub fn normalized(&self) -> f64 {
|
||||||
|
match self {
|
||||||
|
Force::Calibrated {
|
||||||
|
force,
|
||||||
|
max_possible_force,
|
||||||
|
altitude_angle,
|
||||||
|
} => {
|
||||||
|
let force = match altitude_angle {
|
||||||
|
Some(altitude_angle) => force / altitude_angle.sin(),
|
||||||
|
None => *force,
|
||||||
|
};
|
||||||
|
force / max_possible_force
|
||||||
|
}
|
||||||
|
Force::Normalized(force) => *force,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Hardware-dependent keyboard scan code.
|
/// Hardware-dependent keyboard scan code.
|
||||||
pub type ScanCode = u32;
|
pub type ScanCode = u32;
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ impl EventLoop {
|
||||||
android_glue::MotionAction::Cancel => TouchPhase::Cancelled,
|
android_glue::MotionAction::Cancel => TouchPhase::Cancelled,
|
||||||
},
|
},
|
||||||
location,
|
location,
|
||||||
|
force: None, // TODO
|
||||||
id: motion.pointer_id as u64,
|
id: motion.pointer_id as u64,
|
||||||
device_id: DEVICE_ID,
|
device_id: DEVICE_ID,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -362,6 +362,7 @@ extern "C" fn touch_callback(
|
||||||
phase,
|
phase,
|
||||||
id: touch.identifier as u64,
|
id: touch.identifier as u64,
|
||||||
location,
|
location,
|
||||||
|
force: None, // TODO
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,24 @@ pub enum UITouchPhase {
|
||||||
Cancelled,
|
Cancelled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(isize)]
|
||||||
|
pub enum UIForceTouchCapability {
|
||||||
|
Unknown = 0,
|
||||||
|
Unavailable,
|
||||||
|
Available,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(isize)]
|
||||||
|
pub enum UITouchType {
|
||||||
|
Direct = 0,
|
||||||
|
Indirect,
|
||||||
|
Pencil,
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UIEdgeInsets {
|
pub struct UIEdgeInsets {
|
||||||
|
|
|
@ -6,13 +6,14 @@ use objc::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
event::{DeviceId as RootDeviceId, Event, Touch, TouchPhase, WindowEvent},
|
event::{DeviceId as RootDeviceId, Event, Force, Touch, TouchPhase, WindowEvent},
|
||||||
platform::ios::MonitorHandleExtIOS,
|
platform::ios::MonitorHandleExtIOS,
|
||||||
platform_impl::platform::{
|
platform_impl::platform::{
|
||||||
app_state::AppState,
|
app_state::AppState,
|
||||||
event_loop,
|
event_loop,
|
||||||
ffi::{
|
ffi::{
|
||||||
id, nil, CGFloat, CGPoint, CGRect, UIInterfaceOrientationMask, UIRectEdge, UITouchPhase,
|
id, nil, CGFloat, CGPoint, CGRect, UIForceTouchCapability, UIInterfaceOrientationMask,
|
||||||
|
UIRectEdge, UITouchPhase, UITouchType,
|
||||||
},
|
},
|
||||||
window::PlatformSpecificWindowBuilderAttributes,
|
window::PlatformSpecificWindowBuilderAttributes,
|
||||||
DeviceId,
|
DeviceId,
|
||||||
|
@ -218,6 +219,27 @@ unsafe fn get_window_class() -> &'static Class {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let location: CGPoint = msg_send![touch, locationInView: nil];
|
let location: CGPoint = msg_send![touch, locationInView: nil];
|
||||||
|
let touch_type: UITouchType = msg_send![touch, type];
|
||||||
|
let trait_collection: id = msg_send![object, traitCollection];
|
||||||
|
let touch_capability: UIForceTouchCapability =
|
||||||
|
msg_send![trait_collection, forceTouchCapability];
|
||||||
|
let force = if touch_capability == UIForceTouchCapability::Available {
|
||||||
|
let force: CGFloat = msg_send![touch, force];
|
||||||
|
let max_possible_force: CGFloat = msg_send![touch, maximumPossibleForce];
|
||||||
|
let altitude_angle: Option<f64> = if touch_type == UITouchType::Pencil {
|
||||||
|
let angle: CGFloat = msg_send![touch, altitudeAngle];
|
||||||
|
Some(angle as _)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Some(Force::Calibrated {
|
||||||
|
force: force as _,
|
||||||
|
max_possible_force: max_possible_force as _,
|
||||||
|
altitude_angle,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let touch_id = touch as u64;
|
let touch_id = touch as u64;
|
||||||
let phase: UITouchPhase = msg_send![touch, phase];
|
let phase: UITouchPhase = msg_send![touch, phase];
|
||||||
let phase = match phase {
|
let phase = match phase {
|
||||||
|
@ -235,6 +257,7 @@ unsafe fn get_window_class() -> &'static Class {
|
||||||
device_id: RootDeviceId(DeviceId { uiscreen }),
|
device_id: RootDeviceId(DeviceId { uiscreen }),
|
||||||
id: touch_id,
|
id: touch_id,
|
||||||
location: (location.x as f64, location.y as f64).into(),
|
location: (location.x as f64, location.y as f64).into(),
|
||||||
|
force,
|
||||||
phase,
|
phase,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,6 +39,7 @@ pub(crate) fn implement_touch<T: 'static>(
|
||||||
),
|
),
|
||||||
phase: TouchPhase::Started,
|
phase: TouchPhase::Started,
|
||||||
location: (x, y).into(),
|
location: (x, y).into(),
|
||||||
|
force: None, // TODO
|
||||||
id: id as u64,
|
id: id as u64,
|
||||||
}),
|
}),
|
||||||
wid,
|
wid,
|
||||||
|
@ -61,6 +62,7 @@ pub(crate) fn implement_touch<T: 'static>(
|
||||||
),
|
),
|
||||||
phase: TouchPhase::Ended,
|
phase: TouchPhase::Ended,
|
||||||
location: pt.location.into(),
|
location: pt.location.into(),
|
||||||
|
force: None, // TODO
|
||||||
id: id as u64,
|
id: id as u64,
|
||||||
}),
|
}),
|
||||||
pt.wid,
|
pt.wid,
|
||||||
|
@ -78,6 +80,7 @@ pub(crate) fn implement_touch<T: 'static>(
|
||||||
),
|
),
|
||||||
phase: TouchPhase::Moved,
|
phase: TouchPhase::Moved,
|
||||||
location: (x, y).into(),
|
location: (x, y).into(),
|
||||||
|
force: None, // TODO
|
||||||
id: id as u64,
|
id: id as u64,
|
||||||
}),
|
}),
|
||||||
pt.wid,
|
pt.wid,
|
||||||
|
@ -94,6 +97,7 @@ pub(crate) fn implement_touch<T: 'static>(
|
||||||
),
|
),
|
||||||
phase: TouchPhase::Cancelled,
|
phase: TouchPhase::Cancelled,
|
||||||
location: pt.location.into(),
|
location: pt.location.into(),
|
||||||
|
force: None, // TODO
|
||||||
id: pt.id as u64,
|
id: pt.id as u64,
|
||||||
}),
|
}),
|
||||||
pt.wid,
|
pt.wid,
|
||||||
|
|
|
@ -918,6 +918,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
device_id: mkdid(xev.deviceid),
|
device_id: mkdid(xev.deviceid),
|
||||||
phase,
|
phase,
|
||||||
location,
|
location,
|
||||||
|
force: None, // TODO
|
||||||
id: xev.detail as u64,
|
id: xev.detail as u64,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
|
@ -1499,6 +1499,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
location,
|
location,
|
||||||
|
force: None, // TODO
|
||||||
id: input.dwID as u64,
|
id: input.dwID as u64,
|
||||||
device_id: DEVICE_ID,
|
device_id: DEVICE_ID,
|
||||||
}),
|
}),
|
||||||
|
@ -1603,6 +1604,7 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
location,
|
location,
|
||||||
|
force: None, // TODO
|
||||||
id: pointer_info.pointerId as u64,
|
id: pointer_info.pointerId as u64,
|
||||||
device_id: DEVICE_ID,
|
device_id: DEVICE_ID,
|
||||||
}),
|
}),
|
||||||
|
|
Loading…
Reference in a new issue