Skip to content

Instantly share code, notes, and snippets.

@ttdoda
Last active November 15, 2018 11:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ttdoda/09f685bff1333c4393cde7b25887fca4 to your computer and use it in GitHub Desktop.
Save ttdoda/09f685bff1333c4393cde7b25887fca4 to your computer and use it in GitHub Desktop.
端末が落ちます (下方向に)
#!/usr/bin/env ruby
#
# fall.rb -- 端末が落ちます (下方向に)
#
# 対応端末:
# dttermのウィンドウ制御シーケンスに一通り対応していれば動くはず……だけど意外と少ないんだ、これが
# 手元で動作するのを確認したのは xterm, Tera Term, mintty の三つ
#
# License: CC0
#$gravity = 2.4
$gravity = 3
require 'timeout'
include Math
$stdout.sync = 1
def getCSIstr(t = 1)
resp = ""
Timeout.timeout(t) {
while c = $stdin.getc
case c.ord
when 0x1b
c = $stdin.getc
break if c.chr == "["
$stdin.ungetc c
when 0x9c
break
when 3, 4
return ""
when 0..0x1f
raise
end
end
while c = $stdin.getc
case c.ord
when 0x20..0x3f
resp << c.chr
when 0x40..0x7e
resp << c.chr
break
else
raise
end
end
}
resp
end
def moveTo(x, y)
print "\e[3;#{x.to_i};#{y.to_i}t"
end
def resizeTerm(h, w)
print "\e[8;#{h};#{w}t"
end
def getCurrentPosition
begin
system("stty raw -echo")
print "\e[13t"
case getCSIstr(0)
when ""
return [-1, -1]
when /(\d+)\;(\d+);(\d+)t/
raise unless $1 == "3"
else
raise
end
[$2.to_i, $3.to_i]
ensure
system("stty #{$saved_mode}")
end
end
def do_fall(x, y, maxY)
dirV = 0
begin
while true
y += dirV
if y > maxY
y = maxY
dirV /= 2
break if dirV <= 1
dirV = -dirV
elsif y < 0
y = 0
end
dirV += $gravity
moveTo x, y
sleep 0.02
end
end
end
maxX = 0
maxY = 0
termWidth = -1
termHeight = -1
origX = -1
origY = -1
$saved_mode = `stty -g`
begin
system("stty raw -echo")
print "\e[18t"
raise unless /(\d+)\;(\d+);(\d+)t/ =~ getCSIstr && $1 == "8"
termHeight = $2.to_i
termWidth = $3.to_i
print "\e[13t"
raise unless /(\d+)\;(\d+);(\d+)t/ =~ getCSIstr && $1 == "3"
origX = $2.to_i
origY = $3.to_i
resizeTerm 25, 81
print "\e[14t"
raise unless /(\d+)\;(\d+);(\d+)t/ =~ getCSIstr && $1 == "4"
tmpHeight = $2.to_i
tmpWidth = $3.to_i
resizeTerm 24, 80
print "\e[14t"
raise unless /(\d+)\;(\d+);(\d+)t/ =~ getCSIstr && $1 == "4"
winHeight = $2.to_i
winWidth = $3.to_i
cellHeight = tmpHeight - winHeight
cellWidth = tmpWidth - winWidth
print "\e[19t"
raise unless /(\d+)\;(\d+);(\d+)t/ =~ getCSIstr && $1 == "9"
rootHeight = $2.to_i * cellHeight
rootWidth = $3.to_i * cellWidth
maxY = rootHeight - winHeight
maxX = rootWidth - winWidth
rescue Timeout::Error, RuntimeError
puts "not supported terminal"
resizeTerm(termHeight, termWidth) if termHeight > 0 && termWidth > 0
moveTo(origX, origY) if origX >= 0 && origY >= 0
exit 1
ensure
system("stty #{$saved_mode}")
end
begin
do_fall(origX, origY, maxY)
while true
sleep 1
x, y = getCurrentPosition
break if x < 0
do_fall(x, y, maxY) if y != maxY
end
rescue Interrupt
exit 0
ensure
resizeTerm(termHeight, termWidth)
moveTo(origX, origY)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment