this repo has no description
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

tty(windows): parse mouse events

+91 -1
+91 -1
src/windows/Tty.zig
··· 5 5 const std = @import("std"); 6 6 const Event = @import("../event.zig").Event; 7 7 const Key = @import("../Key.zig"); 8 + const Mouse = @import("../Mouse.zig"); 8 9 const windows = std.os.windows; 9 10 10 11 stdin: windows.HANDLE, ··· 16 17 17 18 // a buffer to write key text into 18 19 buf: [4]u8 = undefined, 20 + 21 + /// The last mouse button that was pressed. We store the previous state of button presses on each 22 + /// mouse event so we can detect which button was released 23 + last_mouse_button_press: u16 = 0, 19 24 20 25 pub var global_tty: ?Tty = null; 21 26 ··· 278 283 else => return .{ .key_press = key }, 279 284 } 280 285 }, 281 - 0x0002 => { // TODO: Parse mouse events 286 + 0x0002 => { // Mouse event 282 287 // see https://learn.microsoft.com/en-us/windows/console/mouse-event-record-str 288 + 289 + const event = input_record.Event.MouseEvent; 290 + 291 + // High word of dwButtonState represents mouse wheel. Positive is wheel_up, negative 292 + // is wheel_down 293 + // Low word represents button state 294 + const mouse_wheel_direction: i32 = blk: { 295 + const wheelu64: u64 = event.dwButtonState >> 16; 296 + const wheelu32: u32 = @truncate(wheelu64); 297 + break :blk @bitCast(wheelu32); 298 + }; 299 + 300 + const buttons: u16 = @truncate(event.dwButtonState); 301 + // save the current state when we are done 302 + defer self.last_mouse_button_press = buttons; 303 + const button_xor = self.last_mouse_button_press ^ buttons; 304 + 305 + var event_type: Mouse.Type = .press; 306 + const btn: Mouse.Button = switch (button_xor) { 307 + 0x0000 => blk: { 308 + // Check wheel event 309 + if (event.dwEventFlags & 0x0004 > 0) { 310 + if (mouse_wheel_direction > 0) 311 + break :blk .wheel_up 312 + else 313 + break :blk .wheel_down; 314 + } 315 + 316 + // If we have no change but one of the buttons is still pressed we have a 317 + // drag event. Find out which button is held down 318 + if (buttons > 0 and event.dwEventFlags & 0x0001 > 0) { 319 + event_type = .drag; 320 + if (buttons & 0x0001 > 0) break :blk .left; 321 + if (buttons & 0x0002 > 0) break :blk .right; 322 + if (buttons & 0x0004 > 0) break :blk .middle; 323 + if (buttons & 0x0008 > 0) break :blk .button_8; 324 + if (buttons & 0x0010 > 0) break :blk .button_9; 325 + } 326 + 327 + if (event.dwEventFlags & 0x0001 > 0) event_type = .motion; 328 + break :blk .none; 329 + }, 330 + 0x0001 => blk: { 331 + if (buttons & 0x0001 == 0) event_type = .release; 332 + break :blk .left; 333 + }, 334 + 0x0002 => blk: { 335 + if (buttons & 0x0002 == 0) event_type = .release; 336 + break :blk .right; 337 + }, 338 + 0x0004 => blk: { 339 + if (buttons & 0x0004 == 0) event_type = .release; 340 + break :blk .middle; 341 + }, 342 + 0x0008 => blk: { 343 + if (buttons & 0x0008 == 0) event_type = .release; 344 + break :blk .button_8; 345 + }, 346 + 0x0010 => blk: { 347 + if (buttons & 0x0010 == 0) event_type = .release; 348 + break :blk .button_9; 349 + }, 350 + else => { 351 + std.log.warn("unknown mouse event: {}", .{event}); 352 + continue; 353 + }, 354 + }; 355 + 356 + const shift: u32 = 0x0010; 357 + const alt: u32 = 0x0001 | 0x0002; 358 + const ctrl: u32 = 0x0004 | 0x0008; 359 + const mods: Mouse.Modifiers = .{ 360 + .shift = event.dwControlKeyState & shift > 0, 361 + .alt = event.dwControlKeyState & alt > 0, 362 + .ctrl = event.dwControlKeyState & ctrl > 0, 363 + }; 364 + 365 + const mouse: Mouse = .{ 366 + .col = @as(u16, @bitCast(event.dwMousePosition.X)), // Windows reports with 0 index 367 + .row = @as(u16, @bitCast(event.dwMousePosition.Y)), // Windows reports with 0 index 368 + .mods = mods, 369 + .type = event_type, 370 + .button = btn, 371 + }; 372 + return .{ .mouse = mouse }; 283 373 }, 284 374 0x0004 => { // Screen resize events 285 375 // NOTE: Even though the event comes with a size, it may not be accurate. We ask for