Merge branch 'master' into finnish

Conflicts:
	po/solaar.pot - run po-compile.sh
This commit is contained in:
Tomi Leppänen 2013-09-29 16:24:06 +03:00
commit d5f14bb5f8
26 changed files with 497 additions and 86 deletions

View File

@ -82,10 +82,10 @@ Mice (Unifying):
| M525 | 2.0 | yes | - | | | M525 | 2.0 | yes | - | |
| M600 Touch | 2.0 | yes | | | | M600 Touch | 2.0 | yes | | |
| M705 Marathon | 1.0 | yes | - | smooth scrolling | | M705 Marathon | 1.0 | yes | - | smooth scrolling |
| T400 Zone Touch | | | | | | T400 Zone Touch | 2.0 | yes | | |
| T620 Touch | 2.0 | yes | | | | T620 Touch | 2.0 | yes | | |
| Performance MX | 1.0 | yes | R/W | | | Performance MX | 1.0 | yes | R/W | |
| Anywhere MX | 1.0 | yes | - | | | Anywhere MX | 1.0 | yes | R/W | smooth scrolling |
| Cube | 2.0 | yes | | | | Cube | 2.0 | yes | | |

View File

@ -0,0 +1,88 @@
Receiver
LZ301AR-DJ
M/N:C-U0007
(ltunify)
Serial number: D1759614
Firmware version: 012.001.00019
Bootloader version: BL.002.014
Supported notification flags: 00 09 00
- 01: Wireless Notifications
- 08: Software Present
Mouse
(ltunify)
HID++ version: 1.0
Device index 1
Mouse
Name: Anywhere MX
Wireless Product ID: 1017
Serial number: 13865F99
Firmware version: 016.001.00040
Bootloader version: BL.002.010
(solaar)
Unifying Receiver
Device path : /dev/hidraw2
USB id : 046d:c52b
Serial : D1759614
Firmware : 12.01.B0019
Bootloader : 02.14
Has 1 paired device(s) out of a maximum of 6.
Notifications: (none)
Device activity counters: 1=19
1: Anywhere Mouse MX
Codename : Anywhere MX
Kind : mouse
Wireless PID : 1017
Protocol : HID++ 1.0
Polling rate : 8 ms (125Hz)
Serial number: 13865F99
Firmware: 16.01.B0040
Bootloader: 02.10
Other: 00.06
The power switch is located on the base.
Notifications: (none).
Battery: 100%, discharging.
(scan-registers)
# Old notification flags: 000000
# 00 - Enabled Notifications, supported flags: Battery Status (10)
>> ( 0.792) [10 01 8100 100000] b'\x10\x01\x81\x00\x10\x00\x00'
# 01 - scrolling settings?
# Flags:
# 0x40 - Enable Smooth Scrolling
# 0x02 - "confuse KDE", see https://github.com/pwr/Solaar/issues/115
<< ( 0.011) [10 01 8101 000000] b'\x10\x01\x81\x01\x00\x00\x00'
>> ( 1.710) [10 01 8101 020000] b'\x10\x01\x81\x01\x02\x00\x00'
# 0D - battery level. first byte is remaining charge in percent; second is
# (guessed) maximum?; third is charge status (30=discharging)
# "10 ix 0D 64 64 30 00" is a battery notification (when enabled)
<< ( 9.789) [10 01 810D 000000] b'\x10\x01\x81\r\x00\x00\x00'
>> ( 9.816) [10 01 810D 646430] b'\x10\x01\x81\rdd0'
# 63 - DPI (range 0x80-0x8e (inclusive))
<< ( 75.521) [10 01 8163 000000] b'\x10\x01\x81c\x00\x00\x00'
>> ( 75.550) [10 01 8163 890000] b'\x10\x01\x81c\x89\x00\x00'
# D0 - ?
<< ( 163.118) [10 01 81D0 000000] b'\x10\x01\x81\xd0\x00\x00\x00'
>> ( 163.148) [10 01 81D0 000000] b'\x10\x01\x81\xd0\x00\x00\x00'
# D4 - ?
<< ( 166.034) [10 01 81D4 000000] b'\x10\x01\x81\xd4\x00\x00\x00'
>> ( 166.063) [10 01 81D4 000008] b'\x10\x01\x81\xd4\x00\x00\x08'
# F1 - firmware/bootloader version
<< ( 187.172) [10 01 81F1 000000] b'\x10\x01\x81\xf1\x00\x00\x00'
>> ( 187.199) [10 01 8F81 F10300] b'\x10\x01\x8f\x81\xf1\x03\x00'
# F3 - ?
<< ( 188.629) [10 01 81F3 000000] b'\x10\x01\x81\xf3\x00\x00\x00'
>> ( 188.661) [10 01 81F3 000000] b'\x10\x01\x81\xf3\x00\x00\x00'
# FD - ?
<< ( 195.715) [10 01 83FD 000000] b'\x10\x01\x83\xfd\x00\x00\x00'
>> ( 195.746) [11 01 83FD 00000000000000000000000000000000] b'\x11\x01\x83\xfd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

39
docs/devices/k750.txt Normal file
View File

@ -0,0 +1,39 @@
(from Julien Danjou)
(solaar)
2: Wireless Solar Keyboard K750
Codename : K750
Kind : keyboard
Wireless PID : 4002
Protocol : HID++ 2.0
Polling rate : 20 ms (50Hz)
Serial number: 5692B2EC
Firmware: RQK 33.00.B0015
Bootloader: DFU 00.02.B0003
The power switch is located on the edge of top right corner.
Supports 11 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: REPROG CONTROLS {1B00}
5: WIRELESS DEVICE STATUS {1D4B}
6: unknown:1DF3 {1DF3} hidden
7: FN INVERSION {40A0}
8: ENCRYPTION {4100}
9: SOLAR DASHBOARD {4301}
10: KEYBOARD LAYOUT {4520}
Has 12 reprogrammable keys:
0: MY HOME => HomePage FN sensitive, is FN, reprogrammable
1: Mail => Email FN sensitive, is FN, reprogrammable
2: SEARCH => Search FN sensitive, is FN, reprogrammable
3: Calculator => Calculator FN sensitive, is FN, reprogrammable
4: MEDIA PLAYER => Music FN sensitive, is FN, reprogrammable
5: Previous => Previous FN sensitive, is FN
6: Play/Pause => Play/Pause FN sensitive, is FN
7: Next => Next FN sensitive, is FN
8: Mute => Mute FN sensitive, is FN
9: Volume Down => Volume Down FN sensitive, is FN
10: Volume Up => Volume Up FN sensitive, is FN
11: SLEEP => Sleep FN sensitive, is FN, reprogrammable
Battery status unavailable.

View File

@ -1,2 +1,56 @@
No non-error messages received for GET_REG and GET_REG_LONG. Perhaps because Mouse
this is a HID++ 2.0 device? (ltunify)
HID++ version: 2.0
Device index 1
Mouse
Name: M525
Wireless Product ID: 4013
Serial number: DAFA335E
Device was unavailable, version information not available.
Total number of HID++ 2.0 features: 12
0: [0000] IRoot
1: [0001] IFeatureSet
2: [0003] IFirmwareInfo
3: [0005] GetDeviceNameType
4: [1000] batteryLevelStatus
5: [1D4B] WirelessDeviceStatus
6: [1DF3] H unknown
7: [1B00] SpecialKeysMSEButtons
8: [1DF0] H unknown
9: [1F03] H unknown
10: [2100] VerticalScrolling
11: [2120] HiResScrolling
12: [2200] MousePointer
(O = obsolete feature; H = SW hidden feature;
I = reserved for internal use)
(solaar)
1: Wireless Mouse M525
Codename : M525
Kind : mouse
Wireless PID : 4013
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: DAFA335E
Firmware: RQM 27.02.B0028
The power switch is located on the base.
Supports 13 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: DEVICE FW VERSION {0003}
3: DEVICE NAME {0005}
4: BATTERY STATUS {1000}
5: WIRELESS DEVICE STATUS {1D4B}
6: unknown:1DF3 {1DF3} hidden
7: REPROG CONTROLS {1B00}
8: unknown:1DF0 {1DF0} hidden
9: unknown:1F03 {1F03} hidden
10: VERTICAL SCROLLING {2100}
11: HI RES SCROLLING {2120}
12: MOUSE POINTER {2200}
Has 5 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable
3: BACK AS BUTTON 4 => Back mse, reprogrammable
4: FORWARD AS BUTTON 5 => BrowserForward mse, reprogrammable
Battery: 90%, discharging.

109
docs/devices/t400.txt Normal file
View File

@ -0,0 +1,109 @@
Receiver
LZ2388S-DJ
M/N:C-U0007
(ltunify)
Serial number: E6B794F8
Firmware version: 012.001.00019
Bootloader version: BL.002.014
Mouse
(ltunify)
HID++ version: 2.0
Device index 1
Mouse
Name: T400
Wireless Product ID: 4026
Serial number: 131A3093
Device was unavailable, version information not available.
Total number of HID++ 2.0 features: 27
0: [0000] IRoot
1: [0001] IFeatureSet
2: [0002] unknown
3: [0003] IFirmwareInfo
4: [0005] GetDeviceNameType
5: [00C0] DFUControl
6: [1000] batteryLevelStatus
7: [1802] HI unknown
8: [1810] HI unknown
9: [1830] HI unknown
10: [1850] HI unknown
11: [1860] HI unknown
12: [1890] HI unknown
13: [18A0] HI unknown
14: [18E3] HI unknown
15: [1B00] SpecialKeysMSEButtons
16: [1D4B] WirelessDeviceStatus
17: [1DF3] HI unknown
18: [1E00] H unknown
19: [1E80] HI unknown
20: [1F03] HI unknown
21: [1F04] HI unknown
22: [2100] VerticalScrolling
23: [2101] H unknown
24: [2120] HiResScrolling
25: [2200] MousePointer
26: [6110] H TouchmouseRawPoints
27: [1B03] ReprogControlsV3
(O = obsolete feature; H = SW hidden feature;
I = reserved for internal use)
(solaar)
Unifying Receiver
Device path : /dev/hidraw2
USB id : 046d:c52b
Serial : E6B794F8
Firmware : 12.01.B0019
Bootloader : 02.14
Has 1 paired device(s) out of a maximum of 6.
Notifications: (none)
Device activity counters: 1=134
1: Zone Touch Mouse T400
Codename : T400
Kind : mouse
Wireless PID : 4026
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: 131A3093
Firmware: RQM 39.00.B0029
Bootloader: BL 03.00
Hardware: 72
Other:
The power switch is located on the base.
Supports 28 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: FEATURE INFO {0002}
3: DEVICE FW VERSION {0003}
4: DEVICE NAME {0005}
5: DFUCONTROL {00C0}
6: BATTERY STATUS {1000}
7: unknown:1802 {1802} internal, hidden
8: unknown:1810 {1810} internal, hidden
9: unknown:1830 {1830} internal, hidden
10: unknown:1850 {1850} internal, hidden
11: unknown:1860 {1860} internal, hidden
12: unknown:1890 {1890} internal, hidden
13: unknown:18A0 {18A0} internal, hidden
14: unknown:18E3 {18E3} internal, hidden
15: REPROG CONTROLS {1B00}
16: WIRELESS DEVICE STATUS {1D4B}
17: unknown:1DF3 {1DF3} internal, hidden
18: unknown:1E00 {1E00} hidden
19: unknown:1E80 {1E80} internal, hidden
20: unknown:1F03 {1F03} internal, hidden
21: unknown:1F04 {1F04} internal, hidden
22: VERTICAL SCROLLING {2100}
23: unknown:2101 {2101} hidden
24: HI RES SCROLLING {2120}
25: MOUSE POINTER {2200}
26: TOUCHMOUSE RAW POINTS {6110} hidden
27: REPROG CONTROLS V3 {1B03}
Has 7 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable
3: METRO START SCREEN => MetroStartScreen mse, reprogrammable
4: ZOOMIN => Do Nothing mse, reprogrammable
5: ZOOMOUT => Do Nothing mse, reprogrammable
6: BACK HSCROLL => TouchBackForwardHorzScroll
Battery: 100%, discharging.

94
docs/devices/t650.txt Normal file
View File

@ -0,0 +1,94 @@
Receiver
LZ2458D-DJ
M/N:C-U0008
(ltunify)
Serial number: 28E69A3E
Firmware version: 024.000.00018
Bootloader version: BL.000.006
Touchpad
(ltunify)
HID++ version: 2.0
Device index 1
Touchpad
Name: T650
Wireless Product ID: 4101
Serial number: 22205A4D
Device was unavailable, version information not available.
Total number of HID++ 2.0 features: 22
0: [0000] IRoot
1: [0001] IFeatureSet
2: [0002] unknown
3: [0003] IFirmwareInfo
4: [0005] GetDeviceNameType
5: [1000] batteryLevelStatus
6: [1D4B] WirelessDeviceStatus
7: [1DF3] HI unknown
8: [1B00] SpecialKeysMSEButtons
9: [1F03] HI unknown
10: [2100] VerticalScrolling
11: [2120] HiResScrolling
12: [2200] MousePointer
13: [00C0] DFUControl
14: [1E80] HI unknown
15: [6100] TouchpadRawXy
16: [1860] HI unknown
17: [1E00] H unknown
18: [1B01] ReprogControlsV2
19: [1890] HI unknown
20: [18E5] HI unknown
21: [18A0] HI unknown
22: [1830] HI unknown
(O = obsolete feature; H = SW hidden feature;
I = reserved for internal use)
(solaar)
Unifying Receiver
Device path : /dev/hidraw2
USB id : 046d:c52b
Serial : 28E69A3E
Firmware : 24.00.B0018
Bootloader : 00.06
Has 1 paired device(s) out of a maximum of 6.
Notifications: (none)
Device activity counters: 1=221
1: Wireless Rechargeable Touchpad T650
Codename : T650
Kind : touchpad
Wireless PID : 4101
Protocol : HID++ 2.0
Polling rate : 8 ms (125Hz)
Serial number: 22205A4D
Firmware: RQM 41.01.B0037
Bootloader: BL 03.00
Hardware: 72
Other:
The power switch is located on the base.
Supports 23 HID++ 2.0 features:
0: ROOT {0000}
1: FEATURE SET {0001}
2: FEATURE INFO {0002}
3: DEVICE FW VERSION {0003}
4: DEVICE NAME {0005}
5: BATTERY STATUS {1000}
6: WIRELESS DEVICE STATUS {1D4B}
7: unknown:1DF3 {1DF3} internal, hidden
8: REPROG CONTROLS {1B00}
9: unknown:1F03 {1F03} internal, hidden
10: VERTICAL SCROLLING {2100}
11: HI RES SCROLLING {2120}
12: MOUSE POINTER {2200}
13: DFUCONTROL {00C0}
14: unknown:1E80 {1E80} internal, hidden
15: TOUCHPAD RAW XY {6100}
16: unknown:1860 {1860} internal, hidden
17: unknown:1E00 {1E00} hidden
18: REPROG CONTROLS V2 {1B01}
19: unknown:1890 {1890} internal, hidden
20: unknown:18E5 {18E5} internal, hidden
21: unknown:18A0 {18A0} internal, hidden
22: unknown:1830 {1830} internal, hidden
Has 2 reprogrammable keys:
0: LEFT CLICK => LeftClick mse, reprogrammable
1: RIGHT CLICK => RightClick mse, reprogrammable
Battery: 50%, discharging.

View File

@ -210,9 +210,10 @@ class FeaturesArray(object):
indices = index.indices(len(self.features)) indices = index.indices(len(self.features))
return [self.__getitem__(i) for i in range(*indices)] return [self.__getitem__(i) for i in range(*indices)]
def __contains__(self, value): def __contains__(self, featureId):
"""Tests whether the list contains given Feature ID"""
if self._check(): if self._check():
ivalue = int(value) ivalue = int(featureId)
may_have = False may_have = False
for f in self.features: for f in self.features:
@ -220,8 +221,6 @@ class FeaturesArray(object):
may_have = True may_have = True
elif ivalue == int(f): elif ivalue == int(f):
return True return True
elif ivalue < int(f):
break
if may_have: if may_have:
reply = self.device.request(0x0000, _pack('!H', ivalue)) reply = self.device.request(0x0000, _pack('!H', ivalue))
@ -231,17 +230,16 @@ class FeaturesArray(object):
self.features[index] = FEATURE[ivalue] self.features[index] = FEATURE[ivalue]
return True return True
def index(self, value): def index(self, featureId):
"""Gets the Feature Index for a given Feature ID"""
if self._check(): if self._check():
may_have = False may_have = False
ivalue = int(value) ivalue = int(featureId)
for index, f in enumerate(self.features): for index, f in enumerate(self.features):
if f is None: if f is None:
may_have = True may_have = True
elif ivalue == int(f): elif ivalue == int(f):
return index return index
elif ivalue < int(f):
raise ValueError("%r not in list" % value)
if may_have: if may_have:
reply = self.device.request(0x0000, _pack('!H', ivalue)) reply = self.device.request(0x0000, _pack('!H', ivalue))
@ -250,7 +248,7 @@ class FeaturesArray(object):
self.features[index] = FEATURE[ivalue] self.features[index] = FEATURE[ivalue]
return index return index
raise ValueError("%r not in list" % value) raise ValueError("%r not in list" % featureId)
def __iter__(self): def __iter__(self):
if self._check(): if self._check():

View File

@ -127,7 +127,7 @@ def _process_hidpp10_custom_notification(device, status, n):
status.set_battery_info(charge, status_text) status.set_battery_info(charge, status_text)
return True return True
if n.sub_id == _R.illumination: if n.sub_id == _R.keyboard_illumination:
# message layout: 10 ix 17("address") <??> <?> <??> <light level 1=off..5=max> # message layout: 10 ix 17("address") <??> <?> <??> <light level 1=off..5=max>
# TODO anything we can do with this? # TODO anything we can do with this?
if _log.isEnabledFor(_INFO): if _log.isEnabledFor(_INFO):
@ -189,7 +189,7 @@ def _process_hidpp10_notification(device, status, n):
if n.address == 0x01: if n.address == 0x01:
if _log.isEnabledFor(_DEBUG): if _log.isEnabledFor(_DEBUG):
_log.debug("%s: device powered on", device) _log.debug("%s: device powered on", device)
reason = str(status) or _("powered on") reason = status.to_string() or _("powered on")
status.changed(active=True, alert=_ALERT.NOTIFICATION, reason=reason) status.changed(active=True, alert=_ALERT.NOTIFICATION, reason=reason)
else: else:
_log.warn("%s: unknown %s", device, n) _log.warn("%s: unknown %s", device, n)

View File

@ -139,7 +139,7 @@ class DeviceStatus(dict):
# timestamp of when this status object was last updated # timestamp of when this status object was last updated
self.updated = 0 self.updated = 0
def __str__(self): def to_string(self):
def _items(): def _items():
comma = False comma = False
@ -163,8 +163,6 @@ class DeviceStatus(dict):
return ''.join(i for i in _items()) return ''.join(i for i in _items())
__unicode__ = __str__
def __repr__(self): def __repr__(self):
return '{' + ', '.join('\'%s\': %r' % (k, v) for k, v in self.items()) + '}' return '{' + ', '.join('\'%s\': %r' % (k, v) for k, v in self.items()) + '}'
@ -202,9 +200,9 @@ class DeviceStatus(dict):
# only show the notification once # only show the notification once
alert = ALERT.NOTIFICATION | ALERT.ATTENTION alert = ALERT.NOTIFICATION | ALERT.ATTENTION
if isinstance(level, _NamedInt): if isinstance(level, _NamedInt):
reason = 'battery: %s (%s)' % (level, status) reason = '%s: %s (%s)' % (_("Battery"), _(str(level)), _(str(status)))
else: else:
reason = 'battery: %d%% (%s)' % (level, status) reason = '%s: %d%% (%s)' % (_("Battery"), level, _(str(status)))
if changed or reason: if changed or reason:
# update the leds on the device, if any # update the leds on the device, if any

View File

@ -73,12 +73,15 @@ def _create_parser():
_cli_parser, actions = _create_parser() _cli_parser, actions = _create_parser()
print_help = _cli_parser.print_help
def _receivers(): def _receivers(dev_path=None):
from logitech_receiver import Receiver from logitech_receiver import Receiver
from logitech_receiver.base import receivers from logitech_receiver.base import receivers
for dev_info in receivers(): for dev_info in receivers():
if dev_path is not None and dev_path != dev_info.path:
continue
try: try:
r = Receiver.open(dev_info) r = Receiver.open(dev_info)
if _log.isEnabledFor(_DEBUG): if _log.isEnabledFor(_DEBUG):
@ -129,21 +132,23 @@ def _find_device(receivers, name):
raise Exception("no device found matching '%s'" % name) raise Exception("no device found matching '%s'" % name)
def run(cli_args=None): def run(cli_args=None, hidraw_path=None):
if cli_args == 'help':
_cli_parser.print_help()
return
if cli_args: if cli_args:
action = cli_args[0] action = cli_args[0]
args = _cli_parser.parse_args(cli_args) args = _cli_parser.parse_args(cli_args)
else: else:
args = _cli_parser.parse_args() args = _cli_parser.parse_args()
# Python 3 has an undocumented 'feature' that breaks parsing empty args
# http://bugs.python.org/issue16308
if not 'cmd' in args:
_cli_parser.print_usage(_sys.stderr)
_sys.stderr.write('%s: error: too few arguments\n' % NAME.lower())
_sys.exit(2)
action = args.action action = args.action
assert action in actions assert action in actions
try: try:
c = list(_receivers()) c = list(_receivers(hidraw_path))
if not c: if not c:
raise Exception('Logitech receiver not found') raise Exception('Logitech receiver not found')

View File

@ -107,10 +107,13 @@ def _print_device(dev):
if battery is not None: if battery is not None:
from logitech_receiver.common import NamedInt as _NamedInt from logitech_receiver.common import NamedInt as _NamedInt
level, status = battery level, status = battery
if isinstance(level, _NamedInt): if level is not None:
text = str(level) if isinstance(level, _NamedInt):
text = str(level)
else:
text = '%d%%' % level
else: else:
text = '%d%%' % level text = 'N/A'
print (' Battery: %s, %s.' % (text, status)) print (' Battery: %s, %s.' % (text, status))
else: else:
print (' Battery status unavailable.') print (' Battery status unavailable.')
@ -128,12 +131,14 @@ def run(receivers, args, find_receiver, find_device):
for r in receivers: for r in receivers:
_print_receiver(r) _print_receiver(r)
count = r.count() count = r.count()
for dev in r: if count:
print ('') for dev in r:
_print_device(dev) print ('')
count -= 1 _print_device(dev)
if count == 0: count -= 1
break if not count:
break
print ('')
return return
dev = find_receiver(receivers, device_name) dev = find_receiver(receivers, device_name)

View File

@ -42,6 +42,10 @@ def _parse_arguments():
arg_parser = argparse.ArgumentParser(prog=NAME.lower()) arg_parser = argparse.ArgumentParser(prog=NAME.lower())
arg_parser.add_argument('-d', '--debug', action='count', default=0, arg_parser.add_argument('-d', '--debug', action='count', default=0,
help='print logging messages, for debugging purposes (may be repeated for extra verbosity)') help='print logging messages, for debugging purposes (may be repeated for extra verbosity)')
arg_parser.add_argument('-D', '--hidraw', action='store', dest='hidraw_path', metavar='PATH',
help='unifying receiver to use; the first detected receiver if unspecified. Example: /dev/hidraw2')
arg_parser.add_argument('--restart-on-wake-up', action='store_true',
help='restart Solaar on sleep wake-up (experimental)')
arg_parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__) arg_parser.add_argument('-V', '--version', action='version', version='%(prog)s ' + __version__)
arg_parser.add_argument('--help-actions', action='store_true', arg_parser.add_argument('--help-actions', action='store_true',
help='print help for the optional actions') help='print help for the optional actions')
@ -51,7 +55,8 @@ def _parse_arguments():
args = arg_parser.parse_args() args = arg_parser.parse_args()
if args.help_actions: if args.help_actions:
return 'help' _cli.print_help()
return
import logging import logging
if args.debug > 0: if args.debug > 0:
@ -62,11 +67,11 @@ def _parse_arguments():
logging.root.addHandler(logging.NullHandler()) logging.root.addHandler(logging.NullHandler())
logging.root.setLevel(logging.ERROR) logging.root.setLevel(logging.ERROR)
if args.action: if not args.action:
return args.action if logging.root.isEnabledFor(logging.INFO):
logging.info("language %s (%s), translations path %s", _i18n.language, _i18n.encoding, _i18n.path)
if logging.root.isEnabledFor(logging.INFO): return args
logging.info("language %s (%s), translations path %s", _i18n.language, _i18n.encoding, _i18n.path)
def main(): def main():
@ -76,9 +81,9 @@ def main():
import signal import signal
signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGINT, signal.SIG_DFL)
cli_action = _parse_arguments() args = _parse_arguments()
if cli_action: if not args: return
return _cli.run(cli_action) if args.action: return _cli.run(args.action, args.hidraw_path)
_require('gi.repository', 'python-gi') _require('gi.repository', 'python-gi')
_require('gi.repository.Gtk', 'gir1.2-gtk-3.0') _require('gi.repository.Gtk', 'gir1.2-gtk-3.0')
@ -87,6 +92,13 @@ def main():
import solaar.ui as ui import solaar.ui as ui
import solaar.listener as listener import solaar.listener as listener
listener.setup_scanner(ui.status_changed, ui.error_dialog) listener.setup_scanner(ui.status_changed, ui.error_dialog)
import solaar.upower as _upower
if args.restart_on_wake_up:
_upower.watch(listener.start_all, listener.stop_all)
else:
_upower.watch(listener.ping_all)
# main UI event loop # main UI event loop
ui.run_loop(listener.start_all, listener.stop_all) ui.run_loop(listener.start_all, listener.stop_all)
except Exception as e: except Exception as e:

View File

@ -268,9 +268,16 @@ def stop_all():
l.join() l.join()
# stop/start all receiver threads on suspend/resume events, if possible def ping_all():
from . import upower for l in _all_listeners.values():
upower.watch(start_all, stop_all) count = l.receiver.count()
if count:
for dev in l.receiver:
dev.ping()
l._status_changed(dev)
count -= 1
if not count:
break
from logitech_receiver import base as _base from logitech_receiver import base as _base

View File

@ -70,6 +70,7 @@ def _create_choice_control(setting):
_write_async(s, cbbox.get_active_id(), cbbox.get_parent()) _write_async(s, cbbox.get_active_id(), cbbox.get_parent())
c = Gtk.ComboBoxText() c = Gtk.ComboBoxText()
# TODO i18n text entries
for entry in setting.choices: for entry in setting.choices:
c.append(str(entry), str(entry)) c.append(str(entry), str(entry))
c.connect('changed', _combo_notify, setting) c.connect('changed', _combo_notify, setting)

View File

@ -117,7 +117,7 @@ try:
elif dev.status is None: elif dev.status is None:
message = _("unpaired") message = _("unpaired")
elif bool(dev.status): elif bool(dev.status):
message = dev.status.__str__() or _("connected") message = dev.status.to_string() or _("connected")
else: else:
message = _("offline") message = _("offline")

View File

@ -281,7 +281,7 @@ def _generate_tooltip_lines():
if number is None: # receiver if number is None: # receiver
continue continue
p = str(status) p = status.to_string()
if p: # does it have any properties to print? if p: # does it have any properties to print?
yield '<b>%s</b>' % name yield '<b>%s</b>' % name
if status: if status:

View File

@ -530,7 +530,7 @@ def _update_details(button):
if read_all: if read_all:
for fw in list(device.firmware): for fw in list(device.firmware):
yield (' ' + str(fw.kind), (fw.name + ' ' + fw.version).strip()) yield (' ' + _(str(fw.kind)), (fw.name + ' ' + fw.version).strip())
elif device.kind is None or device.online: elif device.kind is None or device.online:
yield (' %s' % _("Firmware"), '...') yield (' %s' % _("Firmware"), '...')

View File

@ -43,7 +43,7 @@ def _resume():
_resume_callback() _resume_callback()
def watch(on_resume_callback, on_suspend_callback): def watch(on_resume_callback=None, on_suspend_callback=None):
"""Register callback for suspend/resume events. """Register callback for suspend/resume events.
They are called only if the system DBus is running, and the UPower daemon is available.""" They are called only if the system DBus is running, and the UPower daemon is available."""
global _resume_callback, _suspend_callback global _resume_callback, _suspend_callback

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "Project-Id-Version: solaar 0.9.2\n" msgstr "Project-Id-Version: solaar 0.9.2\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-11 16:49+0300\n" "POT-Creation-Date: 2013-09-29 16:22+0300\n"
"PO-Revision-Date: 2013-08-05 18:49+0300\n" "PO-Revision-Date: 2013-08-05 18:49+0300\n"
"Last-Translator: Tomi Leppänen\n" "Last-Translator: Tomi Leppänen\n"
"Language-Team: none\n" "Language-Team: none\n"
@ -179,6 +179,7 @@ msgid " paired devices."
msgstr " paritettua laitetta" msgstr " paritettua laitetta"
#: lib/logitech_receiver/status.py:149 lib/logitech_receiver/status.py:151 #: lib/logitech_receiver/status.py:149 lib/logitech_receiver/status.py:151
#: lib/logitech_receiver/status.py:203 lib/logitech_receiver/status.py:205
#: lib/solaar/ui/window.py:143 #: lib/solaar/ui/window.py:143
msgid "Battery" msgid "Battery"
msgstr "Akku" msgstr "Akku"
@ -252,11 +253,11 @@ msgstr "Tietoja"
msgid "Unpair" msgid "Unpair"
msgstr "Poista paritus" msgstr "Poista paritus"
#: lib/solaar/ui/config_panel.py:97 #: lib/solaar/ui/config_panel.py:98
msgid "Working" msgid "Working"
msgstr "Työskentelee" msgstr "Työskentelee"
#: lib/solaar/ui/config_panel.py:100 #: lib/solaar/ui/config_panel.py:101
msgid "Read/write operation failed." msgid "Read/write operation failed."
msgstr "Luku/kirjoitus operaatio epäonnistui." msgstr "Luku/kirjoitus operaatio epäonnistui."
@ -349,11 +350,11 @@ msgid "The wireless link between this device and its receiver is not "
"within range." "within range."
msgstr "Langaton yhteys laitteen ja vastaanottimen välillä ei ole salattu.\n" msgstr "Langaton yhteys laitteen ja vastaanottimen välillä ei ole salattu.\n"
"\n" "\n"
"Osoitinlaitteita (hiiret, ohjainpallot, tasohiiret) käytettäessä se on pieni " "Osoitinlaitteita (hiiret, ohjainpallot, tasohiiret) käytettäessä se "
"tietoturvallisuusriski.\n" "on pieni tietoturvallisuusriski.\n"
"\n" "\n"
"Kuitenkin, näppäimistöjen kanssa se on suuri tietoturvallisuusriski sillä " "Kuitenkin, näppäimistöjen kanssa se on suuri tietoturvallisuusriski "
"kolmannet osapuolet\n" "sillä kolmannet osapuolet\n"
"voivat lukea huomaamattomasti kirjoitetun tekstin yhteyden kantaman " "voivat lukea huomaamattomasti kirjoitetun tekstin yhteyden kantaman "
"sisällä." "sisällä."
@ -420,7 +421,6 @@ msgid "Protocol"
msgstr "Yhteyskäytäntö" msgstr "Yhteyskäytäntö"
#: lib/solaar/ui/window.py:524 #: lib/solaar/ui/window.py:524
#. fuzzy
msgid "Polling rate" msgid "Polling rate"
msgstr "Päivitysnopeus" msgstr "Päivitysnopeus"

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "Project-Id-Version: solaar 0.9.2\n" msgstr "Project-Id-Version: solaar 0.9.2\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-08 21:51+0200\n" "POT-Creation-Date: 2013-08-25 01:33+0300\n"
"PO-Revision-Date: 2013-08-07 14:43+0200\n" "PO-Revision-Date: 2013-08-07 14:43+0200\n"
"Last-Translator: Damien Lallement <dams@mageia.org>\n" "Last-Translator: Damien Lallement <dams@mageia.org>\n"
"Language-Team: Language: fr\n" "Language-Team: Language: fr\n"
@ -255,11 +255,11 @@ msgstr "À propos de"
msgid "Unpair" msgid "Unpair"
msgstr "Déconnecter" msgstr "Déconnecter"
#: lib/solaar/ui/config_panel.py:97 #: lib/solaar/ui/config_panel.py:98
msgid "Working" msgid "Working"
msgstr "En fonctionnement" msgstr "En fonctionnement"
#: lib/solaar/ui/config_panel.py:100 #: lib/solaar/ui/config_panel.py:101
msgid "Read/write operation failed." msgid "Read/write operation failed."
msgstr "Les opérations de lecture/écriture ont échoué." msgstr "Les opérations de lecture/écriture ont échoué."

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "Project-Id-Version: solaar 0.9.1\n" msgstr "Project-Id-Version: solaar 0.9.1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-08 21:53+0200\n" "POT-Creation-Date: 2013-08-25 01:33+0300\n"
"PO-Revision-Date: 2013-07-23 10:41+0100\n" "PO-Revision-Date: 2013-07-23 10:41+0100\n"
"Last-Translator: Adrian Piotrowicz <nexces@nxstudio.pl>\n" "Last-Translator: Adrian Piotrowicz <nexces@nxstudio.pl>\n"
"Language-Team: none\n" "Language-Team: none\n"
@ -255,11 +255,11 @@ msgstr "O"
msgid "Unpair" msgid "Unpair"
msgstr "Usuń parowanie" msgstr "Usuń parowanie"
#: lib/solaar/ui/config_panel.py:97 #: lib/solaar/ui/config_panel.py:98
msgid "Working" msgid "Working"
msgstr "Pracuję" msgstr "Pracuję"
#: lib/solaar/ui/config_panel.py:100 #: lib/solaar/ui/config_panel.py:101
msgid "Read/write operation failed." msgid "Read/write operation failed."
msgstr "Operacja odczytu/zapisu nie powiodła się." msgstr "Operacja odczytu/zapisu nie powiodła się."

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "Project-Id-Version: solaar 0.9.1\n" msgstr "Project-Id-Version: solaar 0.9.1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-08 21:53+0200\n" "POT-Creation-Date: 2013-08-25 01:33+0300\n"
"PO-Revision-Date: 2013-07-17 20:27+0100\n" "PO-Revision-Date: 2013-07-17 20:27+0100\n"
"Last-Translator: Daniel Pavel <daniel.pavel@gmail.com>\n" "Last-Translator: Daniel Pavel <daniel.pavel@gmail.com>\n"
"Language-Team: none\n" "Language-Team: none\n"
@ -251,11 +251,11 @@ msgstr "Despre"
msgid "Unpair" msgid "Unpair"
msgstr "Deconectează" msgstr "Deconectează"
#: lib/solaar/ui/config_panel.py:97 #: lib/solaar/ui/config_panel.py:98
msgid "Working" msgid "Working"
msgstr "Prelucrez" msgstr "Prelucrez"
#: lib/solaar/ui/config_panel.py:100 #: lib/solaar/ui/config_panel.py:101
msgid "Read/write operation failed." msgid "Read/write operation failed."
msgstr "Operațiunea a eșuat." msgstr "Operațiunea a eșuat."

View File

@ -7,7 +7,7 @@
msgid "" msgid ""
msgstr "Project-Id-Version: solaar 0.9.2\n" msgstr "Project-Id-Version: solaar 0.9.2\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-11 16:49+0300\n" "POT-Creation-Date: 2013-09-29 16:22+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -173,6 +173,7 @@ msgid " paired devices."
msgstr "" msgstr ""
#: lib/logitech_receiver/status.py:149 lib/logitech_receiver/status.py:151 #: lib/logitech_receiver/status.py:149 lib/logitech_receiver/status.py:151
#: lib/logitech_receiver/status.py:203 lib/logitech_receiver/status.py:205
#: lib/solaar/ui/window.py:143 #: lib/solaar/ui/window.py:143
msgid "Battery" msgid "Battery"
msgstr "" msgstr ""
@ -242,11 +243,11 @@ msgstr ""
msgid "Unpair" msgid "Unpair"
msgstr "" msgstr ""
#: lib/solaar/ui/config_panel.py:97 #: lib/solaar/ui/config_panel.py:98
msgid "Working" msgid "Working"
msgstr "" msgstr ""
#: lib/solaar/ui/config_panel.py:100 #: lib/solaar/ui/config_panel.py:101
msgid "Read/write operation failed." msgid "Read/write operation failed."
msgstr "" msgstr ""

View File

@ -6,8 +6,8 @@
msgid "" msgid ""
msgstr "Project-Id-Version: solaar 0.9.1\n" msgstr "Project-Id-Version: solaar 0.9.1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-08-08 19:46+0200\n" "POT-Creation-Date: 2013-08-25 01:33+0300\n"
"PO-Revision-Date: 2013-07-27 16:28+0100\n" "PO-Revision-Date: 2013-08-20 22:43+0100\n"
"Last-Translator: Daniel Zippert & Emelie Snecker <daniel@zippert." "Last-Translator: Daniel Zippert & Emelie Snecker <daniel@zippert."
"se>\n" "se>\n"
"Language-Team: none\n" "Language-Team: none\n"
@ -98,15 +98,15 @@ msgstr "Annan"
#: lib/logitech_receiver/notifications.py:67 #: lib/logitech_receiver/notifications.py:67
msgid "closed" msgid "closed"
msgstr "låst" msgstr "inaktiverat"
#: lib/logitech_receiver/notifications.py:67 #: lib/logitech_receiver/notifications.py:67
msgid "open" msgid "open"
msgstr "öppen" msgstr "aktiverat"
#: lib/logitech_receiver/notifications.py:67 #: lib/logitech_receiver/notifications.py:67
msgid "pairing lock is " msgid "pairing lock is "
msgstr "parkopplingsläge låst" msgstr "parkopplingsläget är "
#: lib/logitech_receiver/notifications.py:150 lib/solaar/ui/notify.py:118 #: lib/logitech_receiver/notifications.py:150 lib/solaar/ui/notify.py:118
msgid "unpaired" msgid "unpaired"
@ -207,8 +207,8 @@ msgstr "Behörighetsfel"
#, python-format #, python-format
msgid "Found a Logitech Receiver (%s), but did not have permission to open " msgid "Found a Logitech Receiver (%s), but did not have permission to open "
"it." "it."
msgstr "En Logitech mottagare hittades (%s), men behörighet att använda " msgstr "En Logitech mottagare hittades (%s), men behörighet att använda den "
"den saknas." "saknas."
#: lib/solaar/ui/__init__.py:51 #: lib/solaar/ui/__init__.py:51
msgid "If you've just installed Solaar, try removing the receiver and " msgid "If you've just installed Solaar, try removing the receiver and "
@ -227,13 +227,13 @@ msgstr "Misslyckades att bryta parkoppling mellan %{device} och %{receiver}."
#: lib/solaar/ui/__init__.py:56 #: lib/solaar/ui/__init__.py:56
msgid "The receiver returned an error, with no further details." msgid "The receiver returned an error, with no further details."
msgstr "Mottagaren rapporterade ett fel, utan specifika detaljer." msgstr "Mottagaren rapporterade ett fel, utan specifika detaljer."
#: lib/solaar/ui/about.py:39 #: lib/solaar/ui/about.py:39
msgid "Shows status of devices connected\n" msgid "Shows status of devices connected\n"
"through wireless Logitech receivers." "through wireless Logitech receivers."
msgstr "Visa status för enheter kopplade till\n" msgstr "Visa status för enheter kopplade till\n"
"din trådlösa Logitech mottagare" "din trådlösa Logitech mottagare"
#: lib/solaar/ui/about.py:48 #: lib/solaar/ui/about.py:48
msgid "GUI design" msgid "GUI design"
@ -256,11 +256,11 @@ msgstr "Om"
msgid "Unpair" msgid "Unpair"
msgstr "Ta bort parkoppling" msgstr "Ta bort parkoppling"
#: lib/solaar/ui/config_panel.py:97 #: lib/solaar/ui/config_panel.py:98
msgid "Working" msgid "Working"
msgstr "Lyckades" msgstr "Lyckades"
#: lib/solaar/ui/config_panel.py:100 #: lib/solaar/ui/config_panel.py:101
msgid "Read/write operation failed." msgid "Read/write operation failed."
msgstr "Läsning/Skrivning misslyckades." msgstr "Läsning/Skrivning misslyckades."
@ -286,7 +286,7 @@ msgstr "Se till så att enheten inom räckhåll, och har tillräckligt laddat "
#: lib/solaar/ui/pair_window.py:137 #: lib/solaar/ui/pair_window.py:137
msgid "A new device was detected, but it is not compatible with this " msgid "A new device was detected, but it is not compatible with this "
"receiver." "receiver."
msgstr "En ny enhet upptäcktes, men är inte kompatibel med mottagaren. " msgstr "En ny enhet upptäcktes, men är inte kompatibel med mottagaren. "
#: lib/solaar/ui/pair_window.py:139 #: lib/solaar/ui/pair_window.py:139
#, python-format #, python-format
@ -303,7 +303,7 @@ msgstr "Ny enhet har hittats"
#: lib/solaar/ui/pair_window.py:180 #: lib/solaar/ui/pair_window.py:180
msgid "The wireless link is not encrypted" msgid "The wireless link is not encrypted"
msgstr "Den trådlösa anslutningen är okrypterad" msgstr "Den trådlösa anslutningen är okrypterad"
#: lib/solaar/ui/pair_window.py:197 #: lib/solaar/ui/pair_window.py:197
msgid "pair new device" msgid "pair new device"
@ -337,7 +337,7 @@ msgstr "ingen status"
#: lib/solaar/ui/window.py:58 #: lib/solaar/ui/window.py:58
msgid "The wireless link between this device and its receiver is encrypted." msgid "The wireless link between this device and its receiver is encrypted."
msgstr "Den trådlösa anslutningen är krypterad." msgstr "Den trådlösa anslutningen är krypterad."
#: lib/solaar/ui/window.py:59 #: lib/solaar/ui/window.py:59
msgid "The wireless link between this device and its receiver is not " msgid "The wireless link between this device and its receiver is not "

View File

@ -71,7 +71,7 @@ battery status.
requires=['pyudev (>= 0.13)', 'gi.repository.GObject (>= 2.0)', 'gi.repository.Gtk (>= 3.0)'], requires=['pyudev (>= 0.13)', 'gi.repository.GObject (>= 2.0)', 'gi.repository.Gtk (>= 3.0)'],
package_dir={'': 'lib'}, package_dir={'': 'lib'},
packages=['hidapi', 'logitech_receiver', 'solaar', 'solaar.ui'], packages=['hidapi', 'logitech_receiver', 'solaar', 'solaar.ui', 'solaar.cli'],
data_files=list(_data_files()), data_files=list(_data_files()),
scripts=_glob('bin/*'), scripts=_glob('bin/*'),
) )