0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

マウスを自動で移動してスクリーンセイバーの起動を抑制する

Last updated at Posted at 2022-01-30

概要

PowerShell の Class の手習いに「マウスふるふる」的なスクリプトを作成してみました。
実用向きというよりはお遊びのスクリプトですが、もし利用される場合はこちらの記事のスクリプトと組み合わせることをお薦めします。

特長

  • 手でマウスを動かした最後の位置を中心として、自動でマウスが移動します。
  • 連続した自動移動では慣性(前回移動の勢いみないなもの)を維持して曲線的に移動します。
  • 自動移動の大きさは正規分布に従います(たまに大きく動く)。

コード

mousejiggler.ps1
# by earthdiver1
##################
$linear   = $false  # マウスを常に直線的に移動する場合は $true に変更 
$std      =  100.0  # 最後に手でマウスを止めた場所を中心とした自動移動距離(縦・横)の標準偏差[pixel]
$int_minS =   1000  # マウスを手で動かしていない場合の、自動移動までの最小待機時間[msec]
$int_maxS =  10000  # マウスを手で動かしていない場合の、自動移動までの最大待機時間[msec]
$int_minL =  60000  # マウスを手で動かした場合の、自動移動までの最小待機時間[msec]
$int_maxL = 180000  # マウスを手で動かした場合の、自動移動までの最大待機時間[msec]
##################

Add-Type -A System.Drawing
Add-Type -A System.Windows.Forms
Add-Type -T @'
using System.Runtime.InteropServices;
public static class Win32 {
   [DllImport("user32.dll")]public extern static void mouse_event(int dwFlags,int dx,int dy,int dwData,int dwExtraInfo);
}
'@

iex @'
class myPoint {
   [double]$x
   [double]$y
   myPoint ([double]$x, [double]$y) { $this.x = $x      ; $this.y = $y      }
   myPoint ([double]$scalar)        { $this.x = $scalar ; $this.y = $scalar }
   myPoint ([Drawing.Point]$p)      { $this.x = $p.x    ; $this.y = $p.y    }
   [myPoint] Round()                { return [myPoint]::new([Math]::Round($this.x), [Math]::Round($this.y)) }
   [Drawing.Point] ToPoint()        { return [Drawing.Point]::new([int][Math]::Round($this.x), [int][Math]::Round($this.y)) }
   [bool] Equals([object]$other)    { return $this.x -eq $other.x -and $this.y -eq $other.y }
   static [myPoint] op_Addition    ([myPoint]$left, [myPoint]$right) { return [myPoint]::new($left.x + $right.x, $left.y + $right.y) }
   static [myPoint] op_Subtraction ([myPoint]$left, [myPoint]$right) { return [myPoint]::new($left.x - $right.x, $left.y - $right.y) }
   static [myPoint] op_Multiply    ([myPoint]$left, [myPoint]$right) { return [myPoint]::new($left.x * $right.x, $left.y * $right.y) }
   static [myPoint] op_Multiply    ([myPoint]$left, [double]$right)  { return [myPoint]::new($left.x * $right  , $left.y * $right  ) }
   static [myPoint] op_Implicit    ([double]$scalar)                 { return [double]$scalar }
}
'@

function Normal ($mu, $sigma) { 
   # 平均 $mu, 標準偏差 $sigma の(近似的な)正規分布に従う乱数を返す。
   return ((1..12 | %{ Get-Random -Minimum 0.0 -Maximum 1.0 } | Measure-Object -Sum).Sum - 6.0) * $sigma + $mu
}

function SmoothMove ($start, $end) {
   if ($inertia.x -eq -9999.0) {
      $bezier = ($start + $end) * 0.5
   } else {
      $bezier = $start + $inertia
   }
   for ( $i = 1; $i -le 50; $i++ ) {
      $t = $i/50
      $p = $start*(1-$t)*(1-$t) + $bezier*2*(1-$t)*$t + $end*$t*$t
      [Windows.Forms.Cursor]::Position = $p.ToPoint()
      [Win32]::mouse_event(0x0001, 0, 0, 0, 0)
      $before = [Windows.Forms.Cursor]::Position
      Microsoft.PowerShell.Utility\Start-Sleep -MilliSeconds 10
      $after = [Windows.Forms.Cursor]::Position
      if ($after -ne $before) { break }
      if ($i -eq 40) { $script:inertia = $end - $p }
   }
}

$epsilon = 5  # 許容誤差(振動などによってマウスが移動することを考慮)
$p_init  = [myPoint]::new(-9999.0, -9999.0)
$p_last  = $p_init

while ( $true ) {
   $p_now = [myPoint]::new([Windows.Forms.Cursor]::Position)
   if ([Math]::Abs($p_now.x - $p_last.x) -le $epsilon -and `
       [Math]::Abs($p_now.y - $p_last.y) -le $epsilon      ) {
      $p_new = ([myPoint]::new((Normal $p_base.x $std), (Normal $p_base.y $std))).Round()
      SmoothMove $p_now $p_new
      $p_last = [myPoint]::new([Windows.Forms.Cursor]::Position)
      if ($linear -or $p_last -ne $p_new) { $inertia = $p_init }
      $interval = Get-Random -Minimum $int_minS -Maximum $int_maxS
   } else {
      $p_base = $p_now
      $p_last = $p_now
      $inertia = $p_init
      $interval = Get-Random -Minimum $int_minL -Maximum $int_maxL
   }
   Start-Sleep -MilliSeconds $interval
}

備考

  • スクリプトの構文解析の時点(Add-Type コマンドレットの実行前)で Class定義が検証されて 「[Drawing.Point] の型がみつからない」というエラーが発生してしまうのを回避するために Class定義を iexInvoke-Expression)で実行しています1
  • 暗黙の型変換が邪魔をして、(両側の型が異なる場合の)演算子のオーバーローディングがうまく働かなかったのですが、op_Implicit メソッドの定義で暗黙の型変換を半ば強引に無効化することで回避できました(裏技?)。

 
クリエイティブ・コモンズ 表示 - 継承 4.0 国際

  1. 他のバージョンでは検証していませんが、少なくとも PowerShell 5.1では using assembly を使っても駄目なようです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?