     1→//! Session management for the agent
     2→//!
     3→//! Handles the lifecycle of a remote session including:
     4→//! - Connection to server
     5→//! - Authentication
     6→//! - Frame capture and encoding loop
     7→//! - Input event handling
     8→
     9→use crate::capture::{self, Capturer, Display};
    10→use crate::config::Config;
    11→use crate::encoder::{self, Encoder};
    12→use crate::input::InputController;
    13→use crate::proto::{Message, message};
    14→use crate::transport::WebSocketTransport;
    15→use anyhow::Result;
    16→use std::sync::Arc;
    17→use std::time::{Duration, Instant};
    18→use tokio::sync::mpsc;
    19→
    20→/// Session manager handles the remote control session
    21→pub struct SessionManager {
    22→    config: Config,
    23→    transport: Option<WebSocketTransport>,
    24→    state: SessionState,
    25→}
    26→
    27→#[derive(Debug, Clone, PartialEq)]
    28→enum SessionState {
    29→    Disconnected,
    30→    Connecting,
    31→    Connected,
    32→    Active,
    33→}
    34→
    35→impl SessionManager {
    36→    /// Create a new session manager
    37→    pub fn new(config: Config) -> Self {
    38→        Self {
    39→            config,
    40→            transport: None,
    41→            state: SessionState::Disconnected,
    42→        }
    43→    }
    44→
    45→    /// Connect to the server
    46→    pub async fn connect(&mut self) -> Result<()> {
    47→        self.state = SessionState::Connecting;
    48→
    49→        let transport = WebSocketTransport::connect(
    50→            &self.config.server_url,
    51→            &self.config.api_key,
    52→        ).await?;
    53→
    54→        self.transport = Some(transport);
    55→        self.state = SessionState::Connected;
    56→
    57→        Ok(())
    58→    }
    59→
    60→    /// Run the session main loop
    61→    pub async fn run(&mut self) -> Result<()> {
    62→        let transport = self.transport.as_mut()
    63→            .ok_or_else(|| anyhow::anyhow!("Not connected"))?;
    64→
    65→        self.state = SessionState::Active;
    66→
    67→        // Get primary display
    68→        let display = capture::primary_display()?;
    69→        tracing::info!("Using display: {} ({}x{})", display.name, display.width, display.height);
    70→
    71→        // Create capturer
    72→        let mut capturer = capture::create_capturer(
    73→            display.clone(),
    74→            self.config.capture.use_dxgi,
    75→            self.config.capture.gdi_fallback,
    76→        )?;
    77→
    78→        // Create encoder
    79→        let mut encoder = encoder::create_encoder(
    80→            &self.config.encoding.codec,
    81→            self.config.encoding.quality,
    82→        )?;
    83→
    84→        // Create input controller
    85→        let mut input = InputController::new()?;
    86→
    87→        // Calculate frame interval
    88→        let frame_interval = Duration::from_millis(1000 / self.config.capture.fps as u64);
    89→        let mut last_frame_time = Instant::now();
    90→
    91→        // Main loop
    92→        loop {
    93→            // Check for incoming messages (non-blocking)
    94→            while let Some(msg) = transport.try_recv()? {
    95→                self.handle_message(&mut input, msg)?;
    96→            }
    97→
    98→            // Capture and send frame if interval elapsed
    99→            if last_frame_time.elapsed() >= frame_interval {
   100→                last_frame_time = Instant::now();
   101→
   102→                if let Some(frame) = capturer.capture()? {
   103→                    let encoded = encoder.encode(&frame)?;
   104→
   105→                    // Skip empty frames (no changes)
   106→                    if encoded.size > 0 {
   107→                        let msg = Message {
   108→                            payload: Some(message::Payload::VideoFrame(encoded.frame)),
   109→                        };
   110→                        transport.send(msg).await?;
   111→                    }
   112→                }
   113→            }
   114→
   115→            // Small sleep to prevent busy loop
   116→            tokio::time::sleep(Duration::from_millis(1)).await;
   117→
   118→            // Check if still connected
   119→            if !transport.is_connected() {
   120→                tracing::warn!("Connection lost");
   121→                break;
   122→            }
   123→        }
   124→
   125→        self.state = SessionState::Disconnected;
   126→        Ok(())
   127→    }
   128→
   129→    /// Handle incoming message from server
   130→    fn handle_message(&mut self, input: &mut InputController, msg: Message) -> Result<()> {
   131→        match msg.payload {
   132→            Some(message::Payload::MouseEvent(mouse)) => {
   133→                // Handle mouse event
   134→                use crate::proto::MouseEventType;
   135→                use crate::input::MouseButton;
   136→
   137→                match MouseEventType::try_from(mouse.event_type).unwrap_or(MouseEventType::MouseMove) {
   138→                    MouseEventType::MouseMove => {
   139→                        input.mouse_move(mouse.x, mouse.y)?;
   140→                    }
   141→                    MouseEventType::MouseDown => {
   142→                        input.mouse_move(mouse.x, mouse.y)?;
   143→                        if let Some(ref buttons) = mouse.buttons {
   144→                            if buttons.left { input.mouse_click(MouseButton::Left, true)?; }
   145→                            if buttons.right { input.mouse_click(MouseButton::Right, true)?; }
   146→                            if buttons.middle { input.mouse_click(MouseButton::Middle, true)?; }
   147→                        }
   148→                    }
   149→                    MouseEventType::MouseUp => {
   150→                        if let Some(ref buttons) = mouse.buttons {
   151→                            if buttons.left { input.mouse_click(MouseButton::Left, false)?; }
   152→                            if buttons.right { input.mouse_click(MouseButton::Right, false)?; }
   153→                            if buttons.middle { input.mouse_click(MouseButton::Middle, false)?; }
   154→                        }
   155→                    }
   156→                    MouseEventType::MouseWheel => {
   157→                        input.mouse_scroll(mouse.wheel_delta_x, mouse.wheel_delta_y)?;
   158→                    }
   159→                }
   160→            }
   161→
   162→            Some(message::Payload::KeyEvent(key)) => {
   163→                // Handle keyboard event
   164→                input.key_event(key.vk_code as u16, key.down)?;
   165→            }
   166→
   167→            Some(message::Payload::SpecialKey(special)) => {
   168→                use crate::proto::SpecialKey;
   169→                match SpecialKey::try_from(special.key).ok() {
   170→                    Some(SpecialKey::CtrlAltDel) => {
   171→                        input.send_ctrl_alt_del()?;
   172→                    }
   173→                    _ => {}
   174→                }
   175→            }
   176→
   177→            Some(message::Payload::Heartbeat(_)) => {
   178→                // Respond to heartbeat
   179→                // TODO: Send heartbeat ack
   180→            }
   181→
   182→            Some(message::Payload::Disconnect(disc)) => {
   183→                tracing::info!("Disconnect requested: {}", disc.reason);
   184→                return Err(anyhow::anyhow!("Disconnect: {}", disc.reason));
   185→            }
   186→
   187→            _ => {
   188→                // Ignore unknown messages
   189→            }
   190→        }
   191→
   192→        Ok(())
   193→    }
   194→}
   195→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

//! Session management for the agent
//!
//! Handles the lifecycle of a remote session including:
//! - Connection to server
//! - Authentication
//! - Frame capture and encoding loop
//! - Input event handling

use crate::capture::{self, Capturer, Display};
use crate::config::Config;
use crate::encoder::{self, Encoder};
use crate::input::InputController;
use crate::proto::{Message, message};
use crate::transport::WebSocketTransport;
use anyhow::Result;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::mpsc;

/// Session manager handles the remote control session
pub struct SessionManager {
    config: Config,
    transport: Option<WebSocketTransport>,
    state: SessionState,
}

#[derive(Debug, Clone, PartialEq)]
enum SessionState {
    Disconnected,
    Connecting,
    Connected,
    Active,
}

impl SessionManager {
    /// Create a new session manager
    pub fn new(config: Config) -> Self {
        Self {
            config,
            transport: None,
            state: SessionState::Disconnected,
        }
    }

    /// Connect to the server
    pub async fn connect(&mut self) -> Result<()> {
        self.state = SessionState::Connecting;

        let transport = WebSocketTransport::connect(
            &self.config.server_url,
            &self.config.api_key,
        ).await?;

        self.transport = Some(transport);
        self.state = SessionState::Connected;

        Ok(())
    }

    /// Run the session main loop
    pub async fn run(&mut self) -> Result<()> {
        let transport = self.transport.as_mut()
            .ok_or_else(|| anyhow::anyhow!("Not connected"))?;

        self.state = SessionState::Active;

        // Get primary display
        let display = capture::primary_display()?;
        tracing::info!("Using display: {} ({}x{})", display.name, display.width, display.height);

        // Create capturer
        let mut capturer = capture::create_capturer(
            display.clone(),
            self.config.capture.use_dxgi,
            self.config.capture.gdi_fallback,
        )?;

        // Create encoder
        let mut encoder = encoder::create_encoder(
            &self.config.encoding.codec,
            self.config.encoding.quality,
        )?;

        // Create input controller
        let mut input = InputController::new()?;

        // Calculate frame interval
        let frame_interval = Duration::from_millis(1000 / self.config.capture.fps as u64);
        let mut last_frame_time = Instant::now();

        // Main loop
        loop {
            // Check for incoming messages (non-blocking)
            while let Some(msg) = transport.try_recv()? {
                self.handle_message(&mut input, msg)?;
            }

            // Capture and send frame if interval elapsed
            if last_frame_time.elapsed() >= frame_interval {
                last_frame_time = Instant::now();

                if let Some(frame) = capturer.capture()? {
                    let encoded = encoder.encode(&frame)?;

                    // Skip empty frames (no changes)
                    if encoded.size > 0 {
                        let msg = Message {
                            payload: Some(message::Payload::VideoFrame(encoded.frame)),
                        };
                        transport.send(msg).await?;
                    }
                }
            }

            // Small sleep to prevent busy loop
            tokio::time::sleep(Duration::from_millis(1)).await;

            // Check if still connected
            if !transport.is_connected() {
                tracing::warn!("Connection lost");
                break;
            }
        }

        self.state = SessionState::Disconnected;
        Ok(())
    }

    /// Handle incoming message from server
    fn handle_message(&mut self, input: &mut InputController, msg: Message) -> Result<()> {
        match msg.payload {
            Some(message::Payload::MouseEvent(mouse)) => {
                // Handle mouse event
                use crate::proto::MouseEventType;
                use crate::input::MouseButton;

                match MouseEventType::try_from(mouse.event_type).unwrap_or(MouseEventType::MouseMove) {
                    MouseEventType::MouseMove => {
                        input.mouse_move(mouse.x, mouse.y)?;
                    }
                    MouseEventType::MouseDown => {
                        input.mouse_move(mouse.x, mouse.y)?;
                        if let Some(ref buttons) = mouse.buttons {
                            if buttons.left { input.mouse_click(MouseButton::Left, true)?; }
                            if buttons.right { input.mouse_click(MouseButton::Right, true)?; }
                            if buttons.middle { input.mouse_click(MouseButton::Middle, true)?; }
                        }
                    }
                    MouseEventType::MouseUp => {
                        if let Some(ref buttons) = mouse.buttons {
                            if buttons.left { input.mouse_click(MouseButton::Left, false)?; }
                            if buttons.right { input.mouse_click(MouseButton::Right, false)?; }
                            if buttons.middle { input.mouse_click(MouseButton::Middle, false)?; }
                        }
                    }
                    MouseEventType::MouseWheel => {
                        input.mouse_scroll(mouse.wheel_delta_x, mouse.wheel_delta_y)?;
                    }
                }
            }

            Some(message::Payload::KeyEvent(key)) => {
                // Handle keyboard event
                input.key_event(key.vk_code as u16, key.down)?;
            }

            Some(message::Payload::SpecialKey(special)) => {
                use crate::proto::SpecialKey;
                match SpecialKey::try_from(special.key).ok() {
                    Some(SpecialKey::CtrlAltDel) => {
                        input.send_ctrl_alt_del()?;
                    }
                    _ => {}
                }
            }

            Some(message::Payload::Heartbeat(_)) => {
                // Respond to heartbeat
                // TODO: Send heartbeat ack
            }

            Some(message::Payload::Disconnect(disc)) => {
                tracing::info!("Disconnect requested: {}", disc.reason);
                return Err(anyhow::anyhow!("Disconnect: {}", disc.reason));
            }

            _ => {
                // Ignore unknown messages
            }
        }

        Ok(())
    }
}


     1→//! WebSocket client transport
     2→//!
     3→//! Handles WebSocket connection to the GuruConnect server with:
     4→//! - TLS encryption
     5→//! - Automatic reconnection
     6→//! - Protobuf message serialization
     7→
     8→use crate::proto::Message;
     9→use anyhow::{Context, Result};
    10→use bytes::Bytes;
    11→use futures_util::{SinkExt, StreamExt};
    12→use prost::Message as ProstMessage;
    13→use std::collections::VecDeque;
    14→use std::sync::Arc;
    15→use tokio::net::TcpStream;
    16→use tokio::sync::Mutex;
    17→use tokio_tungstenite::{
    18→    connect_async, tungstenite::protocol::Message as WsMessage, MaybeTlsStream, WebSocketStream,
    19→};
    20→
    21→type WsStream = WebSocketStream<MaybeTlsStream<TcpStream>>;
    22→
    23→/// WebSocket transport for server communication
    24→pub struct WebSocketTransport {
    25→    stream: Arc<Mutex<WsStream>>,
    26→    incoming: VecDeque<Message>,
    27→    connected: bool,
    28→}
    29→
    30→impl WebSocketTransport {
    31→    /// Connect to the server
    32→    pub async fn connect(url: &str, api_key: &str) -> Result<Self> {
    33→        // Append API key as query parameter
    34→        let url_with_auth = if url.contains('?') {
    35→            format!("{}&api_key={}", url, api_key)
    36→        } else {
    37→            format!("{}?api_key={}", url, api_key)
    38→        };
    39→
    40→        tracing::info!("Connecting to {}", url);
    41→
    42→        let (ws_stream, response) = connect_async(&url_with_auth)
    43→            .await
    44→            .context("Failed to connect to WebSocket server")?;
    45→
    46→        tracing::info!("Connected, status: {}", response.status());
    47→
    48→        Ok(Self {
    49→            stream: Arc::new(Mutex::new(ws_stream)),
    50→            incoming: VecDeque::new(),
    51→            connected: true,
    52→        })
    53→    }
    54→
    55→    /// Send a protobuf message
    56→    pub async fn send(&mut self, msg: Message) -> Result<()> {
    57→        let mut stream = self.stream.lock().await;
    58→
    59→        // Serialize to protobuf binary
    60→        let mut buf = Vec::with_capacity(msg.encoded_len());
    61→        msg.encode(&mut buf)?;
    62→
    63→        // Send as binary WebSocket message
    64→        stream
    65→            .send(WsMessage::Binary(buf.into()))
    66→            .await
    67→            .context("Failed to send message")?;
    68→
    69→        Ok(())
    70→    }
    71→
    72→    /// Try to receive a message (non-blocking)
    73→    pub fn try_recv(&mut self) -> Result<Option<Message>> {
    74→        // Return buffered message if available
    75→        if let Some(msg) = self.incoming.pop_front() {
    76→            return Ok(Some(msg));
    77→        }
    78→
    79→        // Try to receive more messages
    80→        let stream = self.stream.clone();
    81→        let result = tokio::task::block_in_place(|| {
    82→            tokio::runtime::Handle::current().block_on(async {
    83→                let mut stream = stream.lock().await;
    84→
    85→                // Use try_next for non-blocking receive
    86→                match tokio::time::timeout(
    87→                    std::time::Duration::from_millis(1),
    88→                    stream.next(),
    89→                )
    90→                .await
    91→                {
    92→                    Ok(Some(Ok(ws_msg))) => Ok(Some(ws_msg)),
    93→                    Ok(Some(Err(e))) => Err(anyhow::anyhow!("WebSocket error: {}", e)),
    94→                    Ok(None) => {
    95→                        // Connection closed
    96→                        Ok(None)
    97→                    }
    98→                    Err(_) => {
    99→                        // Timeout - no message available
   100→                        Ok(None)
   101→                    }
   102→                }
   103→            })
   104→        });
   105→
   106→        match result? {
   107→            Some(ws_msg) => {
   108→                if let Some(msg) = self.parse_message(ws_msg)? {
   109→                    Ok(Some(msg))
   110→                } else {
   111→                    Ok(None)
   112→                }
   113→            }
   114→            None => Ok(None),
   115→        }
   116→    }
   117→
   118→    /// Receive a message (blocking)
   119→    pub async fn recv(&mut self) -> Result<Option<Message>> {
   120→        // Return buffered message if available
   121→        if let Some(msg) = self.incoming.pop_front() {
   122→            return Ok(Some(msg));
   123→        }
   124→
   125→        let mut stream = self.stream.lock().await;
   126→
   127→        match stream.next().await {
   128→            Some(Ok(ws_msg)) => self.parse_message(ws_msg),
   129→            Some(Err(e)) => {
   130→                self.connected = false;
   131→                Err(anyhow::anyhow!("WebSocket error: {}", e))
   132→            }
   133→            None => {
   134→                self.connected = false;
   135→                Ok(None)
   136→            }
   137→        }
   138→    }
   139→
   140→    /// Parse a WebSocket message into a protobuf message
   141→    fn parse_message(&mut self, ws_msg: WsMessage) -> Result<Option<Message>> {
   142→        match ws_msg {
   143→            WsMessage::Binary(data) => {
   144→                let msg = Message::decode(Bytes::from(data))
   145→                    .context("Failed to decode protobuf message")?;
   146→                Ok(Some(msg))
   147→            }
   148→            WsMessage::Ping(data) => {
   149→                // Pong is sent automatically by tungstenite
   150→                tracing::trace!("Received ping");
   151→                Ok(None)
   152→            }
   153→            WsMessage::Pong(_) => {
   154→                tracing::trace!("Received pong");
   155→                Ok(None)
   156→            }
   157→            WsMessage::Close(frame) => {
   158→                tracing::info!("Connection closed: {:?}", frame);
   159→                self.connected = false;
   160→                Ok(None)
   161→            }
   162→            WsMessage::Text(text) => {
   163→                // We expect binary protobuf, but log text messages
   164→                tracing::warn!("Received unexpected text message: {}", text);
   165→                Ok(None)
   166→            }
   167→            _ => Ok(None),
   168→        }
   169→    }
   170→
   171→    /// Check if connected
   172→    pub fn is_connected(&self) -> bool {
   173→        self.connected
   174→    }
   175→
   176→    /// Close the connection
   177→    pub async fn close(&mut self) -> Result<()> {
   178→        let mut stream = self.stream.lock().await;
   179→        stream.close(None).await?;
   180→        self.connected = false;
   181→        Ok(())
   182→    }
   183→}
   184→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

//! WebSocket client transport
//!
//! Handles WebSocket connection to the GuruConnect server with:
//! - TLS encryption
//! - Automatic reconnection
//! - Protobuf message serialization

use crate::proto::Message;
use anyhow::{Context, Result};
use bytes::Bytes;
use futures_util::{SinkExt, StreamExt};
use prost::Message as ProstMessage;
use std::collections::VecDeque;
use std::sync::Arc;
use tokio::net::TcpStream;
use tokio::sync::Mutex;
use tokio_tungstenite::{
    connect_async, tungstenite::protocol::Message as WsMessage, MaybeTlsStream, WebSocketStream,
};

type WsStream = WebSocketStream<MaybeTlsStream<TcpStream>>;

/// WebSocket transport for server communication
pub struct WebSocketTransport {
    stream: Arc<Mutex<WsStream>>,
    incoming: VecDeque<Message>,
    connected: bool,
}

impl WebSocketTransport {
    /// Connect to the server
    pub async fn connect(url: &str, api_key: &str) -> Result<Self> {
        // Append API key as query parameter
        let url_with_auth = if url.contains('?') {
            format!("{}&api_key={}", url, api_key)
        } else {
            format!("{}?api_key={}", url, api_key)
        };

        tracing::info!("Connecting to {}", url);

        let (ws_stream, response) = connect_async(&url_with_auth)
            .await
            .context("Failed to connect to WebSocket server")?;

        tracing::info!("Connected, status: {}", response.status());

        Ok(Self {
            stream: Arc::new(Mutex::new(ws_stream)),
            incoming: VecDeque::new(),
            connected: true,
        })
    }

    /// Send a protobuf message
    pub async fn send(&mut self, msg: Message) -> Result<()> {
        let mut stream = self.stream.lock().await;

        // Serialize to protobuf binary
        let mut buf = Vec::with_capacity(msg.encoded_len());
        msg.encode(&mut buf)?;

        // Send as binary WebSocket message
        stream
            .send(WsMessage::Binary(buf.into()))
            .await
            .context("Failed to send message")?;

        Ok(())
    }

    /// Try to receive a message (non-blocking)
    pub fn try_recv(&mut self) -> Result<Option<Message>> {
        // Return buffered message if available
        if let Some(msg) = self.incoming.pop_front() {
            return Ok(Some(msg));
        }

        // Try to receive more messages
        let stream = self.stream.clone();
        let result = tokio::task::block_in_place(|| {
            tokio::runtime::Handle::current().block_on(async {
                let mut stream = stream.lock().await;

                // Use try_next for non-blocking receive
                match tokio::time::timeout(
                    std::time::Duration::from_millis(1),
                    stream.next(),
                )
                .await
                {
                    Ok(Some(Ok(ws_msg))) => Ok(Some(ws_msg)),
                    Ok(Some(Err(e))) => Err(anyhow::anyhow!("WebSocket error: {}", e)),
                    Ok(None) => {
                        // Connection closed
                        Ok(None)
                    }
                    Err(_) => {
                        // Timeout - no message available
                        Ok(None)
                    }
                }
            })
        });

        match result? {
            Some(ws_msg) => {
                if let Some(msg) = self.parse_message(ws_msg)? {
                    Ok(Some(msg))
                } else {
                    Ok(None)
                }
            }
            None => Ok(None),
        }
    }

    /// Receive a message (blocking)
    pub async fn recv(&mut self) -> Result<Option<Message>> {
        // Return buffered message if available
        if let Some(msg) = self.incoming.pop_front() {
            return Ok(Some(msg));
        }

        let mut stream = self.stream.lock().await;

        match stream.next().await {
            Some(Ok(ws_msg)) => self.parse_message(ws_msg),
            Some(Err(e)) => {
                self.connected = false;
                Err(anyhow::anyhow!("WebSocket error: {}", e))
            }
            None => {
                self.connected = false;
                Ok(None)
            }
        }
    }

    /// Parse a WebSocket message into a protobuf message
    fn parse_message(&mut self, ws_msg: WsMessage) -> Result<Option<Message>> {
        match ws_msg {
            WsMessage::Binary(data) => {
                let msg = Message::decode(Bytes::from(data))
                    .context("Failed to decode protobuf message")?;
                Ok(Some(msg))
            }
            WsMessage::Ping(data) => {
                // Pong is sent automatically by tungstenite
                tracing::trace!("Received ping");
                Ok(None)
            }
            WsMessage::Pong(_) => {
                tracing::trace!("Received pong");
                Ok(None)
            }
            WsMessage::Close(frame) => {
                tracing::info!("Connection closed: {:?}", frame);
                self.connected = false;
                Ok(None)
            }
            WsMessage::Text(text) => {
                // We expect binary protobuf, but log text messages
                tracing::warn!("Received unexpected text message: {}", text);
                Ok(None)
            }
            _ => Ok(None),
        }
    }

    /// Check if connected
    pub fn is_connected(&self) -> bool {
        self.connected
    }

    /// Close the connection
    pub async fn close(&mut self) -> Result<()> {
        let mut stream = self.stream.lock().await;
        stream.close(None).await?;
        self.connected = false;
        Ok(())
    }
}


Now I understand the errors better. Let me fix them:

1. **mouse.rs** - `XBUTTON1` and `XBUTTON2` are no longer in KeyboardAndMouse. In newer Windows crate versions, these are constants in a different module. I'll need to define them locally since they're just constants (0x0001 and 0x0002).

2. **session/mod.rs** - Line 69: `display.name` conflict with tracing's display() function. Need to rename the variable.

3. **dxgi.rs** -
   - Line 98: `GetDesc()` now returns the value directly instead of taking a mutable reference
   - Line 104: Same `display` naming conflict
   - Line 137: Same `GetDesc()` issue
   - Line 172: `D3D11_CPU_ACCESS_READ` type mismatch - need to use `.0` to get the raw value
   - Line 182: `SetEvictionPriority` expects the enum directly, not `.0`

4. **keyboard.rs** - Lines 93, 107: `code_unit` is now `&mut u16` from the iterator, need to dereference

5. **websocket.rs** - Line 128: borrow conflict - need to drop the guard before calling self method

Let me fix all of these.


Now I understand all the issues. Let me fix them one by one:


Edit

#[cfg(windows)]
use windows::Win32::UI::Input::KeyboardAndMouse::{
    SendInput, INPUT, INPUT_0, INPUT_MOUSE, MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL,
    MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP,
    MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK,
    MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT, XBUTTON1, XBUTTON2,
};

#[cfg(windows)]
use windows::Win32::UI::Input::KeyboardAndMouse::{
    SendInput, INPUT, INPUT_0, INPUT_MOUSE, MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL,
    MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP,
    MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK,
    MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT,
};

// XButton constants (not exported in newer windows crate versions)
#[cfg(windows)]
const XBUTTON1: u32 = 0x0001;
#[cfg(windows)]
const XBUTTON2: u32 = 0x0002;


            MouseButton::X1 => (MOUSEEVENTF_XDOWN, XBUTTON1 as u32),
            MouseButton::X2 => (MOUSEEVENTF_XDOWN, XBUTTON2 as u32),

            MouseButton::X1 => (MOUSEEVENTF_XDOWN, XBUTTON1),
            MouseButton::X2 => (MOUSEEVENTF_XDOWN, XBUTTON2),


            MouseButton::X1 => (MOUSEEVENTF_XUP, XBUTTON1 as u32),
            MouseButton::X2 => (MOUSEEVENTF_XUP, XBUTTON2 as u32),

            MouseButton::X1 => (MOUSEEVENTF_XUP, XBUTTON1),
            MouseButton::X2 => (MOUSEEVENTF_XUP, XBUTTON2),


The file C:\Users\MikeSwanson\claude-projects\guru-connect\agent\src\input\mouse.rs has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
     2→
     3→use super::MouseButton;
     4→use anyhow::Result;
     5→
     6→#[cfg(windows)]
     7→use windows::Win32::UI::Input::KeyboardAndMouse::{
     8→    SendInput, INPUT, INPUT_0, INPUT_MOUSE, MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL,
     9→    MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP,
    10→    MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK,
    11→    MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT,
    12→};
    13→
    14→// XButton constants (not exported in newer windows crate versions)
    15→#[cfg(windows)]
    16→const XBUTTON1: u32 = 0x0001;
    17→#[cfg(windows)]
    18→const XBUTTON2: u32 = 0x0002;
    19→
    20→#[cfg(windows)]
    21→use windows::Win32::UI::WindowsAndMessaging::{
    22→    GetSystemMetrics, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN,

#[cfg(windows)]
use windows::Win32::UI::Input::KeyboardAndMouse::{
    SendInput, INPUT, INPUT_0, INPUT_MOUSE, MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL,
    MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP,
    MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK,
    MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT,
};

// XButton constants (not exported in newer windows crate versions)
#[cfg(windows)]
const XBUTTON1: u32 = 0x0001;
#[cfg(windows)]
const XBUTTON2: u32 = 0x0002;

//! Mouse input simulation using Windows SendInput API

use super::MouseButton;
use anyhow::Result;

#[cfg(windows)]
use windows::Win32::UI::Input::KeyboardAndMouse::{
    SendInput, INPUT, INPUT_0, INPUT_MOUSE, MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL,
    MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP,
    MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK,
    MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT, XBUTTON1, XBUTTON2,
};

#[cfg(windows)]
use windows::Win32::UI::WindowsAndMessaging::{
    GetSystemMetrics, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN,
    SM_YVIRTUALSCREEN,
};

/// Mouse input controller
pub struct MouseController {
    /// Virtual screen dimensions for coordinate translation
    #[cfg(windows)]
    virtual_screen: VirtualScreen,
}

#[cfg(windows)]
struct VirtualScreen {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
}

impl MouseController {
    /// Create a new mouse controller
    pub fn new() -> Result<Self> {
        #[cfg(windows)]
        {
            let virtual_screen = unsafe {
                VirtualScreen {
                    x: GetSystemMetrics(SM_XVIRTUALSCREEN),
                    y: GetSystemMetrics(SM_YVIRTUALSCREEN),
                    width: GetSystemMetrics(SM_CXVIRTUALSCREEN),
                    height: GetSystemMetrics(SM_CYVIRTUALSCREEN),
                }
            };

            Ok(Self { virtual_screen })
        }

        #[cfg(not(windows))]
        {
            anyhow::bail!("Mouse input only supported on Windows")
        }
    }

    /// Move mouse to absolute screen coordinates
    #[cfg(windows)]
    pub fn move_to(&mut self, x: i32, y: i32) -> Result<()> {
        // Convert screen coordinates to normalized absolute coordinates (0-65535)
        let norm_x = ((x - self.virtual_screen.x) * 65535) / self.virtual_screen.width;
        let norm_y = ((y - self.virtual_screen.y) * 65535) / self.virtual_screen.height;

        let input = INPUT {
            r#type: INPUT_MOUSE,
            Anonymous: INPUT_0 {
                mi: MOUSEINPUT {
                    dx: norm_x,
                    dy: norm_y,
                    mouseData: 0,
                    dwFlags: MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK,
                    time: 0,
                    dwExtraInfo: 0,
                },
            },
        };

        self.send_input(&[input])
    }

    /// Press mouse button down
    #[cfg(windows)]
    pub fn button_down(&mut self, button: MouseButton) -> Result<()> {
        let (flags, data) = match button {
            MouseButton::Left => (MOUSEEVENTF_LEFTDOWN, 0),
            MouseButton::Right => (MOUSEEVENTF_RIGHTDOWN, 0),
            MouseButton::Middle => (MOUSEEVENTF_MIDDLEDOWN, 0),
            MouseButton::X1 => (MOUSEEVENTF_XDOWN, XBUTTON1 as u32),
            MouseButton::X2 => (MOUSEEVENTF_XDOWN, XBUTTON2 as u32),
        };

        let input = INPUT {
            r#type: INPUT_MOUSE,
            Anonymous: INPUT_0 {
                mi: MOUSEINPUT {
                    dx: 0,
                    dy: 0,
                    mouseData: data,
                    dwFlags: flags,
                    time: 0,
                    dwExtraInfo: 0,
                },
            },
        };

        self.send_input(&[input])
    }

    /// Release mouse button
    #[cfg(windows)]
    pub fn button_up(&mut self, button: MouseButton) -> Result<()> {
        let (flags, data) = match button {
            MouseButton::Left => (MOUSEEVENTF_LEFTUP, 0),
            MouseButton::Right => (MOUSEEVENTF_RIGHTUP, 0),
            MouseButton::Middle => (MOUSEEVENTF_MIDDLEUP, 0),
            MouseButton::X1 => (MOUSEEVENTF_XUP, XBUTTON1 as u32),
            MouseButton::X2 => (MOUSEEVENTF_XUP, XBUTTON2 as u32),
        };

        let input = INPUT {
            r#type: INPUT_MOUSE,
            Anonymous: INPUT_0 {
                mi: MOUSEINPUT {
                    dx: 0,
                    dy: 0,
                    mouseData: data,
                    dwFlags: flags,
                    time: 0,
                    dwExtraInfo: 0,
                },
            },
        };

        self.send_input(&[input])
    }

    /// Scroll mouse wheel
    #[cfg(windows)]
    pub fn scroll(&mut self, delta_x: i32, delta_y: i32) -> Result<()> {
        let mut inputs = Vec::new();

        // Vertical scroll
        if delta_y != 0 {
            inputs.push(INPUT {
                r#type: INPUT_MOUSE,
                Anonymous: INPUT_0 {
                    mi: MOUSEINPUT {
                        dx: 0,
                        dy: 0,
                        mouseData: delta_y as u32,
                        dwFlags: MOUSEEVENTF_WHEEL,
                        time: 0,
                        dwExtraInfo: 0,
                    },
                },
            });
        }

        // Horizontal scroll
        if delta_x != 0 {
            inputs.push(INPUT {
                r#type: INPUT_MOUSE,
                Anonymous: INPUT_0 {
                    mi: MOUSEINPUT {
                        dx: 0,
                        dy: 0,
                        mouseData: delta_x as u32,
                        dwFlags: MOUSEEVENTF_HWHEEL,
                        time: 0,
                        dwExtraInfo: 0,
                    },
                },
            });
        }

        if !inputs.is_empty() {
            self.send_input(&inputs)?;
        }

        Ok(())
    }

    /// Send input events
    #[cfg(windows)]
    fn send_input(&self, inputs: &[INPUT]) -> Result<()> {
        let sent = unsafe {
            SendInput(inputs, std::mem::size_of::<INPUT>() as i32)
        };

        if sent as usize != inputs.len() {
            anyhow::bail!("SendInput failed: sent {} of {} inputs", sent, inputs.len());
        }

        Ok(())
    }

    #[cfg(not(windows))]
    pub fn move_to(&mut self, _x: i32, _y: i32) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }

    #[cfg(not(windows))]
    pub fn button_down(&mut self, _button: MouseButton) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }

    #[cfg(not(windows))]
    pub fn button_up(&mut self, _button: MouseButton) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }

    #[cfg(not(windows))]
    pub fn scroll(&mut self, _delta_x: i32, _delta_y: i32) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }
}

-    MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT, XBUTTON1, XBUTTON2,

+    MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT,

+// XButton constants (not exported in newer windows crate versions)


The file C:\Users\MikeSwanson\claude-projects\guru-connect\agent\src\input\mouse.rs has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
    91→        let (flags, data) = match button {
    92→            MouseButton::Left => (MOUSEEVENTF_LEFTDOWN, 0),
    93→            MouseButton::Right => (MOUSEEVENTF_RIGHTDOWN, 0),
    94→            MouseButton::Middle => (MOUSEEVENTF_MIDDLEDOWN, 0),
    95→            MouseButton::X1 => (MOUSEEVENTF_XDOWN, XBUTTON1),
    96→            MouseButton::X2 => (MOUSEEVENTF_XDOWN, XBUTTON2),
    97→        };
    98→
    99→        let input = INPUT {
   100→            r#type: INPUT_MOUSE,

            MouseButton::X1 => (MOUSEEVENTF_XDOWN, XBUTTON1),
            MouseButton::X2 => (MOUSEEVENTF_XDOWN, XBUTTON2),

//! Mouse input simulation using Windows SendInput API

use super::MouseButton;
use anyhow::Result;

#[cfg(windows)]
use windows::Win32::UI::Input::KeyboardAndMouse::{
    SendInput, INPUT, INPUT_0, INPUT_MOUSE, MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL,
    MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP,
    MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK,
    MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT,
};

// XButton constants (not exported in newer windows crate versions)
#[cfg(windows)]
const XBUTTON1: u32 = 0x0001;
#[cfg(windows)]
const XBUTTON2: u32 = 0x0002;

#[cfg(windows)]
use windows::Win32::UI::WindowsAndMessaging::{
    GetSystemMetrics, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN,
    SM_YVIRTUALSCREEN,
};

/// Mouse input controller
pub struct MouseController {
    /// Virtual screen dimensions for coordinate translation
    #[cfg(windows)]
    virtual_screen: VirtualScreen,
}

#[cfg(windows)]
struct VirtualScreen {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
}

impl MouseController {
    /// Create a new mouse controller
    pub fn new() -> Result<Self> {
        #[cfg(windows)]
        {
            let virtual_screen = unsafe {
                VirtualScreen {
                    x: GetSystemMetrics(SM_XVIRTUALSCREEN),
                    y: GetSystemMetrics(SM_YVIRTUALSCREEN),
                    width: GetSystemMetrics(SM_CXVIRTUALSCREEN),
                    height: GetSystemMetrics(SM_CYVIRTUALSCREEN),
                }
            };

            Ok(Self { virtual_screen })
        }

        #[cfg(not(windows))]
        {
            anyhow::bail!("Mouse input only supported on Windows")
        }
    }

    /// Move mouse to absolute screen coordinates
    #[cfg(windows)]
    pub fn move_to(&mut self, x: i32, y: i32) -> Result<()> {
        // Convert screen coordinates to normalized absolute coordinates (0-65535)
        let norm_x = ((x - self.virtual_screen.x) * 65535) / self.virtual_screen.width;
        let norm_y = ((y - self.virtual_screen.y) * 65535) / self.virtual_screen.height;

        let input = INPUT {
            r#type: INPUT_MOUSE,
            Anonymous: INPUT_0 {
                mi: MOUSEINPUT {
                    dx: norm_x,
                    dy: norm_y,
                    mouseData: 0,
                    dwFlags: MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK,
                    time: 0,
                    dwExtraInfo: 0,
                },
            },
        };

        self.send_input(&[input])
    }

    /// Press mouse button down
    #[cfg(windows)]
    pub fn button_down(&mut self, button: MouseButton) -> Result<()> {
        let (flags, data) = match button {
            MouseButton::Left => (MOUSEEVENTF_LEFTDOWN, 0),
            MouseButton::Right => (MOUSEEVENTF_RIGHTDOWN, 0),
            MouseButton::Middle => (MOUSEEVENTF_MIDDLEDOWN, 0),
            MouseButton::X1 => (MOUSEEVENTF_XDOWN, XBUTTON1 as u32),
            MouseButton::X2 => (MOUSEEVENTF_XDOWN, XBUTTON2 as u32),
        };

        let input = INPUT {
            r#type: INPUT_MOUSE,
            Anonymous: INPUT_0 {
                mi: MOUSEINPUT {
                    dx: 0,
                    dy: 0,
                    mouseData: data,
                    dwFlags: flags,
                    time: 0,
                    dwExtraInfo: 0,
                },
            },
        };

        self.send_input(&[input])
    }

    /// Release mouse button
    #[cfg(windows)]
    pub fn button_up(&mut self, button: MouseButton) -> Result<()> {
        let (flags, data) = match button {
            MouseButton::Left => (MOUSEEVENTF_LEFTUP, 0),
            MouseButton::Right => (MOUSEEVENTF_RIGHTUP, 0),
            MouseButton::Middle => (MOUSEEVENTF_MIDDLEUP, 0),
            MouseButton::X1 => (MOUSEEVENTF_XUP, XBUTTON1 as u32),
            MouseButton::X2 => (MOUSEEVENTF_XUP, XBUTTON2 as u32),
        };

        let input = INPUT {
            r#type: INPUT_MOUSE,
            Anonymous: INPUT_0 {
                mi: MOUSEINPUT {
                    dx: 0,
                    dy: 0,
                    mouseData: data,
                    dwFlags: flags,
                    time: 0,
                    dwExtraInfo: 0,
                },
            },
        };

        self.send_input(&[input])
    }

    /// Scroll mouse wheel
    #[cfg(windows)]
    pub fn scroll(&mut self, delta_x: i32, delta_y: i32) -> Result<()> {
        let mut inputs = Vec::new();

        // Vertical scroll
        if delta_y != 0 {
            inputs.push(INPUT {
                r#type: INPUT_MOUSE,
                Anonymous: INPUT_0 {
                    mi: MOUSEINPUT {
                        dx: 0,
                        dy: 0,
                        mouseData: delta_y as u32,
                        dwFlags: MOUSEEVENTF_WHEEL,
                        time: 0,
                        dwExtraInfo: 0,
                    },
                },
            });
        }

        // Horizontal scroll
        if delta_x != 0 {
            inputs.push(INPUT {
                r#type: INPUT_MOUSE,
                Anonymous: INPUT_0 {
                    mi: MOUSEINPUT {
                        dx: 0,
                        dy: 0,
                        mouseData: delta_x as u32,
                        dwFlags: MOUSEEVENTF_HWHEEL,
                        time: 0,
                        dwExtraInfo: 0,
                    },
                },
            });
        }

        if !inputs.is_empty() {
            self.send_input(&inputs)?;
        }

        Ok(())
    }

    /// Send input events
    #[cfg(windows)]
    fn send_input(&self, inputs: &[INPUT]) -> Result<()> {
        let sent = unsafe {
            SendInput(inputs, std::mem::size_of::<INPUT>() as i32)
        };

        if sent as usize != inputs.len() {
            anyhow::bail!("SendInput failed: sent {} of {} inputs", sent, inputs.len());
        }

        Ok(())
    }

    #[cfg(not(windows))]
    pub fn move_to(&mut self, _x: i32, _y: i32) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }

    #[cfg(not(windows))]
    pub fn button_down(&mut self, _button: MouseButton) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }

    #[cfg(not(windows))]
    pub fn button_up(&mut self, _button: MouseButton) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }

    #[cfg(not(windows))]
    pub fn scroll(&mut self, _delta_x: i32, _delta_y: i32) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }
}

-            MouseButton::X1 => (MOUSEEVENTF_XDOWN, XBUTTON1 as u32),

-            MouseButton::X2 => (MOUSEEVENTF_XDOWN, XBUTTON2 as u32),

+            MouseButton::X1 => (MOUSEEVENTF_XDOWN, XBUTTON1),

+            MouseButton::X2 => (MOUSEEVENTF_XDOWN, XBUTTON2),


The file C:\Users\MikeSwanson\claude-projects\guru-connect\agent\src\input\mouse.rs has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
   119→        let (flags, data) = match button {
   120→            MouseButton::Left => (MOUSEEVENTF_LEFTUP, 0),
   121→            MouseButton::Right => (MOUSEEVENTF_RIGHTUP, 0),
   122→            MouseButton::Middle => (MOUSEEVENTF_MIDDLEUP, 0),
   123→            MouseButton::X1 => (MOUSEEVENTF_XUP, XBUTTON1),
   124→            MouseButton::X2 => (MOUSEEVENTF_XUP, XBUTTON2),
   125→        };
   126→
   127→        let input = INPUT {
   128→            r#type: INPUT_MOUSE,

            MouseButton::X1 => (MOUSEEVENTF_XUP, XBUTTON1),
            MouseButton::X2 => (MOUSEEVENTF_XUP, XBUTTON2),

//! Mouse input simulation using Windows SendInput API

use super::MouseButton;
use anyhow::Result;

#[cfg(windows)]
use windows::Win32::UI::Input::KeyboardAndMouse::{
    SendInput, INPUT, INPUT_0, INPUT_MOUSE, MOUSEEVENTF_ABSOLUTE, MOUSEEVENTF_HWHEEL,
    MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP,
    MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_VIRTUALDESK,
    MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP, MOUSEINPUT,
};

// XButton constants (not exported in newer windows crate versions)
#[cfg(windows)]
const XBUTTON1: u32 = 0x0001;
#[cfg(windows)]
const XBUTTON2: u32 = 0x0002;

#[cfg(windows)]
use windows::Win32::UI::WindowsAndMessaging::{
    GetSystemMetrics, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN,
    SM_YVIRTUALSCREEN,
};

/// Mouse input controller
pub struct MouseController {
    /// Virtual screen dimensions for coordinate translation
    #[cfg(windows)]
    virtual_screen: VirtualScreen,
}

#[cfg(windows)]
struct VirtualScreen {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
}

impl MouseController {
    /// Create a new mouse controller
    pub fn new() -> Result<Self> {
        #[cfg(windows)]
        {
            let virtual_screen = unsafe {
                VirtualScreen {
                    x: GetSystemMetrics(SM_XVIRTUALSCREEN),
                    y: GetSystemMetrics(SM_YVIRTUALSCREEN),
                    width: GetSystemMetrics(SM_CXVIRTUALSCREEN),
                    height: GetSystemMetrics(SM_CYVIRTUALSCREEN),
                }
            };

            Ok(Self { virtual_screen })
        }

        #[cfg(not(windows))]
        {
            anyhow::bail!("Mouse input only supported on Windows")
        }
    }

    /// Move mouse to absolute screen coordinates
    #[cfg(windows)]
    pub fn move_to(&mut self, x: i32, y: i32) -> Result<()> {
        // Convert screen coordinates to normalized absolute coordinates (0-65535)
        let norm_x = ((x - self.virtual_screen.x) * 65535) / self.virtual_screen.width;
        let norm_y = ((y - self.virtual_screen.y) * 65535) / self.virtual_screen.height;

        let input = INPUT {
            r#type: INPUT_MOUSE,
            Anonymous: INPUT_0 {
                mi: MOUSEINPUT {
                    dx: norm_x,
                    dy: norm_y,
                    mouseData: 0,
                    dwFlags: MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK,
                    time: 0,
                    dwExtraInfo: 0,
                },
            },
        };

        self.send_input(&[input])
    }

    /// Press mouse button down
    #[cfg(windows)]
    pub fn button_down(&mut self, button: MouseButton) -> Result<()> {
        let (flags, data) = match button {
            MouseButton::Left => (MOUSEEVENTF_LEFTDOWN, 0),
            MouseButton::Right => (MOUSEEVENTF_RIGHTDOWN, 0),
            MouseButton::Middle => (MOUSEEVENTF_MIDDLEDOWN, 0),
            MouseButton::X1 => (MOUSEEVENTF_XDOWN, XBUTTON1),
            MouseButton::X2 => (MOUSEEVENTF_XDOWN, XBUTTON2),
        };

        let input = INPUT {
            r#type: INPUT_MOUSE,
            Anonymous: INPUT_0 {
                mi: MOUSEINPUT {
                    dx: 0,
                    dy: 0,
                    mouseData: data,
                    dwFlags: flags,
                    time: 0,
                    dwExtraInfo: 0,
                },
            },
        };

        self.send_input(&[input])
    }

    /// Release mouse button
    #[cfg(windows)]
    pub fn button_up(&mut self, button: MouseButton) -> Result<()> {
        let (flags, data) = match button {
            MouseButton::Left => (MOUSEEVENTF_LEFTUP, 0),
            MouseButton::Right => (MOUSEEVENTF_RIGHTUP, 0),
            MouseButton::Middle => (MOUSEEVENTF_MIDDLEUP, 0),
            MouseButton::X1 => (MOUSEEVENTF_XUP, XBUTTON1 as u32),
            MouseButton::X2 => (MOUSEEVENTF_XUP, XBUTTON2 as u32),
        };

        let input = INPUT {
            r#type: INPUT_MOUSE,
            Anonymous: INPUT_0 {
                mi: MOUSEINPUT {
                    dx: 0,
                    dy: 0,
                    mouseData: data,
                    dwFlags: flags,
                    time: 0,
                    dwExtraInfo: 0,
                },
            },
        };

        self.send_input(&[input])
    }

    /// Scroll mouse wheel
    #[cfg(windows)]
    pub fn scroll(&mut self, delta_x: i32, delta_y: i32) -> Result<()> {
        let mut inputs = Vec::new();

        // Vertical scroll
        if delta_y != 0 {
            inputs.push(INPUT {
                r#type: INPUT_MOUSE,
                Anonymous: INPUT_0 {
                    mi: MOUSEINPUT {
                        dx: 0,
                        dy: 0,
                        mouseData: delta_y as u32,
                        dwFlags: MOUSEEVENTF_WHEEL,
                        time: 0,
                        dwExtraInfo: 0,
                    },
                },
            });
        }

        // Horizontal scroll
        if delta_x != 0 {
            inputs.push(INPUT {
                r#type: INPUT_MOUSE,
                Anonymous: INPUT_0 {
                    mi: MOUSEINPUT {
                        dx: 0,
                        dy: 0,
                        mouseData: delta_x as u32,
                        dwFlags: MOUSEEVENTF_HWHEEL,
                        time: 0,
                        dwExtraInfo: 0,
                    },
                },
            });
        }

        if !inputs.is_empty() {
            self.send_input(&inputs)?;
        }

        Ok(())
    }

    /// Send input events
    #[cfg(windows)]
    fn send_input(&self, inputs: &[INPUT]) -> Result<()> {
        let sent = unsafe {
            SendInput(inputs, std::mem::size_of::<INPUT>() as i32)
        };

        if sent as usize != inputs.len() {
            anyhow::bail!("SendInput failed: sent {} of {} inputs", sent, inputs.len());
        }

        Ok(())
    }

    #[cfg(not(windows))]
    pub fn move_to(&mut self, _x: i32, _y: i32) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }

    #[cfg(not(windows))]
    pub fn button_down(&mut self, _button: MouseButton) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }

    #[cfg(not(windows))]
    pub fn button_up(&mut self, _button: MouseButton) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }

    #[cfg(not(windows))]
    pub fn scroll(&mut self, _delta_x: i32, _delta_y: i32) -> Result<()> {
        anyhow::bail!("Mouse input only supported on Windows")
    }
}

-            MouseButton::X1 => (MOUSEEVENTF_XUP, XBUTTON1 as u32),

-            MouseButton::X2 => (MOUSEEVENTF_XUP, XBUTTON2 as u32),

+            MouseButton::X1 => (MOUSEEVENTF_XUP, XBUTTON1),

+            MouseButton::X2 => (MOUSEEVENTF_XUP, XBUTTON2),


Good. Now let me fix the session/mod.rs display naming conflict, the dxgi.rs GetDesc and other issues, the keyboard.rs wScan issue, and the websocket.rs borrow issue.


Now let me fix the session/mod.rs display naming conflict:


        // Get primary display
        let display = capture::primary_display()?;
        tracing::info!("Using display: {} ({}x{})", display.name, display.width, display.height);

        // Get primary display
        let primary_display = capture::primary_display()?;
        tracing::info!("Using display: {} ({}x{})", primary_display.name, primary_display.width, primary_display.height);


        // Create capturer
        let mut capturer = capture::create_capturer(
            display.clone(),
            self.config.capture.use_dxgi,
            self.config.capture.gdi_fallback,
        )?;

        // Create capturer
        let mut capturer = capture::create_capturer(
            primary_display.clone(),
            self.config.capture.use_dxgi,
            self.config.capture.gdi_fallback,
        )?;


The file C:\Users\MikeSwanson\claude-projects\guru-connect\agent\src\session\mod.rs has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
    63→            .ok_or_else(|| anyhow::anyhow!("Not connected"))?;
    64→
    65→        self.state = SessionState::Active;
    66→
    67→        // Get primary display
    68→        let primary_display = capture::primary_display()?;
    69→        tracing::info!("Using display: {} ({}x{})", primary_display.name, primary_display.width, primary_display.height);
    70→
    71→        // Create capturer
    72→        let mut capturer = capture::create_capturer(
    73→            display.clone(),

        // Get primary display
        let primary_display = capture::primary_display()?;
        tracing::info!("Using display: {} ({}x{})", primary_display.name, primary_display.width, primary_display.height);

//! Session management for the agent
//!
//! Handles the lifecycle of a remote session including:
//! - Connection to server
//! - Authentication
//! - Frame capture and encoding loop
//! - Input event handling

use crate::capture::{self, Capturer, Display};
use crate::config::Config;
use crate::encoder::{self, Encoder};
use crate::input::InputController;
use crate::proto::{Message, message};
use crate::transport::WebSocketTransport;
use anyhow::Result;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::mpsc;

/// Session manager handles the remote control session
pub struct SessionManager {
    config: Config,
    transport: Option<WebSocketTransport>,
    state: SessionState,
}

#[derive(Debug, Clone, PartialEq)]
enum SessionState {
    Disconnected,
    Connecting,
    Connected,
    Active,
}

impl SessionManager {
    /// Create a new session manager
    pub fn new(config: Config) -> Self {
        Self {
            config,
            transport: None,
            state: SessionState::Disconnected,
        }
    }

    /// Connect to the server
    pub async fn connect(&mut self) -> Result<()> {
        self.state = SessionState::Connecting;

        let transport = WebSocketTransport::connect(
            &self.config.server_url,
            &self.config.api_key,
        ).await?;

        self.transport = Some(transport);
        self.state = SessionState::Connected;

        Ok(())
    }

    /// Run the session main loop
    pub async fn run(&mut self) -> Result<()> {
        let transport = self.transport.as_mut()
            .ok_or_else(|| anyhow::anyhow!("Not connected"))?;

        self.state = SessionState::Active;

        // Get primary display
        let display = capture::primary_display()?;
        tracing::info!("Using display: {} ({}x{})", display.name, display.width, display.height);

        // Create capturer
        let mut capturer = capture::create_capturer(
            display.clone(),
            self.config.capture.use_dxgi,
            self.config.capture.gdi_fallback,
        )?;

        // Create encoder
        let mut encoder = encoder::create_encoder(
            &self.config.encoding.codec,
            self.config.encoding.quality,
        )?;

        // Create input controller
        let mut input = InputController::new()?;

        // Calculate frame interval
        let frame_interval = Duration::from_millis(1000 / self.config.capture.fps as u64);
        let mut last_frame_time = Instant::now();

        // Main loop
        loop {
            // Check for incoming messages (non-blocking)
            while let Some(msg) = transport.try_recv()? {
                self.handle_message(&mut input, msg)?;
            }

            // Capture and send frame if interval elapsed
            if last_frame_time.elapsed() >= frame_interval {
                last_frame_time = Instant::now();

                if let Some(frame) = capturer.capture()? {
                    let encoded = encoder.encode(&frame)?;

                    // Skip empty frames (no changes)
                    if encoded.size > 0 {
                        let msg = Message {
                            payload: Some(message::Payload::VideoFrame(encoded.frame)),
                        };
                        transport.send(msg).await?;
                    }
                }
            }

            // Small sleep to prevent busy loop
            tokio::time::sleep(Duration::from_millis(1)).await;

            // Check if still connected
            if !transport.is_connected() {
                tracing::warn!("Connection lost");
                break;
            }
        }

        self.state = SessionState::Disconnected;
        Ok(())
    }

    /// Handle incoming message from server
    fn handle_message(&mut self, input: &mut InputController, msg: Message) -> Result<()> {
        match msg.payload {
            Some(message::Payload::MouseEvent(mouse)) => {
                // Handle mouse event
                use crate::proto::MouseEventType;
                use crate::input::MouseButton;

                match MouseEventType::try_from(mouse.event_type).unwrap_or(MouseEventType::MouseMove) {
                    MouseEventType::MouseMove => {
                        input.mouse_move(mouse.x, mouse.y)?;
                    }
                    MouseEventType::MouseDown => {
                        input.mouse_move(mouse.x, mouse.y)?;
                        if let Some(ref buttons) = mouse.buttons {
                            if buttons.left { input.mouse_click(MouseButton::Left, true)?; }
                            if buttons.right { input.mouse_click(MouseButton::Right, true)?; }
                            if buttons.middle { input.mouse_click(MouseButton::Middle, true)?; }
                        }
                    }
                    MouseEventType::MouseUp => {
                        if let Some(ref buttons) = mouse.buttons {
                            if buttons.left { input.mouse_click(MouseButton::Left, false)?; }
                            if buttons.right { input.mouse_click(MouseButton::Right, false)?; }
                            if buttons.middle { input.mouse_click(MouseButton::Middle, false)?; }
                        }
                    }
                    MouseEventType::MouseWheel => {
                        input.mouse_scroll(mouse.wheel_delta_x, mouse.wheel_delta_y)?;
                    }
                }
            }

            Some(message::Payload::KeyEvent(key)) => {
                // Handle keyboard event
                input.key_event(key.vk_code as u16, key.down)?;
            }

            Some(message::Payload::SpecialKey(special)) => {
                use crate::proto::SpecialKey;
                match SpecialKey::try_from(special.key).ok() {
                    Some(SpecialKey::CtrlAltDel) => {
                        input.send_ctrl_alt_del()?;
                    }
                    _ => {}
                }
            }

            Some(message::Payload::Heartbeat(_)) => {
                // Respond to heartbeat
                // TODO: Send heartbeat ack
            }

            Some(message::Payload::Disconnect(disc)) => {
                tracing::info!("Disconnect requested: {}", disc.reason);
                return Err(anyhow::anyhow!("Disconnect: {}", disc.reason));
            }

            _ => {
                // Ignore unknown messages
            }
        }

        Ok(())
    }
}

-        let display = capture::primary_display()?;

-        tracing::info!("Using display: {} ({}x{})", display.name, display.width, display.height);

+        let primary_display = capture::primary_display()?;

+        tracing::info!("Using display: {} ({}x{})", primary_display.name, primary_display.width, primary_display.height);


The file C:\Users\MikeSwanson\claude-projects\guru-connect\agent\src\session\mod.rs has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
    67→        // Get primary display
    68→        let primary_display = capture::primary_display()?;
    69→        tracing::info!("Using display: {} ({}x{})", primary_display.name, primary_display.width, primary_display.height);
    70→
    71→        // Create capturer
    72→        let mut capturer = capture::create_capturer(
    73→            primary_display.clone(),
    74→            self.config.capture.use_dxgi,
    75→            self.config.capture.gdi_fallback,
    76→        )?;
    77→
    78→        // Create encoder
    79→        let mut encoder = encoder::create_encoder(
    80→            &self.config.encoding.codec,

        // Create capturer
        let mut capturer = capture::create_capturer(
            primary_display.clone(),
            self.config.capture.use_dxgi,
            self.config.capture.gdi_fallback,
        )?;

//! Session management for the agent
//!
//! Handles the lifecycle of a remote session including:
//! - Connection to server
//! - Authentication
//! - Frame capture and encoding loop
//! - Input event handling

use crate::capture::{self, Capturer, Display};
use crate::config::Config;
use crate::encoder::{self, Encoder};
use crate::input::InputController;
use crate::proto::{Message, message};
use crate::transport::WebSocketTransport;
use anyhow::Result;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::mpsc;

/// Session manager handles the remote control session
pub struct SessionManager {
    config: Config,
    transport: Option<WebSocketTransport>,
    state: SessionState,
}

#[derive(Debug, Clone, PartialEq)]
enum SessionState {
    Disconnected,
    Connecting,
    Connected,
    Active,
}

impl SessionManager {
    /// Create a new session manager
    pub fn new(config: Config) -> Self {
        Self {
            config,
            transport: None,
            state: SessionState::Disconnected,
        }
    }

    /// Connect to the server
    pub async fn connect(&mut self) -> Result<()> {
        self.state = SessionState::Connecting;

        let transport = WebSocketTransport::connect(
            &self.config.server_url,
            &self.config.api_key,
        ).await?;

        self.transport = Some(transport);
        self.state = SessionState::Connected;

        Ok(())
    }

    /// Run the session main loop
    pub async fn run(&mut self) -> Result<()> {
        let transport = self.transport.as_mut()
            .ok_or_else(|| anyhow::anyhow!("Not connected"))?;

        self.state = SessionState::Active;

        // Get primary display
        let primary_display = capture::primary_display()?;
        tracing::info!("Using display: {} ({}x{})", primary_display.name, primary_display.width, primary_display.height);

        // Create capturer
        let mut capturer = capture::create_capturer(
            display.clone(),
            self.config.capture.use_dxgi,
            self.config.capture.gdi_fallback,
        )?;

        // Create encoder
        let mut encoder = encoder::create_encoder(
            &self.config.encoding.codec,
            self.config.encoding.quality,
        )?;

        // Create input controller
        let mut input = InputController::new()?;

        // Calculate frame interval
        let frame_interval = Duration::from_millis(1000 / self.config.capture.fps as u64);
        let mut last_frame_time = Instant::now();

        // Main loop
        loop {
            // Check for incoming messages (non-blocking)
            while let Some(msg) = transport.try_recv()? {
                self.handle_message(&mut input, msg)?;
            }

            // Capture and send frame if interval elapsed
            if last_frame_time.elapsed() >= frame_interval {
                last_frame_time = Instant::now();

                if let Some(frame) = capturer.capture()? {
                    let encoded = encoder.encode(&frame)?;

                    // Skip empty frames (no changes)
                    if encoded.size > 0 {
                        let msg = Message {
                            payload: Some(message::Payload::VideoFrame(encoded.frame)),
                        };
                        transport.send(msg).await?;
                    }
                }
            }

            // Small sleep to prevent busy loop
            tokio::time::sleep(Duration::from_millis(1)).await;

            // Check if still connected
            if !transport.is_connected() {
                tracing::warn!("Connection lost");
                break;
            }
        }

        self.state = SessionState::Disconnected;
        Ok(())
    }

    /// Handle incoming message from server
    fn handle_message(&mut self, input: &mut InputController, msg: Message) -> Result<()> {
        match msg.payload {
            Some(message::Payload::MouseEvent(mouse)) => {
                // Handle mouse event
                use crate::proto::MouseEventType;
                use crate::input::MouseButton;

                match MouseEventType::try_from(mouse.event_type).unwrap_or(MouseEventType::MouseMove) {
                    MouseEventType::MouseMove => {
                        input.mouse_move(mouse.x, mouse.y)?;
                    }
                    MouseEventType::MouseDown => {
                        input.mouse_move(mouse.x, mouse.y)?;
                        if let Some(ref buttons) = mouse.buttons {
                            if buttons.left { input.mouse_click(MouseButton::Left, true)?; }
                            if buttons.right { input.mouse_click(MouseButton::Right, true)?; }
                            if buttons.middle { input.mouse_click(MouseButton::Middle, true)?; }
                        }
                    }
                    MouseEventType::MouseUp => {
                        if let Some(ref buttons) = mouse.buttons {
                            if buttons.left { input.mouse_click(MouseButton::Left, false)?; }
                            if buttons.right { input.mouse_click(MouseButton::Right, false)?; }
                            if buttons.middle { input.mouse_click(MouseButton::Middle, false)?; }
                        }
                    }
                    MouseEventType::MouseWheel => {
                        input.mouse_scroll(mouse.wheel_delta_x, mouse.wheel_delta_y)?;
                    }
                }
            }

            Some(message::Payload::KeyEvent(key)) => {
                // Handle keyboard event
                input.key_event(key.vk_code as u16, key.down)?;
            }

            Some(message::Payload::SpecialKey(special)) => {
                use crate::proto::SpecialKey;
                match SpecialKey::try_from(special.key).ok() {
                    Some(SpecialKey::CtrlAltDel) => {
                        input.send_ctrl_alt_del()?;
                    }
                    _ => {}
                }
            }

            Some(message::Payload::Heartbeat(_)) => {
                // Respond to heartbeat
                // TODO: Send heartbeat ack
            }

            Some(message::Payload::Disconnect(disc)) => {
                tracing::info!("Disconnect requested: {}", disc.reason);
                return Err(anyhow::anyhow!("Disconnect: {}", disc.reason));
            }

            _ => {
                // Ignore unknown messages
            }
        }

        Ok(())
    }
}


Now let me fix the dxgi.rs issues - GetDesc returning value instead of taking reference, and the type mismatches.


Now fix dxgi.rs - GetDesc returns value, and type fixes:


            // Get duplication description
            let mut desc = DXGI_OUTDUPL_DESC::default();
            duplication.GetDesc(&mut desc);

            tracing::info!(
                "Created DXGI duplication: {}x{}, display: {}",
                desc.ModeDesc.Width,
                desc.ModeDesc.Height,
                display.name
            );

            // Get duplication description
            let desc = duplication.GetDesc();

            tracing::info!(
                "Created DXGI duplication: {}x{}, display: {}",
                desc.ModeDesc.Width,
                desc.ModeDesc.Height,
                display_info.name
            );


    /// Create D3D device and output duplication
    fn create_duplication(
        display: &Display,
    ) -> Result<(ID3D11Device, ID3D11DeviceContext, IDXGIOutputDuplication, DXGI_OUTDUPL_DESC)> {
        unsafe {
            // Create DXGI factory
            let factory: IDXGIFactory1 = CreateDXGIFactory1()
                .context("Failed to create DXGI factory")?;

            // Find the adapter and output for this display
            let (adapter, output) = Self::find_adapter_output(&factory, display)?;

    /// Create D3D device and output duplication
    fn create_duplication(
        display_info: &Display,
    ) -> Result<(ID3D11Device, ID3D11DeviceContext, IDXGIOutputDuplication, DXGI_OUTDUPL_DESC)> {
        unsafe {
            // Create DXGI factory
            let factory: IDXGIFactory1 = CreateDXGIFactory1()
                .context("Failed to create DXGI factory")?;

            // Find the adapter and output for this display
            let (adapter, output) = Self::find_adapter_output(&factory, display_info)?;


                    // Check if this is the display we want
                    let mut desc = Default::default();
                    output.GetDesc(&mut desc)?;

                    // Check if this is the display we want
                    let desc = output.GetDesc()?;


desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ.0 as u32;


The file C:\Users\MikeSwanson\claude-projects\guru-connect\agent\src\capture\dxgi.rs has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
    92→            // Create output duplication
    93→            let duplication = output1.DuplicateOutput(&device)
    94→                .context("Failed to create output duplication")?;
    95→
    96→            // Get duplication description
    97→            let desc = duplication.GetDesc();
    98→
    99→            tracing::info!(
   100→                "Created DXGI duplication: {}x{}, display: {}",
   101→                desc.ModeDesc.Width,
   102→                desc.ModeDesc.Height,
   103→                display_info.name
   104→            );
   105→
   106→            Ok((device, context, duplication, desc))
   107→        }
   108→    }

            // Get duplication description
            let desc = duplication.GetDesc();

            tracing::info!(
                "Created DXGI duplication: {}x{}, display: {}",
                desc.ModeDesc.Width,
                desc.ModeDesc.Height,
                display_info.name
            );

//! DXGI Desktop Duplication screen capture
//!
//! Uses the Windows Desktop Duplication API (available on Windows 8+) for
//! high-performance, low-latency screen capture with hardware acceleration.
//!
//! Reference: RustDesk's scrap library implementation

use super::{CapturedFrame, Capturer, DirtyRect, Display};
use anyhow::{Context, Result};
use std::ptr;
use std::time::Instant;

use windows::Win32::Graphics::Direct3D::D3D_DRIVER_TYPE_UNKNOWN;
use windows::Win32::Graphics::Direct3D11::{
    D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D,
    D3D11_CPU_ACCESS_READ, D3D11_SDK_VERSION, D3D11_TEXTURE2D_DESC,
    D3D11_USAGE_STAGING, D3D11_MAPPED_SUBRESOURCE, D3D11_MAP_READ,
};
use windows::Win32::Graphics::Dxgi::{
    CreateDXGIFactory1, IDXGIAdapter1, IDXGIFactory1, IDXGIOutput, IDXGIOutput1,
    IDXGIOutputDuplication, IDXGIResource, DXGI_ERROR_ACCESS_LOST,
    DXGI_ERROR_WAIT_TIMEOUT, DXGI_OUTDUPL_DESC, DXGI_OUTDUPL_FRAME_INFO,
    DXGI_RESOURCE_PRIORITY_MAXIMUM,
};
use windows::core::Interface;

/// DXGI Desktop Duplication capturer
pub struct DxgiCapturer {
    display: Display,
    device: ID3D11Device,
    context: ID3D11DeviceContext,
    duplication: IDXGIOutputDuplication,
    staging_texture: Option<ID3D11Texture2D>,
    width: u32,
    height: u32,
    last_frame: Option<Vec<u8>>,
}

impl DxgiCapturer {
    /// Create a new DXGI capturer for the specified display
    pub fn new(display: Display) -> Result<Self> {
        let (device, context, duplication, desc) = Self::create_duplication(&display)?;

        Ok(Self {
            display,
            device,
            context,
            duplication,
            staging_texture: None,
            width: desc.ModeDesc.Width,
            height: desc.ModeDesc.Height,
            last_frame: None,
        })
    }

    /// Create D3D device and output duplication
    fn create_duplication(
        display: &Display,
    ) -> Result<(ID3D11Device, ID3D11DeviceContext, IDXGIOutputDuplication, DXGI_OUTDUPL_DESC)> {
        unsafe {
            // Create DXGI factory
            let factory: IDXGIFactory1 = CreateDXGIFactory1()
                .context("Failed to create DXGI factory")?;

            // Find the adapter and output for this display
            let (adapter, output) = Self::find_adapter_output(&factory, display)?;

            // Create D3D11 device
            let mut device: Option<ID3D11Device> = None;
            let mut context: Option<ID3D11DeviceContext> = None;

            D3D11CreateDevice(
                &adapter,
                D3D_DRIVER_TYPE_UNKNOWN,
                None,
                Default::default(),
                None,
                D3D11_SDK_VERSION,
                Some(&mut device),
                None,
                Some(&mut context),
            )
            .context("Failed to create D3D11 device")?;

            let device = device.context("D3D11 device is None")?;
            let context = context.context("D3D11 context is None")?;

            // Get IDXGIOutput1 interface
            let output1: IDXGIOutput1 = output.cast()
                .context("Failed to get IDXGIOutput1 interface")?;

            // Create output duplication
            let duplication = output1.DuplicateOutput(&device)
                .context("Failed to create output duplication")?;

            // Get duplication description
            let mut desc = DXGI_OUTDUPL_DESC::default();
            duplication.GetDesc(&mut desc);

            tracing::info!(
                "Created DXGI duplication: {}x{}, display: {}",
                desc.ModeDesc.Width,
                desc.ModeDesc.Height,
                display.name
            );

            Ok((device, context, duplication, desc))
        }
    }

    /// Find the adapter and output for the specified display
    fn find_adapter_output(
        factory: &IDXGIFactory1,
        display: &Display,
    ) -> Result<(IDXGIAdapter1, IDXGIOutput)> {
        unsafe {
            let mut adapter_idx = 0u32;

            loop {
                // Enumerate adapters
                let adapter: IDXGIAdapter1 = match factory.EnumAdapters1(adapter_idx) {
                    Ok(a) => a,
                    Err(_) => break,
                };

                let mut output_idx = 0u32;

                loop {
                    // Enumerate outputs for this adapter
                    let output: IDXGIOutput = match adapter.EnumOutputs(output_idx) {
                        Ok(o) => o,
                        Err(_) => break,
                    };

                    // Check if this is the display we want
                    let mut desc = Default::default();
                    output.GetDesc(&mut desc)?;

                    let name = String::from_utf16_lossy(
                        &desc.DeviceName[..desc.DeviceName.iter().position(|&c| c == 0).unwrap_or(desc.DeviceName.len())]
                    );

                    if name == display.name || desc.Monitor.0 as isize == display.handle {
                        return Ok((adapter, output));
                    }

                    output_idx += 1;
                }

                adapter_idx += 1;
            }

            // If we didn't find the specific display, use the first one
            let adapter: IDXGIAdapter1 = factory.EnumAdapters1(0)
                .context("No adapters found")?;
            let output: IDXGIOutput = adapter.EnumOutputs(0)
                .context("No outputs found")?;

            Ok((adapter, output))
        }
    }

    /// Create or get the staging texture for CPU access
    fn get_staging_texture(&mut self, src_texture: &ID3D11Texture2D) -> Result<&ID3D11Texture2D> {
        if self.staging_texture.is_none() {
            unsafe {
                let mut desc = D3D11_TEXTURE2D_DESC::default();
                src_texture.GetDesc(&mut desc);

                desc.Usage = D3D11_USAGE_STAGING;
                desc.BindFlags = Default::default();
                desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
                desc.MiscFlags = Default::default();

                let mut staging: Option<ID3D11Texture2D> = None;
                self.device.CreateTexture2D(&desc, None, Some(&mut staging))
                    .context("Failed to create staging texture")?;
                let staging = staging.context("Staging texture is None")?;

                // Set high priority
                let resource: IDXGIResource = staging.cast()?;
                resource.SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM.0)?;

                self.staging_texture = Some(staging);
            }
        }

        Ok(self.staging_texture.as_ref().unwrap())
    }

    /// Acquire the next frame from the desktop
    fn acquire_frame(&mut self, timeout_ms: u32) -> Result<Option<(ID3D11Texture2D, DXGI_OUTDUPL_FRAME_INFO)>> {
        unsafe {
            let mut frame_info = DXGI_OUTDUPL_FRAME_INFO::default();
            let mut desktop_resource: Option<IDXGIResource> = None;

            let result = self.duplication.AcquireNextFrame(
                timeout_ms,
                &mut frame_info,
                &mut desktop_resource,
            );

            match result {
                Ok(_) => {
                    let resource = desktop_resource.context("Desktop resource is None")?;

                    // Check if there's actually a new frame
                    if frame_info.LastPresentTime == 0 {
                        self.duplication.ReleaseFrame().ok();
                        return Ok(None);
                    }

                    let texture: ID3D11Texture2D = resource.cast()
                        .context("Failed to cast to ID3D11Texture2D")?;

                    Ok(Some((texture, frame_info)))
                }
                Err(e) if e.code() == DXGI_ERROR_WAIT_TIMEOUT => {
                    // No new frame available
                    Ok(None)
                }
                Err(e) if e.code() == DXGI_ERROR_ACCESS_LOST => {
                    // Desktop duplication was invalidated, need to recreate
                    tracing::warn!("Desktop duplication access lost, will need to recreate");
                    Err(anyhow::anyhow!("Access lost"))
                }
                Err(e) => {
                    Err(e).context("Failed to acquire frame")
                }
            }
        }
    }

    /// Copy frame data to CPU-accessible memory
    fn copy_frame_data(&mut self, texture: &ID3D11Texture2D) -> Result<Vec<u8>> {
        unsafe {
            // Get or create staging texture
            let staging = self.get_staging_texture(texture)?.clone();

            // Copy from GPU texture to staging texture
            self.context.CopyResource(&staging, texture);

            // Map the staging texture for CPU read
            let mut mapped = D3D11_MAPPED_SUBRESOURCE::default();
            self.context
                .Map(&staging, 0, D3D11_MAP_READ, 0, Some(&mut mapped))
                .context("Failed to map staging texture")?;

            // Copy pixel data
            let src_pitch = mapped.RowPitch as usize;
            let dst_pitch = (self.width * 4) as usize;
            let height = self.height as usize;

            let mut data = vec![0u8; dst_pitch * height];

            let src_ptr = mapped.pData as *const u8;
            for y in 0..height {
                let src_row = src_ptr.add(y * src_pitch);
                let dst_row = data.as_mut_ptr().add(y * dst_pitch);
                ptr::copy_nonoverlapping(src_row, dst_row, dst_pitch);
            }

            // Unmap
            self.context.Unmap(&staging, 0);

            Ok(data)
        }
    }

    /// Extract dirty rectangles from frame info
    fn extract_dirty_rects(&self, _frame_info: &DXGI_OUTDUPL_FRAME_INFO) -> Option<Vec<DirtyRect>> {
        // TODO: Implement dirty rectangle extraction using
        // IDXGIOutputDuplication::GetFrameDirtyRects and GetFrameMoveRects
        // For now, return None to indicate full frame update
        None
    }
}

impl Capturer for DxgiCapturer {
    fn capture(&mut self) -> Result<Option<CapturedFrame>> {
        // Try to acquire a frame with 100ms timeout
        let frame_result = self.acquire_frame(100)?;

        let (texture, frame_info) = match frame_result {
            Some((t, f)) => (t, f),
            None => return Ok(None), // No new frame
        };

        // Copy frame data to CPU memory
        let data = self.copy_frame_data(&texture)?;

        // Release the frame
        unsafe {
            self.duplication.ReleaseFrame().ok();
        }

        // Extract dirty rectangles if available
        let dirty_rects = self.extract_dirty_rects(&frame_info);

        Ok(Some(CapturedFrame {
            width: self.width,
            height: self.height,
            data,
            timestamp: Instant::now(),
            display_id: self.display.id,
            dirty_rects,
        }))
    }

    fn display(&self) -> &Display {
        &self.display
    }

    fn is_valid(&self) -> bool {
        // Could check if duplication is still valid
        true
    }
}

impl Drop for DxgiCapturer {
    fn drop(&mut self) {
        // Release any held frame
        unsafe {
            self.duplication.ReleaseFrame().ok();
        }
    }
}

-            let mut desc = DXGI_OUTDUPL_DESC::default();

-            duplication.GetDesc(&mut desc);

+            let desc = duplication.GetDesc();


The file C:\Users\MikeSwanson\claude-projects\guru-connect\agent\src\capture\dxgi.rs has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
    52→            last_frame: None,
    53→        })
    54→    }
    55→
    56→    /// Create D3D device and output duplication
    57→    fn create_duplication(
    58→        display_info: &Display,
    59→    ) -> Result<(ID3D11Device, ID3D11DeviceContext, IDXGIOutputDuplication, DXGI_OUTDUPL_DESC)> {
    60→        unsafe {
    61→            // Create DXGI factory
    62→            let factory: IDXGIFactory1 = CreateDXGIFactory1()
    63→                .context("Failed to create DXGI factory")?;
    64→
    65→            // Find the adapter and output for this display
    66→            let (adapter, output) = Self::find_adapter_output(&factory, display_info)?;
    67→
    68→            // Create D3D11 device
    69→            let mut device: Option<ID3D11Device> = None;
    70→            let mut context: Option<ID3D11DeviceContext> = None;

    /// Create D3D device and output duplication
    fn create_duplication(
        display_info: &Display,
    ) -> Result<(ID3D11Device, ID3D11DeviceContext, IDXGIOutputDuplication, DXGI_OUTDUPL_DESC)> {
        unsafe {
            // Create DXGI factory
            let factory: IDXGIFactory1 = CreateDXGIFactory1()
                .context("Failed to create DXGI factory")?;

            // Find the adapter and output for this display
            let (adapter, output) = Self::find_adapter_output(&factory, display_info)?;

//! DXGI Desktop Duplication screen capture
//!
//! Uses the Windows Desktop Duplication API (available on Windows 8+) for
//! high-performance, low-latency screen capture with hardware acceleration.
//!
//! Reference: RustDesk's scrap library implementation

use super::{CapturedFrame, Capturer, DirtyRect, Display};
use anyhow::{Context, Result};
use std::ptr;
use std::time::Instant;

use windows::Win32::Graphics::Direct3D::D3D_DRIVER_TYPE_UNKNOWN;
use windows::Win32::Graphics::Direct3D11::{
    D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D,
    D3D11_CPU_ACCESS_READ, D3D11_SDK_VERSION, D3D11_TEXTURE2D_DESC,
    D3D11_USAGE_STAGING, D3D11_MAPPED_SUBRESOURCE, D3D11_MAP_READ,
};
use windows::Win32::Graphics::Dxgi::{
    CreateDXGIFactory1, IDXGIAdapter1, IDXGIFactory1, IDXGIOutput, IDXGIOutput1,
    IDXGIOutputDuplication, IDXGIResource, DXGI_ERROR_ACCESS_LOST,
    DXGI_ERROR_WAIT_TIMEOUT, DXGI_OUTDUPL_DESC, DXGI_OUTDUPL_FRAME_INFO,
    DXGI_RESOURCE_PRIORITY_MAXIMUM,
};
use windows::core::Interface;

/// DXGI Desktop Duplication capturer
pub struct DxgiCapturer {
    display: Display,
    device: ID3D11Device,
    context: ID3D11DeviceContext,
    duplication: IDXGIOutputDuplication,
    staging_texture: Option<ID3D11Texture2D>,
    width: u32,
    height: u32,
    last_frame: Option<Vec<u8>>,
}

impl DxgiCapturer {
    /// Create a new DXGI capturer for the specified display
    pub fn new(display: Display) -> Result<Self> {
        let (device, context, duplication, desc) = Self::create_duplication(&display)?;

        Ok(Self {
            display,
            device,
            context,
            duplication,
            staging_texture: None,
            width: desc.ModeDesc.Width,
            height: desc.ModeDesc.Height,
            last_frame: None,
        })
    }

    /// Create D3D device and output duplication
    fn create_duplication(
        display: &Display,
    ) -> Result<(ID3D11Device, ID3D11DeviceContext, IDXGIOutputDuplication, DXGI_OUTDUPL_DESC)> {
        unsafe {
            // Create DXGI factory
            let factory: IDXGIFactory1 = CreateDXGIFactory1()
                .context("Failed to create DXGI factory")?;

            // Find the adapter and output for this display
            let (adapter, output) = Self::find_adapter_output(&factory, display)?;

            // Create D3D11 device
            let mut device: Option<ID3D11Device> = None;
            let mut context: Option<ID3D11DeviceContext> = None;

            D3D11CreateDevice(
                &adapter,
                D3D_DRIVER_TYPE_UNKNOWN,
                None,
                Default::default(),
                None,
                D3D11_SDK_VERSION,
                Some(&mut device),
                None,
                Some(&mut context),
            )
            .context("Failed to create D3D11 device")?;

            let device = device.context("D3D11 device is None")?;
            let context = context.context("D3D11 context is None")?;

            // Get IDXGIOutput1 interface
            let output1: IDXGIOutput1 = output.cast()
                .context("Failed to get IDXGIOutput1 interface")?;

            // Create output duplication
            let duplication = output1.DuplicateOutput(&device)
                .context("Failed to create output duplication")?;

            // Get duplication description
            let desc = duplication.GetDesc();

            tracing::info!(
                "Created DXGI duplication: {}x{}, display: {}",
                desc.ModeDesc.Width,
                desc.ModeDesc.Height,
                display_info.name
            );

            Ok((device, context, duplication, desc))
        }
    }

    /// Find the adapter and output for the specified display
    fn find_adapter_output(
        factory: &IDXGIFactory1,
        display: &Display,
    ) -> Result<(IDXGIAdapter1, IDXGIOutput)> {
        unsafe {
            let mut adapter_idx = 0u32;

            loop {
                // Enumerate adapters
                let adapter: IDXGIAdapter1 = match factory.EnumAdapters1(adapter_idx) {
                    Ok(a) => a,
                    Err(_) => break,
                };

                let mut output_idx = 0u32;

                loop {
                    // Enumerate outputs for this adapter
                    let output: IDXGIOutput = match adapter.EnumOutputs(output_idx) {
                        Ok(o) => o,
                        Err(_) => break,
                    };

                    // Check if this is the display we want
                    let mut desc = Default::default();
                    output.GetDesc(&mut desc)?;

                    let name = String::from_utf16_lossy(
                        &desc.DeviceName[..desc.DeviceName.iter().position(|&c| c == 0).unwrap_or(desc.DeviceName.len())]
                    );

                    if name == display.name || desc.Monitor.0 as isize == display.handle {
                        return Ok((adapter, output));
                    }

                    output_idx += 1;
                }

                adapter_idx += 1;
            }

            // If we didn't find the specific display, use the first one
            let adapter: IDXGIAdapter1 = factory.EnumAdapters1(0)
                .context("No adapters found")?;
            let output: IDXGIOutput = adapter.EnumOutputs(0)
                .context("No outputs found")?;

            Ok((adapter, output))
        }
    }

    /// Create or get the staging texture for CPU access
    fn get_staging_texture(&mut self, src_texture: &ID3D11Texture2D) -> Result<&ID3D11Texture2D> {
        if self.staging_texture.is_none() {
            unsafe {
                let mut desc = D3D11_TEXTURE2D_DESC::default();
                src_texture.GetDesc(&mut desc);

                desc.Usage = D3D11_USAGE_STAGING;
                desc.BindFlags = Default::default();
                desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
                desc.MiscFlags = Default::default();

                let mut staging: Option<ID3D11Texture2D> = None;
                self.device.CreateTexture2D(&desc, None, Some(&mut staging))
                    .context("Failed to create staging texture")?;
                let staging = staging.context("Staging texture is None")?;

                // Set high priority
                let resource: IDXGIResource = staging.cast()?;
                resource.SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM.0)?;

                self.staging_texture = Some(staging);
            }
        }

        Ok(self.staging_texture.as_ref().unwrap())
    }

    /// Acquire the next frame from the desktop
    fn acquire_frame(&mut self, timeout_ms: u32) -> Result<Option<(ID3D11Texture2D, DXGI_OUTDUPL_FRAME_INFO)>> {
        unsafe {
            let mut frame_info = DXGI_OUTDUPL_FRAME_INFO::default();
            let mut desktop_resource: Option<IDXGIResource> = None;

            let result = self.duplication.AcquireNextFrame(
                timeout_ms,
                &mut frame_info,
                &mut desktop_resource,
            );

            match result {
                Ok(_) => {
                    let resource = desktop_resource.context("Desktop resource is None")?;

                    // Check if there's actually a new frame
                    if frame_info.LastPresentTime == 0 {
                        self.duplication.ReleaseFrame().ok();
                        return Ok(None);
                    }

                    let texture: ID3D11Texture2D = resource.cast()
                        .context("Failed to cast to ID3D11Texture2D")?;

                    Ok(Some((texture, frame_info)))
                }
                Err(e) if e.code() == DXGI_ERROR_WAIT_TIMEOUT => {
                    // No new frame available
                    Ok(None)
                }
                Err(e) if e.code() == DXGI_ERROR_ACCESS_LOST => {
                    // Desktop duplication was invalidated, need to recreate
                    tracing::warn!("Desktop duplication access lost, will need to recreate");
                    Err(anyhow::anyhow!("Access lost"))
                }
                Err(e) => {
                    Err(e).context("Failed to acquire frame")
                }
            }
        }
    }

    /// Copy frame data to CPU-accessible memory
    fn copy_frame_data(&mut self, texture: &ID3D11Texture2D) -> Result<Vec<u8>> {
        unsafe {
            // Get or create staging texture
            let staging = self.get_staging_texture(texture)?.clone();

            // Copy from GPU texture to staging texture
            self.context.CopyResource(&staging, texture);

            // Map the staging texture for CPU read
            let mut mapped = D3D11_MAPPED_SUBRESOURCE::default();
            self.context
                .Map(&staging, 0, D3D11_MAP_READ, 0, Some(&mut mapped))
                .context("Failed to map staging texture")?;

            // Copy pixel data
            let src_pitch = mapped.RowPitch as usize;
            let dst_pitch = (self.width * 4) as usize;
            let height = self.height as usize;

            let mut data = vec![0u8; dst_pitch * height];

            let src_ptr = mapped.pData as *const u8;
            for y in 0..height {
                let src_row = src_ptr.add(y * src_pitch);
                let dst_row = data.as_mut_ptr().add(y * dst_pitch);
                ptr::copy_nonoverlapping(src_row, dst_row, dst_pitch);
            }

            // Unmap
            self.context.Unmap(&staging, 0);

            Ok(data)
        }
    }

    /// Extract dirty rectangles from frame info
    fn extract_dirty_rects(&self, _frame_info: &DXGI_OUTDUPL_FRAME_INFO) -> Option<Vec<DirtyRect>> {
        // TODO: Implement dirty rectangle extraction using
        // IDXGIOutputDuplication::GetFrameDirtyRects and GetFrameMoveRects
        // For now, return None to indicate full frame update
        None
    }
}

impl Capturer for DxgiCapturer {
    fn capture(&mut self) -> Result<Option<CapturedFrame>> {
        // Try to acquire a frame with 100ms timeout
        let frame_result = self.acquire_frame(100)?;

        let (texture, frame_info) = match frame_result {
            Some((t, f)) => (t, f),
            None => return Ok(None), // No new frame
        };

        // Copy frame data to CPU memory
        let data = self.copy_frame_data(&texture)?;

        // Release the frame
        unsafe {
            self.duplication.ReleaseFrame().ok();
        }

        // Extract dirty rectangles if available
        let dirty_rects = self.extract_dirty_rects(&frame_info);

        Ok(Some(CapturedFrame {
            width: self.width,
            height: self.height,
            data,
            timestamp: Instant::now(),
            display_id: self.display.id,
            dirty_rects,
        }))
    }

    fn display(&self) -> &Display {
        &self.display
    }

    fn is_valid(&self) -> bool {
        // Could check if duplication is still valid
        true
    }
}

impl Drop for DxgiCapturer {
    fn drop(&mut self) {
        // Release any held frame
        unsafe {
            self.duplication.ReleaseFrame().ok();
        }
    }
}

-            let (adapter, output) = Self::find_adapter_output(&factory, display)?;

+            let (adapter, output) = Self::find_adapter_output(&factory, display_info)?;