1use std::mem::MaybeUninit;
17
18use crate::{
19 alloc::{Allocator, Object},
20 error::{Error, Result, from_result, from_result_with_len},
21 ffi::{self, MouseEncoderOption as Opt},
22 key,
23 terminal::Terminal,
24};
25
26#[doc(inline)]
27pub use ffi::MousePosition as Position;
28
29#[derive(Debug)]
32pub struct Encoder<'alloc>(Object<'alloc, ffi::MouseEncoderImpl>);
33
34impl<'alloc> Encoder<'alloc> {
35 pub fn new() -> Result<Self> {
37 unsafe { Self::new_inner(std::ptr::null()) }
39 }
40
41 pub fn new_with_alloc<'ctx: 'alloc>(alloc: &'alloc Allocator<'ctx>) -> Result<Self> {
46 unsafe { Self::new_inner(alloc.to_raw()) }
48 }
49
50 unsafe fn new_inner(alloc: *const ffi::Allocator) -> Result<Self> {
51 let mut raw: ffi::MouseEncoder = std::ptr::null_mut();
52 let result = unsafe { ffi::ghostty_mouse_encoder_new(alloc, &raw mut raw) };
53 from_result(result)?;
54 Ok(Self(Object::new(raw)?))
55 }
56
57 unsafe fn setopt(
58 &mut self,
59 option: ffi::MouseEncoderOption::Type,
60 value: *const std::ffi::c_void,
61 ) {
62 unsafe { ffi::ghostty_mouse_encoder_setopt(self.0.as_raw(), option, value) }
63 }
64
65 pub fn encode_to_vec(&mut self, event: &Event, vec: &mut Vec<u8>) -> Result<()> {
75 let remaining = vec.capacity() - vec.len();
76
77 let written = match self.encode_to_uninit_buf(event, vec.spare_capacity_mut()) {
78 Ok(v) => Ok(v),
79 Err(Error::OutOfSpace { required }) => {
80 vec.reserve(required - remaining);
82 self.encode_to_uninit_buf(event, vec.spare_capacity_mut())
83 }
84 Err(e) => Err(e),
85 };
86
87 unsafe { vec.set_len(vec.len() + written?) };
90 Ok(())
91 }
92
93 pub fn encode(&mut self, event: &Event, buf: &mut [u8]) -> Result<usize> {
100 self.encode_to_uninit_buf(event, unsafe {
102 std::slice::from_raw_parts_mut(buf.as_mut_ptr().cast(), buf.len())
103 })
104 }
105
106 fn encode_to_uninit_buf(
107 &mut self,
108 event: &Event,
109 buf: &mut [MaybeUninit<u8>],
110 ) -> Result<usize> {
111 let mut written: usize = 0;
112 let result = unsafe {
113 ffi::ghostty_mouse_encoder_encode(
114 self.0.as_raw(),
115 event.0.as_raw(),
116 buf.as_mut_ptr().cast(),
117 buf.len(),
118 &raw mut written,
119 )
120 };
121 from_result_with_len(result, written)
122 }
123
124 pub fn set_options_from_terminal(&mut self, terminal: &Terminal<'_, '_>) -> &mut Self {
129 unsafe {
130 ffi::ghostty_mouse_encoder_setopt_from_terminal(
131 self.0.as_raw(),
132 terminal.inner.as_raw(),
133 );
134 }
135 self
136 }
137 pub fn set_tracking_mode(&mut self, value: TrackingMode) -> &mut Self {
139 unsafe {
140 self.setopt(Opt::EVENT, std::ptr::from_ref(&value).cast());
141 }
142 self
143 }
144 pub fn set_format(&mut self, value: Format) -> &mut Self {
146 unsafe {
147 self.setopt(Opt::FORMAT, std::ptr::from_ref(&value).cast());
148 }
149 self
150 }
151 pub fn set_size(&mut self, value: EncoderSize) -> &mut Self {
153 let raw: ffi::MouseEncoderSize = value.into();
154 unsafe {
155 self.setopt(Opt::SIZE, std::ptr::from_ref(&raw).cast());
156 }
157 self
158 }
159 pub fn set_any_button_pressed(&mut self, value: bool) -> &mut Self {
161 unsafe {
162 self.setopt(Opt::ANY_BUTTON_PRESSED, std::ptr::from_ref(&value).cast());
163 }
164 self
165 }
166 pub fn set_track_last_cell(&mut self, value: bool) -> &mut Self {
168 unsafe {
169 self.setopt(Opt::TRACK_LAST_CELL, std::ptr::from_ref(&value).cast());
170 }
171 self
172 }
173
174 pub fn reset(&mut self) {
178 unsafe { ffi::ghostty_mouse_encoder_reset(self.0.as_raw()) }
179 }
180}
181
182impl Drop for Encoder<'_> {
183 fn drop(&mut self) {
184 unsafe { ffi::ghostty_mouse_encoder_free(self.0.as_raw()) }
185 }
186}
187
188#[derive(Debug)]
191pub struct Event<'alloc>(Object<'alloc, ffi::MouseEventImpl>);
192
193impl<'alloc> Event<'alloc> {
194 pub fn new() -> Result<Self> {
196 unsafe { Self::new_inner(std::ptr::null()) }
198 }
199
200 pub fn new_with_alloc<'ctx: 'alloc>(alloc: &'alloc Allocator<'ctx>) -> Result<Self> {
205 unsafe { Self::new_inner(alloc.to_raw()) }
207 }
208
209 unsafe fn new_inner(alloc: *const ffi::Allocator) -> Result<Self> {
210 let mut raw: ffi::MouseEvent = std::ptr::null_mut();
211 let result = unsafe { ffi::ghostty_mouse_event_new(alloc, &raw mut raw) };
212 from_result(result)?;
213 Ok(Self(Object::new(raw)?))
214 }
215
216 pub fn set_action(&mut self, action: Action) -> &mut Self {
218 unsafe {
219 ffi::ghostty_mouse_event_set_action(self.0.as_raw(), action as ffi::MouseAction::Type);
220 }
221 self
222 }
223
224 #[must_use]
226 pub fn action(&self) -> Action {
227 unsafe { ffi::ghostty_mouse_event_get_action(self.0.as_raw()) }
228 .try_into()
229 .unwrap_or(Action::Press)
230 }
231
232 pub fn set_button(&mut self, button: Option<Button>) -> &mut Self {
234 if let Some(button) = button {
235 unsafe {
236 ffi::ghostty_mouse_event_set_button(
237 self.0.as_raw(),
238 button as ffi::MouseButton::Type,
239 );
240 }
241 } else {
242 unsafe { ffi::ghostty_mouse_event_clear_button(self.0.as_raw()) }
243 }
244 self
245 }
246
247 #[must_use]
249 pub fn button(&self) -> Option<Button> {
250 let mut button = ffi::MouseButton::UNKNOWN;
251 let has_button =
252 unsafe { ffi::ghostty_mouse_event_get_button(self.0.as_raw(), &raw mut button) };
253 if has_button {
254 Some(button.try_into().unwrap_or(Button::Unknown))
255 } else {
256 None
257 }
258 }
259
260 pub fn set_mods(&mut self, mods: key::Mods) -> &mut Self {
262 unsafe { ffi::ghostty_mouse_event_set_mods(self.0.as_raw(), mods.bits()) }
263 self
264 }
265
266 #[must_use]
268 pub fn mods(&self) -> key::Mods {
269 key::Mods::from_bits_retain(unsafe { ffi::ghostty_mouse_event_get_mods(self.0.as_raw()) })
270 }
271
272 pub fn set_position(&mut self, pos: Position) -> &mut Self {
274 unsafe { ffi::ghostty_mouse_event_set_position(self.0.as_raw(), pos) }
275 self
276 }
277
278 #[must_use]
280 pub fn position(&self) -> Position {
281 unsafe { ffi::ghostty_mouse_event_get_position(self.0.as_raw()) }
282 }
283}
284
285impl Drop for Event<'_> {
286 fn drop(&mut self) {
287 unsafe { ffi::ghostty_mouse_event_free(self.0.as_raw()) }
288 }
289}
290
291#[repr(u32)]
293#[derive(Clone, Copy, Debug, PartialEq, Eq, int_enum::IntEnum)]
294#[non_exhaustive]
295pub enum TrackingMode {
296 None = ffi::MouseTrackingMode::NONE,
298 X10 = ffi::MouseTrackingMode::X10,
300 Normal = ffi::MouseTrackingMode::NORMAL,
302 Button = ffi::MouseTrackingMode::BUTTON,
304 Any = ffi::MouseTrackingMode::ANY,
306}
307
308#[repr(u32)]
310#[derive(Clone, Copy, Debug, PartialEq, Eq, int_enum::IntEnum)]
311#[non_exhaustive]
312#[expect(missing_docs, reason = "missing upstream docs")]
313pub enum Format {
314 X10 = ffi::MouseFormat::X10,
315 Utf8 = ffi::MouseFormat::UTF8,
316 Sgr = ffi::MouseFormat::SGR,
317 Urxvt = ffi::MouseFormat::URXVT,
318 SgrPixels = ffi::MouseFormat::SGR_PIXELS,
319}
320
321#[derive(Clone, Copy, Debug, PartialEq, Eq)]
326pub struct EncoderSize {
327 pub screen_width: u32,
329 pub screen_height: u32,
331 pub cell_width: u32,
333 pub cell_height: u32,
335 pub padding_top: u32,
337 pub padding_bottom: u32,
339 pub padding_right: u32,
341 pub padding_left: u32,
343}
344
345impl From<EncoderSize> for ffi::MouseEncoderSize {
346 fn from(value: EncoderSize) -> Self {
347 Self {
348 size: std::mem::size_of::<Self>(),
349 screen_width: value.screen_width,
350 screen_height: value.screen_height,
351 cell_width: value.cell_width,
352 cell_height: value.cell_height,
353 padding_top: value.padding_top,
354 padding_bottom: value.padding_bottom,
355 padding_right: value.padding_right,
356 padding_left: value.padding_left,
357 }
358 }
359}
360
361#[repr(u32)]
363#[derive(Clone, Copy, Debug, PartialEq, Eq, int_enum::IntEnum)]
364#[non_exhaustive]
365pub enum Action {
366 Press = ffi::MouseAction::PRESS,
368 Release = ffi::MouseAction::RELEASE,
370 Motion = ffi::MouseAction::MOTION,
372}
373
374#[repr(u32)]
376#[derive(Clone, Copy, Debug, PartialEq, Eq, int_enum::IntEnum)]
377#[non_exhaustive]
378#[expect(missing_docs, reason = "self-explanatory")]
379pub enum Button {
380 Unknown = ffi::MouseButton::UNKNOWN,
381 Left = ffi::MouseButton::LEFT,
382 Right = ffi::MouseButton::RIGHT,
383 Middle = ffi::MouseButton::MIDDLE,
384 Four = ffi::MouseButton::FOUR,
385 Five = ffi::MouseButton::FIVE,
386 Six = ffi::MouseButton::SIX,
387 Seven = ffi::MouseButton::SEVEN,
388 Eight = ffi::MouseButton::EIGHT,
389 Nine = ffi::MouseButton::NINE,
390 Ten = ffi::MouseButton::TEN,
391 Eleven = ffi::MouseButton::ELEVEN,
392}