Skip to content

Instantly share code, notes, and snippets.

@penguin2716
Created March 8, 2012 05:16
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 penguin2716/1998867 to your computer and use it in GitHub Desktop.
Save penguin2716/1998867 to your computer and use it in GitHub Desktop.
MikutterSocketServerが動いてるmikutterにツイートを飛ばすmikutter大陸的なやつ
#!/usr/bin/env ruby
#-*- coding: utf-8 -*-
require 'gtk2'
require 'socket'
# mikutter_server.rb の "localhost" を "0.0.0.0" に変えると別のマシンからもアクセスできるよん
# ユーザ設定の読み込み
CONFIG = "#{ENV['HOME']}/.mikutterworldrc"
VALID_CONFIG = ['host', 'port', 'footer']
$host = 'localhost'
$port = 3939
$footer = ''
def loadUserConfig
if File.exists?(CONFIG)
f = open(CONFIG, "r")
f.each do |line|
VALID_CONFIG.each do |t|
if line =~ /^#{t}\s*=\s*'(.*)'/
case t
when 'host'
$host = $1
when 'port'
$port = $1.to_i
when 'footer'
$footer = $1
end
break
end
end
end
f.close
end
end
def setUserConfig
if File.exists?(CONFIG)
config = "#-*- coding: utf-8 -*-\n"
config += "host = '#{$host}'\n"
config += "port = '#{$port}'\n"
config += "footer = '#{$footer}'\n"
f = open(CONFIG, "w")
f.write(config)
f.close
end
end
module Gtk
class EmacsLikeTextView < Gtk::TextView
# @@hist_limit : 履歴スタックの最大保存数
# @@control_targetkey : Ctrlで装飾してEmacsっぽいキーバインドにするキー.
# 元から割り当てられていた機能は呼ばない.
# @@control_unselectkey : 選択トグルを自動的にOFFにするキー.
# @@post_history : ポスト履歴を保存するグローバルスタック
# @@post_history_ptr : ポスト履歴のスタックポインタ
# @select : 選択トグルのON/OFFを格納
# @history_stack : 履歴スタック
# @stack_ptr : 履歴スタックポインタ
# @isundo : undoによる変更かどうかの確認
@@hist_limit = 8000
@@control_targetkey = ['A', 'space', 'g', 'f', 'b', 'n', 'p', 'a',
'e', 'd', 'h', 'w', 'k', 'y', 'slash', 'z']
@@control_unselectkey = ['g', 'd', 'h', 'w', 'k', 'y', 'slash', 'z']
@@mod1_targetkey = ['f', 'b', 'a', 'e', 'w', 'd', 'h', 'n', 'p']
@@mod1_unselectkey = ['w', 'd', 'h', 'n', 'p']
@@post_history = []
@@post_history_ptr = 0
def initialize
super
@select = false
@history_stack = []
@history_stack.push(self.buffer.text)
@stack_ptr = 0
@isundo = false
# バッファが変更されたら自動的に履歴スタックに積む
self.buffer.signal_connect('changed') {
if not @isundo then
@history_stack += @history_stack[@stack_ptr..-2].reverse
self.push_buffer
@stack_ptr = @history_stack.length - 1
end
}
# キーバインドの追加
self.signal_connect('key_press_event') { |w, e|
if Gdk::Window::ModifierType::CONTROL_MASK ==
e.state & Gdk::Window::CONTROL_MASK and
Gdk::Keyval.to_name(e.keyval) == 'slash' then
@isundo = true
else
@isundo = false
end
# Mod1 による装飾
if Gdk::Window::ModifierType::MOD1_MASK ==
e.state & Gdk::Window::MOD1_MASK then
key = Gdk::Keyval.to_name(e.keyval)
# 選択トグルの解除
if @@mod1_unselectkey.select{|k| k == key}.length > 0 then
@select = false
end
case key
when 'f'
self.move_cursor(Gtk::MOVEMENT_WORDS, 1, @select)
when 'b'
self.move_cursor(Gtk::MOVEMENT_WORDS, -1, @select)
when 'a'
self.move_cursor(Gtk::MOVEMENT_BUFFER_ENDS, -1, @select )
when 'e'
self.move_cursor(Gtk::MOVEMENT_BUFFER_ENDS, 1, @select )
when 'd'
delete_from_cursor(Gtk::DELETE_WORD_ENDS, 1)
when 'h'
delete_from_cursor(Gtk::DELETE_WORD_ENDS, -1)
when 'w'
self.copy_clipboard
self.select_all(false)
when 'n'
self.redoGlobalStack
when 'p'
self.undoGlobalStack
end
# Emacsっぽいキーバインドとして実行したら,もとから割り当てられていた機能は呼ばない
if @@mod1_targetkey.select{|k| k == key}.length > 0 then
true
else
false
end
# Control による装飾
elsif Gdk::Window::ModifierType::CONTROL_MASK ==
e.state & Gdk::Window::CONTROL_MASK then
key = Gdk::Keyval.to_name(e.keyval)
# 選択トグルの解除
if @@control_unselectkey.select{|k| k == key}.length > 0 then
@select = false
end
case key
when 'A' # 全選択
self.select_all(true)
when 'space' # 選択トグルのON/OFF
if @select then
@select = false
else
@select = true
end
when 'g' # 選択解除
self.select_all(false)
when 'f' # 右に移動
self.move_cursor(Gtk::MOVEMENT_VISUAL_POSITIONS, 1, @select)
when 'b' # 左に移動
self.move_cursor(Gtk::MOVEMENT_VISUAL_POSITIONS, -1, @select)
when 'n' # 次の行に移動
self.move_cursor(Gtk::MOVEMENT_DISPLAY_LINES, 1, @select)
when 'p' # 前の行に移動
self.move_cursor(Gtk::MOVEMENT_DISPLAY_LINES, -1, @select)
when 'a' # 行頭へ移動
self.move_cursor(Gtk::MOVEMENT_PARAGRAPH_ENDS, -1, @select)
when 'e' # 行末へ移動
self.move_cursor(Gtk::MOVEMENT_PARAGRAPH_ENDS, 1, @select)
when 'd' # Deleteの挙動
self.delete_from_cursor(Gtk::DELETE_CHARS, 1)
when 'h' # BackSpaceの挙動
self.delete_from_cursor(Gtk::DELETE_CHARS, -1)
when 'w' # カット
self.cut_clipboard
when 'k' # 現在位置から行末までカット.行末の場合はDeleteの挙動になる
before = self.buffer.text
self.move_cursor(Gtk::MOVEMENT_PARAGRAPH_ENDS, 1, true)
self.cut_clipboard
if before == self.buffer.text then
self.delete_from_cursor(Gtk::DELETE_CHARS, 1)
end
when 'y' # 現在位置に貼り付け
self.paste_clipboard
when 'slash', 'z' # undoの挙動
self.undo
end
# Emacsっぽいキーバインドとして実行したら,もとから割り当てられていた機能は呼ばない
if @@control_targetkey.select{|k| k == key}.length > 0 then
true
else
false
end
end
}
end
# 現在のバッファと最新の履歴が異なっていればスタックに現在の状態を追加
def push_buffer
if @history_stack == nil then
@history_stack = ['']
end
if self.buffer.text != '' then
if @history_stack[-1] != self.buffer.text then
@history_stack.push(self.buffer.text)
end
if @history_stack.length > @@hist_limit then
@history_stack = @history_stack[(@history_stack.length - @@hist_limit)..-1]
end
end
end
# undoの実装.バッファの内容を変更すると自動的に履歴スタックに追加されるので,
# 履歴スタックに追加したら最新の履歴を捨てる
def undo
top = @history_stack[@stack_ptr]
if top != nil then
if top == self.buffer.text then
# 最新履歴が現在の状態と同じなら,2番目の履歴を参照
decStackPtr
second = @history_stack[@stack_ptr]
if second != nil then
self.buffer.set_text(second)
else # 上から2番目が空
self.buffer.set_text('')
end
else
self.buffer.set_text(top)
end
else # 履歴スタックが空
self.buffer.set_text('')
end
end
def incStackPtr
if @history_stack.length > @stack_ptr + 1 then
@stack_ptr += 1
end
end
def decStackPtr
if @stack_ptr > 0 then
@stack_ptr -= 1
end
end
# 初期状態にリセットする.現在は使っていない
def reset
@history_stack = []
@select = false
end
def pushGlobalStack
@@post_history_ptr = @@post_history.length
@@post_history.push(self.buffer.text)
end
def undoGlobalStack
if @@post_history != []
self.buffer.set_text(@@post_history[@@post_history_ptr])
@@post_history_ptr = (@@post_history_ptr - 1) % @@post_history.length
end
end
def redoGlobalStack
if @@post_history != []
self.buffer.set_text(@@post_history[@@post_history_ptr])
@@post_history_ptr = (@@post_history_ptr + 1) % @@post_history.length
end
end
end
end
loadUserConfig
dialog = Gtk::Dialog.new("mikutter大陸")
$etv = Gtk::EmacsLikeTextView.new
$etv.set_wrap_mode(Gtk::TextTag::WRAP_CHAR)
$footer_entry = Gtk::Entry.new
$host_entry = Gtk::Entry.new
$host_entry.set_width_chars(16)
$port_entry = Gtk::Entry.new
$port_entry.set_width_chars(6)
countLabel = Gtk::Label.new("140")
$etv.buffer.signal_connect('changed') {
countLabel.set_text( (140 - $etv.buffer.text.size - $footer_entry.text.size).to_s )
}
$footer_entry.signal_connect('changed') {
countLabel.set_text( (140 - $etv.buffer.text.size - $footer_entry.text.size).to_s )
}
$footer_entry.set_text($footer)
$host_entry.set_text($host)
$port_entry.set_text($port.to_s)
def saveConfig
$host = $host_entry.text
$port = $port_entry.text.to_i
$footer = $footer_entry.text
setUserConfig
end
def post(inputstr)
if(inputstr.length > 140)
inputstr = inputstr[0..139]
end
s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in($port_entry.text.to_i, $host_entry.text)
begin
s.connect(sockaddr)
s.write inputstr
s.close
saveConfig
Gtk.main_quit
rescue
$etv.buffer.set_text("error: Connection failed.\nType C-/ to recover message.")
end
end
dialog.signal_connect('key_press_event') { |w, e|
if Gdk::Keyval.to_name(e.keyval) == 'q' or
Gdk::Keyval.to_name(e.keyval) == 'Escape'
Gtk.main_quit
true
elsif Gdk::Window::ModifierType::CONTROL_MASK ==
e.state & Gdk::Window::CONTROL_MASK and
Gdk::Keyval.to_name(e.keyval) == 'Return'
inputstr = $etv.buffer.text + $footer_entry.text
post(inputstr)
else
false
end
}
dialog.signal_connect('destroy') {
Gtk.main_quit
}
send_button = Gtk::Button.new("Post")
save_button = Gtk::Button.new("Save")
send_button.signal_connect('clicked') do
inputstr = $etv.buffer.text + $footer_entry.text
post(inputstr)
end
save_button.signal_connect('clicked') do
saveConfig
end
hbox = Gtk::HBox.new(false, 5)\
.add(\
Gtk::VBox.new(false, 5)\
.add($etv)\
.pack_start(\
Gtk::HBox.new(false, 5)\
.pack_start(Gtk::Label.new("footer:"), false)\
.add($footer_entry), false)\
.pack_start(\
Gtk::HBox.new(false, 5)\
.pack_start(Gtk::Label.new("host:"), false)\
.add($host_entry)\
.pack_start(Gtk::Label.new("port:"), false)\
.add($port_entry)\
.pack_start(save_button, false)\
.pack_start(send_button, false)\
, false)\
)\
.pack_start(countLabel, false)
dialog.vbox.add(hbox)
dialog.vbox.show_all
dialog.show
dialog.set_size_request(250,150)
Gtk.main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment