소스 검색

less intrusive mouse and keyboard

Jariullah Safi 4 달 전
부모
커밋
e6e4272d4e
5개의 변경된 파일과 47개의 추가작업 그리고 7개의 파일을 삭제
  1. 10 7
      ARCHITECTURE.md
  2. 1 0
      OpenPuck/controllers.h
  3. 33 0
      OpenPuck/puck_hid.cpp
  4. 1 0
      OpenPuck/puck_hid.h
  5. 2 0
      OpenPuck/rf_link.cpp

+ 10 - 7
ARCHITECTURE.md

@@ -211,13 +211,16 @@ Waking the host is an **explicit gesture, never a side effect of input**. While
 personality sends *nothing* (no `0x45` forwards, no lizard mouse/keyboard, no periodic `0x79`/`0x7B` status) —
 a suspended-bus `sendReport` can itself translate into a host wake, which made the PC wake on any trackpad
 graze and nearly impossible to keep asleep. The only wake triggers are a **Steam-button short press** or a
-**controller connect**, detected in `rf_link.cpp` (guarded by `USBDevice.suspended()`), which call
-`USBDevice.remoteWakeup()` — the device-level USB resume signal.
-
-(An earlier build also injected a post-resume "nudge" — a synthetic space-bar + mouse click on the puck's own
-HID reports — on the theory that some hosts ignore a bare resume. It was removed: once the wake-mouse interface
-gave the device a wait-wake-armed `mouhid` function the resume alone is honored, and the synthetic input had
-side effects on the host, e.g. landing on the desktop/taskbar after wake and launching apps.)
+**controller connect**, detected in `rf_link.cpp` (guarded by `USBDevice.suspended()`). Each fires two things:
+
+1. `USBDevice.remoteWakeup()` — the device-level USB resume signal; and
+2. `g_active->wakeEvent()` — queues a **wake nudge**, because a bare resume signal is **not** enough to wake
+   some hosts (Windows especially): they only wake when real keyboard/mouse input *follows* the resume. Once
+   the bus is back up, the puck personality plays a HARMLESS nudge on its own reports (`wakeNudgeTask` in
+   `puck_hid.cpp`): a **mouse jiggle** (move a few px and back, no button) + a lone **Left-Ctrl tap**. It can't
+   be sent *during* suspend (reports can't cross a suspended bus), so it's delivered right after resume.
+   (It originally sent a left *click* + *space*, which woke the host but also clicked/activated whatever was
+   focused — it kept launching the browser. Move + modifier wake just as well with no actionable side effect.)
 
 The board LED is a wake debugger (`status_led.cpp`): dark in all steady states (including while armed), and a
 500 ms flash at the moment a `remoteWakeup()` is actually sent. Flash + host stays asleep = the resume was sent

+ 1 - 0
OpenPuck/controllers.h

@@ -23,6 +23,7 @@ public:
   virtual void begin() = 0;
   virtual void onReport45(const uint8_t* rep, bool fresh, uint8_t bodyTlen) { (void)rep; (void)fresh; (void)bodyTlen; }
   virtual void task() {}
+  virtual void wakeEvent() {}   // a wake gesture fired while suspended; queue any post-resume input the host needs to actually wake
   virtual bool isPuck() const { return false; }
 };
 

+ 33 - 0
OpenPuck/puck_hid.cpp

@@ -191,10 +191,43 @@ void SteamPuckController::onReport45(const uint8_t* rep, bool fresh, uint8_t bod
   }
 }
 
+// ---- wake nudge: real HID input delivered right after the bus resumes. A bare USB resume signal is NOT
+// enough to wake some hosts (Windows in particular) -- they only wake when actual keyboard/mouse input
+// follows. So on a deliberate wake gesture we play a HARMLESS nudge on the puck's own kb/mouse reports:
+// a mouse JIGGLE (move a few px and back, NO button) + a lone Left-Ctrl tap. Earlier this sent a left CLICK
+// and SPACE, which woke the host but also clicked/activated whatever was focused (it kept launching the
+// browser). Move + modifier wake just as well with no actionable side effect. Queued by wakeEvent() (called
+// from rf_link on a Steam-button short press / controller connect while suspended); stepped ~15ms per phase.
+// Reports can't cross a suspended bus, so it's delivered once the bus has resumed.
+static uint8_t       g_nudgeStep = 0;      // 0=idle; 1=jiggle+, 2=jiggle-, 3=Ctrl down, 4=Ctrl up
+static unsigned long g_nudgeMs = 0;
+#define NUDGE_JIGGLE_PX 10
+void SteamPuckController::wakeEvent(){
+  g_nudgeStep = 1; g_nudgeMs = millis();
+}
+static void wakeNudgeTask(){
+  if(!g_nudgeStep) return;
+  if(millis()-g_nudgeMs > 5000){ g_nudgeStep=0; return; }            // bus never resumed -> drop the nudge
+  if(USBDevice.suspended()) return;                                   // wait for resume; reports can't cross a suspended bus
+  if(g_connSlot<0 || g_connSlot>=NSLOT || !hid[g_connSlot].ready()) return;
+  static unsigned long stepMs=0;
+  if(millis()-stepMs < 15) return;                                    // pace the edges
+  stepMs=millis();
+  switch(g_nudgeStep){
+    case 1: case 2: {   // mouse jiggle: move +N then -N (net zero cursor), no buttons -> wakes, clicks nothing
+      hid_mouse_report_t m; m.buttons=0; m.x=(g_nudgeStep==1)?NUDGE_JIGGLE_PX:-NUDGE_JIGGLE_PX; m.y=0; m.wheel=0; m.pan=0;
+      hid[g_connSlot].sendReport(0x40,&m,sizeof m); break; }
+    case 3: { uint8_t k[8]={KEYBOARD_MODIFIER_LEFTCTRL,0,0,0,0,0,0,0}; hid[g_connSlot].sendReport(0x41,k,8); break; }  // lone modifier: inert
+    case 4: { uint8_t k[8]={0,0,0,0,0,0,0,0};                         hid[g_connSlot].sendReport(0x41,k,8); break; }  // release
+  }
+  g_nudgeStep = (g_nudgeStep>=4) ? 0 : (uint8_t)(g_nudgeStep+1);
+}
+
 // USB connection presentation (like the real dongle): report 0x79 = connection state (01=disc, 02=conn),
 // edge-triggered, + periodic 0x7B status. Live-captured: this is what Steam reads to mark the controller
 // connected. Without it Steam shows disconnected even though 0x45 input is streaming.
 void SteamPuckController::task(){
+  wakeNudgeTask();
   if (USBDevice.suspended()) return;   // no periodic 0x79/0x7B while the host sleeps -- those sends can wake it too
   static bool usbConn=false; static unsigned long last79=0, last7B=0;
   bool conn = (g_connSlot>=0 && millis()-g_connReplyMs < 300);

+ 1 - 0
OpenPuck/puck_hid.h

@@ -22,6 +22,7 @@ public:
   void begin() override;
   void onReport45(const uint8_t* rep, bool fresh, uint8_t bodyTlen) override;
   void task() override;
+  void wakeEvent() override;   // queue the harmless post-resume wake nudge (mouse jiggle + Ctrl tap)
   bool isPuck() const override { return true; }
 };
 extern SteamPuckController g_steamPuck;

+ 2 - 0
OpenPuck/rf_link.cpp

@@ -156,6 +156,7 @@ uint8_t rfConnTx(uint8_t ch, uint8_t s1, const uint8_t* payload, uint8_t plen){
                 if(steamNow && !steamWasDown) steamDownMs=millis();                                                            // rising edge: record press time
                 if(!steamNow && steamWasDown && millis()-steamDownMs<1000u && USBDevice.suspended()){                          // falling edge within 1 s -> short press -> wake
                   USBDevice.remoteWakeup(); ledWakePulse();
+                  if(g_active) g_active->wakeEvent();   // post-resume nudge (host needs real input to actually wake)
                 }
                 steamWasDown=steamNow;
               }
@@ -254,6 +255,7 @@ void rfLinkTask(){
     bool nowRfConn=(g_connSlot>=0 && millis()-g_connReplyMs<300);
     if(nowRfConn && !wasRfConn && USBDevice.suspended()){
       USBDevice.remoteWakeup(); ledWakePulse();
+      if(g_active) g_active->wakeEvent();   // post-resume nudge (host needs real input to actually wake)
     }
     wasRfConn=nowRfConn;
   }