summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2011-05-29 00:35:47 +0200
committerFlorent Le Coz <louiz@louiz.org>2011-05-29 00:35:47 +0200
commit0db064fdf7831e6a74a0571b5fd544db53a41a16 (patch)
tree978f179af63404031a7a94ffcaf6d1df46e4224f
parent67881b977954c9cf330ceebc97cd400152b8c550 (diff)
parent8d3053bd93db2e976f49a3a32038712083d411a7 (diff)
downloadpoezio-0db064fdf7831e6a74a0571b5fd544db53a41a16.tar.gz
poezio-0db064fdf7831e6a74a0571b5fd544db53a41a16.tar.bz2
poezio-0db064fdf7831e6a74a0571b5fd544db53a41a16.tar.xz
poezio-0db064fdf7831e6a74a0571b5fd544db53a41a16.zip
Merge, whatever
-rw-r--r--locale/poezio.pot571
-rw-r--r--src/core.py40
-rw-r--r--src/keyboard.py79
3 files changed, 488 insertions, 202 deletions
diff --git a/locale/poezio.pot b/locale/poezio.pot
index 939adea1..fc66ac67 100644
--- a/locale/poezio.pot
+++ b/locale/poezio.pot
@@ -8,140 +8,135 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-06-13 16:13+0200\n"
+"POT-Creation-Date: 2011-05-28 23:53+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
-#: src/connection.py:105
-#, python-format
-msgid ""
-"Error: Could not authenticate. Please make sure the server you chose (%s) "
-"supports anonymous authentication"
+#: src/core.py:59
+msgid "A password is required"
+msgstr ""
+
+#: src/core.py:60
+msgid "Permission denied"
+msgstr ""
+
+#: src/core.py:61
+msgid "The room does'nt exist"
+msgstr ""
+
+#: src/core.py:62
+msgid "Your are not allowed to create a new room"
+msgstr ""
+
+#: src/core.py:63
+msgid "A reserved nick must be used"
+msgstr ""
+
+#: src/core.py:64
+msgid "You are not in the member list"
+msgstr ""
+
+#: src/core.py:65
+msgid "This nickname is already in use or has been reserved"
+msgstr ""
+
+#: src/core.py:66
+msgid "The maximum number of users has been reached"
msgstr ""
-#: src/gui.py:67
+#: src/core.py:113
msgid ""
-"Usage: /join [room_name][/nick] [password]\n"
+"Usage: /join [room_name][@server][/nick] [password]\n"
"Join: Join the specified room. You can specify a nickname after a slash (/). "
"If no nickname is specified, you will use the default_nick in the "
"configuration file. You can omit the room name: you will then join the room "
"you're looking at (useful if you were kicked). You can also provide a "
-"password to join the room.\n"
+"room_name without specifying a server, the server of the room you're "
+"currently in will be used. You can also provide a password to join the "
+"room.\n"
"Examples:\n"
"/join room@server.tld\n"
-"/join room@server.tld/ John\n"
+"/join room@server.tld/John\n"
+"/join room2\n"
"/join /me_again\n"
"/join\n"
"/join room@server.tld/my_nick password\n"
-"/join / pass"
+"/join / password"
msgstr ""
-#: src/gui.py:68
-msgid ""
-"Usage: /quit\n"
-"Quit: Just disconnect from the server and exit poezio."
-msgstr ""
-
-#: src/gui.py:69
+#: src/core.py:114
msgid ""
"Usage: /exit\n"
"Exit: Just disconnect from the server and exit poezio."
msgstr ""
-#: src/gui.py:70
+#: src/core.py:115
msgid ""
"Usage: /next\n"
"Next: Go to the next room."
msgstr ""
-#: src/gui.py:71
-msgid ""
-"Usage: /n\n"
-"N: Go to the next room."
-msgstr ""
-
-#: src/gui.py:72
+#: src/core.py:116
msgid ""
"Usage: /prev\n"
"Prev: Go to the previous room."
msgstr ""
-#: src/gui.py:73
-msgid ""
-"Usage: /p\n"
-"P: Go to the previous room."
-msgstr ""
-
-#: src/gui.py:74
+#: src/core.py:117
msgid ""
"Usage: /win <number>\n"
"Win: Go to the specified room."
msgstr ""
-#: src/gui.py:75
+#: src/core.py:118
msgid ""
"Usage: /w <number>\n"
"W: Go to the specified room."
msgstr ""
-#: src/gui.py:76
-msgid "Usage: /ignore <nickname> \\Ignore: Ignore a specified nickname."
-msgstr ""
-
-#: src/gui.py:77
+#: src/core.py:119
msgid ""
-"Usage: /unignore <nickname>\\Unignore: Remove the specified nickname from "
-"the ignore list."
+"Usage: /show <availability> [status message]\n"
+"Show: Sets your availability and (optionaly) your status message. The "
+"<availability> argument is one of \"available, chat, away, afk, dnd, busy, xa"
+"\" and the optional [status] argument will be your status message."
msgstr ""
-#: src/gui.py:78
+#: src/core.py:120
msgid ""
-"Usage: /part [message]\n"
-" Part: disconnect from a room. You can specify an optional message."
+"Usage: /status <availability> [status message]\n"
+"Status: Sets your availability and (optionaly) your status message. The "
+"<availability> argument is one of \"available, chat, away, afk, dnd, busy, xa"
+"\" and the optional [status] argument will be your status message."
msgstr ""
-#: src/gui.py:79
-msgid ""
-"Usage: /show <availability> [status]\n"
-"Show: Change your availability and (optionaly) your status. The "
-"<availability> argument is one of \"avail, available, ok, here, chat, away, "
-"afk, dnd, busy, xa\" and the optional [message] argument will be your status "
-"message"
-msgstr ""
-
-#: src/gui.py:80
+#: src/core.py:121
msgid ""
"Usage: /away [message]\n"
-"Away: Sets your availability to away and (optional) sets your status "
-"message. This is equivalent to '/show away [message]'"
+"Away: Sets your availability to away and (optionaly) your status message. "
+"This is equivalent to '/status away [message]'"
msgstr ""
-#: src/gui.py:81
+#: src/core.py:122
msgid ""
"Usage: /busy [message]\n"
-"Busy: Sets your availability to busy and (optional) sets your status "
-"message. This is equivalent to '/show busy [message]'"
+"Busy: Sets your availability to busy and (optionaly) your status message. "
+"This is equivalent to '/status busy [message]'"
msgstr ""
-#: src/gui.py:82
-msgid ""
-"Usage: /avail [message]\n"
-"Avail: Sets your availability to available and (optional) sets your status "
-"message. This is equivalent to '/show available [message]'"
-msgstr ""
-
-#: src/gui.py:83
+#: src/core.py:123
msgid ""
"Usage: /available [message]\n"
-"Available: Sets your availability to available and (optional) sets your "
-"status message. This is equivalent to '/show available [message]'"
+"Available: Sets your availability to available and (optionaly) your status "
+"message. This is equivalent to '/status available [message]'"
msgstr ""
-#: src/gui.py:84
+#: src/core.py:124
msgid ""
"Usage: /bookmark [roomname][/nick]\n"
"Bookmark: Bookmark the specified room (you will then auto-join it on each "
@@ -151,7 +146,7 @@ msgid ""
"room (instead of default_nick)"
msgstr ""
-#: src/gui.py:85
+#: src/core.py:125
msgid ""
"Usage: /set <option> [value]\n"
"Set: Sets the value to the option in your configuration file. You can, for "
@@ -160,197 +155,471 @@ msgid ""
"(nothing) by providing no [value] after <option>."
msgstr ""
-#: src/gui.py:86
+#: src/core.py:126
msgid ""
-"Usage: /kick <nick> [reason]\n"
-"Kick: Kick the user with the specified nickname. You also can give an "
-"optional reason."
+"Usage: /theme\n"
+"Theme: Reload the theme defined in the config file."
msgstr ""
-#: src/gui.py:87
+#: src/core.py:127
msgid ""
-"Usage: /topic <subject> \n"
-"Topic: Change the subject of the room"
+"Usage: /list\n"
+"List: get the list of public chatrooms on the specified server"
msgstr ""
-#: src/gui.py:88
+#: src/core.py:128
msgid ""
-"Usage: /query <nick>\n"
-"Query: Open a private conversation with <nick>. This nick has to be present "
-"in the room you're currently in."
+"Usage: /message <jid> [optional message]\n"
+"Message: Open a conversation with the specified JID (even if it is not in "
+"our roster), and send a message to it, if specified"
msgstr ""
-#: src/gui.py:90
+#: src/core.py:129
msgid ""
-"Usage: /nick <nickname> \n"
-"Nick: Change your nickname in the current room"
+"Usage: /version <jid>\n"
+"Version: get the software version of the given JID (usually its XMPP client "
+"and Operating System)"
+msgstr ""
+
+#: src/core.py:130
+msgid ""
+"Usage: /connect\n"
+"Connect: disconnect from the remote server if you are currently connected "
+"and then connect to it again"
+msgstr ""
+
+#: src/core.py:131
+msgid ""
+"Usage: /server_cycle [domain] [message]\n"
+"Server Cycle: disconnect and reconnects in all the rooms in domain."
+msgstr ""
+
+#: src/core.py:192
+msgid "Welcome to poezio!"
+msgstr ""
+
+#: src/core.py:391
+msgid "Connection to remote server failed"
msgstr ""
-#: src/gui.py:219
-msgid "Welcome on Poezio \\o/!"
+#: src/core.py:400
+msgid "Disconnected from server."
msgstr ""
-#: src/gui.py:220
+#: src/core.py:406
+msgid "Authentication failed."
+msgstr ""
+
+#: src/core.py:412
+msgid "Connected to server."
+msgstr ""
+
+#: src/core.py:419
+msgid "Authentication success."
+msgstr ""
+
+#: src/core.py:420
#, python-format
msgid "Your JID is %s"
msgstr ""
-#: src/gui.py:281
+#: src/core.py:860
msgid "Unknown error"
msgstr ""
-#: src/gui.py:282
+#: src/core.py:862 src/tabs.py:1680
#, python-format
-msgid "Error: %(code)s-%(msg)s: %(body)s"
+msgid "Error: %(code)s - %(msg)s: %(body)s"
msgstr ""
-#: src/gui.py:285
+#: src/core.py:865
+#, python-format
+msgid "Error: %(msg)s: %(body)s"
+msgstr ""
+
+#: src/core.py:868
msgid ""
"To provide a password in order to join the room, type \"/join / password"
"\" (replace \"password\" by the real password)"
msgstr ""
-#: src/gui.py:345
+#: src/core.py:874
+msgid ""
+"You can join the room with an other nick, by typing \"/join /other_nick\""
+msgstr ""
+
+#: src/core.py:923
+#, python-format
+msgid "%(nick)s set the subject to: %(subject)s"
+msgstr ""
+
+#: src/core.py:925
+#, python-format
+msgid "The subject is: %(subject)s"
+msgstr ""
+
+#: src/core.py:960
#, python-format
msgid "message received for a non-existing room: %s"
msgstr ""
-#: src/gui.py:351
+#: src/core.py:986
+msgid "Available commands are: "
+msgstr ""
+
+#: src/core.py:991
+msgid ""
+"\n"
+"Type /help <command_name> to know what each command does"
+msgstr ""
+
+#: src/core.py:998
#, python-format
-msgid "%(nick)s changed the subject to: %(subject)s"
+msgid "Unknown command: %s"
+msgstr ""
+
+#: src/core.py:1060 src/tabs.py:551
+msgid "an unknown software"
+msgstr ""
+
+#: src/core.py:1061 src/tabs.py:552
+msgid "unknown"
msgstr ""
-#: src/gui.py:353
+#: src/core.py:1062 src/tabs.py:553
+msgid "on an unknown platform"
+msgstr ""
+
+#: src/core.py:1215
+msgid "You didn't specify a server for the room you want to join"
+msgstr ""
+
+#: src/core.py:1276
#, python-format
-msgid "The subject is: %(subject)s"
+msgid "Your bookmarks are now: %s"
msgstr ""
-#: src/gui.py:389
+#: src/core.py:1347
+msgid "No server specified"
+msgstr ""
+
+#: src/core.py:1474 src/tabs.py:144
#, python-format
-msgid "Your nickname is %s"
+msgid "Unknown command (%s)"
+msgstr ""
+
+#: src/core.py:1474 src/tabs.py:144
+msgid "Error"
+msgstr ""
+
+#: src/tabs.py:59
+msgid "busy"
+msgstr ""
+
+#: src/tabs.py:60
+msgid "away"
+msgstr ""
+
+#: src/tabs.py:61
+msgid "not available"
msgstr ""
-#: src/gui.py:391
+#: src/tabs.py:62
+msgid "chatty"
+msgstr ""
+
+#: src/tabs.py:63
+msgid "available"
+msgstr ""
+
+#: src/tabs.py:263
+msgid ""
+"Usage: /say <message>\n"
+"Say: Just send the message.\n"
+" Useful if you want your message to "
+"begin with a '/'"
+msgstr ""
+
+#: src/tabs.py:457
+msgid ""
+"Usage: /ignore <nickname> \n"
+"Ignore: Ignore a specified nickname."
+msgstr ""
+
+#: src/tabs.py:458
+msgid ""
+"Usage: /unignore <nickname>\n"
+"Unignore: Remove the specified nickname from the ignore list."
+msgstr ""
+
+#: src/tabs.py:459
+msgid ""
+"Usage: /kick <nick> [reason]\n"
+"Kick: Kick the user with the specified nickname. You also can give an "
+"optional reason."
+msgstr ""
+
+#: src/tabs.py:460
+msgid ""
+"Usage: /topic <subject>\n"
+"Topic: Change the subject of the room"
+msgstr ""
+
+#: src/tabs.py:461
+msgid ""
+"Usage: /query <nick> [message]\n"
+"Query: Open a private conversation with <nick>. This nick has to be present "
+"in the room you're currently in. If you specified a message after the "
+"nickname, it will immediately be sent to this user"
+msgstr ""
+
+#: src/tabs.py:462
+msgid ""
+"Usage: /part [message]\n"
+" Part: disconnect from a room. You can specify an optional message."
+msgstr ""
+
+#: src/tabs.py:463
+msgid ""
+"Usage: /nick <nickname>\n"
+"Nick: Change your nickname in the current room"
+msgstr ""
+
+#: src/tabs.py:464
+msgid ""
+"Usage: /recolor\n"
+"Recolor: Re-assign a color to all participants of the current room, based on "
+"the last time they talked. Use this if the participants currently talking "
+"have too many identical colors."
+msgstr ""
+
+#: src/tabs.py:465
+msgid ""
+"Usage: /cycle [message]\n"
+"Cycle: Leaves the current room and rejoin it immediately"
+msgstr ""
+
+#: src/tabs.py:466
+msgid ""
+"Usage: /info <nickname>\n"
+"Info: Display some information about the user in the MUC: his/here role, "
+"affiliation, status and status message."
+msgstr ""
+
+#: src/tabs.py:467
+msgid ""
+"Usage: /configure\n"
+"Configure: Configure the current room, through a form."
+msgstr ""
+
+#: src/tabs.py:468
+msgid ""
+"Usage: /version <jid or nick>\n"
+"Version: get the software version of the given JID or nick in room (usually "
+"its XMPP client and Operating System)"
+msgstr ""
+
+#: src/tabs.py:602
+#, python-format
+msgid "Cannot find user: %s"
+msgstr ""
+
+#: src/tabs.py:610
#, python-format
-msgid "%s is in the room"
+msgid "The subject of the room is: %s"
msgstr ""
-#: src/gui.py:402
+#: src/tabs.py:664 src/tabs.py:682
#, python-format
-msgid "%(nick)s joined the room %(roomname)s"
+msgid "%s is not in the room"
msgstr ""
-#: src/gui.py:414
+#: src/tabs.py:666
#, python-format
-msgid "%(old)s is now known as %(new)s"
+msgid "%s is already ignored"
msgstr ""
-#: src/gui.py:418
+#: src/tabs.py:669
#, python-format
-msgid "%(old_nick)s is now known as %(new_nick)s"
+msgid "%s is now ignored"
msgstr ""
-#: src/gui.py:437
+#: src/tabs.py:684
#, python-format
-msgid "You have been kicked by %(by)s. Reason: %(reason)s"
+msgid "%s is not ignored"
msgstr ""
-#: src/gui.py:439
+#: src/tabs.py:687
#, python-format
-msgid "You have been kicked. Reason: %s"
+msgid "%s is now unignored"
msgstr ""
-#: src/gui.py:442
+#: src/tabs.py:822
#, python-format
-msgid "%(nick)s has been kicked by %(by)s. Reason: %(reason)s"
+msgid "5Your nickname is 3%s"
msgstr ""
-#: src/gui.py:444
+#: src/tabs.py:891
#, python-format
-msgid "%(nick)s has been kicked. Reason: %(reason)s"
+msgid "1%(spec)s 3You5 have been banned by 4%(by)s"
msgstr ""
-#: src/gui.py:450 src/gui.py:453
+#: src/tabs.py:893
#, python-format
-msgid "%s has left the room"
+msgid "1%(spec)s 3You5 have been banned."
msgstr ""
-#: src/gui.py:457
+#: src/tabs.py:896
#, python-format
-msgid "%s changed his/her status: "
+msgid "1%(spec)s 3%(nick)s5 has been banned by 4%(by)s"
msgstr ""
-#: src/gui.py:459
+#: src/tabs.py:898
#, python-format
-msgid "affiliation: %s,"
+msgid "1%(spec)s 3%(nick)s5 has been banned"
msgstr ""
-#: src/gui.py:461
+#: src/tabs.py:900
#, python-format
-msgid "role: %s,"
+msgid "5 Reason: 6%(reason)s5"
msgstr ""
-#: src/gui.py:463
+#: src/tabs.py:914
#, python-format
-msgid "show: %s,"
+msgid "1%(spec)s 3You5 have been kicked by 3%(by)s"
msgstr ""
-#: src/gui.py:465
+#: src/tabs.py:916
#, python-format
-msgid "status: %s,"
+msgid "1%(spec)s 3You5 have been kicked."
msgstr ""
-#: src/gui.py:518
+#: src/tabs.py:922
#, python-format
-msgid "Error: unknown command (%s)"
+msgid "1%(spec)s 3%(nick)s5 has been kicked by 3%(by)s"
msgstr ""
-#: src/gui.py:534
-msgid "Available commands are: "
+#: src/tabs.py:924
+#, python-format
+msgid "1%(spec)s 3%(nick)s5 has been kicked"
msgstr ""
-#: src/gui.py:537
-msgid ""
-"\n"
-"Type /help <command_name> to know what each command does"
+#: src/tabs.py:926
+#, python-format
+msgid "5 Reason: 6%(reason)s"
msgstr ""
-#: src/gui.py:542
+#: src/tabs.py:940
#, python-format
-msgid "Unknown command: %s"
+msgid "1%(spec)s 3%(nick)s5 has left the room"
msgstr ""
-#: src/gui.py:616
+#: src/tabs.py:942
#, python-format
-msgid "already in room [%s]"
+msgid "1%(spec)s 3%(nick)s5 (4%(jid)s5) has left the room"
msgstr ""
-#: src/gui.py:720
+#: src/tabs.py:955
#, python-format
-msgid "%s is now ignored"
+msgid "3%s5 changed: "
msgstr ""
-#: src/gui.py:722
+#: src/tabs.py:957
#, python-format
-msgid "%s is already ignored"
+msgid "affiliation: %s, "
msgstr ""
-#: src/gui.py:736
+#: src/tabs.py:960
#, python-format
-msgid "%s was not ignored"
+msgid "role: %s, "
msgstr ""
-#: src/gui.py:741
+#: src/tabs.py:963
#, python-format
-msgid "%s is now unignored"
+msgid "show: %s, "
msgstr ""
-#: src/gui.py:798
+#: src/tabs.py:966
#, python-format
-msgid "The subject of the room is: %s"
+msgid "status: %s, "
+msgstr ""
+
+#: src/tabs.py:1002 src/tabs.py:1496
+msgid ""
+"Usage: /unquery\n"
+"Unquery: close the tab"
+msgstr ""
+
+#: src/tabs.py:1003 src/tabs.py:1497
+msgid "Usage: /part\\Part: close the tab"
+msgstr ""
+
+#: src/tabs.py:1113
+#, python-format
+msgid "\"[%(old_nick)s]\" is now known as \"[%(new_nick)s]\""
+msgstr ""
+
+#: src/tabs.py:1122
+#, python-format
+msgid "%(spec)s \"[%(nick)s]\" has left the room"
msgstr ""
-#: src/window.py:135
+#: src/tabs.py:1124
#, python-format
-msgid "%(nick)s from room %(room)s"
+msgid "%(spec)s \"[%(nick)s]\" has left the room \"(%(status)s)\""
+msgstr ""
+
+#: src/tabs.py:1155
+msgid ""
+"Usage: /deny [jid]\n"
+"Deny: Use this command to remove and deny your presence to the provided JID "
+"(or the selected contact in your roster), who is asking you to be in his/"
+"here roster"
+msgstr ""
+
+#: src/tabs.py:1156
+msgid ""
+"Usage: /accept [jid]\n"
+"Accept: Use this command to authorize the provided JID (or the selected "
+"contact in your roster), to see your presence, and to ask to subscribe to it "
+"(mutual presence subscription)."
+msgstr ""
+
+#: src/tabs.py:1157
+msgid ""
+"Usage: /add <jid>\\Add: Use this command to add the specified JID to your "
+"roster. The reverse authorization will automatically be accepted if the "
+"remote JID accepts your subscription, leading to a mutual presence "
+"subscription."
+msgstr ""
+
+#: src/tabs.py:1158
+msgid ""
+"Usage: /remove [jid]\\Remove: Use this command to remove the specified JID "
+"from your roster. This wil unsubscribe you from its presence, cancel its "
+"subscription to yours, and remove the item from your roster"
+msgstr ""
+
+#: src/tabs.py:1159
+msgid ""
+"Usage: /export [/path/to/file]\n"
+"Export: Use this command to export your contacts into /path/to/file if "
+"specified, or $HOME/poezio_contacts if not."
+msgstr ""
+
+#: src/tabs.py:1160
+msgid ""
+"Usage: /import [/path/to/file]\n"
+"Import: Use this command to import your contacts from /path/to/file if "
+"specified, or $HOME/poezio_contacts if not."
+msgstr ""
+
+#: src/tabs.py:1206
+msgid "No JID specified"
+msgstr ""
+
+#: src/tabs.py:1631
+msgid ""
+"Usage: /close\n"
+"Close: Just close this tab"
msgstr ""
diff --git a/src/core.py b/src/core.py
index f96a61a8..44c967ca 100644
--- a/src/core.py
+++ b/src/core.py
@@ -670,23 +670,31 @@ class Core(object):
"""
# curses.ungetch(0) # FIXME
while self.running:
- char = self.read_keyboard()
+ char_list = self.read_keyboard()
# Special case for M-x where x is a number
- if char.startswith('M-') and len(char) == 3:
- try:
- nb = int(char[2])
- except ValueError:
- pass
- else:
- if self.current_tab().nb == nb:
- self.go_to_previous_tab()
+ if len(char_list) == 1:
+ char = char_list[0]
+ if char.startswith('M-') and len(char) == 3:
+ try:
+ nb = int(char[2])
+ except ValueError:
+ pass
else:
- self.command_win('%d' % nb)
- # search for keyboard shortcut
- if char in self.key_func:
- self.key_func[char]()
+ if self.current_tab().nb == nb:
+ self.go_to_previous_tab()
+ else:
+ self.command_win('%d' % nb)
+ # search for keyboard shortcut
+ if char in self.key_func:
+ self.key_func[char]()
+ else:
+ res = self.do_command(char)
+ if res:
+ self.refresh_window()
else:
- self.do_command(char)
+ for char in char_list:
+ self.do_command(char)
+ self.refresh_window()
self.doupdate()
def current_tab(self):
@@ -1419,9 +1427,7 @@ class Core(object):
def do_command(self, key):
if not key:
return
- res = self.current_tab().on_input(key)
- if res:
- self.refresh_window()
+ return self.current_tab().on_input(key)
def on_roster_enter_key(self, roster_row):
"""
diff --git a/src/keyboard.py b/src/keyboard.py
index 27edca5f..f3dd14db 100644
--- a/src/keyboard.py
+++ b/src/keyboard.py
@@ -24,8 +24,6 @@ shortcut, like ^A, M-a or KEY_RESIZE)
import time
-last_timeout = time.time()
-
def get_next_byte(s):
"""
Read the next byte of the utf-8 char
@@ -41,44 +39,57 @@ def get_next_byte(s):
return (None, c)
return (ord(c), c.encode('latin-1')) # returns a number and a bytes object
-def read_char(s):
+def read_char(s, timeout=1000):
"""
Read one utf-8 char
see http://en.wikipedia.org/wiki/UTF-8#Description
"""
- global last_timeout
- s.timeout(1000)
+ s.timeout(timeout) # The timeout for timed events to be checked every second
+ ret_list = []
+ # The list of all chars. For example if you paste a text, the list the chars pasted
+ # so that they can be handled at once.
(first, char) = get_next_byte(s)
- if first is None and char is None:
- last_timeout = time.time()
- return None
- if not isinstance(first, int): # Keyboard special, like KEY_HOME etc
- return char
- if first == 127 or first == 8:
- return "KEY_BACKSPACE"
- if first < 127: # ASCII char on one byte
- if first <= 26: # transform Ctrl+* keys
- char = chr(first + 64)
- # if char == 'M' and time.time() - last_char_time < 0.0005:
- # char = 'J'
- return "^"+char
- if first == 27:
- second = read_char(s)
- res = 'M-%s' % (second,)
- return res
- if 194 <= first:
- (code, c) = get_next_byte(s) # 2 bytes char
- char += c
- if 224 <= first:
- (code, c) = get_next_byte(s) # 3 bytes char
- char += c
- if 240 <= first:
- (code, c) = get_next_byte(s) # 4 bytes char
- char += c
- try:
- return char.decode('utf-8') # return all the concatened byte objets, decoded
- except UnicodeDecodeError:
+ while first is not None or char is not None:
+ if not isinstance(first, int): # Keyboard special, like KEY_HOME etc
+ return [char]
+ if first == 127 or first == 8:
+ return ["KEY_BACKSPACE"]
+ s.timeout(0) # we are now getting the missing utf-8 bytes to get a whole char
+ if first < 127: # ASCII char on one byte
+ if first <= 26: # transform Ctrl+* keys
+ char = chr(first + 64)
+ ret_list.append("^"+char)
+ (first, char) = get_next_byte(s)
+ continue
+ if first == 27:
+ second = read_char(s, 0)
+ res = 'M-%s' % (second[0],)
+ ret_list.append(res)
+ (first, char) = get_next_byte(s)
+ continue
+ if 194 <= first:
+ (code, c) = get_next_byte(s) # 2 bytes char
+ char += c
+ if 224 <= first:
+ (code, c) = get_next_byte(s) # 3 bytes char
+ char += c
+ if 240 <= first:
+ (code, c) = get_next_byte(s) # 4 bytes char
+ char += c
+ try:
+ ret_list.append(char.decode('utf-8')) # return all the concatened byte objets, decoded
+ except UnicodeDecodeError:
+ return None
+ # s.timeout(1) # timeout to detect a paste of many chars
+ (first, char) = get_next_byte(s)
+ if not ret_list:
+ # nothing at all was read, that’s a timed event timeout
return None
+ if len(ret_list) != 1:
+ if ret_list[-1] == '^M':
+ ret_list.pop(-1)
+ return [char if char != '^M' else '^J' for char in ret_list]
+ return ret_list
if __name__ == '__main__':
import curses