Elmord's Magic Valley

Software, lingüística e rock'n'roll. Sometimes in English.

Gambiarras LaTeXísticas

2014-12-18 00:25 -0200. Tags: comp, latex, mundane

Neste post apresento duas pequenas gambiarras que eu descobri durante a confecção do meu PEP e TI.

Inserindo recortes de PDFs como figuras

O comando \includegraphics do pacote graphicx permite inserir imagens em diversos formatos, incluindo PDF. (Para usar o comando, inclua \usepackage{graphicx} no começo do seu documento LaTeX. O graphicx vem no pacote texlive-latex-base no Debian.) Por ser um formato de imagem vetorial, a qualidade do resultado normalmente é melhor do que incluir um PNG ou similar. Além disso, o \includegraphics permite inserir "recortes" do PDF, usando as opções page, clip e trim. Por exemplo, você pode usar algo como o seguinte trecho para recortar uma figura de um PDF existente e inseri-la como uma figura no documento atual:

\begin{figure}
\centering
\includegraphics[page=4,clip=true,trim=4cm 20.5cm 4cm 5cm]{arquivofeliz.pdf}
\caption{Gráfico roubado de \cite{fulano-et-al-2014}}
\label{graph1}
\end{figure}

page especifica a página do PDF, clip=true habilita o recorte, e trim consiste de quatro tamanhos especificando quanto se deseja cortar fora da esquerda, de baixo, da direita, e de cima da página, nessa ordem (i.e., em sentido anti-horário começando da esquerda). Acertar os valores de trim exige um pouco de tentativa e erro. Além disso, é possível especificar parâmetros como width=15cm para redimensionar a figura. Mais informações aqui.

Isso é útil para incluir figuras de outros documentos, ou para exportar gráficos, tabelas e afins de outros programas para o LaTeX, já que muitos programas são capazes de imprimir/exportar para PDF. Você pode usar isso para importar tabelas do Open/LibreOffice Calc, por exemplo.

Citation needed

Às vezes as abreviações/reformatações de nomes de autor no BibTeX falham miseravelmente. Por exemplo, se você tiver no seu arquivo .bib algo como:

@ELECTRONIC{rust,
  title = {The Rust Reference},
  author = {The Rust Project Developers},
  year = {2014},
  howpublished = {\url{http://doc.rust-lang.org/reference.html}},
  note = {Accessed in December 2014}
}

no estilo de bibliografia abnt-ufrgs (e, presumivelmente, no abntex também), a referência fica como "DEVELOPERS, T. R. P". Se você trocar por author = {Rust Project Developers, The}, a referência fica como "RUST PROJECT DEVELOPERS, T.". Provavelmente existe um jeito bonito e elegante de contornar esse problema, mas a solução suja que eu encontrei foi que se o nome do autor for colocado entre (mais um par de) chaves, ele é usado literalmente na referência (mantendo maiúsculas e minúsculas inclusive). Assim, podemos usar:

@ELECTRONIC{rust,
  title = {The Rust Reference},
  author = {{RUST PROJECT DEVELOPERS, The}},
  year = {2014},
  howpublished = {\url{http://doc.rust-lang.org/reference.html}},
  note = {Accessed in December 2014}
}

para obter o resultado desejado. Só tem um problema: agora as referências inline com \citep{rust} e companhia aparecem como "(RUST PROJECT DEVELOPERS, The, 2014)". A solução suja que eu encontrei foi definir um alias de citação:

\defcitealias{rust}{RUST, 2014}

e citar usando \citepalias ao invés de \citep (ou \citetalias para não incluir os parênteses (mas os detalhes dependem do bibliography style usado, acho)).

(Disclaimer: talvez as normas da ABNT realmente requeiram "RUST PROJECT DEVELOPERS" ao invés de meramente "RUST" na citação, mas não fui atrás para descobrir. De qualquer forma, imagino que o "The" não deva ser incluso.)

Happy kludging.

1 comentário

My very brief affair with Btrfs

2014-09-14 01:38 -0300. Tags: comp, unix, mundane, ramble

Meia dúzia de dias atrás eu migrei meu / para Btrfs. Hoje eu reformatei a partição como ext4 e recuperei meu backup do / da semana passada.

O causo foi assim. Para usar o Btrfs, eu atualizei meu kernel para o 3.16, já que diversas melhorias foram realizadas no suporte a Btrfs nessa versão. Porém, o driver da minha placa de rede wireless (o broadcom-sta) andava não se comportando muito bem, o iwconfig hoje resolveu não listar nenhuma rede, e eu resolvi bootar com o meu kernel 3.14 anterior para ver se a situação melhorava. (Na verdade, com a atualização do kernel 3.2 para 3.14, que eu fiz para poder usar o Btrfs, eu tive que substituir o broadcom-sta da stable pelo da testing, e desde então ele já andava com uns comportamentos desagradáveis (tais como emitir um trace sempre que a wi-fi era iniciada), mas aparentemente a wi-fi estava funcionando corretamente mesmo assim.) Até aí, tudo transcorreu normalmente. Kernel 3.14 bootado, wi-fi funcionando, todos comemora.

Eis que eu fui abrir o aptitude (já não lembro mais por que motivo), e o módulo do Btrfs capota, emitindo algum erro sobre quotas/qgroups. Reiniciei a máquina com o kernel 3.14, fui abrir o aptitude de novo, mesmo erro. Agora não lembro mais a seqüência exata das ações, mas em algum momento eu desativei o suporte a quotas (btrfs quota disable /), abri o aptitude de novo, e dessa vez ele abriu. Porém, turns out que, no piripaque do filesystem, meu /var/lib/dpkg/status virou um arquivo vazio, e o aptitude abriu me mostrando nenhum pacote instalado e me oferecendo para baixar 3GB de pacotes (i.e., todos os pacotes que eu tinha na máquina). Nesse momento eu me disse "well, fuck", reformatei o / como ext4 e recuperei o backup que eu tinha feito quando fui migrar para Btrfs (que por sorte eu ainda não tinha apagado).

Moral da história: Talvez se eu tivesse me mantido usando o kernel 3.16 eu não tivesse tido esse problema. Porém, depois dessa experiência, e dado que na atual conjuntura eu deveria estar me preocupando com o mestrado e não com a saúde do meu filesystem, eu prefiro esperar mais uns meses para ver se o Btrfs fica mais estável e experimentá-lo de novo. Enquanto isso, eu voltei para o kernel 3.2 da stable, que pode não ser new and shiny, mas é sólido como uma rocha, forte como um touro e pesado como uma porpeta.

3 comentários

Partição de sistema Btrfs no Debian

2014-09-12 03:03 -0300. Tags: comp, unix, mundane

Btrfs é um sistema de arquivos relativamente "recente" (o desenvolvimento começou em 2008) com um bocado de features interessantes. Neste post, falarei uma porção de coisas sobre como usar uma partição Btrfs como sistema de arquivos raiz no Debian. O Btrfs ainda é considerado experimental (embora seja bastante estável em kernels recentes), e eu não confiaria meus arquivos pessoais a ele no momento (meu /home é uma partição ext4), mas como sistema de arquivos raiz de uma máquina de uso pessoal (que se eu perder é só reinstalar), acredito que os benefícios compensam os riscos.

[Update: Aparentemente ele não é tão estável assim.]

E que benefícios são esses?

A principal razão pela qual eu migrei meu / para Btrfs foi para usar sua feature de snapshots, que permite criar uma "duplicata" do estado do sistema de arquivos em um dado momento. A criação de um snapshot não duplica os arquivos; ao invés disso, os arquivos são compartilhados entre as duas "versões" do sistema de arquivos, e só são copiados à medida em que são modificados, o que torna a criação do snapshot praticamente instantânea e não consome espaço desnecessariamente. Com isso você pode, por exemplo, tirar um snapshot do /, atualizar/bagunçar o sistema e, se alguma coisa der errado, voltar ao estado anterior são e salvo.

Requisitos mínimos

Kernel 3.14 ou superior. O suporte a Btrfs do kernel atual (3.2) do Debian stable é bastante precário (eu consegui derrubar ele com um for ((i=0; ; i++)); do mkdir $i; done em um filesystem recém criado). As opções são:

btrfs-tools 3.14 ou superior. Disponível tanto no repositório da backports quanto no da unstable.

Adaptando o initramfs

Para poder bootar a partir de um raiz Btrfs, você precisará adicionar suporte ao filesystem ao seu initramfs. Para isso, adicione as seguintes linhas ao /etc/initramfs-tools/modules:

crc32c
btrfs

e execute update-initramfs -u -k all.

A linha crc32c é particularmente relevante: Geralmente, o update-initramfs é esperto o suficiente para incluir junto com um módulo todas as suas dependências no initramfs. Porém, por um bug no módulo btrfs, ele não indica explicitamente sua dependência pelo módulo crc32c. Se o módulo crc32c não for incluído manualmente na lista, a carga do módulo btrfs falhará no boot, com uma mensagem do tipo can't load module btrfs (kernel/fs/btrfs/btrfs.ko): unknown symbol in module, or unknown parameter. (Isso me tomou uma boa hora de sofrimento.)

Migrando para Btrfs

Para transformar seu raiz em Btrfs, você precisará bootar com um outro sistema e seguir uma de duas rotas:

Antes de reiniciar

Antes de rebootar o sistema no filesystem recém criado, lembre-se de altarar o etc/fstab do sistema. Você poderá ter que trocar:

Se o seu /boot fica dentro na mesma partição que o raiz, você pode ter que fazer alguma mudança no seu gerenciador de boot para garantir que ele consiga ler o Btrfs. O GRUB 2 aparentemente consegue ler Btrfs sem problemas. (Eu ainda uso o bom e velho GRUB 0.97, mas meu /boot é uma partição ext2 separada.)

Subvolumes e snapshots

O Btrfs organiza o filesystem em subvolumes. Inicialmente, o filesystem contém apenas um "subvolume raiz", mas outros subvolumes podem ser criados com o comando btrfs subvolume create /caminho/novo-nome, onde /caminho é um diretório dentro do filesystem de interesse. btrfs subvolume list /caminho lista todos os subvolumes (e respectivos IDs) contidos em um filesystem.

O comando btrfs subvolume snapshot /caminho-subvol-origem /caminho-subvol-destino duplica um subvolume, i.e., cria um "snapshot". Depois da duplicação, os dois subvolumes são independentes: alterações em um não se refletem no outro.

Um filesystem Btrfs possui um subvolume padrão, i.e., o subvolume que é usado como raiz do filesystem se nenhum outro for especificado. Inicialmente, o "subvolume raiz" é o padrão, mas você pode usar o comando btrfs subvolume set-default ID /caminho (onde ID é o ID mostrado por btrfs subvolume list) para escolher outro. Com isso você pode setar o subvolume padrão para um snapshot com um estado anterior do sistema, por exemplo, reiniciar a máquina, e magicamente seu sistema volta a ser o que era no momento do snapshot.

Você pode montar um subvolume diferente do padrão passando a opção -o subvolid=ID para o comando mount. -o subvolid=0 monta o subvolume raiz original. Você pode montar a mesma partição mais de uma vez.

Como eu mencionei antes, ao invés de copiar o backup do sistema diretamente para o raiz da nova partição, pode ser mais conveniente criar um subvolume primeiro, especialmente se você pretende usar a feature de snapshots com freqüência. Por exemplo, ao criar o filesystem:

# mount /dev/xxx /mnt/sistema
# cp -avx /mnt/sistema /algum/lugar/backup
# umount /mnt/sistema
# mkfs.btrfs -f /dev/xxx
# mount /dev/xxx /mnt/sistema
# btrfs subvolume create /mnt/sistema/current
# btrfs subvolume list /mnt/sistema
ID 264 gen 142 top level 5 path current
# btrfs subvolume set-default 264 /mnt/sistema
# cp -avx /algum/lugar/backup/* /mnt/sistema/current
# (realize as adaptações pré-boot adequadas)

Com o subvolume padrão setado, você pode reiniciar e bootar o sistema novo normalmente. Quando você quiser fazer um snapshot, basta montar o raiz original em algum lugar (e.g., /mnt/root) e fazer as operações de interesse:

# mount -o subvolid=0 /dev/xxx /mnt/root
# btrfs subvolume snapshot /mnt/root/current /mnt/root/snapshot-20120912
# umount /mnt/root

Feito isso, você pode bagunçar com seu sistema à vontade e, se quiser voltar atrás, pode executar:

btrfs subvolume set-default ID-do-snapshot

e reiniciar a partir do snapshot. Ou, se preferir não alterar o snapshot, você pode duplicá-lo primeiro e reiniciar pela cópia:

# mount -o subvolid=0 /dev/xxx /mnt/root
# btrfs subvolume snapshot /mnt/root/snapshot-20120912 /mnt/root/current2
# btrfs subvolume list /mnt/root
ID 264 gen 142 top level 5 path current
ID 266 gen 142 top level 5 path snapshot-20120912
ID 268 gen 142 top level 5 path current2
# btrfs subvolume set-default 268 /mnt/root
# reboot

Lembre-se de depois apagar o current antigo (com btrfs subvolume delete /mnt/root/current), caso não queira que ele fique ocupando espaço para sempre.

A vantagem de criar um subvolume primeiro antes de copiar o sistema é deixar o subvolume raiz original contendo apenas subvolumes, evitando misturar subvolumes e arquivos de sistema no mesmo nível. Isso permite manipular todos os subvolumes/snapshots da mesma maneira (qualquer versão do sistema pode ser apagada facilmente, por exemplo; com o sistema no raiz original isso não seria possível).

Observações sortidas

O utilitário btrfs permite abreviar comandos, desde que as abreviações não sejam ambíguas. Por exemplo, btrfs subvolume list / pode ser escrito como btrfs sub l /.

Espaço usado e livre em Btrfs são conceitos um tanto quanto curiosos, devido ao mecanismo de copy-on-write, suporte a compressão e outras peculiaridades do Btrfs. O comando btrfs filesystem df /caminho pode dar um resultado mais preciso do que o df -h.

Descobrir o espaço utilizado por cada subvolume é uma questão mais complicada (até porque subvolumes podem compartilhar dados). Se o mecanismo de quotas for habilitado no subvolume raiz original (com o comando btrfs quota enable /mnt/root), é possível usar o comando btrfs qgroup show /, que lista a quantidade de dados apontada por cada subvolume e a quantidade de dados não compartilhada com nenhum outro subvolume (e que portanto seria liberada se o subvolume fosse apagado). Para mais informações, dê uma olhada neste artigo.

É possível criar um snapshot somente-leitura passando a opção -r para o comando btrfs subvolume snapshot. A vantagem é que é mais difícil de destruir um backup do sistema assim. A desvantagem é que não é mais possível bootar pelo snapshot como se fosse um sistema comum.

2 comentários

Zoom lento no MPlayer

2013-08-27 23:52 -0300. Tags: comp, unix, mundane

Esses dias fui assistir um filme com uma resolução maior do que a minha tela com o mplayer e meu Atom não estava dando conta de fazer o zoom out/scaling em tempo real.

Solução? O mplayer suporta uma opção -sws N, que permite escolher o algoritmo de software scaling a ser usado. Usando -sws 4, obtém-se um zoom de qualidade levemente pior, mas que consome menos processamento.

Outra opção útil é -autosync N, que controla a sincronia entre áudio e vídeo. A documentação do mplayer recomenda -autosync 30 para resolver problemas de sincronia com drivers de áudio problemáticos. No meu caso, -autosync 1 pareceu funcionar melhor. Não sei exatamente o que faz essa opção, sinceramente. Para mais informações, consulte a manpage do mplayer.

Quem me contou foi esse cara.

1 comentário

Determinando a posição do cursor em um arquivo com o lsof

2013-07-18 23:21 -0300. Tags: comp, unix, mundane

Às vezes executamos comandos do tipo:

cat imagem_grande_que_demora_para_copiar.img >/dev/sdb

e queremos saber o andamento do processo. Quando copiamos os dados de um disco para um arquivo podemos simplesmente olhar o tamanho do arquivo para ter uma idéia do andamento da operação, mas quando o destino é um disco isso não é possível.

É possível, entretanto, olhar a posição do cursor no arquivo. No Unix, todo arquivo aberto tem associado a si um cursor, i.e., a posição a partir da qual operações de leitura e escrita operam por padrão; cada leitura ou escrita no arquivo avança a posição do cursor.

Podemos utilizar um programinha chamado lsof (list open files, pacote lsof no Debian/Ubuntu) para visualizar diversas informações sobre arquivos abertos, dentre elas a posição do cursor. Por padrão, o lsof mostra uma coluna que contém ou a posição do cursor ou o tamanho do arquivo, dependendo do tipo de arquivo; a opção -o (offset) força o lsof a mostrar sempre o cursor. Além disso, por padrão o lsof mostra a posição em hexadecimal se ela ocupar mais de 8 dígitos decimais; a opção -o 0 desabilita esse comportamento. As duas opções podem ser combinadas como -oo0.

Por padrão, todos os arquivos abertos são listados. É possível especificar os nomes dos arquivos a serem listados, ou os nomes (-c nome) ou PIDs (-p pid) dos processos cujos arquivos abertos se deseja ver. Por exemplo:

# cat /dev/sda5 >/dev/sda6 &
[1] 28252
# lsof -oo0 /dev/sda6
COMMAND   PID USER   FD   TYPE DEVICE      OFFSET NODE NAME
cat     28252 root    1w   BLK    8,6 0t254476288 1303 /dev/sda6

Para mais informações, consulte a manpage do lsof.

Appendix A: Do fato de que ninguém deveria usar dd para copiar discos sem uma boa razão

# ls -lah foo
-rw-r--r-- 1 root root 512M Jul 18 23:00 foo
# time cat foo >bar

real    0m21.304s
user    0m0.068s
sys     0m5.212s
# time dd if=foo of=bar
1048576+0 records in
1048576+0 records out
536870912 bytes (537 MB) copied, 39.397 s, 13.6 MB/s

real    0m39.621s
user    0m1.528s
sys     0m25.910s

O motivo para isso é que o dd sempre copia os arquivos usando um tamanho de bloco fixo (indicado pelo parâmetro bs=tamanho, 512 bytes por padrão), enquanto o cat usa um tamanho de bloco "ótimo", o que permite que ele faça a cópia com menos chamadas de sistema (o que se reflete no tempo de sys na saída do comando time). Alternativamente, você pode especificar um tamanho de bloco maior para o dd (e.g., bs=1M), mas isso não apresenta nenhuma vantagem sobre usar o cat, a menos que você queira especificar o tamanho do arquivo também (e.g., no clássico dd if=/dev/zero of=foo bs=1M count=512 (que no entanto também pode ser substituído por um head -c 512M /dev/zero >foo)).

1 comentário

Gravando áudio e eliminando ruído com o SoX

2013-04-26 19:52 -0300. Tags: comp, unix, audio, mundane

O SoX (SOund eXchange; pacotes sox e libsox-fmt-all no Debian) é uma biblioteca e um programa de linha de comando que permitem converter entre diversos formatos de arquivo de áudio, opcionalmente aplicando filtros. A sintaxe básica do comando sox é:

sox [opções-globais]
    [opções-de-formato] entrada1
    [[opções-de-formato] entrada2 ...]
    [opções-de-formato] saída
    [filtros ...]

Por exemplo, para gravar do microfone (usando ALSA) em um arquivo WAV:

sox -t alsa default -t wav blabla.wav

(Use Control-C para terminar a gravação. Tecnicamente o -t wav pode ser omitido, já que o sox é capaz de deduzir o formato do arquivo pela extensão.)

Um par de filtros particularmente interessante é o noiseprof/noisered, que permitem eliminar ou reduzir ruído constante de fundo. Isso é feito em duas etapas. Primeiro, executa-se o sox com o filtro noiseprof [profile.txt] sobre uma "amostra de silêncio", i.e., um trecho de áudio que consista apenas do ruído de fundo, de maneira a produzir um profile de ruído. Você pode capturar o "silêncio" do microfone ou de algum outro arquivo que consista apenas de silêncio (a opção --null pode ser usada no lugar do arquivo de saída, já que estamos interessados apenas no profile de ruído):

sox -t alsa default --null noiseprof profile.txt

sox algum-arquivo-que-consista-apenas-de-silêncio.wav --null noiseprof profile.txt

Alternativamente, você pode selecionar um trecho de um arquivo com o filtro trim início [duração] e usá-lo como fonte de silêncio:

# Seleciona o intervalo de de 1s até 2.5s. Aqui usamos '-t alsa default' como
# saída para podermos ouvir se o trecho selecionado de fato corresponde a "silêncio".

sox entrada.wav -t alsa default trim 1 1.5 noiseprof profile.txt

Se o nome do arquivo de profile for omitido, o sox escreve o profile na stdout.

Gerado o profile de ruído, podemos usar o filtro noisered [profile.txt [quantidade]] para remover o ruído do arquivo completo. quantidade é um número entre 0 e 1 indicando a quantidade de ruído que deve ser removida. Quanto maior o número, mais ruído será removido – e mais não-ruído também. Experimente com números pequenos (e.g., 0, 0.05, 0.1, etc.) primeiro.

sox entrada.wav saída.wav noisered profile.txt 0.05

Se você tem um microfone problemático, você pode querer guardar o arquivo de profile para usos futuros (assumindo que o padrão de ruído produzido seja sempre o mesmo).

Se o arquivo de entrada para o noisered não for especificado ou for -, o sox lê o profile da stdin. Assim, você pode combinar o profiling e a redução em um pipeline:

sox entrada.wav --null trim 0 1 noiseprof | sox entrada.wav saída.wav noisered - 0.05

Para mais informações, consulte a manpage do sox.

2 comentários

Convertendo arquivos com o LibreOffice pela linha de comando

2013-03-08 02:04 -0300. Tags: comp, unix, mundane

Acabei de descobrir que é possível converter entre os formatos de documento suportados pelo LibreOffice/OpenOffice pela linha de comando. A sintaxe é:

libreoffice --invisible --convert-to extensão[:nome-do-filtro]
            [--outdir diretório-de-saída] arquivo...

Mais de um arquivo pode ser especificado. Se o diretório de saída for omitido, o diretório atual é utilizado. --invisible faz com que a interface gráfica não seja carregada. Por exemplo, para converter uma apresentação em ODP para PDF, você pode usar o comando:

libreoffice --convert-to pdf apresentacao-feliz.odp

Quem me contou foi esse cara (e a manpage do libreoffice). Também existe um programa chamado unoconv, mas não cheguei a experimentá-lo.

Comentários

Múltiplos keymaps no X

2013-02-09 03:50 -0200. Tags: comp, unix, mundane, kbd

(O script desenvolvido neste post pode ser encontrado aqui.)

Em um episódio anterior deste blog, vimos como usar o xmodmap para alterar o keymap do X. Também vimos que embora o xmodmap seja muito mais simples de usar do que o XKB, ele está semi-obsoleto e não lida muito bem com certos recursos mais modernos do XKB. Recentemente eu descobri mais um: o xmodmap não funciona direito com múltiplos teclados (e.g., um teclado builtin de notebook e um teclado externo). Especificamente:

  1. O xmodmap altera os layouts de todos os teclados conectados; não é possível atribuir um layout US para um teclado e um ABNT-2 para outro, por exemplo;
  2. O xmodmap altera apenas os layouts dos teclados conectados; se você ligar um novo teclado, ele assumirá o layout default, e você terá que rodar o xmodmap novamente para afetá-lo.

Sendo assim, temos dois problemas a resolver: detectar quando um teclado é conectado (o que independe de usarmos xmodmap ou XKB), e atribuir um layout a ele (o que exige o XKB se quisermos usar um layout específico para cada teclado; se quisermos apenas propagar o layout corrente para o novo teclado, podemos usar o xmodmap).

Detectando o teclado

A maneira mais palatável que eu encontrei de detectar o teclado* é monitorando o arquivo de log do X (/var/log/Xorg.n.log, onde n é o número do display). As linhas relevantes do arquivo têm a forma:

[ 10848.216] (II) XINPUT: Adding extended input device "GASIA GASIA USB KB Pro" (type: KEYBOARD)

Podemos fazer um script que monitora esse arquivo com o comando tail -f, filtra apenas os dados que nos interessam, e fica em um laço aguardando que novas linhas sejam escritas no arquivo:

#!/bin/bash

[[ $DISPLAY == :* ]] || echo "$0: Oops, remote display?" >&2
display="${DISPLAY##*:}"
display="${display%%.*}"

logfile="/var/log/Xorg.$display.log"

tail -n +1 -f "$logfile" |
    sed -une 's/.*XINPUT: Adding extended input device "\([^"]*\)" (type: \([^)]*\)).*/\2\t\1/p' |
    while IFS=$'\t' read type name; do

        echo "Dispositivo detectado: $name"
        # comandos...

    done

Salve esse script em algum local apropriado (e.g., ~/bin/xinput-monitor) e dê-lhe permissão de execução (chmod +x ~/bin/xinput-monitor). Você pode executá-lo como está para testar se os dispositivos estão sendo realmente detectados (experimente conectar um teclado externo com o script rodando).

A opção -n +1 faz com que o tail imprima o conteúdo do arquivo desde a primeira linha antes de começar a monitorá-lo; isso faz com que o script "detecte" mesmo os dispositivos que já estavam conectados antes de ele rodar. Se você não desejar esse comportamento, pode trocar o -n +1 por -n 0.

Se tudo o que você quer é rodar o xmodmap (ou qualquer outro comando) quando um dispositivo é conectado, basta colocar o comando no trecho indicado no while. Feito isso, basta pôr o script para rodar na inicialização de seu ambiente gráfico (colocando uma linha do tipo ~/bin/xinput-monitor & no seu ~/.xinitrc ou ~/.xsession, ou em algum arquivo de configuração do seu ambiente gráfico favorito).

Note que nem todos os dispositivos listados são teclados (nem mesmo todos os dispositivos com type: KEYBOARD são teclados); se você não quiser executar o xmodmap uma vez para cada um desses dispositivos (o que em tese é inofensivo, mas nunca se sabe), você pode usar um if ou case para ignorar os dispositivos que não lhe interessam. Por exemplo:

    ...
    while IFS=$'\t' read type name; do
        echo "Dispositivo detectado: $name"

        case "$name" in
            'Power Button'|'Video Bus'|'Integrated Webcam'|*'Synaptics'*)
                # Não faz nada.
                ;;
            *)
                # Os comandos que desejamos executar quando um teclado é conectado.
                xmodmap ~/.xmodmaprc
                xset r rate 250
                xkbset exp =m
                ;;
        esac
    done

Setando um layout específico para cada teclado

Para atribuir um layout individual para cada teclado conectado, teremos que abandonar o bom[citation needed] e velho xmodmap e entrar no maravilhoso[dubious – discuss] mundo do XKB. Felizmente, usar um layout pronto com o XKB é bem simples: basta executar um comando como:

# Layout ABNT-2.
setxkbmap -device device_id br abnt2

# Layout US internacional (com acentos).
setxkbmap -device device_id us intl

A opção -device device_id indica qual teclado o comando deve afetar. Se ela não for especificada, o comando afeta todos os teclados.

O grande problema é determinar o device_id de cada teclado; ele pode variar dependendo dos dispositivos presentes e da ordem em que o X os encontra. Aparentemente o id não aparece no arquivo de log do X. A solução é usar o xinput (que vem no pacote xinput no Debian, Ubuntu e companhia), um comando que permite ver e modificar diversas configurações de dispositivos de entrada no X (tais como os dez mil parâmetros que controlam velocidade, aceleração, gestures e outras firulas de touchpads), entre outras coisas. O comando xinput list produz uma listagem dos dispositivos presentes e respectivos ids, com a seguinte cara:

# xinput list
⎡ Virtual core pointer                          \tid=2\t[master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                \tid=4\t[slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad                \tid=13\t[slave  pointer  (2)]
⎜   ↳ GASIA GASIA USB KB Pro                    \tid=10\t[slave  pointer  (2)]
⎣ Virtual core keyboard                         \tid=3\t[master keyboard (2)]
    ↳ Virtual core XTEST keyboard               \tid=5\t[slave  keyboard (3)]
    ↳ Power Button                              \tid=6\t[slave  keyboard (3)]
    ↳ Video Bus                                 \tid=7\t[slave  keyboard (3)]
    ↳ Power Button                              \tid=8\t[slave  keyboard (3)]
    ↳ Integrated Webcam                         \tid=11\t[slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard              \tid=12\t[slave  keyboard (3)]
    ↳ GASIA GASIA USB KB Pro                    \tid=9\t[slave  keyboard (3)]

(Os \t representam TABs.)

Um problema visível nessa saída é que pode haver mais de um dispositivo com o mesmo nome (temos dois Power Button e dois GASIA GASIA USB KB Pro (sendo que um deles é um mouse (!))). Como chamar o setxkbmap sobre um não-teclado parece não ter efeito algum, podemos simplesmente tentar os dois ids e nos darmos por satisfeitos.

O primeiro passo é obter os ids a partir dos nomes. Para isso, podemos recorrer ao sed:

        device_ids="$(xinput list | sed -n "s|.*↳ $name *\tid=\([^\t]*\)\t.*|\1|p")"

Com os ids à mão, basta executar o setxkbmap para cada id, usando os parâmetros apropriados dependendo do nome do dispositivo detectado (altere as cláusulas do case para "configurar" o script para os seus teclados e layouts):

        for id in $device_ids; do
            case "$name" in
                'AT Translated Set 2 keyboard') setxkbmap -device "$id" us intl ;;
                'Some weird keyboard')          setxkbmap -device "$id" is ;;
                *)                              setxkbmap -device "$id" br abnt2 ;;
            esac
        done

'Tis over

E era isso. Eis uma versão completa do script. Ficou faltando resolver o problema de portar um xmodmaprc personalizado (caso você tenha um) para o XKB, mas isso fica para um próximo post.

(Este foi o 100-ésimo post do blog, por sinal.)

____

* Outra maneira freqüentemente citada pelo povo da Internet é alterar as configurações do udev para rodar um script quando o teclado é conectado. Além de exigir direitos de root, o script vai ter que descobrir o nome que o X atribui ao teclado por vodu, vai rodar como root (a menos que você tome a precaução de fazer o script trocar para o usuário "dono" da sessão X, o que implica descobrir quem é o dono), e você vai ter que tomar precauções para o caso de haver mais de um display X rodando (por exemplo, se você estiver usando a função "trocar de usuário" de certos ambientes gráficos). Just say no.

Comentários

Proxy Auto-Config

2012-11-14 01:24 -0200. Tags: comp, web, mundane

Problema: fazer o browser usar um servidor proxy para apenas alguns sites.

Solução: Existe uma tecnologia de última geração inventada pela Netscape em 1996 chamada Proxy Auto-Config (PAC). A idéia é mui simples e bella: escreve-se um arquivo JavaScript definindo uma função FindProxyForURL(url, host). Essa função recebe a URL e o hostname da página que o browser está tentando acessar, e retorna uma string especificando como o acesso deverá ocorrer:

A esse script estão disponíveis algumas funções para manipulação de URLs e hostnames, além das funções normais do JavaScript.

No meu caso, o objetivo é acessar o portal da ACM através do proxy do Instituto de Informática, para poder baixar papers, e usar uma conexão direta para todos os outros sites. O arquivo PAC fica algo como:

function FindProxyForURL(url, host) {
    if (dnsDomainIs(host, "dl.acm.org"))
        return "PROXY 127.0.0.1:3128";
    else
        return "DIRECT";
}

De posse do arquivo PAC, basta configurar o browser para usá-lo. No Firefox, selecione Preferences > Advanced > Network > (Connection) Settings... > Automatic proxy configuration URL, e insira a URL para o arquivo (no caso de um arquivo local, algo como file:///caminho/do/arquivo.pac).

Note que você poderia escrever um script para substituir esse arquivo automaticamente de acordo com a presença de servidor(es) proxy, ou apontar a URL para um script CGI/PHP/whatever em um servidor HTTP para gerar a configuração de proxy dinamicamente.

Quem me contou foi esse povo.

1 comentário

15 graus a leste

2012-10-15 00:27 -0300. Tags: comp, unix, mundane, random

No próximo domingo, dia 21 de outubro de 2012, diversas cidades brasileiras sofrerão um deslocamento de 15 graus para leste, e por conseguinte estarão sob o fuso-horário -2. Habitantes dessas cidades deverão ajustar seus relógios de acordo. O fenômeno geológico ocorre todo ano por volta da terceira semana de outubro, e encerra-se por volta da terceira semana de fevereiro do ano seguinte, quando um deslocamento reverso restaura as posições originais das cidades.

Graças à regularidade do fenômeno, muitos sistemas operacionais já vêm preparados para realizar a mudança de fuso-horário automaticamente. A usuários que ajustam seus relógios manualmente, recomenda-se ajustar o fuso-horário do sistema (com um comando do tipo ln -sf /usr/share/zoneinfo/Etc/GMT+2 /etc/localtime em sistemas GNU/Linux), ao invés de adiantar o relógio em uma hora, já que o relógio do sistema é mantido em UTC, que não é afetado pelo deslocamento.

(Os nomes dos fusos-horários em /usr/share/zoneinfo/Etc possuem sinais contrários aos dos nomes convencionais dos fusos (i.e., o fuso-horário -2 corresponde ao arquivo GMT+2). A convenção de sinais anti-intuitivos vem de uma longa tradição na comunidade científica enraizada na nomenclatura das cargas elétricas.)

Recomenda-se fortemente manter-se sentado em uma cadeira firme durante o deslocamento, por razões de segurança.

1 comentário

Main menu

Posts recentes

Comentários recentes

Tags

comp (114) prog (51) life (44) unix (32) random (27) lang (27) about (24) mind (22) mundane (21) pldesign (20) in-english (19) lisp (17) web (17) ramble (15) img (13) rant (12) privacy (10) scheme (8) freedom (8) lash (7) music (7) esperanto (7) bash (7) academia (7) home (6) mestrado (6) shell (6) conlang (5) copyright (5) misc (5) worldly (4) book (4) php (4) latex (4) editor (4) politics (4) etymology (3) wrong (3) android (3) film (3) tour-de-scheme (3) kbd (3) c (3) security (3) emacs (3) network (3) poem (2) cook (2) physics (2) comic (2) llvm (2) treta (2) lows (2) audio (1) wm (1) philosophy (1) kindle (1) pointless (1) perl (1)

Elsewhere

Quod vide


Copyright © 2010-2018 Vítor De Araújo
O conteúdo deste blog, a menos que de outra forma especificado, pode ser utilizado segundo os termos da licença Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.

Powered by Blognir.