1a5ae21e4Smrg#!/usr/bin/env perl 204b94745Smrg# $XTermId: xorblink.pl,v 1.16 2017/12/24 21:03:54 tom Exp $ 35307cd1aSmrg# ----------------------------------------------------------------------------- 45307cd1aSmrg# Copyright 2017 by Thomas E. Dickey 55307cd1aSmrg# 65307cd1aSmrg# All Rights Reserved 75307cd1aSmrg# 85307cd1aSmrg# Permission is hereby granted, free of charge, to any person obtaining a 95307cd1aSmrg# copy of this software and associated documentation files (the 105307cd1aSmrg# "Software"), to deal in the Software without restriction, including 115307cd1aSmrg# without limitation the rights to use, copy, modify, merge, publish, 125307cd1aSmrg# distribute, sublicense, and/or sell copies of the Software, and to 135307cd1aSmrg# permit persons to whom the Software is furnished to do so, subject to 145307cd1aSmrg# the following conditions: 155307cd1aSmrg# 165307cd1aSmrg# The above copyright notice and this permission notice shall be included 175307cd1aSmrg# in all copies or substantial portions of the Software. 185307cd1aSmrg# 195307cd1aSmrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 205307cd1aSmrg# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 215307cd1aSmrg# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 225307cd1aSmrg# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 235307cd1aSmrg# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 245307cd1aSmrg# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 255307cd1aSmrg# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 265307cd1aSmrg# 275307cd1aSmrg# Except as contained in this notice, the name(s) of the above copyright 285307cd1aSmrg# holders shall not be used in advertising or otherwise to promote the 295307cd1aSmrg# sale, use or other dealings in this Software without prior written 305307cd1aSmrg# authorization. 315307cd1aSmrg# ----------------------------------------------------------------------------- 32a5ae21e4Smrg# walk through the different states of cursor-blinking, with annotation 33a5ae21e4Smrg# 34a5ae21e4Smrg# Manual: 35a5ae21e4Smrg# +bc turn off text cursor blinking. This overrides the cursorBlink 36a5ae21e4Smrg# resource. 37a5ae21e4Smrg# 38a5ae21e4Smrg# -bc turn on text cursor blinking. This overrides the cursorBlink 39a5ae21e4Smrg# resource. 40a5ae21e4Smrg# 41a5ae21e4Smrg# cursorBlink (class CursorBlink) 42a5ae21e4Smrg# Specifies whether to make the cursor blink. The default is 43a5ae21e4Smrg# "false". 44a5ae21e4Smrg# 45a5ae21e4Smrg# Xterm-dev uses two variables to determine whether the cursor 46a5ae21e4Smrg# blinks. One is set by this resource. The other is set by 47a5ae21e4Smrg# control sequences (private mode 12 and DECSCUSR). Xterm-dev 48a5ae21e4Smrg# tests the XOR of the two variables. 49a5ae21e4Smrg# 50a5ae21e4Smrg# Enable Blinking Cursor (resource cursorblink) 51a5ae21e4Smrg# Enable (or disable) the blinking-cursor feature. This 52a5ae21e4Smrg# corresponds to the -bc option and the cursorBlink 53a5ae21e4Smrg# resource. There is also an escape sequence (see Xterm- 54a5ae21e4Smrg# dev Control Sequences). The menu entry and the escape 55a5ae21e4Smrg# sequence states are XOR'd: if both are enabled, the 56a5ae21e4Smrg# cursor will not blink, if only one is enabled, the cursor 57a5ae21e4Smrg# will blink. 58a5ae21e4Smrg# 59a5ae21e4Smrg# set-cursorblink(on/off/toggle) 60a5ae21e4Smrg# This action sets, unsets or toggles the cursorBlink resource. 61a5ae21e4Smrg# It is also invoked from the cursorblink entry in vtMenu. 62a5ae21e4Smrg# 63a5ae21e4Smrg# Control sequences: 64a5ae21e4Smrg# 65a5ae21e4Smrg# CSI ? Pm h 66a5ae21e4Smrg# DEC Private Mode Set (DECSET). 67a5ae21e4Smrg# Ps = 1 2 -> Start Blinking Cursor (att610). 68a5ae21e4Smrg# 69a5ae21e4Smrg# CSI ? Pm l 70a5ae21e4Smrg# DEC Private Mode Reset (DECRST). 71a5ae21e4Smrg# Ps = 1 2 -> Stop Blinking Cursor (att610). 72a5ae21e4Smrg# 73a5ae21e4Smrg# CSI Ps SP q 74a5ae21e4Smrg# Set cursor style (DECSCUSR, VT520). 75a5ae21e4Smrg# Ps = 0 -> blinking block. 76a5ae21e4Smrg# Ps = 1 -> blinking block (default). 77a5ae21e4Smrg# Ps = 2 -> steady block. 78a5ae21e4Smrg# Ps = 3 -> blinking underline. 79a5ae21e4Smrg# Ps = 4 -> steady underline. 80a5ae21e4Smrg# Ps = 5 -> blinking bar (xterm). 81a5ae21e4Smrg# Ps = 6 -> steady bar (xterm). 82a5ae21e4Smrg# 83a5ae21e4Smrguse strict; 84a5ae21e4Smrg 85a5ae21e4Smrguse Term::ReadKey; 86a5ae21e4Smrg 87a5ae21e4Smrguse IO::Handle; 88a5ae21e4SmrgSTDERR->autoflush(1); 89a5ae21e4SmrgSTDOUT->autoflush(1); 90a5ae21e4Smrg 91a5ae21e4Smrgour %DECSET = ( 92a5ae21e4Smrg "\e[?12h", "Start Blinking Cursor (AT&T 610)", 93a5ae21e4Smrg "\e[?12l", "Stop Blinking Cursor (AT&T 610)" 94a5ae21e4Smrg); 95a5ae21e4Smrg 96a5ae21e4Smrgour %DECSCUSR = ( 97a5ae21e4Smrg "\e[0 q", 98a5ae21e4Smrg "blinking block", 99a5ae21e4Smrg "\e[1 q", 100a5ae21e4Smrg "blinking block (default)", 101a5ae21e4Smrg "\e[2 q", 102a5ae21e4Smrg "steady block", 103a5ae21e4Smrg "\e[3 q", 104a5ae21e4Smrg "blinking underline", 105a5ae21e4Smrg "\e[4 q", 106a5ae21e4Smrg "steady underline", 107a5ae21e4Smrg "\e[5 q", 108a5ae21e4Smrg "blinking bar (xterm)", 109a5ae21e4Smrg "\e[6 q", 110a5ae21e4Smrg "steady bar (xterm)" 111a5ae21e4Smrg); 112a5ae21e4Smrg 113a5ae21e4Smrgsub show($$) { 114a5ae21e4Smrg my $seq = shift; 115a5ae21e4Smrg my $txt = shift; 116a5ae21e4Smrg printf "%s -> %s\n", &visible($seq), $txt; 117a5ae21e4Smrg} 118a5ae21e4Smrg 119a5ae21e4Smrgsub get_reply($$) { 120a5ae21e4Smrg my $seq = shift; 121a5ae21e4Smrg my $end = shift; 122a5ae21e4Smrg printf STDERR "%s", $seq; 123a5ae21e4Smrg my $key; 124a5ae21e4Smrg my $result = ""; 125a5ae21e4Smrg $key = ReadKey(0); 126a5ae21e4Smrg $result .= $key; 127a5ae21e4Smrg if ( $key eq "\e" ) { 128a5ae21e4Smrg 129a5ae21e4Smrg while (1) { 130a5ae21e4Smrg $key = ReadKey(100); 131a5ae21e4Smrg $result .= $key; 132a5ae21e4Smrg next if ( length($result) < length($end) ); 133a5ae21e4Smrg last if ( substr( $result, -length($end) ) eq $end ); 134a5ae21e4Smrg } 135a5ae21e4Smrg } 136a5ae21e4Smrg return $result; 137a5ae21e4Smrg} 138a5ae21e4Smrg 139a5ae21e4Smrgsub mode_value($) { 140a5ae21e4Smrg my $value = shift; 141a5ae21e4Smrg if ( $value eq 1 ) { 142a5ae21e4Smrg $value = "set"; 143a5ae21e4Smrg } 144a5ae21e4Smrg elsif ( $value eq 2 ) { 145a5ae21e4Smrg $value = "reset"; 146a5ae21e4Smrg } 147a5ae21e4Smrg elsif ( $value eq 3 ) { 148a5ae21e4Smrg $value = "*set"; 149a5ae21e4Smrg } 150a5ae21e4Smrg elsif ( $value eq 4 ) { 151a5ae21e4Smrg $value = "*reset"; 152a5ae21e4Smrg } 153a5ae21e4Smrg else { 154a5ae21e4Smrg $value = &visible( "?" . $value ); 155a5ae21e4Smrg } 156a5ae21e4Smrg return $value; 157a5ae21e4Smrg} 158a5ae21e4Smrg 159a5ae21e4Smrgsub DECRQM($) { 160a5ae21e4Smrg my $mode = shift; 161a5ae21e4Smrg my $sequence = sprintf( "\e[?%d\$p", $mode ); 162a5ae21e4Smrg my $reply = &get_reply( $sequence, "y" ); 163a5ae21e4Smrg if ( $reply =~ /^\e\[\?$mode;\d+\$y$/ ) { 164a5ae21e4Smrg $reply =~ s/^\e\[\?$mode;(\d+)\$y$/$1/; 165a5ae21e4Smrg } 166a5ae21e4Smrg return &mode_value($reply); 167a5ae21e4Smrg} 168a5ae21e4Smrg 169a5ae21e4Smrgsub DECRQSS($) { 170a5ae21e4Smrg my $request = shift; 171a5ae21e4Smrg my $ending = "\e\\"; 172a5ae21e4Smrg my $sequence = sprintf( "\eP\$q%s$ending", $request ); 173a5ae21e4Smrg my $reply = &get_reply( $sequence, $ending ); 174a5ae21e4Smrg 175a5ae21e4Smrg # xterm responds with 176a5ae21e4Smrg # DCS 1 $ r Pt ST for valid requests, 177a5ae21e4Smrg # DCS 0 $ r Pt ST for invalid requests. 178a5ae21e4Smrg #if ( $reply =~ /^\eP1\$r.*$ending$/ ) { 179a5ae21e4Smrg if ( $reply =~ /^\eP1\$r\d+ q\e\\$/ ) { 180a5ae21e4Smrg $reply =~ s/^\eP1\$r(\d+) q\e\\$/$1/; 181a5ae21e4Smrg } 182a5ae21e4Smrg return &visible($reply); 183a5ae21e4Smrg} 184a5ae21e4Smrg 185a5ae21e4Smrgsub get_key() { 186a5ae21e4Smrg my $key; 187a5ae21e4Smrg do { 188a5ae21e4Smrg $key = ReadKey(0); 189a5ae21e4Smrg if ( $key eq "\e" ) { 190a5ae21e4Smrg while ( ReadKey(10) !~ /[@-~]/ ) { 191a5ae21e4Smrg # 192a5ae21e4Smrg } 193a5ae21e4Smrg } 194a5ae21e4Smrg } while ( $key eq "\e" ); 195a5ae21e4Smrg return $key; 196a5ae21e4Smrg} 197a5ae21e4Smrg 198a5ae21e4Smrgsub visible($) { 199a5ae21e4Smrg my $txt = shift; 200a5ae21e4Smrg $txt =~ s/\e/\\e/g; 201a5ae21e4Smrg $txt =~ s/\a/\\a/g; 202a5ae21e4Smrg return $txt; 203a5ae21e4Smrg} 204a5ae21e4Smrg 205a5ae21e4Smrgsub test($$) { 206a5ae21e4Smrg my $set = shift; 207a5ae21e4Smrg my $msg = shift; 208a5ae21e4Smrg 209a5ae21e4Smrg ReadMode 'raw'; 210a5ae21e4Smrg 211a5ae21e4Smrg printf STDERR "%s\t[", &visible($set); 212a5ae21e4Smrg 213a5ae21e4Smrg # save the cursor position 214a5ae21e4Smrg printf STDERR "\e7"; 215a5ae21e4Smrg 216a5ae21e4Smrg # send the escape sequence 217a5ae21e4Smrg printf STDERR "%s", $set; 218a5ae21e4Smrg 219a5ae21e4Smrg # print the description 220a5ae21e4Smrg printf STDERR "X] "; 221a5ae21e4Smrg 222a5ae21e4Smrg printf STDERR " [C=%s,", &DECRQSS(" q"); 223a5ae21e4Smrg printf STDERR "B=%s,", &DECRQM(12); 224a5ae21e4Smrg printf STDERR "M=%s,%s]", &DECRQM(13), &DECRQM(14); 225a5ae21e4Smrg printf STDERR " %s", $msg; 226a5ae21e4Smrg printf STDERR "\e[0J"; 227a5ae21e4Smrg 228a5ae21e4Smrg # restore the cursor position 229a5ae21e4Smrg printf STDERR "\e8"; 230a5ae21e4Smrg 231a5ae21e4Smrg # wait for any key 232a5ae21e4Smrg my $key = &get_key; 233a5ae21e4Smrg ReadMode 'restore'; 234a5ae21e4Smrg 235a5ae21e4Smrg # print newline 236a5ae21e4Smrg printf STDERR "\n"; 237a5ae21e4Smrg 238a5ae21e4Smrg # A backspace response makes the current line reprint (to test menus) 239a5ae21e4Smrg return ( $key ne "\b" and $key ne "\177" ) ? 1 : 0; 240a5ae21e4Smrg} 241a5ae21e4Smrg 242a5ae21e4Smrgif ( -t STDOUT ) { 243a5ae21e4Smrg printf "Legend:\n"; 244a5ae21e4Smrg printf " C = cursor shape (1,2 block, 3,4 underline, 5,6 left-bar)\n"; 245a5ae21e4Smrg printf " B = escape-sequence blink\n"; 246a5ae21e4Smrg printf " M = menu blink and XOR mode\n"; 247a5ae21e4Smrg printf "\n"; 248a5ae21e4Smrg printf "An asterisk means the mode is always set or reset.\n"; 249a5ae21e4Smrg printf "Press any key to proceed; press backspace to reprint line.\n"; 250a5ae21e4Smrg printf "\n"; 251a5ae21e4Smrg my @DECSET = sort keys %DECSET; 252a5ae21e4Smrg my @DECSCUSR = sort keys %DECSCUSR; 253a5ae21e4Smrg 254a5ae21e4Smrg for ( my $h = 0 ; $h <= $#DECSET ; ++$h ) { 255a5ae21e4Smrg $h-- unless &test( $DECSET[$h], $DECSET{ $DECSET[$h] } ); 256a5ae21e4Smrg } 257a5ae21e4Smrg for my $l ( 0 .. $#DECSCUSR ) { 258a5ae21e4Smrg $l-- unless &test( $DECSCUSR[$l], $DECSCUSR{ $DECSCUSR[$l] } ); 259a5ae21e4Smrg } 260a5ae21e4Smrg} 261a5ae21e4Smrgelse { 262a5ae21e4Smrg printf "DECSET (AT&T 610 blinking cursor):\n"; 263a5ae21e4Smrg for my $key ( sort keys %DECSET ) { 264a5ae21e4Smrg &show( $key, $DECSET{$key} ); 265a5ae21e4Smrg } 266a5ae21e4Smrg 267a5ae21e4Smrg printf "DECSCUSR:\n"; 268a5ae21e4Smrg for my $key ( sort keys %DECSCUSR ) { 269a5ae21e4Smrg &show( $key, $DECSCUSR{$key} ); 270a5ae21e4Smrg } 271a5ae21e4Smrg} 272a5ae21e4Smrg1; 273